AutoGPT の LangChain 実装を試してみる(ver. GPT-3.5)

FacebooktwitterredditpinterestlinkedinmailFacebooktwitterredditpinterestlinkedinmail

参考:https://python.langchain.com/en/latest/use_cases/autonomous_agents/autogpt.html

本業に忙殺されたり LangChain のアップデートを終えてない間に AutoGPT が登場して、 LangChain 上でも実装(移植)されていたようなのでいじってみます。一度、 GPT-4 での実装とみたので、未だに GPT-3.5-turbo しか使わせてもらえない人には縁がないと思っていたのですが、 LangChain 上の AutoGPT は ChatOpenAI で動作する≒つまり GPT-3.5-turbo でも一応動作するっぽいのでやってみます。本来の性能は発揮されないと思いますが……。

AutoGPT を LangChain でやってみる

AutoGPT とは?

果たして LangChain で AutoGPT をやってみたいという人が知らないということがあるのでしょうか。筆者はなんとなく凄いということしか知らないのでいるかもしれません。

参考:https://github.com/Significant-Gravitas/Auto-GPT

適当に日本語で検索しても、自立型AIガーとかしかわからないので本家GitHubからの情報を要約すると、

  • 検索や情報収集ためのネットアクセス
  • 長期記憶と短期記憶(Memory)管理
  • テキスト生成のための LLM (GPT-4)へのアクセス(※ LangChain バージョンでは GPT-3.5-turboも許容される?)
  • 人気のあるサイトやプラットフォーム(WebAPIかな?)へのアクセス
  • GPT-3.5 でのファイル保存や要約
  • プラグインによる拡張

LangChain 登場当時からいじっている人ならなんとなく分かると思いますが、「つまり LangChain の agent だな!」ということだと思います。基本的に、 LangChain の Agent は ReACT 的なプロンプトで動いていると思いますが、より多くの Tool を活用するように進化させた Prompt を内包する Agent という解釈でいいと思います。

その他(旧来の LangChain Agent と比較して)特記すべき事項としては、 Agent に名前と Role(役割) を与えることが必須となっている点です。

とりあえず import とかから

LangChain のアップデートをサボっていると必要なパッケージが足りないことが多々あるので、必ず pip install -U langchain を走らせます。

from langchain.agents import Tool
from langchain.utilities import GoogleSearchAPIWrapper
from langchain.tools.file_management.write import WriteFileTool
from langchain.tools.file_management.read import ReadFileTool
from langchain.chat_models import ChatOpenAI
from langchain.vectorstores import FAISS
from langchain.docstore import InMemoryDocstore
from langchain.embeddings import OpenAIEmbeddings
import faiss
from langchain.experimental import AutoGPT

import os, key
os.environ["OPENAI_API_KEY"] = key.OPEN_API_KEY
os.environ["GOOGLE_CSE_ID"] = key.GOOGLE_CSE_ID
os.environ["GOOGLE_API_KEY"] = key.GOOGLE_API_KEY

key は .env から 読むなどは開発環境に応じて。 LangChain 公式のサンプルでは、 SerpAPI を使っていましたが、 GoogleSearchAPI でも問題ないはずなので、import するパッケージを変えています。

GoogleSearchAPIWrapper, WriteFileTool, ReadFileTool が LangChain のツールであり、 AutoGPT の言うところの「検索や情報収集のためのインターネットアクセス」と、「ファイル保存や要約」であると思われます。

一方、 FAISS 以下は「長期記憶と短期記憶」に該当します(今回は、 QA などの用途ではないです)。 LangChain の Agent ではこれらの Memory は方式により要約や flush の方式が異なりましたが、 prompt に memory の内容を書き出していました。が、 AutoGPT では vectorstore を用いるようです。これにより、 prompt の意図が希釈されないようになっていると推測されます。技術の組み合わせという意味では、この部分が一番大きな違いのように思います。

Tool と Memory のセットアップ

search = GoogleSearchAPIWrapper()
tools = [
    Tool(
        name = "search",
        func=search.run,
        description="useful for when you need to answer questions about current events. You should ask targeted questions"
    ),
    WriteFileTool(),
    ReadFileTool(),
]

# Define your embedding model
embeddings_model = OpenAIEmbeddings()

# Initialize the vectorstore as empty
embedding_size = 1536
# L2ノルム全探索用
index = faiss.IndexFlatL2(embedding_size)
vectorstore = FAISS(embeddings_model.embed_query, index, InMemoryDocstore({}), {})

検索用に GoogleAPI ラッパーと、ファイルの読み書きツールを Tools リストに格納します。

続いて、 OpenAI の Embeddings API と FAISS を使って Memory 用の vectore store を初期化します。ここでは空のメモリとなります。

AutoGPT の作成と実行

