0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
27 small wins to finish your pathNext lesson →

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.

python
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.

python
@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.

python
print(lookup_order.name)               # 'lookup_order'
print(lookup_order.description)        # from the docstring
print(lookup_order.params_json_schema) # built from the type hints

Invoking 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.

python
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.

Example
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: str hint, 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 PythonYesYes, via on_invoke_tool
Has a JSON schemaNoYes, from the hints
A model can call itNoYes, 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.
Watch out. The docstring becomes the description the model reads, and the type hints build the schema. Skip the docstring and the model gets an empty description; skip the type hint and the SDK cannot build the argument schema.
Try it yourself
  • 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.