LangGraphでマルチエージェントパイプラインを構築する
LangGraphでエージェントノード、条件付きエッジ、共有状態を有向グラフとして定義し、ループ、分岐、人間参加型のチェックポイントを備えた複雑なマルチエージェントワークフローを実現します。
「LangGraphでマルチエージェントパイプラインを構築する」はCoddyKit上の無料AI Engineering Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Engineering Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Engineering Academyコースには全4レッスンが含まれています。
LangGraphとは
LangGraphはLangChain上に構築されたライブラリで、マルチエージェントのワークフローを有向グラフとして定義できます。グラフのノードはエージェントまたは処理ステップを表し、エッジはノード間の状態の流れを表します。また、条件付きエッジを使うと、現在の状態に基づいて動的にルーティングできます。LangGraphは、実行エンジン、状態の永続化、人間参加型のチェックポイントを処理します。
# pip install langgraph
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
import operator
# Define your shared state schema
class AgentState(TypedDict):
messages: Annotated[list, operator.add] # append-only list
research: str
draft: str
status: strLangGraphで状態を定義する
LangGraphのすべてのワークフローは、すべてのノードが読み書きできる共有状態オブジェクト上で動作します。状態は、グラフ内でデータを受け渡す型付き辞書(TypedDict)です。ノードが実行されると、現在の状態を受け取り、処理を行い、状態にマージする更新内容の辞書を返します。この共有状態モデルにより、エージェント同士を直接結合せずに通信できます。
from typing import TypedDict
class ResearchState(TypedDict):
query: str # input from user
research_notes: str # filled by researcher node
written_draft: str # filled by writer node
review_feedback: str # filled by reviewer node
final_output: str # filled by synthesizer node
iteration_count: int # tracks how many revision loops occurred
# Each node returns a PARTIAL update - only the keys it modifies
def researcher_node(state: ResearchState) -> dict:
notes = do_research(state['query'])
return {'research_notes': notes} # only update this keyエージェントノードの作成
LangGraphでは、各エージェントは現在の状態を受け取り、LLMの呼び出しとツールの実行を行い、状態の更新内容を返すノード関数です。ノードは純粋関数であり、内部状態を保持しません。すべての状態が共有グラフ状態オブジェクトに格納されるため、ワークフローの確認、再開、デバッグが容易になります。
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
llm = ChatOpenAI(model='gpt-4o')
def researcher_node(state: ResearchState) -> dict:
messages = [
SystemMessage(content='You are a research specialist. Find accurate information.'),
HumanMessage(content=f'Research this topic: {state["query"]}')
]
response = llm.invoke(messages)
return {'research_notes': response.content}
def writer_node(state: ResearchState) -> dict:
messages = [
SystemMessage(content='You are a technical writer. Write clear, engaging prose.'),
HumanMessage(content=f'Write a draft using these notes:\n{state["research_notes"]}')
]
response = llm.invoke(messages)
return {'written_draft': response.content}StateGraphでグラフを構築する
ノード関数を定義したら、StateGraphでそれらを接続します。graph.add_node()でノードを追加し、graph.add_edge()でノード間にエッジを追加し、graph.set_entry_point()でエントリーポイントを設定して、graph.compile()でグラフを実行可能な形式にコンパイルします。コンパイル済みグラフは、初期状態を受け取り、最終状態を返すRunnableです。
from langgraph.graph import StateGraph, END
# Build the graph
workflow = StateGraph(ResearchState)
# Add nodes
workflow.add_node('researcher', researcher_node)
workflow.add_node('writer', writer_node)
workflow.add_node('reviewer', reviewer_node)
# Add edges (sequential pipeline)
workflow.set_entry_point('researcher')
workflow.add_edge('researcher', 'writer')
workflow.add_edge('writer', 'reviewer')
workflow.add_edge('reviewer', END)
# Compile into an executable
app = workflow.compile()
# Run it
result = app.invoke({'query': 'What is RAG?', 'iteration_count': 0})
print(result['written_draft'])動的ルーティングのための条件付きエッジ
条件付きエッジを使うと、現在の状態に基づいてグラフから別のノードへルーティングできます。固定されたエッジの代わりに、状態を調べて次のノード名を返すルーティング関数を指定します。これにより、改訂ループ、品質ゲート、人間による承認ステップ、エージェントの出力内容に基づく分岐を実現できます。
def should_revise(state: ResearchState) -> str:
'''Router function: returns the name of the next node.'''
if state['iteration_count'] >= 3:
return 'finalize' # Too many revisions - accept as is
if 'insufficient' in state.get('review_feedback', '').lower():
return 'researcher' # Need more research
if 'rewrite' in state.get('review_feedback', '').lower():
return 'writer' # Needs rewriting
return 'finalize' # Looks good
# Add conditional edge from reviewer
workflow.add_conditional_edges(
'reviewer', # from node
should_revise, # routing function
{
'researcher': 'researcher', # route name -> node name
'writer': 'writer',
'finalize': 'finalizer'
}
)LangGraphでのループと反復
LangGraphはループを標準でサポートしており、エージェントを複数回実行できます。これは、改訂サイクル、失敗時の再試行パターン、反復的な改善に不可欠です。無限ループを防ぐため、状態に必ずループの終了条件(反復回数のカウンターや品質スコアのしきい値など)を含め、条件付きエッジのルーターでその条件を適用してください。
def researcher_node(state: ResearchState) -> dict:
notes = do_research(state['query'])
return {
'research_notes': notes,
'iteration_count': state['iteration_count'] + 1 # always increment
}
def should_continue_research(state: ResearchState) -> str:
# Terminate loop after 3 iterations regardless of quality
if state['iteration_count'] >= 3:
return END
# Continue if research is incomplete
if len(state.get('research_notes', '')) < 500:
return 'researcher' # loop back
return 'writer' # proceed to next stageノードの並列実行
LangGraphでは、ノード内でRunnableParallelを使用するか、複数のノードへ分岐することで並列ブランチを利用できます。独立したサブタスクを同時に実行する必要がある場合は、1つのノードから複数の並列ノードへのファンアウトを作成し、その後、すべての処理を待って結果を共有状態に統合するファンインノードを配置できます。
# Fan-out: one node triggers multiple parallel ones
workflow.add_edge('planner', 'researcher_a')
workflow.add_edge('planner', 'researcher_b')
workflow.add_edge('planner', 'researcher_c')
# Fan-in: aggregator waits for all three
workflow.add_edge('researcher_a', 'aggregator')
workflow.add_edge('researcher_b', 'aggregator')
workflow.add_edge('researcher_c', 'aggregator')
workflow.add_edge('aggregator', 'writer')
# Aggregator merges parallel results
def aggregator_node(state: ResearchState) -> dict:
combined = state.get('notes_a', '') + '\n' + state.get('notes_b', '') + '\n' + state.get('notes_c', '')
return {'research_notes': combined}チェックポイントと人間参加型処理
LangGraphは、チェックポインターのバックエンド(SQLite、Redis、PostgreSQL)と統合することでチェックポイントをサポートします。チェックポイントを有効にすると、各ノードの実行後にグラフの状態が永続化されます。これにより、長時間実行されるワークフローを一時停止して確認し、再開できます。また、特定のノードでグラフを一時停止し、人間が承認または入力を行ってから続行する人間参加型のパターンも利用できます。
from langgraph.checkpoint.sqlite import SqliteSaver
# Use SQLite for persistent checkpoints
checkpointer = SqliteSaver.from_conn_string(':memory:')
app = workflow.compile(checkpointer=checkpointer, interrupt_before=['human_review'])
# First run - pauses at human_review node
thread = {'configurable': {'thread_id': 'my-workflow-1'}}
result = app.invoke({'query': 'Analyze competitors'}, config=thread)
# result.next == 'human_review' -- waiting for human input
# Human provides feedback and resumes
app.update_state(thread, {'review_feedback': 'Good research, proceed with writing'})
final = app.invoke(None, config=thread) # resume from checkpointLangGraphの出力をストリーミングする
LangGraphはストリーミングモードをサポートしており、ワークフロー全体の完了を待たずに、各ノードの完了時点で中間状態の更新を出力します。これは、ユーザーに進捗の一部を表示したい長いパイプラインで役立ちます。app.stream()を使用すると、各ステップの状態スナップショットを反復処理するイテレーターを取得できます。
# Stream intermediate results as each node completes
for event in app.stream({'query': 'What is RAG?'}):
for node_name, node_output in event.items():
print(f'Node completed: {node_name}')
if 'research_notes' in node_output:
print('Research done:', node_output['research_notes'][:100])
if 'written_draft' in node_output:
print('Draft done:', node_output['written_draft'][:100])グラフを可視化する
LangGraphでは、グラフを描画してMermaid図にできます。これは、多数のノードや条件付きエッジを含む複雑なワークフローを理解するうえで非常に役立ちます。app.get_graph().draw_mermaid_png()を呼び出すとPNG画像を取得でき、app.get_graph().draw_mermaid()を呼び出すと、任意のMermaidレンダラーに貼り付けられるMermaid構文を取得できます。
# Visualize the workflow graph
graph_image = app.get_graph().draw_mermaid_png()
with open('workflow.png', 'wb') as f:
f.write(graph_image)
# Or print Mermaid syntax
print(app.get_graph().draw_mermaid())
# Outputs:
# graph TD
# __start__ --> researcher
# researcher --> writer
# writer --> reviewer
# reviewer -->|Good| finalize
# reviewer -->|Needs work| researcherLangGraphエージェントのエンドツーエンド例
ここまでの内容をまとめると、完全なLangGraphマルチエージェントパイプラインでは、TypedDict状態を定義し、各エージェント用のノード関数を作成し、StateGraphで接続し、改訂ループ用の条件付きエッジを追加し、チェックポインター付きでコンパイルして、初期状態で呼び出します。これにより、最小限の定型コードで、堅牢で可観測性があり、再開可能なマルチエージェントワークフローを構築できます。
簡単な確認
このレッスンで学んだLangGraphのマルチエージェントパイプラインについて、理解度を確認しましょう。
レッスンのまとめ
このレッスンでは、LangGraphがマルチエージェントのワークフローを、ノードをエージェント、エッジを処理の流れとする有向グラフとして表現すること、条件付きエッジによって現在の状態に基づく動的ルーティング、ループ、改訂サイクルを実現できること、そしてチェックポイントによって長時間実行されるワークフローを一時停止・再開し、人間参加型の承認を組み込めることを学びました。次は、共有メモリとエージェント間通信について学びます。
よくある質問
「LangGraphでマルチエージェントパイプラインを構築する」レッスンは無料ですか?
はい。「LangGraphでマルチエージェントパイプラインを構築する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Engineering Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Engineering Academyコースには全4レッスンが含まれています。
「LangGraphでマルチエージェントパイプラインを構築する」で何を学びますか?
LangGraphでエージェントノード、条件付きエッジ、共有状態を有向グラフとして定義し、ループ、分岐、人間参加型のチェックポイントを備えた複雑なマルチエージェントワークフローを実現します。 ブラウザで直接実行するハンズオンコードでAI Engineering Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Engineering Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Engineering Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「LangGraphでマルチエージェントパイプラインを構築する」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Engineering Academyレッスンでコードを書いて実行できますか?
はい。すべてのAI Engineering Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 単一エージェントが行き詰まる理由
- オーケストレーター・サブエージェントパターン
- LangGraphでマルチエージェントパイプラインを構築する
- 共有メモリとエージェント間通信