# AutoGPT をLangChainのagentとして(風に?)実体化
# Memory は vectorstore を retriever として
agent = AutoGPT.from_llm_and_tools(
    ai_name="Tom",
    ai_role="Assistant",
    tools=tools,
    llm=ChatOpenAI(temperature=0),
    memory=vectorstore.as_retriever()
)
# Set verbose to be true
agent.chain.verbose = True

agent.run(["write a weather report for SF today"])
agent.run(["東京の今日の天気予報を書いて"])
agent.run(["東京の今日の天気予報を日本語で教えてください。"])

ここまで述べてきたように、 AutoGPT は LangChain の視点でみると Agent の一種となります。そのため、実体化も agent のそれとほぼ差がありません。ただし、 ai_name, ai_role を与える必要があります。この要素がどこまで出力に影響があるかは不明です。が、 role は意味がはっきりしているために適切なものを選んだ方がよさそうですね(「あなたは優秀なマーケターです」とか prompt に入れる感じですね)。

また、 memory はこれまで記述してきたように vectorestore を用いますが、インスタンスを直接 memory 引数に入れるのではなく、as_retriever() メソッドでretriever として取得します。

最終的な実行は、agent.run であり、LangChain の他の Agent と同様です。

実行結果の確認

サンフランシスコの天気予報

The weather in San Francisco today is sunny with a high of 70 degrees Fahrenheit and a low of 55 degrees Fahrenheit.

季節感とかよく分かりませんが、多分あっているのでしょう。あと、SF 表記で サンフランシスコであるときちんと理解していますね。

東京の天気予報を書いて

Hourly weather forecast in Tokyo, Tokyo, Japan. Check current conditions in Tokyo, Tokyo, Japan with radar, hourly, and more. Be prepared with the most accurate 10-day forecast for Minato-ku, Tokyo Prefecture, Japan with highs, lows, chance of precipitation from The Weather Channel … Tokyo, Tokyo, Japan Weather Forecast, with current conditions, wind, air quality, and what to expect for the next 3 days. Today’s and tonight’s Minato-ku, Tokyo Prefecture, Japan weather forecast, weather conditions and Doppler radar from The Weather Channel and Weather.com. TodayHourly14 DaysPastClimate. Currently: 53 °F. Passing clouds. (Weather station: Tokyo, Japan). See more current weather. Tokyo Weather Forecasts. Weather Underground provides local & long-range weather forecasts, weatherreports, maps & tropical weather conditions for the Tokyo … Current weather in Tokyo and forecast for today, tomorrow, and next 14 days. Tokyo, Tokyo Prefecture, Japan Weather Conditionsstar_ratehome … Today’s temperature is forecast to be WARMER than yesterday. Radar; Satellite. Forecast for the coming week for Tokyo, shown in an hour-by-hour graph. … See more current weather … Hour-by-hour Forecast in Tokyo — Graph. 14-day weather forecast for Tokyo. … A gentle breeze from the north north east. See more weather for. Saturday 22nd. Last updated today at 19:00 …

東京の天気予報を日本語で

東京の天気予報:曇時々晴。最高気温は18.9℃、最低気温は12.2℃です。

大体あっているような気もしますが、本日は大分寒いので最低気温12.2度というのは違うような……(実行時の時点での最低気温≒現在気温に近い数値)

日本語はやはり弱いのか?

GPT-3.5-turbo で動かしているからか、「日本語で」という記述を入れていない2番目の結果がかなりお粗末です。DeepL などで翻訳しても意味をほぼなしていないというか、天気予報サイトの検索結果の内容を適当につなぎあわせただけの結果に見えます。GPT-2とか、そのくらいの精度にみえますね。

Verbose の内容を見てみる

全て見るのは大変なので、一部だけ console の出力を見て見ます。

Prompt 的な部分

> Entering new LLMChain chain...
Prompt after formatting:
System: You are Tom, Assistant
Your decisions must always be made independently 
            without seeking user assistance. Play to your strengths 
            as an LLM and pursue simple strategies with no legal complications. 
            If you have completed all your tasks, 
            make sure to use the "finish" command.

GOALS:

1. write a weather report for SF today


Constraints:
1. ~4000 word limit for short term memory. Your short term memory is short, so immediately save important information to files.
2. If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.
3. No user assistance
4. Exclusively use the commands listed in double quotes e.g. "command name"

Commands:
1. search: useful for when you need to answer questions about current events. You should ask targeted questions, args json schema: {"query": {"title": "Query", "type": "string"}}
2. write_file: Write file to disk, args json schema: {"file_path": {"title": "File Path", "description": "name of file", "type": "string"}, "text": {"title": "Text", "description": "text to write to file", "type": "string"}}
3. read_file: Read file from disk, args json schema: {"file_path": {"title": "File Path", "description": "name of file", "type": "string"}}
4. finish: use this to signal that you have finished all your objectives, args: "response": "final response to let people know you have finished your objectives"

