CCCMKホールディングス TECH LABの Tech Blog

TECH LABのエンジニアが技術情報を発信しています

ブログタイトル

LangGraph Supervisorを使ったMulti-Agentシステムの構築

こんにちは、CCCMKホールディングス三浦です。

7月1日です!1年のちょうど折り返し地点ですね。今年の前半戦は色々と学ぶことが多かったです。後半戦はそれを活かして自分で生み出すことにチャレンジしていきたいな、と思っています!

最近生成AIを使ったアプリケーションを開発する際に、"Multi-Agent"というアプローチを検討することがありました。これまでは単一のAgentに複数のツールを与えて対応することが多かったのですが、1つのAgentに複数のツールを与えてもこちらが意図したようにツールを使ってくれないことが多く、また1か所を調整するとAgentの処理全体がおかしくなる・・・といったことがあり、開発の難しさを感じていました。

各Agentをモジュールとして捉え、個別に開発を行い、最後にそれらのAgentを組み合させてアプリケーションのフローを構築する、というアプローチの方が良いのかも、と考えるようになり、"Multi-Agent"の導入の必要性を少しずつ感じるようになりました。そんな中、LangGraphのSupervisorというライブラリを使ってMulti-Agentの構築が比較的簡単に出来る、という情報を知り、今回調べてみることにしました。

実際LangGraph Supervisorを使うと単一のAgentを組み合わせてMulti-Agentのフローをすぐに作ることが出来ますし、Agentの組み合わせ方によってフローの調整が出来そうだと感じました。

単一AgentからMulti-Agentへ

LangGraphの"Multi-agent systems"のページに単一Agentにおける課題とMulti-Agentによるメリットが記載されています。とても納得感のある内容でした。

langchain-ai.lang.chat

このページでは単一Agentのよる課題として以下を挙げています。

  • エージェントが利用できるツールが多すぎて、次にどのツールを呼び出すべきかについて誤った判断をする
  • コンテキストが複雑になりすぎて、単一のエージェントでは追跡できなくなる
  • システム内で複数の専門分野(例:プランナー、リサーチャー、数学の専門家など)が必要となる

比較的小さなフローだとこれらは問題にならないのですが、システムに求められる要件が増えていき、フローが大きくなってくるとこれらがだんだん問題になってきます。オブジェクト指向に似た考えですが、タスクを細かく分割し、それぞれのタスクに対応した専門的なAgentを作り、最後にそれらを組み合わせて全体のフローを作る、というアプローチを取ることで拡張性のある開発が可能になります。

先述したドキュメントでは、Multi-Agentのメリットとして以下が挙げられています。

  • モジュール性: エージェントを分けることでシステムの開発・テスト・保守が容易になる
  • 専門性: 特定分野に特化した専門エージェントを開発することで全体のパフォーマンス向上に繋がる
  • 制御性: エージェント間のコミュニケーションを明示的に制御でき、柔軟性が向上する

LangGraph Supervisor

Multi-Agentのアーキテクチャパターンはいくつかありますが、今回取り上げるのはその中の"Supervisor"というアーキテクチャです。Supervisor(監督者)と呼ばれるAgentが中心に存在する構成で、Supervisorが状況に応じて別のAgentにタスクを渡し、実行結果をSupervisorが受け取り次のAgentにタスクを渡す・・・というステップでタスクを解決します。Agentは必ずSupervisorを経由してコミュニケーションを取り、Supervisor以外のAgent同士では直接コミュニケーションは取らない構成です。

SupervisorタイプのMulti-Agentの構成イメージ

LangGraph SupervisorはLangGraphを使ったSupervisorタイプのMulti-Agentシステムを構築することが出来るライブラリです。Githubのレポジトリはこちらです。

github.com

LangGraph Supervisorで作ることが出来るSupervisor Agentの本質はLangGraphのcreate_react_agent()で構築されるAgent Graph(CompiledStateGraph)です。Supervisor Agentは各Agentにタスクを受け渡すhandoffツールが与えられており、状況に応じてhandoffツールを通じて対応するAgentにタスクがSupervisor Agentから受け渡されます。

LangGraph Supervisorを使ってWebから情報を取得し、レポート化してくれる仕組みを具体的に作ってみましたので、以降具体的な実装方法をご紹介したいと思います。

