跳转至

Agents-as-Tools: Specialist Agents As Callable Tools

Sometimes you want to reuse a specialist agent without handing over the final answer.

In a travel assistant, the controller can call a budget specialist and a writing specialist. The specialists return narrow results. The controller still decides how to answer the user.

That is Agents-as-Tools.

One Sentence

Agents-as-Tools turns specialist takeover into controller calls specialist tools, so expertise is reusable while final-answer ownership stays with the controller.

What Breaks Without It

Problem What it looks like Risk
All expertise in controller prompt Simple Prompt grows heavy
Specialist takes over Professional Conversation owner becomes unclear
Specialist output is unstructured Flexible Controller cannot consume it reliably

What This Pattern Changes

Who Owns
Controller Agent Decides when to call experts and owns final answer
Specialist Agent Tool Receives narrow task and returns narrow result
Python Wraps agent as tool, controls budget and trace

Unlike Handoff, this is a call, not a takeover.

Walk Through One Trace

Round Controller action Specialist result
1 Call math_agent for 7*6 42
2 Call style_agent for one sentence The answer is 42.
3 final Controller returns final answer

Flow

flowchart TD
  U["User task"] --> C["Controller Agent"]
  C -->|call tool| A["math_agent"]
  C -->|call tool| B["style_agent"]
  A --> C
  B --> C
  C --> O["Final answer"]

Code Walk

Wrap a specialist as a tool:

agent_as_tool(
    AgentToolSpec(
        name="math_agent",
        description="Specialist agent for arithmetic questions.",
        model=math_agent,
        system_prompt="You are a math specialist. Return only the numeric answer.",
    ),
    tracer=tracer,
)

The controller still runs ReAct:

out = run_react(controller, task="Compute 7*6 and present it nicely.", tools=tools, limits=RunLimits(max_steps=6), tracer=tracer)

Full example:

from __future__ import annotations

from pathlib import Path

from agent_patterns_lab.patterns.agents_as_tools import AgentToolSpec, agent_as_tool
from agent_patterns_lab.patterns.react import run_react
from agent_patterns_lab.runtime import MockLLM, RunLimits, ToolRegistry, Tracer


def main() -> None:
    tracer = Tracer()

    math_agent = MockLLM(["42"])
    style_agent = MockLLM(["The answer is 42."])

    tools = ToolRegistry(
        [
            agent_as_tool(
                AgentToolSpec(
                    name="math_agent",
                    description="Specialist agent for arithmetic questions.",
                    model=math_agent,
                    system_prompt="You are a math specialist. Return only the numeric answer.",
                ),
                tracer=tracer,
            ),
            agent_as_tool(
                AgentToolSpec(
                    name="style_agent",
                    description="Specialist agent for writing/formatting.",
                    model=style_agent,
                    system_prompt="You are a writer. Produce a single concise sentence.",
                ),
                tracer=tracer,
            ),
        ]
    )

    controller = MockLLM(
        [
            '{"type":"tool","tool":"math_agent","args":{"task":"Compute 7*6"}}',
            '{"type":"tool","tool":"style_agent","args":{"task":"Write a short sentence using the number 42."}}',
            '{"type":"final","answer":"The answer is 42."}',
        ]
    )

    out = run_react(controller, task="Compute 7*6 and present it nicely.", tools=tools, limits=RunLimits(max_steps=6), tracer=tracer)
    print(out)

    trace_path = tracer.export_jsonl(Path(".traces") / "61_agents_as_tools.jsonl")
    print(f"[trace] {trace_path}")


if __name__ == "__main__":
    main()

Run:

UV_CACHE_DIR=.uv_cache PYTHONPATH=src uv run --no-sync python examples/61_agents_as_tools.py

Nearby Patterns

Pattern Final answer owner Use when
Normal tool Controller Capability is deterministic
Agents-as-Tools Controller Capability needs a specialist agent
Handoff Specialist Specialist should take over
Manager-Worker Manager Work is assigned then synthesized

When To Use It

  • Specialist capability is reusable.
  • Controller should keep final-answer ownership.
  • Expert input/output can be contracted.
  • Experts need separate budgets or permissions.

When Not To Use It

  • A normal function is enough.
  • Specialist needs multi-turn user conversation.
  • Controller cannot assess specialist output.
  • Too many experts confuse the controller.

Costs And Common Failures

Failure Symptom Fix
Specialist too broad Every expert can do everything Narrow prompt and tools
Unusable output Controller receives prose blob Use structured output
Budget leak One expert runs too long Per-tool agent limits
Tool soup Many experts exposed Route or keep only high-value experts

Agents-as-Tools fits "expert helps but does not take over".

If the specialist should own the conversation, read Handoff. If a manager assigns workers, read Manager-Worker.

References