Tools
Define and use tools in model and agent workflows.
AI SDK for Python supports multiple types of tools, including function tools
defined in code using @ai.tool, as well as built-in provider-side tools.
Declare function tools
Decorate an async function with @ai.tool:
import ai
@ai.tool
async def contact_mothership(query: str) -> str:
"""Contact the mothership for important decisions."""
return "Soon."The tool name comes from the function name. The model receives the function parameters as a JSON schema and the docstring as the tool description.
Function tools will only be automatically executed by the SDK when used
in the context of the agent. Provider-side tools will always get executed
by the provider, even when passed to ai.stream.
Handle tool errors
Tool exceptions become ToolCallResult events with is_error=True. The model
sees the error text on the next turn:
async with agent.run(model, messages) as stream:
async for event in stream:
if isinstance(event, ai.events.ToolCallResult):
for result in event.results:
if result.is_error:
print(f"{result.tool_name} failed: {result.result}")The original exception is available on event.exception for logging.
Declare tools that stream output
AI SDK for Python supports tools that return async iterables. Use a streaming tool when it needs to return partial output, such as when wrapping a subagent.
Streaming tools use aggregators. An aggregator solves two problems: the tool can yield many values over time, but the agent still needs one final tool result; and your app may want a rich stored result while the model needs a simpler value on the next turn.
The core interface is:
class Aggregator[Item, Result, ModelInput]:
def feed(self, item: Item) -> None: ...
def snapshot(self) -> Result: ...
@classmethod
def to_model_input(cls, snapshot: Result) -> ModelInput: ...Use ai.StreamingTextTool when yielded strings should concatenate into the
tool result:
@ai.tool
async def draft_reply(topic: str) -> ai.StreamingTextTool:
"""Draft a reply."""
yield "Checking "
yield "records for "
yield topicUse ai.StreamingStatusTool[T] when intermediate yields are progress updates
and the last yielded value is the final result.
Use ai.SubAgentTool when a tool streams events from a nested agent. The stored
result is a message bundle, and the model sees the final assistant text.
The agent emits PartialToolCallResult events for those values, then sends
the aggregated result back to the model on the next turn.
Every tool must return an awaitable or an async iterable. Every async iterable
tool needs an aggregator, either through its return annotation or the
aggregator= argument.
Understand tool anatomy
ai.Tool represents tools of all kinds in the SDK.
Each tool carries an optional spec, which is a description consumed by the
model, as well as a tool_config that contains tool-specific execution config
(e.g. retry policy).
AgentTool wraps ai.Tool together with its corresponding Python function,
which allows agent.run to find and call that function when the model requests
to do so.
Pass ai.Tool objects directly to ai.stream when you want the model to emit
tool calls but you do not want the SDK to execute them:
tool = ai.Tool(
kind="function",
name="contact_mothership",
spec=ai.tools.ToolSpec(
description="Contact the mothership.",
params={
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
),
)
async with ai.stream(model, messages, tools=[tool]) as stream:
async for event in stream:
if isinstance(event, ai.events.ToolEnd):
print(event.tool_call.tool_args)Use provider-executed tools
Provider-executed tools run on the provider side. Pass them to ai.stream in
the tools list:
messages = [
ai.user_message("Check the latest mothership telemetry reports."),
]
async with ai.stream(
model,
messages,
tools=[ai.providers.anthropic.tools.web_search(max_uses=3)],
) as stream:
async for event in stream:
if isinstance(event, ai.events.TextDelta):
print(event.chunk, end="", flush=True)When you route through AI Gateway, you can use provider-specific tool factories and AI Gateway tool factories:
tools = [
ai.providers.anthropic.tools.web_search(max_uses=3),
ai.providers.ai_gateway.tools.perplexity_search(max_results=5),
]Use MCP tools
The Model Context Protocol (MCP) adapter converts server tools into agent tools:
uv add "ai[mcp]"tools = await ai.mcp.get_http_tools(
"http://localhost:3000/mcp",
headers={"Authorization": "Bearer your_access_token_here"},
)
agent = ai.Agent(tools=tools)Use ai.mcp.get_stdio_tools for subprocess-based MCP servers.