Skip to main content
Agent as Tool turns any agent into a callable tool so a parent agent can invoke specialists and keep control of the result.
as_tool() returns a Handoff object; passing it into tools=[...] (as the examples on this page do) works reliably as of PraisonAI PR #4146. The parent agent’s constructor converts every Handoff in tools= into a callable tool the LLM can see and execute_tool can dispatch. Before that fix the pattern silently produced an agent the model saw as having no tools at all — no error, only a subtly worse answer.
The user asks for a polished article; the writer agent invokes the researcher as a tool and composes the answer.

Quick Start

1

Simple Usage

2

With Configuration

Pass custom tool_name and description to as_tool() when the default labels are not clear enough for the parent LLM.
3

Direct Invocation

Call the generated tool yourself with execute_tool — the tool exposes an explicit task parameter:
The generated tool now has (task: str) in its signature — the LLM sees it in the schema and fills it, and direct callers must pass it.

How It Works

as_tool() vs Handoffs

Key Difference: With as_tool(), the parent agent retains control and receives results. With handoffs, control transfers entirely to the target agent.
If you previously “worked around” the broken as_tool() by switching to handoffs=, note the workaround wasn’t equivalent — invoke_{name} runs with ContextPolicy.NONE (a genuine clean slate, now that context policies take effect) while transfer_to_{name} shares context per its policy (SUMMARY by default). Now that as_tool() works in tools=[...], switch back if you want the clean-slate behaviour.

API Reference

Agent.as_tool()

str
Tool description for the LLM. Describes what this agent does. Default: "Invoke {agent_name} to complete a subtask and return the result"
str
Custom tool name. Default: invoke_{agent_name} (snake_case)
Handoff
A Handoff configured with ContextPolicy.NONE (no history passed to child).The return type is Handoff (not a callable) because to_tool_function() needs the parent agent that will own this tool — and at as_tool() call time, that parent doesn’t exist yet. Conversion happens automatically the moment you place the result inside a parent’s tools=[...].

Generated tool signature

Because as_tool() always pins ContextPolicy.NONE, the generated callable exposes a task: str keyword-only parameter. This is what the LLM tool schema advertises and what direct execute_tool calls must supply.
str
required
The prompt passed verbatim to the sub-agent. If task is not provided, prompt is accepted as an alias.

Examples

Best Practices

Provide clear tool descriptions so the LLM knows when to invoke each specialist.
Each specialist agent should have one clear purpose.
Keep hierarchies shallow (2-3 levels max) for clarity.
Test each specialist agent independently before composing.
Each channel’s clone rebinds the as_tool() handoff to itself, not the source agent. This means Discord and Telegram clones each get their own invoke_researcher bound to their own chat_history / tools / memory — no cross-channel leakage. You do not need to rebuild tools=[...] per channel; clone_for_channel() handles it.

Troubleshooting

Seeing Tool not recognized in the logs and an empty tool schema? You’re on a PraisonAI version prior to PR #4146. Upgrade to the fixed version, or as a temporary workaround move the entries from tools= to handoffs= (note the different naming and context policy — see the comparison table above).
Seeing "…completed, but no specific task was provided." returned from the tool, and Agent.chat on the sub-agent was never called? You are on a PraisonAI version prior to PR #4232. Upgrade — the generated tool now takes a task string parameter and passes it verbatim as the sub-agent’s prompt.

Handoffs

Transfer control between agents

Multi-Agent Workflows

Coordinate multiple agents

Toolsets

Create custom tools