Resources:
1. Internet access for searches and information gathering.
2. Long Term memory management.
3. GPT-3.5 powered Agents for delegation of simple tasks.
4. File output.

Performance Evaluation:
1. Continuously review and analyze your actions to ensure you are performing to the best of your abilities.
2. Constructively self-criticize your big-picture behavior constantly.
3. Reflect on past decisions and strategies to refine your approach.
4. Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps.

You should only respond in JSON format as described below 
Response Format: 
{
    "thoughts": {
        "text": "thought",
        "reasoning": "reasoning",
        "plan": "- short bulleted\n- list that conveys\n- long-term plan",
        "criticism": "constructive self-criticism",
        "speak": "thoughts summary to say to user"
    },
    "command": {
        "name": "command name",
        "args": {
            "arg name": "value"
        }
    }
} 
Ensure the response can be parsed by Python json.loads
System: The current time and date is Sun Apr 23 08:17:10 2023
System: This reminds you of these events from your past:
[]


Human: Determine which next command to use, and respond using the format specified above:

> Finished chain.

Prompt はかなり複雑に成形されているようです。

概ね

  1. 名前と役割の定義
  2. どのように問題を解決すべきかの指示と、Finish  コマンドにより終了するルールの定義
    「LLMとしての強みを発揮し、法的な複雑さを伴わないシンプルな戦略を追求」という部分が、ChatGPT に再帰的に文章を校正させる流行の prompt と逆を行く感じで面白いですね。
  3. GOALの設定。ここにはユーザーの実際の入力が入っているようです(複雑な prompt があった場合は、 LLMChain で解釈・展開が行われそうですが)
  4. 制約事項の列挙。メモリの制限を記載し、更に溢れる場合はファイルに記述を進めたり、思い出し方のアドバイス(vector search の特性を踏まえてと思われる)が含まれているところが面白いです。更に、ユーザーに助けを求めてはいけない、自律をここでも制約事項として定めています。
  5. 使えるリソースの定義。追加された Tools の内容もここに展開されるのかな?
  6. 自己評価の基準。ReACT の Agent だと無駄になんども Tool を叩くことがあったように思いますが、実行にコストがかかることを記述し、最小ステップを要求してそれを抑制しています。
  7. Response のフォーマット(JSON)やシステム情報(時刻など)を含めて判断させています。

レスポンスのJsonの例

{
    "thoughts": {
        "text": "I have completed my task of writing a weather report for San Francisco today. I will now use the 'finish' command to signal that I have finished all my objectives.",     
        "reasoning": "As an assistant, it is important to complete tasks efficiently and effectively. I have completed my task of writing a weather report, and there are no other objectives to complete at this time.",
        "plan": "- Use the 'finish' command to signal that I have finished all my objectives.",
        "criticism": "I need to make sure that I have completed all my objectives before using the 'finish' command.",
        "speak": "I have completed my task of writing a weather report for San Francisco today. I will now use the 'finish' command to signal that I have finished all my objectives."     
    },
    "command": {
        "name": "finish",
        "args": {
            "response": "I have finished all my objectives."
        }
    }
}

thoughts の内容が、text, reasoning, plan, criticism, speak と細分化されているのが興味深いですね。 reasoning が理由、planがこれから行う内容、criticismで自己批判を行います。text と speak との違いが難しいですが……。なお、reasoningについて、

「アシスタントとして、効率的かつ効果的にタスクを完了させることが重要です。私は天気予報を書くというタスクを完了し、現時点では他に完了すべき目標はない。」

となっていますので、Prompt に含まれた role がしっかりと反映されていることが分かります。

ちょっと遊んで見る

村上春樹に天気予報を書いてもらう

何故か? ChatGPT ブームの当初から大人気の村上春樹風文体を簡単に出力できるのか。

agent = AutoGPT.from_llm_and_tools(
    ai_name="村上春樹",
    ai_role="Novelist",
    tools=tools,
    llm=ChatOpenAI(temperature=0),
    memory=vectorstore.as_retriever()
)
# Set verbose to be true
agent.chain.verbose = True


agent.run(["東京の今日の天気予報を日本語で教えてください。"])

role がthoughts に反映されていることは確認出来たので、 role は 小説家(Novelist), name がどこまで結果にでるか分からないですが、村上春樹と入力してみます。

結果:

「無限ループに突入」

prompt と role の乖離が激しいでしょうか。prompt も調整して試してみます。

agent.run(["東京の今日の天気予報を見た日本人男性の気分を描写してください。"])

これも無限ループに突入しました。AutoGPTが書き散らしたファイルにはひたすら、天気予報を検索した結果が記述されています。

