🔖

langgraph-supervisorでStreamingすると何が出てくるの?

に公開

メモ的な記事。ただただ、どんな情報が出力されるのかの具体例が知りたかったので…。

Supervisorくんは具体的に何をするの?

langgraph-supervisorを使って、LLMのストリーミングを行うと、どのような情報が出力されるのかを確認する。というか、LangGraphでの「ストリーミング」がどんな内容なのかを確認したい。

以下のようなサンプルコードがあるが、最終出力ではなくストリーミング中にどのような情報が出力されるのか。

https://github.com/langchain-ai/langgraph-supervisor-py

サンプルではSupervisorに対して2つのダミーエージェントを指定してるけど、ストリーミングで結果を取得するとデフォルトだとどんな情報がどんな単位で出力されるのかがパッと見はわからない。

# Create supervisor workflow
workflow = create_supervisor(
    [research_agent, math_agent],
    model=model,
    prompt=(
        "You are a team supervisor managing a research expert and a math expert. "
        "For current events, use research_agent. "
        "For math problems, use math_agent."
    )
)
公式のQuickstart全文
from langchain_openai import ChatOpenAI

from langgraph_supervisor import create_supervisor
from langgraph.prebuilt import create_react_agent

model = ChatOpenAI(model="gpt-4o")

# Create specialized agents

def add(a: float, b: float) -> float:
    """Add two numbers."""
    return a + b

def multiply(a: float, b: float) -> float:
    """Multiply two numbers."""
    return a * b

def web_search(query: str) -> str:
    """Search the web for information."""
    return (
        "Here are the headcounts for each of the FAANG companies in 2024:\n"
        "1. **Facebook (Meta)**: 67,317 employees.\n"
        "2. **Apple**: 164,000 employees.\n"
        "3. **Amazon**: 1,551,000 employees.\n"
        "4. **Netflix**: 14,000 employees.\n"
        "5. **Google (Alphabet)**: 181,269 employees."
    )

math_agent = create_react_agent(
    model=model,
    tools=[add, multiply],
    name="math_expert",
    prompt="You are a math expert. Always use one tool at a time."
)

research_agent = create_react_agent(
    model=model,
    tools=[web_search],
    name="research_expert",
    prompt="You are a world class researcher with access to web search. Do not do any math."
)

# Create supervisor workflow
workflow = create_supervisor(
    [research_agent, math_agent],
    model=model,
    prompt=(
        "You are a team supervisor managing a research expert and a math expert. "
        "For current events, use research_agent. "
        "For math problems, use math_agent."
    )
)

# Compile and run
app = workflow.compile()
result = app.invoke({
    "messages": [
        {
            "role": "user",
            "content": "what's the combined headcount of the FAANG companies in 2024?"
        }
    ]
})

LangGraphのストリーミング

https://langchain-ai.github.io/langgraph/agents/streaming/

基本的にはLangGraphのコード上のストリーミングおよびLangGraph APIのそれは、このページに書かれていることがベース。

agent = create_react_agent(
    model="anthropic:claude-3-7-sonnet-latest",
    tools=[get_weather],
)

for stream_mode, chunk in agent.stream(
    {"messages": [{"role": "user", "content": "what is the weather in sf"}]},
    stream_mode=["updates", "messages", "custom"]
):
    print(chunk)
    print("\n")

CompiledGraphstreamメソッドを使うと、3つのレベルでストリーミングされる。

  • updates: エージェントの状態 (= State) の更新
  • messages: LLMからのtoken単位での出力
  • custom: カスタム設定

基本的にはupdatesを使えば、エージェントの状態の更新が定期的に出力されるので処理に合わせたアプリケーションを構築できる。
あるいは、messagesを使えば、LLMからの出力をトークン単位で受け取ることができるので、エージェントの応答をチャットインタフェースで表示したいような要求がある場合にはこちらを使う。
customは、stream_writerを使って、独自のストリーミングを実装することができるので、しっかりとアプリを作り込んでいくならこのあたりを見ていくべきだろう。

