Tool System Integration Explanation
1. Tool Definition - @function_tool Decorator
@function_tool
def run_diagnostic_check(
context: UserAccountContext, product_name: str, issue_description: str
) -> str:
"""
Run a diagnostic check on the customer's product to identify potential issues.
Args:
product_name: Name of the product experiencing issues
issue_description: Description of the problem
"""
diagnostics = [
"✅ Server connectivity: Normal",
"✅ API endpoints: Responsive",
"⚠️ Cache memory: 85% full (recommend clearing)",
"✅ Database connections: Stable",
"⚠️ Last update: 7 days ago (update available)",
]
return f"🔍 Diagnostic results for {product_name}:\n" + "\n".join(diagnostics)
- @function_tool: A decorator that registers a function as a tool.
- Key Features:
- The first parameter is context: UserAccountContext (automatically injected).
- The remaining parameters are provided by the LLM.
- The Docstring is used as the tool description.
- The return value is a string.
2. How the LLM Understands Tools
A. Tool Schema Generation The @function_tool decorator analyzes the function to generate a schema that the LLM can understand:
# Function Definition
@function_tool
def lookup_order_status(context: UserAccountContext, order_number: str) -> str:
"""
Look up the current status and details of an order.
Args:
order_number: Customer's order number
"""
Generated Tool Schema (Internally):
{
"name": "lookup_order_status",
"description": "Look up the current status and details of an order.",
"parameters": {
"type": "object",
"properties": {
"order_number": {
"type": "string",
"description": "Customer's order number"
}
},
"required": ["order_number"]
}
}
B. Providing the Tool List
order_agent = Agent(
name="Order Management Agent",
instructions=dynamic_order_agent_instructions,
tools=[
lookup_order_status,
initiate_return_process,
schedule_redelivery,
expedite_shipping,
],
hooks=AgentToolUsageLoggingHooks(),
)
- tools: A list of tools available to the agent.
- The Runner generates a schema for each tool and provides it to the LLM.
- The LLM selects a tool by referencing this list and schema.
3. Context Automatic Injection Mechanism
A. Context Delivery Path
stream = Runner.run_streamed(
st.session_state["agent"],
message,
session=session,
context=user_account_ctx,
)
- Pass context=user_account_ctx to Runner.run_streamed().
- The Runner internally wraps and manages it using RunContextWrapper.
B. Context Injection During Tool Calls
@function_tool
def lookup_order_status(context: UserAccountContext, order_number: str) -> str:
"""
Look up the current status and details of an order.
Args:
order_number: Customer's order number
"""
statuses = ["processing", "shipped", "in_transit", "delivered"]
# ... implementation details ...
return f"""
📦 Order Status: {order_number}
📍 Shipping to: {context.email}
""".strip()
- If the first parameter is of type UserAccountContext, the Runner automatically injects it.
- The LLM does not provide the context parameter.
- Inside the tool, properties like context.email, context.customer_id, context.tier, etc., can be used.
4. Parameter Generation Process by LLM
A. User Request Analysis
User: "Check the status of order number ORD-123"
B. Tool Selection
LLM Analysis:
- Request: "Check order status"
- Check available tools: lookup_order_status, initiate_return_process, etc.
- Selection: lookup_order_status
C. Tool Schema Analysis
LLM Checks Schema for lookup_order_status:
- name: "lookup_order_status"
- description: "Look up the current status and details of an order."
- parameters: order_number (string, required)
- context is ignored as it is automatically injected.
D. Parameter Extraction
LLM Extracts Parameters from Request: "Check the status of order number ORD-123" → order_number="ORD-123"
E. Tool Call Generation
LLM Generates Tool Call:
JSON{ "tool_name": "lookup_order_status", "parameters": { "order_number": "ORD-123" } }
5. Full Tool Execution Flow
[Step 1] User Request
User: "Check the status of order number ORD-123"
↓
[Step 2] Call Runner.run_streamed()
Runner.run_streamed(
order_agent,
"...",
context=user_account_ctx ← Context Passed
)
↓
[Step 3] Runner Generates Tool Schema
Runner checks order_agent.tools list
→ Analyzes @function_tool decorators
→ Prepares tool list for LLM
↓
[Step 4] Order Agent's LLM Execution
Information provided to LLM:
- Instructions, Tools (Schema), Request, History
↓
[Step 5] LLM Selects Tool & Extracts Parameters
- Tool: lookup_order_status
- Parameter: order_number="ORD-123"
↓
[Step 6] LLM Generates Tool Call
Output: { "function": { "name": "lookup_order_status", ... } }
↓
[Step 7] on_tool_start Hook Called
Displays "🔧 Order Management Agent starting tool..." in sidebar
↓
[Step 8] Runner Executes Tool
Runner calls function:
lookup_order_status(
context=wrapper.context, ← Auto Injected
order_number="ORD-123" ← Provided by LLM
)
↓
[Step 9] Tool Function Logic Execution
Inside lookup_order_status():
- Use context.email, context.tier
- Query order logic
- Return result string
↓
[Step 10] on_tool_end Hook Called
Displays tool result in sidebar
↓
[Step 11] LLM Delivers Result to User
LLM receives tool result → Converts to friendly message
→ "Order ORD-123 is currently in transit..."
6. Handling Parameter Types
def lookup_order_status(context: UserAccountContext, order_number: str) -> str:
- No default value → Required.
- The LLM must extract this from the user request. If missing, it asks the user.
B. Optional Parameters (Default Values)
def lookup_billing_history(context: UserAccountContext, months_back: int = 6) -> str:
- Default value = 6 exists → Optional.
- If the LLM cannot extract it, the default value is used.
C. Multiple Parameters
def initiate_return_process(..., order_number: str, return_reason: str, items: str) -> str:
- Extract multiple parameters from the user request.
- The LLM maps each parameter accordingly.
7. Context Usage Examples
A. Reading Info from Context
📍 Shipping to: {context.email}
- context.email: Customer Email
- context.customer_id: Customer ID
- context.tier: Customer Tier
B. Context-based Conditional Logic
processing_days = 3 if context.is_premium_customer() else 5
- context.is_premium_customer(): Check if premium.
- Premium customers get faster processing (3 days vs 5 days).
C. Context-based Access Control
if not context.is_premium_customer():
return "❌ Expedited shipping upgrade requires Premium membership"
- Feature available only to premium customers.
- Check permissions via Context.
8. Tool Usage Logging - AgentHooks
class AgentToolUsageLoggingHooks(AgentHooks):
async def on_tool_start(self, ...):
# ... Log tool start ...
async def on_tool_end(self, ...):
# ... Log tool result ...
async def on_handoff(self, ...):
# ... Log handoff ...
- AgentHooks: Lifecycle event hooks for the agent.
- Major Methods:
- on_tool_start: Called when a tool starts execution.
- on_tool_end: Called when a tool completes execution (includes result).
- on_handoff: Called when a handoff occurs.
- on_start / on_end: Agent activation/completion.
9. Key Concepts Summary
| Concept | Description |
| @function_tool | Decorator that registers a function as a tool. |
| context | UserAccountContext automatically injected as the first parameter. |
| Tool Schema | Metadata generated for the tool so the LLM can understand it. |
| tools | List of tools to register with the agent. |
| AgentHooks | Class that handles agent lifecycle events. |
| on_tool_start | Hook called when tool execution begins. |
| on_tool_end | Hook called when tool execution completes. |
10. Full System Diagram
┌─────────────────────────────────────────┐
│ User Request │
│ "Check the status of order ORD-123" │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Runner.run_streamed(order_agent, ...) │
│ Pass context=user_account_ctx │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Runner Generates Tool Schema │
│ - Analyze @function_tool decorator │
│ - Parse function signature │
│ - Parse Docstring │
│ - Generate JSON Schema │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Provide Tool Info to LLM │
│ - Agent instructions │
│ - Tool List (with Schema) │
│ - User Request │
│ - Conversation History │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ LLM Selects Tool & Extracts Params │
│ - Analyze User Request │
│ - Select appropriate Tool │
│ - Check Tool Schema │
│ - Extract: order_number="ORD-123" │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ LLM Generates Tool Call │
│ { │
│ "tool_calls": [{ │
│ "function": { │
│ "name": "lookup_order_status", │
│ "arguments": "{\"order_number\": \"ORD-123\"}" │
│ } │
│ }] │
│ } │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Call on_tool_start Hook │
│ - Display tool start in sidebar │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Runner Executes Tool │
│ lookup_order_status( │
│ context=wrapper.context, ← Auto │
│ order_number="ORD-123" ← From LLM │
│ ) │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Tool Function Execution │
│ - Use context.email, id, tier │
│ - Query order status │
│ - Return result string │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Call on_tool_end Hook │
│ - Display tool result in sidebar │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ LLM Delivers Result to User │
│ "Order ORD-123 is currently..." │
└─────────────────────────────────────────┘