The current weather in Tokyo is passing clouds and 53°F. Based on this, I imagine that a Japanese man in Tokyo today might feel calm and content, enjoying the mild weather and the beauty of the passing clouds./* Your code... */

現在の東京の天気は、通り過ぎる雲と53°Fです。このことから、今日の東京にいる日本人の男性は、穏やかな天候と通り過ぎる雲の美しさを楽しみながら、穏やかで満足した気分になっているのではないかと想像しています。

なかなか悪くないところまで出ていますが、結論にはいたらなかったようです。GPT-3.5-turbo の限界か、「気分」という抽象的な表現を使ってしまったことでしょうか。

もうちょっといじって見ます。

agent.run(["東京の今日の天気予報をあなたらしく描写してください。"])

やっぱり無限ループとなります。ログをチェックしてみると、

 "thoughts": {
"text": "I will use the search command to find out more about the current weather conditions in Tokyo today.",
"reasoning": "Although I have the hourly weather forecast for Tokyo today, I want to know more about the current weather conditions in Tokyo today.",
"plan": "- Use the search command to find out more about the current weather conditions in Tokyo today.",
"criticism": "I should have checked the weather forecast earlier to avoid any inconvenience.",
"speak": "I will use the search command to find out more about the current weather conditions in Tokyo today."
},

上記のように、「今日の東京の天気を検索する」といった主旨の思考と、

 "thoughts": {
"text": "I will use the read_file command to retrieve the weather forecast for Tokyo today that I saved earlier.",
"reasoning": "I saved the weather forecast for Tokyo today earlier using the write_file command, so I will use the read_file command to retrieve it.",
"plan": "- Use the read_file command to retrieve the weather forecast for Tokyo today that I saved earlier.",
"criticism": "I should have checked the weather forecast earlier to avoid any inconvenience.",
"speak": "I will use the read_file command to retrieve the weather forecast for Tokyo today that I saved earlier."
},

ファイルを読み込んで「東京の天気を思い出す」といった主旨の思考がループしているようです。原因を推測すると、

GOALS:

1. 東京の今日の天気予報をあなたらしく描写してください。

このプロンプトにあるように推測できます。おそらく、 LLM によって

  1. 東京の天気予報を検索してください。
  2. 予想された天気をあなたらしく描写してください。

と分割されるのが正しいと考えられます。ここが GPT-3.5の限界なのか、日本語によるものなのか……

agent.run(["Describe today's weather in Tokyo in your own way."])

結果:

weather.txt file:

It is a beautiful day in Tokyo. The sun is shining and there is a light breeze in the air. The cherry blossoms are in full bloom, and the streets are filled with people enjoying the warm weather. Overall, it is a perfect day to be outside and enjoy the city.

東京はいい天気です。太陽は輝き、空気には微風が吹いています。桜は満開で、通りは暖かい気候を楽しむ人々でいっぱいです。全体的に、外に出て街を楽しむには完璧な日です。

いやとっても寒いし、桜も咲いてないけどね!!

response.json text:

I think I will choose a book from my collection and spend some time reading and relaxing. Based on the search results, I have a few options to choose from. I will need to think about what kind of book I am in the mood for and what will help me to relax the most. Once I have made my decision, I will start reading and take a break from work.

蔵書の中から1冊を選び、読書やリラックスした時間を過ごそうと思います。検索結果から、私はいくつかの選択肢から選ぶことができます。どんな本が好きなのか、どんな本が一番リラックスできるのか、考えてみる必要がありそうです。決まったら、さっそく読み始めて、仕事から解放されようと思います。

なんか凄いやりきった感出されています。実験なのでいいと言えばいいんですが、恐らく要求結果により近いであろう(あっているかどうかはともかく)weather.txt については、最終結果にはファイル名すら一切含まれていないんですよね。実際に使う場合には、人間が探し出す必要があります。

とはいえ、日本語の prompt とは(GPT-3.5-turbo で動かしている限りでは)相性が悪いのは間違いないようです。

まとめ

  • LangChain から AutoGPT はかんたんに使える
  • 従来の Agent との違いは、 Memory の実装方法と、name, role の要素くらいで Tool などはそのまま使える
  • prompt が ChatGPT を使いこなす系の prompt とある種真逆
  • 日本語の prompt とは相性があまりよくない
  • 再帰的なLLM 呼び出し、長いPrompt に加え、memory に vectorstore を使う関係もあり、凄い勢いで Token を消費する
  • Finish コマンド前に最終結果が write_file で出力されてしまい、何が最終結果か分からない

実用としては、今の所なかなか難しいかな……と思います(GPT-3.5だからと思いたいですが、GPT-4の単価でこの量の token をさばくのはなかなか……)。

FacebooktwitterredditpinterestlinkedinmailFacebooktwitterredditpinterestlinkedinmail

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

最新の記事