A tool is a capability an assistant or agent can use to do work beyond generating text. It might call a code function, search the web, read a file, contact a service, or hand work to another agent. The tool is the available capability; a tool call is the action taken with it. section 2.4.1 section 1.1.3
Consider a research plan. A prompt alone can ask for five tasks, but a tool that returns available research sources lets the agent base those tasks on sources it can actually use. Explicit instructions tell the agent when to call the tool; its result can inform the next step. In a longer workflow, one tool’s output can become another tool’s input. section 2.4.1 section 1.1.2
A practical tool-use cycle is:
- Define a focused capability with a clear name, description, inputs, and expected output. Register it so the agent can discover and call it. section 1.1.3 section 11.1.2
- Give the agent a goal and boundaries. It chooses a tool, supplies arguments, observes the result, and decides whether to continue or stop. section 9.1.1
- Treat timeouts, malformed arguments, and service failures as expected outcomes. Return useful errors, limit retries, and provide a fallback or a way to ask the user. section 1.1.3 section 11.1.2
A tool may live in the agent’s code or be exposed by a local or remote Model Context Protocol (MCP) server. In MCP, tools are actionable capabilities the agent chooses to invoke; resources provide data, while prompts provide reusable templates. Tool access does not itself determine autonomy: an assistant may require approval for each task, while an agent may plan multiple calls, with high-stakes actions still gated by approval. section 2.4.1 section 3.1.3 section 1.1.1
Listing 11.2 02_tool_action_tips.py
from agents import (
Agent,
Runner,
function_tool,
ModelSettings
)
import json
def _failure_error_function(context, e) -> str: #1
return json.dumps({"status": "error", "message": str(e)})
@function_tool(
failure_error_function=_failure_error_function) #1
def lookup_order(order_id: str) -> dict: #2
"""Check order status by ID. Use when the user asks about their order.""" #2
if not order_id.startswith("ORD-"):
raise ValueError("Invalid order id format")
return {"status": "shipped", "eta_days": 3}
tooling_agent = Agent(
name="ToolingAgent",
instructions="Use tools when needed; respond with JSON.", #3
tools=[lookup_order],
model_settings=ModelSettings(
tool_choice="auto", #3
parallel_tool_calls=True, #3
)
)
print(Runner.run_sync(
tooling_agent,
"What's the status of order ORD-123?"
).final_output)
The order-lookup example shows a small typed function registered as a tool. Its description says when to use it, its code checks the order ID, and an error handler returns a failure message rather than letting the error end the run. section 11.1.2
Keep the available tool set small and relevant. Every registered tool adds a description to model calls, even when unused; extra tools increase cost and can make selection harder. Test tool schemas and outputs before relying on them in an agent. section 2.4.1 section 3.6 section 11.1.2













