50代ITエンジニアが学ぶLangChainその5 - エージェントの構築

このシリーズは一旦ここまでです。RAGの次はエージェント。

https://qiita.com/taka_yayoi/items/7ef7e096fd9179faca7d

ノートブックです。

https://github.com/taka-yayoi/langchain_tutorial/blob/main/5.%20%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E3%81%AE%E6%A7%8B%E7%AF%89.ipynb

# エージェントを構築する

言語モデル自体はアクションを実行できず、テキストを出力するだけです。LangChainの大きなユースケースはエージェントの作成です。[エージェント](https://python.langchain.com/docs/concepts/agents/)は、[LLM](https://python.langchain.com/docs/concepts/chat_models/)を推論エンジンとして使用し、実行するアクションと必要な入力を決定するシステムです。アクションを実行した後、その結果をLLMにフィードバックして、さらにアクションが必要かどうか、または終了してもよいかどうかを判断します。これはしばしば[ツール呼び出し](https://python.langchain.com/docs/concepts/tool_calling/)を介して達成されます。

このチュートリアルでは、検索エンジンと対話できるエージェントを構築します。このエージェントに質問をし、検索ツールを呼び出す様子を見て、それと会話することができます。

[Build an Agent \| 🦜️🔗 LangChain](https://python.langchain.com/docs/tutorials/agents/)

## エンドツーエンドのエージェント

以下のコードスニペットは、使用するツールを決定するためにLLMを使用する完全に機能するエージェントを表しています。これは汎用の検索ツールを備えています。会話のメモリを持っており、マルチターンのチャットボットとして使用できます。

ガイドの残りの部分では、個々のコンポーネントと各部分の役割について説明しますが、すぐにコードを取得して始めたい場合は、自由に使用してください！

```py
%pip install -U langchain-community langgraph langchain-anthropic tavily-python langgraph-checkpoint-sqlite langchain-openai mlflow
dbutils.library.restartPython()
```

```py
import mlflow

# MLflow Tracingの有効化
mlflow.langchain.autolog()
```

ここでは検索ツールとして[Tavily](https://tavily.com/)を使うので、APIキーを取得して環境変数に設定しまうs。

```py
import os

os.environ["OPENAI_API_KEY"] = dbutils.secrets.get("demo-token-takaaki.yayoi", "openai_api_key")
# TavilyのAPIキー
os.environ["TAVILY_API_KEY"] = "tvly-..."
```

## エージェントの作成

```py
# 必要な機能をインポート
from langchain_openai import ChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import HumanMessage
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent
from langchain_core.pydantic_v1 import BaseModel

# メモリー
memory = MemorySaver()
# 言語モデル
model = ChatOpenAI(model="gpt-4o-mini")
# 検索ツール
search = TavilySearchResults(max_results=2)
# ツールセット
tools = [search]
# エージェントの作成
agent_executor = create_react_agent(model, tools, checkpointer=memory)
```

グラフを可視化してみます。

```py
from IPython.display import Image, display

display(Image(agent_executor.get_graph().draw_mermaid_png()))
```

まさにエージェント。

![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/83df7f4e-b603-4871-8036-d40f9376f3ee.png)

## エージェントの実行

エージェントが複数のステップを実行する場合、時間がかかることがあります。中間の進捗状況を表示するために、発生したメッセージをストリーミングバックすることができます。

```py
# エージェントを使います
config = {"configurable": {"thread_id": "abc123"}}
for step in agent_executor.stream(
    {"messages": [HumanMessage(content="こんにちは、Takaです！私は東京に住んでいます。")]},
    config,
    stream_mode="values",
):
    step["messages"][-1].pretty_print()
```
```
================================ Human Message =================================

こんにちは、Takaです！私は東京に住んでいます。
================================== Ai Message ==================================

こんにちは、Takaさん！東京に住んでいるのですね。何か特別なことについてお話ししたいことや質問があれば、どうぞ教えてください！
```
![Screenshot 2025-03-10 at 8.48.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/88beeb34-4c4e-4a0c-8fad-2c1b0eeb2b6e.png)

```py
for step in agent_executor.stream(
    {"messages": [HumanMessage(content="私が住んでいる場所の天気はどうですか？")]},
    config,
    stream_mode="values",
):
    step["messages"][-1].pretty_print()
```
```
================================ Human Message =================================

私が住んでいる場所の天気はどうですか？
================================== Ai Message ==================================
Tool Calls:
  tavily_search_results_json (call_S8UsVTvGmpK4WIRg09K9o2YS)
 Call ID: call_S8UsVTvGmpK4WIRg09K9o2YS
  Args:
    query: 東京 天気
================================= Tool Message =================================
Name: tavily_search_results_json

[{"title": "東京（東京）の天気 - Yahoo!天気・災害", "url": "https://weather.yahoo.co.jp/weather/jp/13/4410.html", "content": "パーソナル天気 現在位置： 天気・災害トップ > 関東・信越 > 東京都 > 東京（東京） 大雪に警戒　交通影響や今後の見通し ・大雪への備え ・雨雪レーダー ・警報・注意報 ・運行情報 ・週間天気 今日明日の天気 2025年2月8日 10時00分発表 2月8日(土) 晴れ 9℃[-1] 1℃[0] 時間  0-6 6-12    12-18   18-24 降水  --- 10％ 10％ 10％ 風： 北西の風日中やや強く２３区西部でははじめ北西の風強く 波： 2メートル後1メートル 2月9日(日) 晴れ 11℃[+2] 3℃[+2] 時間  0-6 6-12    12-18   18-24 降水  0％  0％  10％ 0％ 風： 北西の風後北の風２３区西部では北西の風やや強く 波： 1メートル 東京地方の警報・注意報 注意報 強風、波浪、乾燥 東京都の花粉情報 2025年2月8日 7時00分 発表 2/8(土) 少ない 2/9(日) 少ない 花粉の詳しい情報を確認 週間天気 2025年2月8日 8時00分発表 日付 2月10日 (月) 2月11日 (火) 2月12日 (水) 2月13日 (木) 2月14日 (金) 2月15日 (土) 降水 2025年2月8日 10時00分 発表 (C) Mapbox (C) OpenStreetMap (C) LY Corporation Yahoo!地図ガイドライン (C) Mapbox (C) OpenStreetMap (C) LY Corporation Yahoo!地図ガイドライン 2/8(土)9時　寒波ピーク 新たな大雪災害に警戒　あす朝にかけてさらに70〜80センチの降雪予想 Copyright (C) 2025 Weather Map Co., Ltd. All Rights Reserved. © LY Corporation", "score": 0.829285}, {"title": "東京都の天気 - 日本気象協会 tenki.jp", "url": "https://tenki.jp/forecast/3/16/", "content": "東京都の天気 - 日本気象協会 tenki.jp tenki.jpトップ｜ サイトマップ｜ ヘルプ tenki.jp 雨雲レーダー PM2.5分布予測 雷(予報) 雨雲レーダー(過去) 雷(実況) 気象予報士のポイント解説 雨雲レーダー PM2.5分布予測 08(土) 15(土) 08日10:00発表02月08日(土) 千代田区  10/1 10% 新宿区  9/0 10% 世田谷区  9/0 10% 三鷹市  9/0 10% 八王子市  10/-1 10% 青梅市  9/-3 10% 大島町  9/3 10% 八丈町  8/3 50% 小笠原村  18/18 40% 練馬区  9/0 10% 台東区  10/1 10% 品川区  10/1 0% 町田市  10/-1 10% 立川市  9/-1 10% 気象予報士のポイント解説(日直予報士) 今日8日も日本海側は大雪や暴風雪 東海以西の太平洋側も雪による交通の乱れに注意 02/08(土)08:25 花粉の飛散予測 九州から関東「少ない」 南風や気温の上昇で飛散量が増える可能性も 02/08(土)06:50 週末も冬の嵐 8日は名古屋など市街地でも積雪 北陸や東北を中心に積雪が急増 02/08(土)05:58 千代田区 立川市 雨雲 PM2.5 天気予報アプリ-tenki.jp アプリで天気を確認！無料で48時間先までの雨雲レーダーが使える tenki.jpの公式X（旧Twitter） 最新の気象・防災情報や、生活に役立つ情報を毎日リアルタイムに配信中！ 雨雲レーダー PM2.5 雷(予報) 雨雲レーダー(過去) 雷(実況) tenki.jp公式SNS tenki.jp公式アプリ tenki.jp tenki.jp 登山天気 tenki.jpトップ 雨雲レーダー PM2.5分布予測 雷(予報) 雨雲(過去) 雷(実況) 花粉飛散情報(1～5月頃) 桜開花情報(2～5月頃) GWの天気(4～5月頃) 梅雨入り・明け(5～7月頃) 熱中症情報(4～9月頃) 紅葉見頃情報(10～11月頃) ヒートショック(10～3月頃) スキー積雪情報(11～5月頃) 初日の出(12～1月頃) Copyright (C) 2025 日本気象協会 All Rights Reserved. Copyright (C) 2025 ALiNKインターネット All Rights Reserved.", "score": 0.725824}]
================================== Ai Message ==================================

現在の東京の天気は、以下のとおりです。

- **日付**: 2月8日 (土曜日)
- **天気**: 晴れ
- **気温**: 最高9℃、最低1℃
- **降水確率**: 10%（昼間の時間帯）
- **風**: 北西の風がやや強く、23区西部では北西の風が強く吹くことがあります。

明日、2月9日 (日曜日) の予報は:
- **天気**: 晴れ
- **気温**: 最高11℃、最低3℃
- **降水確率**: 0%

詳しい情報は、[Yahoo!天気](https://weather.yahoo.co.jp/weather/jp/13/4410.html) や [tenki.jp](https://tenki.jp/forecast/3/16/) で確認できます。

備えあれば憂いなしなので、外出の際は気を付けてお過ごしください！
```

2月の天気が検索されていますが、ツールとしては動作しています。

![Screenshot 2025-03-10 at 8.48.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/ba0a533f-3a52-481d-ac51-ae3465f1bda4.png)

## トークンのストリーミング

メッセージをストリーミングバックするだけでなく、トークンをストリーミングバックすることも有用です。これを行うには、`stream_mode="messages"`を指定します。

```py
for step, metadata in agent_executor.stream(
    {"messages": [HumanMessage(content="東京の天気は？")]},
    config,
    stream_mode="messages",
):
    if metadata["langgraph_node"] == "agent" and (text := step.text()):
        print(text, end="|")
```
```
東京|の|現在|の|天|気|は|以下|の|通|り|です|。

|-| **|日|付|**|:| |2|月|8|日| (|土|曜日|)
|-| **|天|気|**|:| 晴|れ|
|-| **|最高|気|温|**|:| |9|℃
|-| **|最低|気|温|**|:| |1|℃
|-| **|降|水|確|率|**|:| |10|%|（|昼|間|の|時間|帯|）
|-| **|風|**|:| 北|西|の|風|が|や|や|強|く|、|23|区|西|部|では|北|西|の|風|が|強|い|こと|があります|。

|明|日の|天|気|（|2|月|9|日|）は|、|晴|れ|の|予|報|で|最高|気|温|は|11|℃|、|最低|気|温|は|3|℃|、|降|水|確|率|は|0|%|です|。

|寒|さ|や|風|に|気|を|付|け|て|、|良|い|一|日|を|お|過|ご|し|ください|！|
```

## まとめ

これで終了です！このクイックスタートでは、シンプルなエージェントの作成方法を紹介しました。その後、応答をストリーミングバックする方法を示しました - 中間ステップだけでなく、トークンも含めて！さらに、会話を続けるためのメモリも追加しました。エージェントは学ぶことがたくさんある複雑なトピックです！

エージェントに関する詳細情報は、[LangGraph](https://python.langchain.com/docs/concepts/architecture/#langgraph)のドキュメントを参照してください。独自の概念、チュートリアル、およびハウツーガイドが含まれています。

## 個人的振り返り

- フレームワークというだけあって、RAGやエージェントシステムを構築するためのツールセットが豊富に提供されていて嬉しいです。これを1から開発しろと言われたら大変すぎます。
- 生成AIシステムの開発手法自体が急激に出現、進化し続けている状況なので、ライブラリのバージョンには注意した方が良いと思いました。動かしている途中でも`deprecated`といった警告が出ていましたので。
- 個人的には[LCEL](https://python.langchain.com/v0.1/docs/expression_language/)がUnixのパイプを思い出させてくれて懐かしかったです。使いやすいでし。
- しかし、2年前にはこのようなプログラミングを行うようになるとは想像もしていませんでした。たのしい


### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)