なぜ LangGraph を使うのか
LangChain(LCEL) は、「プロンプト → LLM → 出力」といった一本道のチェーンを作るのには非常に強力です。しかし、より高度な AI エージェントを作ろうとすると、以下のような ループ(循環構造) が必要になります。
- 「LLMの出力がエラーだったら、エラー文を元にもう一度LLMに考え直させる」
- 「ツールを実行した結果を元に、さらに別のツールを使うかLLMに再判断させる」
これをLangChain単体でやろうとすると、コードが複雑な状態になるので。「状態(State)を持つグラフ構造」として、安全に(De-riskingされた状態で)設計・実装できるようにしたのが LangGraph です。
この記事で作るもの
ユーザーの質問に応じて、
- 必要なら「Web検索ツール」を自律的に使い、
- そうでなければ直接回答する
といったシンプルな「Web検索機能付き自律型AIアシスタント」を構築します。
記事を前編・後編の2回に分けます。
- 前編(本記事): LangGraphの基本概念と、State・Nodes・Edgesという3つの部品を作るところまで
- 後編: グラフを完成させ、実際にエージェントを動かす
ささっとパーツを理解する
LangGraph で理解するパーツは、以下の4つです。
| キーワード | 役割 |
|---|---|
| State(状態) | グラフ全体で共有されるデータバッファ(メモリ) |
| Nodes(ノード) | 実際の処理を行う関数(LLMの呼び出し、ツールの実行など) |
| Edges(エッジ) | ノードから次のノードへの遷移ルール(条件分岐含む) |
| Graph(グラフ) | ノードとエッジをまとめた全体のワークフロー |
0. 事前準備と環境構築
まずは必要なライブラリをインストールします。Web検索ツールには専用パッケージの langchain-tavily を使います。
pip install -U langgraph langchain-openai langchain-tavily python-dotenv
次に、API キーを環境変数に設定します。今回は Web 検索ツールとして無料枠のある Tavily API、および OpenAI の API を使用します。
from dotenv import load_dotenv
load_dotenv() # .env に OPENAI_API_KEY / TAVILY_API_KEY を記載しておく
# .env
OPENAI_API_KEY=your-openai-api-key
TAVILY_API_KEY=your-tavily-api-key
1. State(状態)の定義
LangGraphでは、すべてのノードがこの「State」を読み書きしながら進みます。今回はメッセージの履歴を保持するStateを定義します。
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph.message import add_messages
class State(TypedDict):
# add_messagesアノテーションをつけることで、既存の履歴に新しいメッセージが「追加(append)」されるようになる
messages: Annotated[list, add_messages]
5. Nodes(ノード)の作成
次に、具体的な処理を行う「担当者(ノード)」を作ります。
-
LLM(Agent)ノード:ユーザーの質問やこれまでの文脈から、次に何をすべきか(回答するか、ツールを使うか)を判断する -
Tool ノード:LLM の指示に従って検索を実行する
from langchain_openai import ChatOpenAI
from langchain_tavily import TavilySearch
from langgraph.prebuilt import ToolNode
# 1. ツールの準備
tools = [TavilySearch(max_results=2)]
tool_node = ToolNode(tools)
# 2. モデルの準備
model = ChatOpenAI(model="gpt-4o-mini", temperature=0).bind_tools(tools)
# 3. Agentノードとなる関数の定義
def call_model(state: State):
messages = state['messages']
response = model.invoke(messages)
# 新しいメッセージを辞書形式で返すと、Stateに自動で追加(マージ)される
return {"messages": [response]}
3. Edges(エッジ)と条件付き分岐の設計
Agent が「ツールを使う」と判断したか、「直接ユーザーに回答する」と判断したかによって、次に進むルートを切り替える条件付きエッジ(Conditional Edge)を作ります。
from langgraph.graph import END
def should_continue(state: State):
messages = state['messages']
last_message = messages[-1]
# LLMが「ツールを呼び出したい」と言っている場合
if last_message.tool_calls:
return "tools"
# そうでなければ、ここで終了してユーザーに返す
return END
ひとまず準備の完了
ここまでで、グラフを組み立てるための部品(State・Nodes・Edges)が揃いました。
次は、これらを実際に1つのワークフロー(Graph)として組み立て、コンパイルし、実際にエージェントを動かしてストリーミング出力を確認します。
後半編: