langchianlogo

LangChain入門 – 6)Agent エージェント

LangChain入門の6回目です。Agentとは代理人という意味ですが、面倒な仕事を手伝ってくれる助っ人のようなもの考えてください。Agentは仕事をこなすためにツールを使用します。ツールには、検索したり、Pythonを実行したり、数学を解いたりといろいろなものが用意されています。AgentはLLMと協力しながら、どのツールを使ったらよいか考えながら作業を進めてゆきます。

agent1
LangChain入門 – 6)Agent エージェント 6

本記事はFuture Coders独自教材からの抜粋です。

Langchainではあらかじめ幾つかのAgentを用意しています。それぞれ得意なことが異なります。

現時点でサポートされているAgentの種類を確認してみましょう。

from langchain.agents import AgentType
for t in AgentType:
    print(t)

出力は以下のようになりました。わりと速いペースで増えているようです。

AgentType.ZERO_SHOT_REACT_DESCRIPTION
AgentType.REACT_DOCSTORE
AgentType.SELF_ASK_WITH_SEARCH
AgentType.CONVERSATIONAL_REACT_DESCRIPTION
AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION
AgentType.CHAT_CONVERSATIONAL_REACT_DESCRIPTION
AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION
AgentType.OPENAI_FUNCTIONS

主なエージェントは以下の通りです。

  • ZERO_SHOT_REACT_DESCRIPTION = 各ツールの説明文章からどのツールを使うか判断するエージェント
  • REACT_DOCSTORE = 文書の扱いを得意とするエージェント
  • SELF_ASK_WITH_SEARCH = 検索した結果に基づいて判断するエージェント
  • CONVERSATIONAL_REACT_DESCRIPTION = 会話の扱いが得意なエージェント

この中でZERO_SHOT_REACT_DESCRIPTION系のエージェントはツールの説明文章を読んでどのツールを使うか判断します。つまり、ツールは自分を説明する文章を含んでいる必要があります。その内容を確認してみましょう。

以下は、wikipedia, llm-math, open-meteo-apiといったツールの説明文書を確認するコードです。

from langchain_openai import OpenAI
llm = OpenAI()

from langchain.agents import load_tools
tools = load_tools(["wikipedia", "llm-math", "open-meteo-api"], llm=llm)
for t in tools:
    print(f"名前={t.name} 説明={t.description}")

出力は以下のようになりました。

名前=Wikipedia 説明=A wrapper around Wikipedia. Useful for when you need to answer general questions about people, places, companies, facts, historical events, or other subjects. Input should be a search query.
名前=Calculator 説明=Useful for when you need to answer questions about math.
名前=Open Meteo API 説明=Useful for when you want to get weather information from the OpenMeteo API. The input should be a question in natural language that this API can answer.

各ツールの説明内容は英語ですが、それぞれのツールの説明をしていることがわかります。エージェントはこの説明を参考に、計算するときはCalculatorを呼び出したり、天気を調べるときはOpen Meteo APIを呼び出したり、と判断できるようになります。

では、このエージェントとツールをためしてみましょう。

serpapi

serpapiはGoogleなどの検索エンジンを横断的に検索して、その結果を取得する検索用のAPIです。開発者で登録した場合、月5000回の検索までは無料です。利用するにはAPIキーを取得する必要があります。

https://serpapi.com/

アカウントがない場合はRegisterから登録します。

screen agent1
LangChain入門 – 6)Agent エージェント 7

ログインするとAPIキーが取得できます。

screen agent2
LangChain入門 – 6)Agent エージェント 8

serpapiを使用するために、PIPコマンドでモジュールをインストールします。

pip install google-search-results

まずは普通にserpapiをそのまま使ってみましょう。以下「ラーメン」を検索するサンプルです。

import json
from serpapi import GoogleSearch
search = GoogleSearch({
    "q":"ラーメン",
    "num":3,
    "location":"Yokohama",
    "api_key":"e8de952fd0643ff908ca.....................834a3eb45c3960d"
    })

result = search.get_dict()
print(json.dumps(result, ensure_ascii=False, indent=4))

GoogleSearchオブジェクトを作成して、必要なパラメタを適宜設定して、get_dictと実行するだけでGoogle検索の結果が得られます。qが検索ワード、numが件数、locationは場所の指定となります。

以下のように膨大な情報が取得できることが確認できます。