Multi-Agentの構成

今回作ったMulti-Agentの仕組みですが、ユーザーが「LangGraphについてレポートをまとめて」といったクエリを入力すると関連する情報をWebから検索をし、取得した情報を使ってレポートにまとめる、といった動作をします。Supervisorを除くAgentは以下の通りです。

  • search_planner: レポートを書くためにどのように情報をWeb検索を使って収集をしたらよいか、計画を立てる
  • web_searcher: あなたのタスクはクエリとして与えられた情報をWeb検索を使って収集する
  • report_writer: これまでに検索した情報をレポートにまとめ、出力する

web_searcherはWeb検索にAzureの"Bing Web Search API"を使用しました。

各Agentの実装

それぞれのAgentの実装は以下のようにしました。

search_planner

search_plannerはツールの実行は行わず、LLMを使ってどうやってWebから情報検索するのかの計画作成を担当します。Agent Graphとして生成するため、ツールはないですがcreate_react_agent()を呼び出して構築しています。

from langchain_openai import AzureChatOpenAI
from langgraph.prebuilt import create_react_agent

llm = AzureChatOpenAI(model="gpt-4.1-mini",api_version="2025-01-01-preview")

search_planner = create_react_agent(
    llm, 
    tools=[], 
    name="search_planner",
    prompt="あなたのタスクは与えられたテーマに関するレポートを書くためにどのように情報をWeb検索を使って収集をしたらよいか、計画を立てることです。様々な観点でWeb検索を使って情報を収集するための計画をステップバイステップで考えてください。"
)

web_searcher

Web検索はAzureの"Bing Web Search API"を使用しました。そのための事前準備として環境変数BING_SUBSCRIPTION_KEYに接続キーを、BING_SEARCH_URLにAPIのエンドポイントを設定しておきます。

まずAgentに与えるツールを以下のように定義します。

from langchain_community.utilities import BingSearchAPIWrapper

search = BingSearchAPIWrapper(k=4)

def bing_search(query: str) -> str:
    """
    Bing Searchを使って与えられたqueryに関する情報をwebから検索する
    """
    return search.run(query)

このツールを与えたAgentを作成します。

web_searcher = create_react_agent(
    llm,
    tools=[bing_search],
    name="web_searcher",
    prompt="あなたのタスクはクエリとして与えられた情報をWeb検索を使って収集することです。"
)

report_writer

web_searcherが調べた情報をまとめてレポートを作るAgentです。こちらもsearch_plannerと同様にツールは与えず、LLMの生成機能のみを利用します。

report_writer = create_react_agent(
    llm,
    tools=[],
    name="report_writer",
    prompt="あなたは与えられた情報を参照し、それをレポートにまとめる役割を持っています。レポートにはアブストラクト/これまでの前提情報/現在の情報/今後の発展を含めてください。"
)

Supervisorの実装

あとはこれらのAgentを利用するSupervisor Agentを実装するだけです。LangGraph Supervisorを使うととてもシンプルに実現できます。

from langgraph_supervisor import create_supervisor

supervisor_prompt="""
あなたは以下のAgent達の管理を担当しています。ユーザーのクエリをAgentにタスクを与えることで解決してください。

1. search_planner: 与えられたテーマに関するレポートを書くためにどのように情報をWeb検索を使って収集をしたらよいか、計画を立てる。
2. web_searcher: Bing検索を使って情報を検索する
3. report_writer: これまでに検索した情報をレポートにまとめ、出力する

タスクをAgentに与えてください。複数のAgentを並行して呼び出してはいけません。
最後にユーザーのクエリに対する回答を出力してください。ただし、あなた自身がいかなるタスクをこなしてはいけません。
"""

supervisor = create_supervisor(
    agents=[search_planner, web_searcher, report_writer],
    model=llm,
    prompt=supervisor_prompt,
    output_mode="full_history"
).compile()

create_supervisor()output_mode="full_history"というオプションを指定していますが、これは各Agentが実行したツールの結果などの中間情報も含めてAgent間でメッセージをやり取りするための設定です。今回だとweb_searcherがWeb検索ツールを実行しますが、このオプションを指定しない場合、つまりoutput_mode="last_message"を指定した場合はweb_searcherがWeb検索を実行した後にそれを要約した情報だけがメッセージに追加され、Supervisorに渡されます。

