LLMに表データの解析を手伝ってもらえるLangChainのPandas Dataframe Agentの中身がどうなっているのか調べた
最近、LLMを使ったOSSの中身を調べてLLMとどう連携して目的を達成しているのかをいろいろ調べています。今回はLangChainのPandas Dataframe Agentの中身がどうなっているのか気になったので調べたまとめになります。
今回のコードは以下のところにあるので、全体としてどうなっているのか見たい方はこちらをご覧ください。
https://github.com/shu65/langchain_examples/blob/main/LangChain_Pandas_Dataframe_Agent.ipynb
目次
LangChainのPandas Dataframe Agentとは
LLMを使いやすくwrapしてくれるLangChainにはいくつかAgentというLLMとToolと呼ばれるものを組み合わせて実行する仕組みが用意されています。この中でもPandas Dataframe Agentは名前の通りpandasのDataframeに対する操作をLLMにやらせるための仕組みです。
どういうことができるかはこちらのnotebookをご覧ください。
https://python.langchain.com/en/latest/modules/agents/toolkits/examples/pandas.html
この記事では、上のnotebookの実行例の一つを取り上げてどのようにLLMなどと連携しているのかを説明していきたいと思います。
実行例
今回は機械学習でお馴染みのタイタニックのデータを使います。データはここから持ってきました。
https://web.stanford.edu/class/archive/cs/cs109/cs109.1166/problem12.html
どういうデータか詳しく知りたい方は上のページの説明をご覧ください。
また、今回は以下のことをLLMに聞いたときのLLMなどを含めた一連の流れがどうなっているのかを説明していきます。
from langchain.llms import OpenAI
from langchain.agents import create_pandas_dataframe_agent
import pandas as pd
df = pd.read_csv('titanic.csv')
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), df, verbose=True)
agent.run("whats the square root of the average age?")
最後の行がLLMでpandasのDataFrameを操作する部分になっています。やらせたいことは読んで分かる通り、年齢の平均を取って、それのルートを取るという計算をした結果を得るということです。
それではこの後これがどのように実行されるかを見ていきます。
実行の流れ
Pandas Dataframe Agentの大まかな実行の流れは以下の通りです。
zero-shot-react-description
と同じAgentクラスに対し、promptを少し変えたAgentを作成- できたAgentがどのようなコードを実行するかを考える
- 考えに従ってコードを生成
- 生成されたコードを実行
- 実行した結果に基づいて再度考える。以降はこの繰り返して最終結果を得る
このような「考える」と「行動」(LangChain的にはTool)を交互に繰り返すやり方はReActと呼ばれる方法で、以下の論文で提案されています。
Yao, S., Zhao, J., Yu, D., Du, N., Shafran, I., Narasimhan, K., & Cao, Y. (2022). ReAct: Synergizing Reasoning and Acting in Language Models. ArXiv, abs/2210.03629.
zero-shot-react-description
に関しては以前記事を書きましたので、動作について詳しく知りたい方はこちらも併せてご覧ください。
ここからはさきほどの例の場合、LLMと連携してどのような手順で処理をしていくかを見ていきます。
一番最初のpromptに関して
一番最初のpromptは以下のようになっています。
You are working with a pandas dataframe in Python. The name of the dataframe is `df`.
You should use the tools below to answer the question posed of you:
python_repl_ast: A Python shell. Use this to execute python commands. Input should be a valid python command. When using this tool, sometimes output is abbreviated - make sure it does not look abbreviated before using it in your answer.
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [python_repl_ast]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
This is the result of `print(df.head())`:
Survived Pclass Name \
0 0 3 Mr. Owen Harris Braund
1 1 1 Mrs. John Bradley (Florence Briggs Thayer) Cum...
2 1 3 Miss. Laina Heikkinen
3 1 1 Mrs. Jacques Heath (Lily May Peel) Futrelle
4 0 3 Mr. William Henry Allen
Sex Age Siblings/Spouses Aboard Parents/Children Aboard Fare
0 male 22.0 1 0 7.2500
1 female 38.0 1 0 71.2833
2 female 26.0 0 0 7.9250
3 female 35.0 1 0 53.1000
4 male 35.0 0 0 8.0500
Begin!
Question: whats the square root of the average age?
一番最初のpromptが一番大事な部分なので、丁寧に説明していきます。
You are working with a pandas dataframe in Python. The name of the dataframe is `df`.
この部分はzero-shot-react-description
とは違う部分の一つです。最初にpandasのDataFrame
を使うことと、その変数名がdf
であることをLLMに伝えます。
次にこの部分についてです。
You should use the tools below to answer the question posed of you:
python_repl_ast: A Python shell. Use this to execute python commands. Input should be a valid python command. When using this tool, sometimes output is abbreviated - make sure it does not look abbreviated before using it in your answer.
この部分はToolの説明です。Pandas Dataframe Agentの場合はpython_repl_ast
を使うため、このToolがどういうものかをLLMに伝えています。
次にこの部分です。
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [python_repl_ast]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
この部分はzero-shot-react-description
と同じでLLMにReAct的な動きをしてもらうための説明のところです。
そして次はこの部分です。
This is the result of `print(df.head())`:
Survived Pclass Name \
0 0 3 Mr. Owen Harris Braund
1 1 1 Mrs. John Bradley (Florence Briggs Thayer) Cum...
2 1 3 Miss. Laina Heikkinen
3 1 1 Mrs. Jacques Heath (Lily May Peel) Futrelle
4 0 3 Mr. William Henry Allen
Sex Age Siblings/Spouses Aboard Parents/Children Aboard Fare
0 male 22.0 1 0 7.2500
1 female 38.0 1 0 71.2833
2 female 26.0 0 0 7.9250
3 female 35.0 1 0 53.1000
4 male 35.0 0 0 8.0500
ここではDataFrameの一部を出力させてどういうデータであるかをLLMに伝えている部分です。
最後にこの部分です。
Begin!
Question: whats the square root of the average age?
Thought:
動作の開始の合図と、「Question:」から先が実際にAgentを使ってやりたいことをLLMに伝えます。そして、「Thought:」までLLMに入力させて、LLMに何をするべきか考えさせます。
ここから先はLLMの出力と出力されたPythonコードを実行して得られた結果を受け取ってさらにLLMに考えさせるという動作を繰り返していきます。これを順番に説明していきます。
LLMが考えて、Pythonのコードを生成する部分(1回目)
先ほどのpromptをLLMに入力すると以下のような出力が返ってきます。これを順番に見ていきます。
I need to calculate the average age first
Action: python_repl_ast
Action Input: df['Age'].mean()
1行目が先ほどの「Thought:」の続きで、LLMがどのようなことをするべきか考えた部分です。最初は年齢の平均を計算しようと考えて、それを行うためのコードを「Action Input:」から先に出力しています。
このコードを今度は実際に実行します。
Pythonコードの実行
先ほどのPythonのコードをどのように実行するかを説明していきます。実際に実行している部分は、この記事を書いている現在のバージョンではLangChainのここになります。
これは以下のような手順でPythonコードを実行しています。
- LLMの生成したPythonコードを受け取りきれいに整える
- Pythonコードの抽象構文木を生成
- Pythonコードの最後から一つ手前までのコードを実行
- Pythonコードの最後の部分を実行して出力結果、もしくはエラーを得る
3と4でなぜ分けて実行しているかというとToolの説明にある通り、途中の出力は省略して最後だけ得るためであると考えています。
このような流れでPythonコードを実行すると以下の結果が得られえます。
Observation: 29.471443066516347
ここから次に何をするべきかさらに考えて実行していきます。
LLMが考えてPythonのコードを生成し、実行する部分(2回目)
次にLLMの出力とPythonコードの実行は以下のようになります。
I now need to calculate the square root of the average age
Action: python_repl_ast
Action Input: math.sqrt(df['Age'].mean())
Observation: name 'math' is not defined
1行目は先ほどと同じように次に何をするべきかLLMに考えさせた結果の部分です。ここでは年齢の平均のルートを計算するということを考えてコードを生成しています。
このコードを実行すると以下のようなエラーが出力されます。
name 'math' is not defined
まだmath
がインポートされてないので、その部分でエラーがでています。たしかに現状のコードではどこもmath
をインポートしてないので、このエラーがでるのは当然です。
ここからさらにLLMに考えさせます。
LLMが考えてPythonのコードを生成し、実行する部分(3回目)
次にLLMの出力とPythonのコードを実行した結果は以下のようになります。
I need to import the math library
Action: python_repl_ast
Action Input: import math
Observation:
1行目は先ほどと同じように次に何をするべきかLLMに考えさせた結果の部分です。今度はちゃんとmath
をインポートするように考えて、その通りのコードを生成しています。
このコードはインポートだけなので出力はなしです。
LLMが考えてPythonのコードを生成し、実行する部分(4回目)
ここからさらにLLMに考えさせます。
I now need to calculate the square root of the average age
Action: python_repl_ast
Action Input: math.sqrt(df['Age'].mean())
Observation: 5.42876073026951
LLMの考えていることは1行目にでていて、これは2回目のときと同じものになっています。コードも2回目と同じです。
一方、先ほどmath
をインポートしたので、今度はエラーが出ずに正しい計算ができています。
以上がPandas Dataframe Agentの中身になります。
終わりに
今回はLangChainのPandas Dataframe Agentの中身がどうなっているのかを調べたのでまとめを書きました。DataFrameの中の情報をどうやって教えているのか疑問だったのですが、その辺もわかってよかったです。
また、Pythonのast
まわりを知らなかったのでそれについてもいい勉強になりました。
この記事が少しでも他の方の役にたったら幸いです。