{
    "search_metadata": {
        "id": "6502663d359e9971c9fe88f7",
        "status": "Success",
        "json_endpoint": "https://serpapi.com/searches/71b693778593d1dc/6502663d359e9971c9fe88f7.json",
        "created_at": "2023-09-14 01:47:41 UTC",
        "processed_at": "2023-09-14 01:47:41 UTC",
        ....

詳しいAPIの使い方は以下のリンクに記載されています。

このようにserpapiは強力な検索機能を提供してくれますが、このままではLLMと組み合わせることは簡単ではありません。LLMと組み合わせられるように、serpapiのAgentが用意されています。

serpapiとOpenAIを組み合わせたサンプルです。昨日の気温を聞いています。OpenAIだけではこの問いに答えられないはずです。serpapiと組み合わされることで、このような問いにも答えられるようになっていることに注目してください。

import os
os.environ["SERPAPI_API_KEY"] = "e8de952fd06........................b45c3960d"

from langchain_openai import OpenAI
from langchain.agents import load_tools, AgentExecutor, create_react_agent
from langchain import hub

llm = OpenAI(temperature=0.7)
tools = load_tools(["serpapi", "llm-math"], llm=llm)
prompt = hub.pull("hwchase17/react")

agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
r = agent_executor.invoke({"input": """昨日の東京の最高気温は何度ですか?昨日の気温はインターネットから検索してください。
                           摂氏と華氏の両方を、日本語で教えてください。"""})
print(r)

出力は以下のようになりました。

> Entering new  chain...
 I should search for the answer to this question.
Action: Search
Action Input: Tokyo yesterday temperature celsius fahrenheit
Observation: See weather overview. Tokyo Temperature Yesterday. Maximum temperature yesterday: 91 °F (at 1:00 pm) Minimum temperature yesterday: 74 °F (at 3:00 am) Average ...
Thought: I should convert the temperature from Fahrenheit to Celsius.
Action: Calculator
Action Input: 91F to Celsius
Observation: Answer: 32.77777777777778
Thought: I should convert the temperature from Celsius to Fahrenheit
Action: Calculator
Action Input: 74C to Fahrenheit
Observation: Answer: 23.333333333333332
Thought: I now know the final answer
Final Answer: 昨日の東京の最高気温は 32.77777777777778 度 (摂氏)、23.333333333333332 度 (華氏)です。

> Finished chain.
昨日の東京の最高気温は 32.77777777777778 度 (摂氏)、23.333333333333332 度 (華氏)です。

最初に「質問に答えるには検索しなくては」と判断して、「Action: Search」を実行しています。これはserpapiを実行していることにほかなりません。検索結果には、最高気温が91度(華氏)、最低気温が74度(華氏)という結果が含まれていることがわかります。華氏は米国で使われている単位です。次に、「これを摂氏に変換しなくては」と判断して、91度を摂氏に変換して32度という気温を得ています。ここまではよかったのですが、74度を摂氏と勘違いして、華氏に変換して23度という値を得ていることがわかります。回答が正確ではありませんでしたが、検索や計算を実行していることが確認できます。

news-api

news-apiツールを使って最新のニュースを検索してみましょう。このツールを使用するにはユーザ登録を行い、APIキーを取得する必要があります。

以下のサイトからユーザー登録を行って、APIキーを取得してください。

https://newsapi.org/

今回はツールとしてnews-apiとserpapiの2つを用意してみました。質問内容に応じてエージェントがどのようにツールを使い分けるか見てみましょう。

import os
os.environ["SERPAPI_API_KEY"] = "e8de952fd064................51834a3eb45c3960d"
from langchain.agents import load_tools,  AgentType, AgentExecutor, create_react_agent
from langchain_openai import OpenAI
from langchain import hub

llm = OpenAI(temperature=0.7)
tools = load_tools(["news-api","serpapi"], llm=llm, news_api_key="8e8a45685b2543978213a4d2b5e91f65")

prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
r = agent_executor.invoke({"input": "昨日日本で話題になった芸能ニュースを1つ教えてください。回答は日本語でお願いします。"})

print(r)

出力は以下のようになりました。

> Entering new AgentExecutor chain...
 I need to find a source that provides information on Japanese entertainment news.
Action: Search
Action Input: "日本 芸能ニュース"['... 日本に連続弾 ベトナム熱狂 · 田中希実「ごぼう抜き」は好まず · 「逆立ち」で大復活 実況も驚愕 · J1初挑戦の町田が始動「優勝を」 · 田中希実19人抜き ファン大興奮.', '最新の芸能 ニュースや特集をいち早くお届け!最新情報を発信する総合トレンドメディア「ORICON NEWS」では、話題の芸能 のニュースや特集を画像や動画と併せて提供し ...', 'エンタメ・芸能ニュース一覧 · ももクロ リーダー百田夏菜子(29)の結婚をメンバーが祝福【コメント全文】 · 松平健とコロッケが異色コンビ結成“歌って笑って踊ってサンバ” ...', '編集部オススメ ... 羽田空港で航空機炎上…日本航空が支払う補償金「1人一律20万円」の根拠は? ... 【保存版】知っておきたい最新ニュースを簡単インプット!', '芸能のニュース一覧ページ - 日刊 スポーツ新聞社のニュースサイト、ニッカンスポーツ・コム(nikkansports.com)。', '1. NHK中川安奈アナ 番組衣装が「けしからん」と絶賛 ボディライン浮き出たパープルニットが「ぷるぷるして」 · 2. 元女優・若林志穂さん 主演俳優との食事断ったら「 ...', '太田光、日本の株価好調で岸田総理「夏前に賃上げで景気がよくなりそこまで見据えてあぐらを…」 お笑い [1月14日 13:59] · 3時のヒロイン福田麻貴、先輩芸人の神 ...', '芸能ニュース 芸能フォト · アクセスランキング一覧. 特集. 写真広場 · 写真部の ... 日本で四半世紀ぶりの大回顧展. Next. 1; 2; 3; 4. 【PR】イチオシ情報. 中スポ競輪記者 ...', '芸能ニュース記事一覧。ゴシップや速報など芸能人・芸能界の最新ニュースや裏情報をまとめて掲載しています。', '芸能、映画、音楽、アジア・韓流、海外 ・セレブ、アニメ・コミック、グラビア関連の新着ニュース一覧です。新聞社や通信社が配信するニュース速報、最新ニュースを掲 載 ...']I now know the final answer
Final Answer: 最新の芸能ニュースや特集をいち早くお届け!最新情報を発信する総合トレンドメディア「ORICON NEWS」では、話題 の芸能のニュースや特集を画像や動画と併せて提供し ...

> Finished chain.
{'input': '昨日日本で話題になった芸能ニュースを1つ教えてください。回答は日本語でお願いします。', 'output': '最新の芸能ニュースや特集をいち早くお届け!最新情報を発信する総合トレンドメディア「ORICON NEWS」では、話題の芸能のニュースや特集を 画像や動画と併せて提供し ...'}

ActionとAction Inputのところに注目してください。Actionがツール、Action Inputがそのツールへの入力です。

最初のサッカーの結果に関しては、Searchとあるようにserpapiを使用していることがわかります。検索も1回ではなく2回実行して適切な結果を取得しようとしている様子が伺えます。後者の芸能ニュースに関してはNews APIを呼び出していることがわかります。

以下はStreamlitと組み合わせた簡単なニュースアプリのサンプルです。

import streamlit as st
from langchain.agents import load_tools, initialize_agent, AgentType
from langchain.llms import OpenAI

llm = OpenAI(temperature=0.7)
tools = load_tools(["news-api"], llm=llm, news_api_key="8e8......................65")
agent = initialize_agent(tools, llm, AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

st.header("最新ニュース")

with st.sidebar:
    genre = st.radio("ジャンル", ["時事", "経済", "スポーツ", "芸能"])

if st.button("更新"):
    st.subheader(f"{genre}の最新ニュース")
    r = agent.run(f"{genre}の分野で話題になっているニュースを出力してください")
    st.write(r)

ジャンルを選択して、更新ボタンを押下すると最新のニュースが表示されます。

screen agent3
LangChain入門 – 6)Agent エージェント 9

wikipedia

Wikipedia用のツールも用意されています。単にツール名にwikipediaと指定するだけです。APIキーも不要で簡単に利用できます。

from langchain.agents import load_tools,  AgentExecutor, create_react_agent
from langchain_openai import OpenAI
from langchain import hub
llm = OpenAI(temperature=0)

tools = load_tools(["wikipedia"], llm=llm)

prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
r = agent_executor.invoke({"input": "男はつらいよは全部で何シリーズある?。回答は日本語でお願いします。"})

print(r)

出力は以下のようになりました。

> Entering new AgentExecutor chain...
 I should use Wikipedia to find the answer.
Action: Wikipedia
Action Input: 男はつらいよPage: Otoko wa Tsurai yo
Summary: Otoko wa Tsurai yo (男はつらいよ, "It's Tough Being a Man") is a Japanese film series starring Kiyoshi Atsumi as Tora-san (寅さん), a kind-hearted vagabond who is always unlucky in love. The series itself is often referred to as "Tora-san" by its fans.  Spanning 48 installments released between 1969 

<<中略>>

of performances as Tora-san in the previous films. It also stars Chieko Baisho, Gin Maeda, Hidetaka Yoshioka, Kumiko Goto, Mari Natsuki, and Ruriko Asaoka, all recreating their roles from the long running film series. I now know the final answer.
Final Answer: There are 50 films in the Otoko wa Tsurai yo series.

> Finished chain.
{'input': '男はつらいよは全部で何シリーズある?。回答は日本語でお願いします。', 'output': 'There are 50 films in the Otoko wa Tsurai yo series.'}

出力が長いので途中で省略してありますが、正しい結果が得られています(日本語のWikipediaを確認しました)。
ActionにWikipedia、Action Inputに”Otoko wa Turai yo”と入力されていることも確認できます。

llm-math

llm-mathは数学に関する問題を解決するツールです。以下のサンプルではビルゲイツの元奥さんの年齢と、その平方根を求めています。

import os
os.environ["SERPAPI_API_KEY"] = "e8de952....................b45c3960d"
from langchain.agents import load_tools, initialize_agent, AgentType
from langchain.llms import OpenAI

llm = OpenAI(temperature=0)
tools = load_tools(["serpapi","llm-math"], llm=llm)
agent = initialize_agent(tools, llm, AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
r = agent.run("ビルゲイツの元奥さんの年齢は?その年数の平方根を教えてください")
print(r)

出力は以下のようになりました。

> Entering new AgentExecutor chain...
 I should use a search engine to find out more information about Bill Gates' ex-wife.
Action: Search
Action Input: "Bill Gates ex-wife age"59 yearsNow I need to use a calculator to find the square root of 59.
Action: Calculator
Action Input: √59Answer: 7.681145747868608I now know the final answer.
Final Answer: The square root of Bill Gates' ex-wife's age is approximately 7.68.

> Finished chain.
{'input': 'ビルゲイツの元奥さんの年齢は?その年数の平方根を教えてください', 'output': "The square root of Bill Gates' ex-wife's age is approximately 7.68."}

最初のActionでSearchを使って年齢を検索し、次のActionでCalculatorを使っていることが分かります。

演習

agent-ex1.py

serpapiを使って、この一週間のドル円相場を求めてください。

以下は出力例です。

> Entering new  chain...
 現在の為替レートを検索する
Action: Search
Action Input: 今週の為替レート
Observation: 今週のレンジ予想[毎週月曜日 更新]. 今週のレンジ予想. 9月11日 ~ 9月17日. ドル ... お取引した通貨にて、相場の変動による価格変動やスワップポイントの変動により ...
Thought: ドルのレートを見つける
Action: Search
Action Input: ドルの為替レート
Observation: 通貨(通貨単位), 為替レート(円). 外貨→円貨(TTB), 円貨→外貨(TTS). 米ドル(1 USD), 146.69, 147.69. ユーロ(1 EUR), 157.46, 158.86.
Thought: ドルの為替レートを計算する
Action:  None
Final Answer: 1 USD = 146.69 - 147.69円

> Finished chain.
1 USD = 146.69 - 147.69円

agent-ex2.py

wikipediaを使って、ジブリ作品の代表例を出力してください。

出力例

スタジオジブリが作品として発表した作品には、『となりのトトロ』『千と千尋の神隠し』『ハウルの動く城』 『崖の上のポニョ』などがあります。また、ジブリ美術館などもあります。

解答例

agent-ex1.py

import os
os.environ["SERPAPI_API_KEY"] = "e8de952fd0...............3eb45c3960d"
from langchain.agents import load_tools,  AgentExecutor, create_react_agent
from langchain_openai import OpenAI
from langchain import hub
llm = OpenAI()
tools = load_tools(["serpapi"])
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
r = agent_executor.invoke({"input":"今週1ドルが何円だったかを教えてください。回答は日本語でお願いします。"})

print(r)

agent-ex2.py

from langchain.agents import load_tools,  AgentExecutor, create_react_agent
from langchain_openai import OpenAI
from langchain import hub
llm = OpenAI(temperature=0)

llm = OpenAI()
tools = load_tools(["wikipedia"])
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
r = agent_executor.invoke({"input": "ジブリ作品の代表例を教えてください"})

print(r)