LangChainLangChain 1.4 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
46 small wins to finish your pathNext lesson →

Subagents as tools

A subagent is a whole agent wrapped as a tool, so a main agent can call it, choose what to ask it, and combine what several return.

Last updated: 27 Sep, 2026 · LangChain 1.4

The shop already has two agents: the orders agent from lesson 7 and the policies agent from lesson 28. A customer asks one question that touches both. In the subagents pattern a main agent, often called a supervisor, calls each specialist as a tool; they answer it, not the customer.

Wrapping an agent in a tool

python
@tool
def ask_specialist(question: str) -> str:      # looks like any tool
    """One line the main agent reads to know when to call this."""
    reply = specialist_agent.invoke({"messages": [{"role": "user", "content": question}]})
    return reply["messages"][-1].text          # hand back only the final text

The two specialist agents

Each specialist is a whole agent with its own model and tools. last_reply sends it one question and returns the text of its final message.

python
from langchain.agents import create_agent
from langchain.tools import tool
from help_model import HelpModel
from search import search_policies
from shop_model import ShopModel
from tools import lookup_order

orders_agent = create_agent(ShopModel(), tools=[lookup_order])       # knows orders
policies_agent = create_agent(HelpModel(), tools=[search_policies])  # knows policies


def last_reply(agent, question):
    return agent.invoke({"messages": [{"role": "user", "content": question}]})["messages"][-1].text

Wrapping each specialist as a tool

Wrap each specialist in @tool. To the main agent it looks like any other tool: a name, a description and one string argument. The main agent sees a short answer, not the specialist's whole conversation.

python
@tool
def ask_orders(question: str) -> str:
    """Ask the orders specialist where an order is."""
    return last_reply(orders_agent, question)      # only the final text comes back


@tool
def ask_policies(question: str) -> str:
    """Ask the policies specialist about refunds, shipping or accounts."""
    return last_reply(policies_agent, question)

The supervisor model

Now the main agent. When the customer's message arrives, the supervisor reads it and decides which specialists to ask.

python
import re

from langchain.messages import AIMessage
from shop_model import ShopModel


class Supervisor(ShopModel):
    def decide(self, messages):
        if messages[-1].type == "tool":            # the specialists have replied
            return AIMessage("\n".join(m.text for m in messages if m.type == "tool"))
        text = messages[-1].text

Choosing which specialists to ask

It asks the orders specialist about each order id it finds, writing a short question of its own, and asks the policies specialist when the text mentions a policy topic. When both apply, it asks both in one message.

python
        calls = [{"name": "ask_orders", "args": {"question": f"Where is {o}?"}, "id": f"call_{o}"}
                 for o in re.findall(r"\b[A-Z]\d+\b", text)]           # one ask per order id
        if any(word in text.lower() for word in ("refund", "shipping", "password")):
            calls.append({"name": "ask_policies", "args": {"question": text}, "id": "call_policies"})
        if not calls:
            return AIMessage("Which order or policy is this about?")
        return AIMessage("", tool_calls=calls)               # ask them all at once

Giving the supervisor its tools

Give the supervisor the two specialist tools, and it can delegate.

python
from langchain.agents import create_agent
from specialists import ask_orders, ask_policies
from supervisor import Supervisor

agent = create_agent(Supervisor(), tools=[ask_orders, ask_policies])

Running one question through the supervisor

One question that touches both specialists, run through the supervisor. The loop prints each message's type and either its text or the tools it called.

Example
question = "Where is A17, and how long does a refund take?"
result = agent.invoke({"messages": [{"role": "user", "content": question}]})

for message in result["messages"][1:]:
    print(f"{message.type:<4}", message.text or [c["name"] for c in message.tool_calls])

How the supervisor split the question

  • Both specialists ran from one message: the supervisor called ask_orders and ask_policies together, so the first line shows both names.
  • The orders specialist got "Where is A17?", not the whole sentence, because the supervisor writes each subagent's question.
  • The final answer joins the two replies: when the tool results came back, decide returned them combined.
  • A subagent keeps no memory between calls by default, so each question starts it fresh.

One agent vs a supervisor

One agent, all toolsSupervisor with subagents
Who picks the toolOne model, every turnThe supervisor, then each specialist
What a specialist seesThe whole conversationOnly the question it was asked
Combining answersOne model does everythingThe supervisor joins the replies

When to use a subagent

  • One question that spans two areas, such as an order and a refund policy.
  • Keeping each specialist's prompt and tools small, so each one stays reliable.
Watch out. A subagent keeps no memory between calls, so the supervisor must put everything the specialist needs into the question. Send half the question and the specialist answers half of it.
Try it yourself
  • Ask a question with two order ids and count the calls to ask_orders.
  • Ask "How do I reset my password?" and check which specialist answers.
  • Make ask_orders return the specialist's whole message list and print what the supervisor gets.

This is what real progress feels like.