Your agents process text. What if the user asks something that needs a deterministic computation — like 'what is 47 plus 93?' A language model should not do arithmetic; it should call a function.
Give the agent a calculator tool. The agent decides to call it when the prompt needs a number.
@agent.tool_plain is exactly that — a Python function the agent can call. You define the logic; the agent decides when to invoke it:
agent = Agent(model)
@agent.tool_plain
def add(a: int, b: int) -> int:
return a + b
return agent.run_sync(prompt).outputThe decorator goes on a function inside the agent's scope? How does the agent know the tool exists?
@agent.tool_plain registers the function with that specific agent instance. When you call agent.run_sync(prompt), the agent sees the registered tools and can call them if the prompt requires it. Here's the full function:
def agent_with_tool(prompt: str) -> str:
agent = Agent(model)
@agent.tool_plain
def add(a: int, b: int) -> int:
return a + b
result = agent.run_sync(prompt)
output = result.output
print(f"Tool response: {output}")
return outputThe agent is picking the tool — I just defined what the tool does. I built a decision-maker.
That's the Week 4 agency moment. You're no longer writing the sequence of calls — you're defining the menu and letting the agent choose. The tool is deterministic Python; the decision is the model's.
I can add a revenue calculator tool — the agent calls it when the prompt involves numbers and reasons about text for everything else.
Tool names and type annotations matter. The agent reads the function signature to understand when to call it. A function named add with a: int, b: int is clear. A function named process_data with x: any is ambiguous — the agent won't know when to call it.
@agent.tool_plainagent = Agent(model)
@agent.tool_plain
def add(a: int, b: int) -> int:
return a + b
return agent.run_sync(prompt).output@agent.tool_plain registers the function with that specific agent instance. When the model determines the prompt needs this tool, it calls it automatically and incorporates the result into its response.
The agent infers tool purpose from the function name and typed parameters. add(a: int, b: int) -> int is unambiguous. process(x: any) is not — the agent won't know when to call it.
ai-tools lesson_typeThis lesson uses ai-tools model (openrouter/auto-exacto) — tuned specifically for tool-calling tasks.
Your agents process text. What if the user asks something that needs a deterministic computation — like 'what is 47 plus 93?' A language model should not do arithmetic; it should call a function.
Give the agent a calculator tool. The agent decides to call it when the prompt needs a number.
@agent.tool_plain is exactly that — a Python function the agent can call. You define the logic; the agent decides when to invoke it:
agent = Agent(model)
@agent.tool_plain
def add(a: int, b: int) -> int:
return a + b
return agent.run_sync(prompt).outputThe decorator goes on a function inside the agent's scope? How does the agent know the tool exists?
@agent.tool_plain registers the function with that specific agent instance. When you call agent.run_sync(prompt), the agent sees the registered tools and can call them if the prompt requires it. Here's the full function:
def agent_with_tool(prompt: str) -> str:
agent = Agent(model)
@agent.tool_plain
def add(a: int, b: int) -> int:
return a + b
result = agent.run_sync(prompt)
output = result.output
print(f"Tool response: {output}")
return outputThe agent is picking the tool — I just defined what the tool does. I built a decision-maker.
That's the Week 4 agency moment. You're no longer writing the sequence of calls — you're defining the menu and letting the agent choose. The tool is deterministic Python; the decision is the model's.
I can add a revenue calculator tool — the agent calls it when the prompt involves numbers and reasons about text for everything else.
Tool names and type annotations matter. The agent reads the function signature to understand when to call it. A function named add with a: int, b: int is clear. A function named process_data with x: any is ambiguous — the agent won't know when to call it.
@agent.tool_plainagent = Agent(model)
@agent.tool_plain
def add(a: int, b: int) -> int:
return a + b
return agent.run_sync(prompt).output@agent.tool_plain registers the function with that specific agent instance. When the model determines the prompt needs this tool, it calls it automatically and incorporates the result into its response.
The agent infers tool purpose from the function name and typed parameters. add(a: int, b: int) -> int is unambiguous. process(x: any) is not — the agent won't know when to call it.
ai-tools lesson_typeThis lesson uses ai-tools model (openrouter/auto-exacto) — tuned specifically for tool-calling tasks.
Create a free account to get started. Paid plans unlock all tracks.