Skip to content

Phase 12 · Multi-Agent Collaboration (Agent-to-Agent, A2A)

Why

Phase 5 compared several "multi-agent workflow" patterns; Phase 11 used MCP to let one agent call external tools (agent ↔ tool).

But in real production, a single agent rarely works alone — multiple agents often cooperate: a "researcher agent" gathers facts, a "writer agent" turns them into prose, and a "supervisor agent" orchestrates. That is A2A (Agent-to-Agent).

MCP is agent-to-tool; A2A is agent-to-agent. Together they form the bigger picture of "agent interconnection".

This Phase uses a native LangGraph multi-agent (supervisor + worker) — no extra protocol SDK, runs with a single make run. It perfectly echoes the tutorial's thesis: StateGraph + Node + Conditional Edge.

What

A collaborative system built from three state graphs:

  • supervisor: an agent that uses an LLM to decide the next step — outputs researcher / writer / FINISH.
  • researcher: an agent that only lists key points.
  • writer: an agent that turns points into prose.

All three share one messages state and can "see" each other's output; a conditional edge routes between workers based on the supervisor's decision.

        ┌─────────────┐
START → │ supervisor  │ ──researcher──→ ┌────────────┐
        └─────────────┘ ←──────────────│ researcher │
              │FINISH→END               └────────────┘
              └──writer──→ ┌──────────┐
                          │  writer   │ ──→ back to supervisor
                          └──────────┘

How

1. Shared state

next records the supervisor's routing decision; messages accumulates via add_messages.

python
class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]
    next: str

2. Two workers (both agents)

Wrap each role prompt into an independent agent with create_react_agent. Note: the role prompt is injected only for this call via SystemMessage and is not written into the shared state, keeping the conversation trace clean.

python
async def call_researcher(state: AgentState) -> dict:
    agent = create_react_agent(get_chat_model(), tools=[])
    result = await agent.ainvoke(
        {"messages": [SystemMessage(content=RESEARCHER_PROMPT)] + list(state["messages"])}
    )
    answer = result["messages"][-1]
    return {"messages": [answer]}  # append only the final answer to avoid duplication

3. Supervisor routing node

The supervisor node calls the LLM to decide, with a fallback (only accept a valid token):

python
async def supervisor(state: AgentState) -> dict:
    model = get_chat_model()
    decision = await model.ainvoke(
        [HumanMessage(content=ROUTING_INSTRUCTION)] + list(state["messages"])
    )
    text = decision.content.strip()
    for token in ("FINISH", "writer", "researcher"):
        if token in text:
            text = token
            break
    else:
        text = "FINISH"
    return {"messages": [AIMessage(content=f"(supervisor chose: {label})")], "next": text}

4. Assemble the graph with a conditional edge

python
builder = StateGraph(AgentState)
builder.add_node("supervisor", supervisor)
builder.add_node("researcher", call_researcher)
builder.add_node("writer", call_writer)

builder.add_edge(START, "supervisor")
builder.add_conditional_edges(
    "supervisor", should_continue,
    {"researcher": "researcher", "writer": "writer", "FINISH": END},
)
builder.add_edge("researcher", "supervisor")
builder.add_edge("writer", "supervisor")
graph = builder.compile()

Key point: after a worker finishes, it returns to the supervisor, which decides the next step — that is the essence of "supervisor + worker" multi-agent orchestration.

Run

bash
make run p=12
# or python -m examples.p12.hello_chain

The example asks "explain what an Agent is, in three sentences, to a non-technical person". You'll see the terminal print the supervisor's routing decisions, the researcher's points, the writer's prose, and the final messages trace. A typical run:

[supervisor] routing → researcher
[worker] researcher output:
- An agent is software that perceives its environment and acts autonomously
- It uses an LLM to make decisions
- It can call tools to get things done
[supervisor] routing → writer
[worker] writer output:
An agent is like a little assistant……
[supervisor] routing → FINISH

Summary

  • A2A = multiple agents cooperating; MCP = agent calling tools. Together they form "agent interconnection".
  • A native LangGraph multi-agent is simply state graph + node + conditional edge: each agent is a node, the supervisor's decision is the conditional edge.
  • As in Phase 11, workers and supervisor share messages, but role prompts stay out of the shared state to keep the trace clean.
  • Next steps: turn workers into real sub-agents behind MCP servers, adopt the langgraph-supervisor standard handoff pattern, or connect across processes with the Google A2A protocol (this tutorial focuses on the native paradigm and does not expand on the protocol standard).