# Converting Agents to Tools Using AgentTool for Agent Composition

> Learn how to convert AutoGen agents into tools using AgentTool. Enable hierarchical multi-agent orchestration and delegate tasks effectively through standard function calling.

- Repository: [Microsoft/autogen](https://github.com/microsoft/autogen)
- Tags: how-to-guide
- Published: 2026-03-07

---

**AgentTool wraps any AutoGen BaseChatAgent as an invokable tool, enabling hierarchical multi-agent orchestration where master agents delegate tasks to specialist agents through standard function calling.**

The `microsoft/autogen` repository provides the `AgentTool` class to convert standalone agents into composable tools. This pattern allows a "master" agent to invoke specialist agents—such as domain-specific experts—using standard tool-call semantics, creating modular workflows without rewriting orchestration logic.

## How AgentTool Enables Agent Composition

`AgentTool` inherits from `TaskRunnerTool` and serves as a bridge between AutoGen's agent architecture and its tool-calling infrastructure. When you wrap an agent with `AgentTool`, the agent becomes a callable function that other agents can invoke during their reasoning process.

The implementation resides in [`python/packages/autogen-agentchat/src/autogen_agentchat/tools/_agent.py`](https://github.com/microsoft/autogen/blob/main/python/packages/autogen-agentchat/src/autogen_agentchat/tools/_agent.py). At initialization, `AgentTool.__init__` accepts an agent instance (typically `AssistantAgent` or any `BaseChatAgent` subclass) and stores it as the internal task runner. The class definition spans lines 20-36 in this file, where it configures the tool name and description based on the wrapped agent's properties.

## Architecture and Components

The agent-to-tool conversion relies on several coordinated components:

**AgentToolConfig** — A Pydantic model defined in [`_agent.py`](https://github.com/microsoft/autogen/blob/main/_agent.py) (lines 10-18) that stores the serialized agent component and the `return_value_as_last_message` flag. This configuration object enables persistent storage of the tool state.

**TaskRunnerTool** — The abstract base class in [`_task_runner_tool.py`](https://github.com/microsoft/autogen/blob/main/_task_runner_tool.py) that handles task execution, argument validation, and streaming support. `AgentTool` delegates its `run` and `run_stream` methods to this infrastructure, which forwards calls to the wrapped agent's `run` method.

**Component System** — `AgentTool` implements `Component[AgentToolConfig]`, providing `dump_component` and `load_component` methods for serializing the entire tool including the wrapped agent. This enables checkpoint-style workflows where agent states can be saved and restored.

## Practical Implementation: Wrapping Specialist Agents

Below is a complete example demonstrating how to convert specialist agents into tools for a master agent to invoke. Note that the master agent must disable parallel tool calls to ensure correct execution order.

```python
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.tools import AgentTool
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient

async def main() -> None:
    # Initialize model client with parallel_tool_calls disabled (required for AgentTool)

    model_client = OpenAIChatCompletionClient(model="gpt-4.1", parallel_tool_calls=False)

    # Create specialist agents

    math_agent = AssistantAgent(
        name="math_expert",
        model_client=model_client,
        system_message="You are a math expert.",
        description="Solves mathematical problems.",
        model_client_stream=True,
    )
    
    # Convert to tool, returning only the final assistant message

    math_tool = AgentTool(agent=math_agent, return_value_as_last_message=True)

    chemistry_agent = AssistantAgent(
        name="chemistry_expert",
        model_client=model_client,
        system_message="You are a chemistry expert.",
        description="Answers chemistry questions.",
        model_client_stream=True,
    )
    chemistry_tool = AgentTool(agent=chemistry_agent, return_value_as_last_message=True)

    # Create master agent with specialist tools

    master = AssistantAgent(
        name="general_assistant",
        system_message="You are a helpful assistant. Use expert tools when needed.",
        model_client=model_client,
        model_client_stream=True,
        tools=[math_tool, chemistry_tool],
        max_tool_iterations=5,
    )

    # Execute tasks - master will automatically invoke appropriate tools

    await Console(master.run_stream(task="What is the integral of x^2?"))
    await Console(master.run_stream(task="What is the molecular weight of water?"))

asyncio.run(main())

```

## Critical Configuration Requirements

**Disable Parallel Tool Calls** — When configuring the model client for the master agent, you must set `parallel_tool_calls=False`. This requirement is enforced by `AgentTool`'s design and documented in the class docstring in [`_agent.py`](https://github.com/microsoft/autogen/blob/main/_agent.py). Parallel execution can cause race conditions in agent-to-agent delegation.

**Return Value Formatting** — The `return_value_as_last_message` parameter controls output formatting. When `True`, the tool returns only the final assistant message from the wrapped agent. When `False`, `TaskRunnerTool.return_value_as_string` concatenates all non-user messages with their source labels (e.g., "assistant: ...").

## State Persistence and Serialization

`AgentTool` supports full state management through its component interface. The `save_state_json` and `load_state_json` methods delegate to the underlying wrapped agent, preserving internal memory and conversation context.

The repository's test suite in [`python/packages/autogen-agentchat/tests/test_task_runner_tool.py`](https://github.com/microsoft/autogen/blob/main/python/packages/autogen-agentchat/tests/test_task_runner_tool.py) validates this functionality across four key scenarios:

- `test_agent_tool_run` — Verifies synchronous execution returns correct `TaskResult`
- `test_agent_tool_state` — Confirms state saving and loading preserves agent memory (lines 27-42)
- `test_agent_tool_component` — Tests JSON serialization via `dump_component` and `load_component` (lines 44-56)
- `test_agent_tool_stream` — Validates end-to-end streaming orchestration (lines 58-82)

## When to Use AgentTool for Composition

Convert agents to tools when building:

- **Domain-specific delegation pipelines** — Route mathematical, coding, or scientific queries to specialized expert agents defined in [`python/packages/autogen-agentchat/src/autogen_agentchat/agents/assistant_agent.py`](https://github.com/microsoft/autogen/blob/main/python/packages/autogen-agentchat/src/autogen_agentchat/agents/assistant_agent.py)
- **Modular agent marketplaces** — Swap specialist tools in and out of master agents without modifying orchestration code
- **Stateful sub-workflows** — Maintain persistent context across multiple tool invocations using the underlying agent's memory

## Summary

- **AgentTool** converts any `BaseChatAgent` into an invokable tool for hierarchical multi-agent systems according to the `microsoft/autogen` source code
- Located in [`python/packages/autogen-agentchat/src/autogen_agentchat/tools/_agent.py`](https://github.com/microsoft/autogen/blob/main/python/packages/autogen-agentchat/src/autogen_agentchat/tools/_agent.py), it inherits from `TaskRunnerTool` and implements `Component[AgentToolConfig]`
- The master agent must use `parallel_tool_calls=False` to prevent race conditions during tool execution
- `return_value_as_last_message` controls whether the tool returns only the final message or the full conversation history
- Full serialization support enables persistent agent states through `dump_component` and `load_component` methods

## Frequently Asked Questions

### Why must parallel tool calls be disabled when using AgentTool?

The master agent must disable parallel tool calls because `AgentTool` expects sequential execution when delegating to specialist agents. Parallel execution could cause race conditions where multiple tool calls interfere with each other's state or where the master agent receives out-of-order responses. Set `parallel_tool_calls=False` in your `OpenAIChatCompletionClient` or equivalent model client configuration.

### How does AgentTool handle streaming responses?

`AgentTool` delegates streaming to the underlying `TaskRunnerTool` infrastructure, which calls the wrapped agent's `run_stream` method. When the master agent processes a tool call, it receives intermediate events from the specialist agent in real-time, allowing the UI to display progressive results before the final tool result is returned.

### Can I serialize an AgentTool with its wrapped agent state?

Yes. `AgentTool` implements the `Component[AgentToolConfig]` interface, providing `dump_component` and `load_component` methods that serialize both the tool configuration and the internal agent state. This allows you to save a complete agent-tool composition to JSON and restore it later, including the specialist agent's conversation memory and configuration.

### What is the difference between return_value_as_last_message True and False?

When `return_value_as_last_message=True`, the tool returns only the final assistant message content from the wrapped agent's response. When `False`, the tool concatenates all non-user messages from the conversation, prefixing each with its source label (e.g., "assistant: ..."), providing full context of the specialist's reasoning process to the master agent.