report_writerがレポートを作るときになるべく多くの参照情報を与えたかったため今回は"full_history"のオプションを設定しましたが、トークン数を抑えることを考えると"last_message"の方が良いと思います。

あとは以下のように実行することが出来ます。

supervisor.invoke(input={"messages":[{"role": "user", "content": "LangGraphは何が出来るのかレポートにまとめて。"}]}

生成された結果はこのようになりました。いろいろな観点でまとめてくれていて、良さそうな印象を受けました。

LangGraphは、大規模言語モデル(LLM)を活用した複雑なワークフローシステムを構築するためのライブラリで、LangChainツール群の一部です。各LLMエージェントの処理ステップをグラフ構造で表現し、状態管理を行うことで複雑な連携処理や監視を可能にします。
主な機能は以下の通りです:
状態管理とグラフ化により処理の透明性とバグ減少を実現
会話履歴やエージェント状態の永続化、短期・長期メモリによる一貫した対話管理
API連携やモデル切り替えなど拡張可能な設計
ユーザー質問に対する多段階の対話フローを簡潔にコード化
Mermaidによるワークフローの視覚的設計とデバッグ支援
また、LangGraph Cloudを使うことでクラウド上でワークフローをデプロイ・ホスティングし、ログ管理やトレースも可能です。
利用例としては、複雑な条件分岐やループを伴うLLMワークフロー設計、対話型AIの多段階管理、API統合タスクの処理統合などが挙げられます。評判としては、処理の状態管理が明確になり開発・保守が容易になる点、LangChainとの統合で強力なLLMアプリの構築が可能な点、Mermaidによる可視化が設計を助ける点が評価されています。
要約すると、LangGraphはLLMを用いた高度なAIワークフローや対話システムを設計・実装・監視するのに役立つ先進的なフレームワークです。
以上をレポートとしてまとめました。詳細な使い方やコード例などが必要でしたらお知らせください。

Agentの構成を変えてみる

Multi-Agentの面白い点は、Agentの組み合わせを変えることでフロー全体の調整が出来る点だと思います。たとえば今回Web検索をするための計画を事前にsearch_plannerに考えさせる構成にしましたが、もしsearch_plannerを除いたらどんな結果になるのでしょうか?

次のようにsearch_plannerを除いた構成を作り、同じ質問を与えてみます。

supervisor = create_supervisor(
    agents=[web_searcher, report_writer],
    model=llm,
    prompt=supervisor_prompt,
    output_mode="full_history"
).compile()

結果はこちらです。

LangGraphは、大規模言語モデル(LLM)を活用した複雑なワークフローシステムを開発するためのライブラリです。主な機能として、LLMエージェントの処理ステップをグラフ(ステートマシン)として可視化・管理できることが挙げられます。これにより、複数のエージェントが協調して動作するマルチエージェントシステムを簡単に構築可能で、複雑な会話や業務フローの状態管理を効率化します。LangChainツール群の一部ですが、LLMモデルなどから独立して利用でき、複雑な多段階処理や会話管理に強みを持つツールです。今後は、より高度な対話型AIや自動化システムの開発にも貢献すると期待されています。

グラフ構造による表現の話、LangChainと統合されている点に言及していますが、先ほどの結果に比べるとLangGraph Cloudについては触れられていません。search_plannerを含めたほうが色々な視点で情報を取得できているように感じます。

ただしトータルのトークン数はsearch_plannerを含めた場合は26,705、含めない場合は7,043だったので、より多くのトークンを消費してしまいました。状況や要件に応じたAgentの組み方が必要だなと思いました。

まとめ

ということで、今回はLangGraph Supervisorというライブラリを使ってMulti-Agentの仕組みを構築してみました。単一のAgentを作ってまとめ上げる、というシンプルな方法で結構複雑なフローを実装できそうで面白いと感じました。ただ何回か試していると、Supervisorの制御が思うようにいかないことが度々ありました。パラメータやSupervisorのプロンプトの設定をもう少し探って最適な設定を探してみたいと思いました。