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
43 small wins to finish your pathNext lesson

A subagent as a tool

One agent can call others. Wrap each specialist agent in a tool, and a main agent decides which to ask, what to ask, and how to put the answers together.

The shop now has two agents: lesson 7's, which knows orders, and lesson 28's, which knows policies. A customer asks one question about both. In the subagents pattern a main agent, often called a supervisor, calls the specialists as tools; they answer it, never the customer.

Examplespecialists.py
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])
policies_agent = create_agent(HelpModel(), tools=[search_policies])


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

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

Examplespecialists.py, continued
@tool
def ask_orders(question: str) -> str:
    """Ask the orders specialist where an order is."""
    return last_reply(orders_agent, question)


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

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

A main agent that delegates

Examplesupervisor.py
import re

from langchain.messages import AIMessage
from shop_model import ShopModel


class Supervisor(ShopModel):
    def decide(self, messages):
        if messages[-1].type == "tool":
            return AIMessage("\n".join(m.text for m in messages if m.type == "tool"))
        text = messages[-1].text
        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)]
        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)

The supervisor asks the orders specialist about each order it finds, writing a 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. When results come back, it joins them.

Exampleagent.py
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])
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])

Both specialists ran from one message, and the final answer combines their replies. The orders specialist got "Where is A17?", not the customer's whole sentence, because the supervisor decides what each subagent is asked. By default a subagent keeps no memory between calls; each question starts it fresh.

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.

Every expert started right here.