これらは同時に指定することができ、その場合は上記コード断片のようにどのモードに対する出力なのかを判断できるので分岐すればよい。今回はデフォルトでSupervisorくんは何を出力するのかを確認したいので、updatesのみ指定した。

結果

とりあえず、公式サンプルで組み上がるマルチエージェントなグラフに対して以下のようなコードを実行してみた結果を列挙する。

for chunk in app.stream({
        "messages": [{
                "role": "user",
                "content": "what's the combined headcount of the FAANG companies in 2024?",
        }],
    },
    stream_mode=["updates"],
):
    print(chunk)
    print("\n")

全部見たい場合は↓をどうぞ。以下は冗長なので部分を抜粋します。

ぜんぶみる
(
    'updates',
    {
        'supervisor': {
            'messages': [
                HumanMessage(
                    content="what's the combined headcount of the FAANG companies in 2024?",
                    additional_kwargs={},
                    response_metadata={},
                    id='b526be62-5e0d-481f-80f7-7a63da05099e'
                ),
                AIMessage(
                    content='',
                    additional_kwargs={
                        'tool_calls': [{'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'function': {'arguments': '{}', 'name': 'transfer_to_research_expert'}, 'type': 'function'}],
                        'refusal': None
                    },
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 15,
                            'prompt_tokens': 112,
                            'total_tokens': 127,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_5d58a6052a',
                        'id': 'chatcmpl-BgodYl6jENFRqpvT04uEAOnqoX3H1',
                        'service_tier': None,
                        'finish_reason': 'tool_calls',
                        'logprobs': None
                    },
                    name='supervisor',
                    id='run--6cba2462-3869-4bbd-b02a-11072f0eb0d9-0',
                    tool_calls=[{'name': 'transfer_to_research_expert', 'args': {}, 'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'type': 'tool_call'}],
                    usage_metadata={
                        'input_tokens': 112,
                        'output_tokens': 15,
                        'total_tokens': 127,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                ToolMessage(
                    content='Successfully transferred to research_expert',
                    name='transfer_to_research_expert',
                    id='9b713da2-b7c8-42ea-b5e5-67a0efc5a74f',
                    tool_call_id='call_UU4uO15QmKDqwkBao6tOmmua'
                )
            ]
        }
    }
)
(
    'updates',
    {
        'research_expert': {
            'messages': [
                AIMessage(
                    content='Here are the headcounts for each of the FAANG companies in 2024:\n\n1. **Facebook (Meta)**: 67,317 employees\n2. **Apple**: 164,000 employees\n3.**Amazon**: 1,551,000 employees\n4. **Netflix**: 14,000 employees\n5. **Google (Alphabet)**: 181,269 employees\n\nTo find the combined headcount, you can sum these numbers.',
                    additional_kwargs={'refusal': None},
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 98,
                            'prompt_tokens': 683,
                            'total_tokens': 781,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_5d58a6052a',
                        'id': 'chatcmpl-BgodfQH6XfIV5utUlJKtZvhQatBFr',
                        'service_tier': None,
                        'finish_reason': 'stop',
                        'logprobs': None
                    },
                    name='research_expert',
                    id='run--3abad6c2-0cd8-44b5-a342-7f0f12a842fc-0',
                    usage_metadata={
                        'input_tokens': 683,
                        'output_tokens': 98,
                        'total_tokens': 781,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                AIMessage(
                    content='Transferring back to supervisor',
                    additional_kwargs={},
                    response_metadata={'__is_handoff_back': True},
                    name='research_expert',
                    id='e8e67c5c-92d7-4cfe-9838-faa62843daa9',
                    tool_calls=[{'name': 'transfer_back_to_supervisor', 'args': {}, 'id': 'ca401f75-052e-431f-86ae-9a99dcb9b34f', 'type': 'tool_call'}]
                ),
                ToolMessage(
                    content='Successfully transferred back to supervisor',
                    name='transfer_back_to_supervisor',
                    id='23745133-68bc-4718-a95a-32939d53b42f',
                    tool_call_id='ca401f75-052e-431f-86ae-9a99dcb9b34f'
                )
            ]
        }
    }
)
(
    'updates',
    {
        'supervisor': {
            'messages': [
                HumanMessage(
                    content="what's the combined headcount of the FAANG companies in 2024?",
                    additional_kwargs={},
                    response_metadata={},
                    id='b526be62-5e0d-481f-80f7-7a63da05099e'
                ),
                AIMessage(
                    content='',
                    additional_kwargs={
                        'tool_calls': [{'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'function': {'arguments': '{}', 'name': 'transfer_to_research_expert'}, 'type': 'function'}],
                        'refusal': None
                    },
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 15,
                            'prompt_tokens': 112,
                            'total_tokens': 127,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_5d58a6052a',
                        'id': 'chatcmpl-BgodYl6jENFRqpvT04uEAOnqoX3H1',
                        'service_tier': None,
                        'finish_reason': 'tool_calls',
                        'logprobs': None
                    },
                    name='supervisor',
                    id='run--6cba2462-3869-4bbd-b02a-11072f0eb0d9-0',
                    tool_calls=[{'name': 'transfer_to_research_expert', 'args': {}, 'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'type': 'tool_call'}],
                    usage_metadata={
                        'input_tokens': 112,
                        'output_tokens': 15,
                        'total_tokens': 127,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                ToolMessage(
                    content='Successfully transferred to research_expert',
                    name='transfer_to_research_expert',
                    id='9b713da2-b7c8-42ea-b5e5-67a0efc5a74f',
                    tool_call_id='call_UU4uO15QmKDqwkBao6tOmmua'
                ),
                AIMessage(
                    content='Here are the headcounts for each of the FAANG companies in 2024:\n\n1. **Facebook (Meta)**: 67,317 employees\n2. **Apple**: 164,000 employees\n3. **Amazon**: 1,551,000 employees\n4. **Netflix**: 14,000 employees\n5. **Google (Alphabet)**: 181,269 employees\n\nTo find the combined headcount, you can sum these numbers.',
                    additional_kwargs={'refusal': None},
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 98,
                            'prompt_tokens': 683,
                            'total_tokens': 781,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_5d58a6052a',
                        'id': 'chatcmpl-BgodfQH6XfIV5utUlJKtZvhQatBFr',
                        'service_tier': None,
                        'finish_reason': 'stop',
                        'logprobs': None
                    },
                    name='research_expert',
                    id='run--3abad6c2-0cd8-44b5-a342-7f0f12a842fc-0',
                    usage_metadata={
                        'input_tokens': 683,
                        'output_tokens': 98,
                        'total_tokens': 781,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                AIMessage(
                    content='Transferring back to supervisor',
                    additional_kwargs={},
                    response_metadata={'__is_handoff_back': True},
                    name='research_expert',
                    id='e8e67c5c-92d7-4cfe-9838-faa62843daa9',
                    tool_calls=[{'name': 'transfer_back_to_supervisor', 'args': {}, 'id': 'ca401f75-052e-431f-86ae-9a99dcb9b34f', 'type': 'tool_call'}]
                ),
                ToolMessage(
                    content='Successfully transferred back to supervisor',
                    name='transfer_back_to_supervisor',
                    id='23745133-68bc-4718-a95a-32939d53b42f',
                    tool_call_id='ca401f75-052e-431f-86ae-9a99dcb9b34f'
                ),
                AIMessage(
                    content='',
                    additional_kwargs={
                        'tool_calls': [{'id': 'call_Dann03Z73JT4qmR5kJb0O4tl', 'function': {'arguments': '{}', 'name': 'transfer_to_math_expert'}, 'type': 'function'}],
                        'refusal': None
                    },
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 14,
                            'prompt_tokens': 298,
                            'total_tokens': 312,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_5d58a6052a',
                        'id': 'chatcmpl-BgodzWWTbvYupVnkU2OLZjihbF4BW',
                        'service_tier': None,
                        'finish_reason': 'tool_calls',
                        'logprobs': None
                    },
                    name='supervisor',
                    id='run--337b7186-cc14-4c19-bd81-a15978581567-0',
                    tool_calls=[{'name': 'transfer_to_math_expert', 'args': {}, 'id': 'call_Dann03Z73JT4qmR5kJb0O4tl', 'type': 'tool_call'}],
                    usage_metadata={
                        'input_tokens': 298,
                        'output_tokens': 14,
                        'total_tokens': 312,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                ToolMessage(
                    content='Successfully transferred to math_expert',
                    name='transfer_to_math_expert',
                    id='451a97e4-3ed7-419c-a498-66b28d208a0b',
                    tool_call_id='call_Dann03Z73JT4qmR5kJb0O4tl'
                )
            ]
        }
    }
)
(
    'updates',
    {
        'math_expert': {
            'messages': [
                AIMessage(
                    content='The combined headcount of the FAANG companies in 2024 is 1,977,586 employees.',
                    additional_kwargs={'refusal': None},
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 24,
                            'prompt_tokens': 540,
                            'total_tokens': 564,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_ee1d74bde0',
                        'id': 'chatcmpl-BgoeDtqkdmbIRgDvnd4mT1qW63rlC',
                        'service_tier': None,
                        'finish_reason': 'stop',
                        'logprobs': None
                    },
                    name='math_expert',
                    id='run--863560d3-3fda-427e-ba1f-d949502f7b78-0',
                    usage_metadata={
                        'input_tokens': 540,
                        'output_tokens': 24,
                        'total_tokens': 564,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                AIMessage(
                    content='Transferring back to supervisor',
                    additional_kwargs={},
                    response_metadata={'__is_handoff_back': True},
                    name='math_expert',
                    id='69756f6d-0663-48cd-984a-a3c1dd24bdbe',
                    tool_calls=[{'name': 'transfer_back_to_supervisor', 'args': {}, 'id': 'caa1afc9-a100-41e0-9794-04e90adf6daf', 'type': 'tool_call'}]
                ),
                ToolMessage(
                    content='Successfully transferred back to supervisor',
                    name='transfer_back_to_supervisor',
                    id='98b63678-cc3c-415c-97a5-226226ddf865',
                    tool_call_id='caa1afc9-a100-41e0-9794-04e90adf6daf'
                )
            ]
        }
    }
)
(
    'updates',
    {
        'supervisor': {
            'messages': [
                HumanMessage(
                    content="what's the combined headcount of the FAANG companies in 2024?",
                    additional_kwargs={},
                    response_metadata={},
                    id='b526be62-5e0d-481f-80f7-7a63da05099e'
                ),
                AIMessage(
                    content='',
                    additional_kwargs={
                        'tool_calls': [{'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'function': {'arguments': '{}', 'name': 'transfer_to_research_expert'}, 'type': 'function'}],
                        'refusal': None
                    },
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 15,
                            'prompt_tokens': 112,
                            'total_tokens': 127,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_5d58a6052a',
                        'id': 'chatcmpl-BgodYl6jENFRqpvT04uEAOnqoX3H1',
                        'service_tier': None,
                        'finish_reason': 'tool_calls',
                        'logprobs': None
                    },
                    name='supervisor',
                    id='run--6cba2462-3869-4bbd-b02a-11072f0eb0d9-0',
                    tool_calls=[{'name': 'transfer_to_research_expert', 'args': {}, 'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'type': 'tool_call'}],
                    usage_metadata={
                        'input_tokens': 112,
                        'output_tokens': 15,
                        'total_tokens': 127,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                ToolMessage(
                    content='Successfully transferred to research_expert',
                    name='transfer_to_research_expert',
                    id='9b713da2-b7c8-42ea-b5e5-67a0efc5a74f',
                    tool_call_id='call_UU4uO15QmKDqwkBao6tOmmua'
                ),
                AIMessage(
                    content='Here are the headcounts for each of the FAANG companies in 2024:\n\n1. **Facebook (Meta)**: 67,317 employees\n2. **Apple**: 164,000 employees\n3.
**Amazon**: 1,551,000 employees\n4. **Netflix**: 14,000 employees\n5. **Google (Alphabet)**: 181,269 employees\n\nTo find the combined headcount, you can sum these numbers.',
                    additional_kwargs={'refusal': None},
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 98,
                            'prompt_tokens': 683,
                            'total_tokens': 781,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_5d58a6052a',
                        'id': 'chatcmpl-BgodfQH6XfIV5utUlJKtZvhQatBFr',
                        'service_tier': None,
                        'finish_reason': 'stop',
                        'logprobs': None
                    },
                    name='research_expert',
                    id='run--3abad6c2-0cd8-44b5-a342-7f0f12a842fc-0',
                    usage_metadata={
                        'input_tokens': 683,
                        'output_tokens': 98,
                        'total_tokens': 781,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                AIMessage(
                    content='Transferring back to supervisor',
                    additional_kwargs={},
                    response_metadata={'__is_handoff_back': True},
                    name='research_expert',
                    id='e8e67c5c-92d7-4cfe-9838-faa62843daa9',
                    tool_calls=[{'name': 'transfer_back_to_supervisor', 'args': {}, 'id': 'ca401f75-052e-431f-86ae-9a99dcb9b34f', 'type': 'tool_call'}]
                ),
                ToolMessage(
                    content='Successfully transferred back to supervisor',
                    name='transfer_back_to_supervisor',
                    id='23745133-68bc-4718-a95a-32939d53b42f',
                    tool_call_id='ca401f75-052e-431f-86ae-9a99dcb9b34f'
                ),
                AIMessage(
                    content='',
                    additional_kwargs={
                        'tool_calls': [{'id': 'call_Dann03Z73JT4qmR5kJb0O4tl', 'function': {'arguments': '{}', 'name': 'transfer_to_math_expert'}, 'type': 'function'}],
                        'refusal': None
                    },
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 14,
                            'prompt_tokens': 298,
                            'total_tokens': 312,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_5d58a6052a',
                        'id': 'chatcmpl-BgodzWWTbvYupVnkU2OLZjihbF4BW',
                        'service_tier': None,
                        'finish_reason': 'tool_calls',
                        'logprobs': None
                    },
                    name='supervisor',
                    id='run--337b7186-cc14-4c19-bd81-a15978581567-0',
                    tool_calls=[{'name': 'transfer_to_math_expert', 'args': {}, 'id': 'call_Dann03Z73JT4qmR5kJb0O4tl', 'type': 'tool_call'}],
                    usage_metadata={
                        'input_tokens': 298,
                        'output_tokens': 14,
                        'total_tokens': 312,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                ToolMessage(
                    content='Successfully transferred to math_expert',
                    name='transfer_to_math_expert',
                    id='451a97e4-3ed7-419c-a498-66b28d208a0b',
                    tool_call_id='call_Dann03Z73JT4qmR5kJb0O4tl'
                ),
                AIMessage(
                    content='The combined headcount of the FAANG companies in 2024 is 1,977,586 employees.',
                    additional_kwargs={'refusal': None},
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 24,
                            'prompt_tokens': 540,
                            'total_tokens': 564,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_ee1d74bde0',
                        'id': 'chatcmpl-BgoeDtqkdmbIRgDvnd4mT1qW63rlC',
                        'service_tier': None,
                        'finish_reason': 'stop',
                        'logprobs': None
                    },
                    name='math_expert',
                    id='run--863560d3-3fda-427e-ba1f-d949502f7b78-0',
                    usage_metadata={
                        'input_tokens': 540,
                        'output_tokens': 24,
                        'total_tokens': 564,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                ),
                AIMessage(
                    content='Transferring back to supervisor',
                    additional_kwargs={},
                    response_metadata={'__is_handoff_back': True},
                    name='math_expert',
                    id='69756f6d-0663-48cd-984a-a3c1dd24bdbe',
                    tool_calls=[{'name': 'transfer_back_to_supervisor', 'args': {}, 'id': 'caa1afc9-a100-41e0-9794-04e90adf6daf', 'type': 'tool_call'}]
                ),
                ToolMessage(
                    content='Successfully transferred back to supervisor',
                    name='transfer_back_to_supervisor',
                    id='98b63678-cc3c-415c-97a5-226226ddf865',
                    tool_call_id='caa1afc9-a100-41e0-9794-04e90adf6daf'
                ),
                AIMessage(
                    content='The combined headcount of the FAANG companies in 2024 is 1,977,586 employees.',
                    additional_kwargs={'refusal': None},
                    response_metadata={
                        'token_usage': {
                            'completion_tokens': 24,
                            'prompt_tokens': 408,
                            'total_tokens': 432,
                            'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0},
                            'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}
                        },
                        'model_name': 'gpt-4o-2024-08-06',
                        'system_fingerprint': 'fp_ee1d74bde0',
                        'id': 'chatcmpl-BgoeP4VorWVlVWfA4Hx8JbnS4u58U',
                        'service_tier': None,
                        'finish_reason': 'stop',
                        'logprobs': None
                    },
                    name='supervisor',
                    id='run--ce6772fb-3e63-447a-8e97-8b847e15900a-0',
                    usage_metadata={
                        'input_tokens': 408,
                        'output_tokens': 24,
                        'total_tokens': 432,
                        'input_token_details': {'audio': 0, 'cache_read': 0},
                        'output_token_details': {'audio': 0, 'reasoning': 0}
                    }
                )
            ]
        }
    }
)

まず、最初のステータスアップデートでわかるのは、Supervisorからresearch_expertへの転送が行われていること。これはいわゆるエージェント間のハンドオフで、langgraph-spervisorのREADMEにも書かれている通り実体はTool Callingによって実現されている。

ストリーミングされたStateの中では、Supervisorがユーザからの質問を受け取り、research_expertに転送するためのTool Callが行われていることがわかる。ToolMessageがエントリにあることから、SupervisorのTool Calling要請と実際にToolを呼び出してresearch_expertに転送されたところまで (Graphのノードが切り替わったところ=Stateが更新されたところ) がワンセットとなっている。

(
    'updates',
    {
        'supervisor': {
            'messages': [
                HumanMessage(
                    content="what's the combined headcount of the FAANG companies in 2024?",
                ),
                AIMessage(
                    content='',
                    additional_kwargs={
                        'tool_calls': [{'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'function': {'arguments': '{}', 'name': 'transfer_to_research_expert'}, 'type': 'function'}],
                    },
                    name='supervisor',
                    tool_calls=[{'name': 'transfer_to_research_expert', 'args': {}, 'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'type': 'tool_call'}],
                ),
                ToolMessage(
                    content='Successfully transferred to research_expert',
                    name='transfer_to_research_expert',
                )
            ]
        }
    }
)

次にSuperviserからresearch_expertに転送された後の状態が出力される。ここでは、research_expertがFAANG企業の2024年の従業員数を回答し、Supervisorに結果戻すためのハンドオフがTool Callingを通して行われている。

基本的にはState中のmessagesに含める形で、エージェント間の会話としてやり取りが引き継がれていることがわかる。このあたり、会話ではなくて単にオブジェクトとして引き渡したいときなどはグラフ構造の変更も含めて工夫がいるかも知れない。

(
    'updates',
    {
        'research_expert': {
            'messages': [
                AIMessage(
                    content='Here are the headcounts for each of the FAANG companies in 2024:\n\n1. **Facebook (Meta)**: 67,317 employees\n2. **Apple**: 164,000 employees\n3.**Amazon**: 1,551,000 employees\n4. **Netflix**: 14,000 employees\n5. **Google (Alphabet)**: 181,269 employees\n\nTo find the combined headcount, you can sum these numbers.',
                    name='research_expert',
                ),
                AIMessage(
                    content='Transferring back to supervisor',
                    name='research_expert',
                    tool_calls=[{'name': 'transfer_back_to_supervisor', 'args': {}, 'id': 'ca401f75-052e-431f-86ae-9a99dcb9b34f', 'type': 'tool_call'}]
                ),
                ToolMessage(
                    content='Successfully transferred back to supervisor',
                    name='transfer_back_to_supervisor',
                )
            ]
        }
    }
)

Supervisorに戻った後の状態では、research_expertからの回答を受け取ったSupervisorが、さらにmath_expertに転送するためのTool Callingを行っている。ここでも、Tool Callingによるハンドオフが行われている。

(
    'updates',
    {
        'supervisor': {
            'messages': [
                HumanMessage(
                    content="what's the combined headcount of the FAANG companies in 2024?",
                ),
                AIMessage(
                    content='',
                    additional_kwargs={
                        'tool_calls': [{'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'function': {'arguments': '{}', 'name': 'transfer_to_research_expert'}, 'type': 'function'}],
                    },
                    name='supervisor',
                    tool_calls=[{'name': 'transfer_to_research_expert', 'args': {}, 'id': 'call_UU4uO15QmKDqwkBao6tOmmua', 'type': 'tool_call'}],
                ),
                ToolMessage(
                    content='Successfully transferred to research_expert',
                    name='transfer_to_research_expert',
                ),
                AIMessage(
                    content='Here are the headcounts for each of the FAANG companies in 2024:\n\n1. **Facebook (Meta)**: 67,317 employees\n2. **Apple**: 164,000 employees\n3.**Amazon**: 1,551,000 employees\n4. **Netflix**: 14,000 employees\n5. **Google (Alphabet)**: 181,269 employees\n\nTo find the combined headcount, you can sum these numbers.',
                    name='research_expert',
                ),
                AIMessage(
                    content='Transferring back to supervisor',
                    name='research_expert',
                    tool_calls=[{'name': 'transfer_back_to_supervisor', 'args': {}, 'id': 'ca401f75-052e-431f-86ae-9a99dcb9b34f', 'type': 'tool_call'}]
                ),
                ToolMessage(
                    content='Successfully transferred back to supervisor',
                    name='transfer_back_to_supervisor',
                ),
                AIMessage(
                    content='',
                    additional_kwargs={
                        'tool_calls': [{'id': 'call_Dann03Z73JT4qmR5kJb0O4tl', 'function': {'arguments': '{}', 'name': 'transfer_to_math_expert'}, 'type': 'function'}],
                        'refusal': None
                    },
                    name='supervisor',
                    tool_calls=[{'name': 'transfer_to_math_expert', 'args': {}, 'id': 'call_Dann03Z73JT4qmR5kJb0O4tl', 'type': 'tool_call'}],
                ),
                ToolMessage(
                    content='Successfully transferred to math_expert',
                    name='transfer_to_math_expert',
                )
            ]
        }
    }
)

math_expertに転送された後はresearch_expertと同様なので、省略これで大体わかりましたね。

まとめ

なので処理の流れはとストリーミングのタイミングはだいたいこんな感じになるわけですね。

Supervisorからハンドオフされたエージェントの中間結果が必要な場合でも、基本的にはカスタマイズしないでもいい感じで見れそう。

とある通信会社の有志

Discussion