LangChain LangGraph
Module 1 Module 2 Module 3
Module 2 · Tools, State and Multi-Agent
1 2.1 MCP
2 2.1 Travel Agent
3 2.2 Runtime Context
4 2.2 State
5 2.3 Multi Agent
6 2.4 Wedding Planners
7 Bonus: RAG
8 Bonus: SQL
SUM Module Summary
HomeLangChainModule 2 · Tools, State and Multi-Agent2.3 Multi Agent
📓 Notebook 📖 Explained
LANGCHAIN MODULE 2 · LESSON 2.3

Multi-Agent: wrapping sub-agents as tools
Delegation · Routing · Message Trace

This section uses two mathematical sub-Agents to demonstrate multi-Agent orchestration: the main Agent does not do everything directly, but uses specialized sub-Agents through the tool.

1 Why use Multi-Agent

When an Agent takes on too many responsibilities at the same time, prompts become longer and tool selection becomes more confusing. The approach of Multi-Agent is to split the Put capability into multiple specialized Agents, and then the main Agent is responsible for selection and coordination.

Subagent

Focus on a small task, such as just taking square root or squaring.

Wrapper Tool

The logic of Put and Use sub-Agent is encapsulated into a common tool.

Main Agent

Choose which wrapper tool to adjust based on the User problem.

Core pattern

"Agent as Tool": The sub-Agent itself is not directly exposed to the User user, but is called Use by a tool function. The main Agent only needs to learn when to call Use this tool.

2 Define low-level tools first

Notebook first defines two common tools: one to calculate square roots and one to calculate squares. They are child Agent exclusive tools.

Python
@tool
def square_root(x: float) -> float:
    """Calculate the square root of a number"""
    return x ** 0.5

@tool
def square(x: float) -> float:
    """Calculate the square of a number"""
    return x ** 2
Why the simple example matters

The mathematical tools are small, but the structure is consistent with the real business: each sub-Agent has its own tool set and responsibility boundaries.

3 Create two sub-agents

Each sub-Agent only gets the tools it needs. This way it has less space to move and its behavior is more predictable.

Python
subagent_1 = create_agent(
    model=deepseek_model(),
    tools=[square_root],
)

subagent_2 = create_agent(
    model=deepseek_model(),
    tools=[square],
)
AgenttoolResponsibilities
subagent_1square_rootanswer prescription questions
subagent_2squareanswer square question

4 Wrap sub-agents as tools for the main Agent

The master Agent cannot directly "see" the child Agent. Notebook uses two wrapper tools to adjust the Use sub-Agent, and Put the final message of the sub-Agent back to the main Agent.

Python
@tool
def call_subagent_1(x: float) -> float:
    """Call subagent 1 in order to calculate the square root of a number"""
    response = subagent_1.invoke(
        {"messages": [HumanMessage(content=f"Calculate the square root of {x}")]}
    )
    return response["messages"][-1].content

@tool
def call_subagent_2(x: float) -> float:
    """Call subagent 2 in order to calculate the square of a number"""
    response = subagent_2.invoke(
        {"messages": [HumanMessage(content=f"Calculate the square of {x}")]}
    )
    return response["messages"][-1].content
Keep return values simple

Wrapper tool preferably returns the final result or short explanation required by the main Agent. Do not put the entire sub-Agent trace back as it is, otherwise the main Agent context will expand.

5 The main Agent handles routing

After the main Agent gets the two wrapper tools, it will choose which sub-Agent to use based on the user problem. For example "square root" should be routed to call_subagent_1.

Python
main_agent = create_agent(
    model=deepseek_model(),
    tools=[call_subagent_1, call_subagent_2],
)

question = "What is the square root of 456?"
response = main_agent.invoke({"messages": [HumanMessage(content=question)]})

print(response["messages"][-1].content)
User

Asks a math question.

Main Agent

Decides a square-root operation is needed.

Wrapper Tool

Calls the square-root sub-agent.

Subagent

Calls the low-level tool and returns the result.

6 Inspect the message trace

At the end, the notebook uses pprint(response) and model_dump() to inspect message details. This shows when the main Agent issued a tool call, what the tool returned, and how the final answer was formed.

Python
pprint(response)
pprint(response["messages"][1])
pprint(response["messages"][0].model_dump(), sort_dicts=False)
pprint(response["messages"][1].model_dump(), sort_dicts=False)
Debugging focus

Multi-agent issues are often not "the model cannot answer" but "routing was wrong" or "the sub-agent return value does not fit the main Agent." Inspecting the trace is the fastest way to locate the problem.