function_tool: a function the model can call
function_tool is a decorator that turns a plain Python function into a tool the model can call, reading the tool's name, description and argument types from the function itself.
Last updated: 28 Sep, 2026 · openai-agents 0.22.3
An agent answers questions, but a tool is how it looks something up or takes an action. The @function_tool decorator wraps a function so the model can request it by name; the SDK builds the tool's schema from the function's name, docstring and type hints.
The function_tool decorator
Decorate a normal function. The function name becomes the tool name, the docstring becomes the description, and the typed parameters become the schema the model fills in.
from agents import function_tool
@function_tool
def lookup_order(order_id: str) -> str:
"""Return the status of an order by its id.""" # -> description
...Writing the function
Write it as you would any function: a typed argument and a return value. Type hints are what let the SDK build the argument schema, so include them.
@function_tool
def lookup_order(order_id: str) -> str:
"""Return the status of an order by its id."""
orders = {"A17": "Order A17: shipped on 3 March."}
return orders.get(order_id, "No such order.")Reading the generated schema
After decoration, the object carries name, description and params_json_schema. These are what the model sees when it decides whether to call the tool.
print(lookup_order.name) # 'lookup_order'
print(lookup_order.description) # from the docstring
print(lookup_order.params_json_schema) # built from the type hintsInvoking the tool directly
You can run the tool yourself with on_invoke_tool. It is async and takes a ToolContext plus a JSON string of arguments, the same shape the model produces.
import asyncio
from agents.tool_context import ToolContext
ctx = ToolContext(context=None, tool_name="lookup_order",
tool_call_id="call_1", tool_arguments='{"order_id": "A17"}')
out = asyncio.run(lookup_order.on_invoke_tool(ctx, '{"order_id": "A17"}'))Inspecting and calling the tool
This prints the three fields the decorator built, then runs the tool directly to confirm it returns the order status.
from agents import function_tool
from agents.tool_context import ToolContext
import asyncio
@function_tool
def lookup_order(order_id: str) -> str:
"""Return the status of an order by its id."""
orders = {"A17": "Order A17: shipped on 3 March."}
return orders.get(order_id, "No such order.")
print("name:", lookup_order.name)
print("description:", lookup_order.description)
print("schema:", lookup_order.params_json_schema)
ctx = ToolContext(context=None, tool_name="lookup_order",
tool_call_id="call_1", tool_arguments='{"order_id": "A17"}')
out = asyncio.run(lookup_order.on_invoke_tool(ctx, '{"order_id": "A17"}'))
print("invoke:", out)What the decorator built from the function
- name is the function name,
lookup_order. - description is the docstring text; the model reads it to decide when to call the tool.
- params_json_schema was built from the
order_id: strhint, marking it a required string. - on_invoke_tool parsed the JSON arguments and ran the function, returning the status string.
A plain function vs a function_tool
| Plain function | @function_tool | |
|---|---|---|
| Callable in Python | Yes | Yes, via on_invoke_tool |
| Has a JSON schema | No | Yes, from the hints |
| A model can call it | No | Yes, by name |
Where tools fit a shop agent
- Looking up an order, a price or a delivery date at run time.
- Taking an action such as starting a refund or cancelling an order.
- Reaching data the model was never trained on, like today's stock.
Related
- Previous: Runner and the RunResult object
- Next: How the agent runs a tool then answers
- Reference: Tools
- Add a second order to the dict and invoke with its id.
- Delete the docstring and print
lookup_order.description. - Invoke with
'{"order_id": "Z9"}'and read the fallback string.
Every expert started right here.