python
from pydantic import BaseModel
# =========================
# 1. 参数模型
# =========================
class CalculatorArgs(BaseModel):
a: float
b: float
class WeatherArgs(BaseModel):
city: str
# =========================
# 2. 真正执行工具的函数
# =========================
def calculator(a, b):
print(f"执行 calculator({a}, {b})")
return a * b
def get_weather(city):
print(f"执行 get_weather({city})")
return f"{city} 今天晴天,25℃"
# =========================
# 3. Tool 类
# =========================
class Tool:
def __init__(
self,
name,
description,
args_model,
function
):
self.name = name
self.description = description
self.args_model = args_model
self.function = function
def execute(self, arguments):
# ① Pydantic 验证参数
args = self.args_model(**arguments)
# ② 执行真正的 Python 函数
result = self.function(**args.model_dump())
return result
def schema(self):
return {
"type": "function",
"name": self.name,
"description": self.description,
"parameters": self.args_model.model_json_schema()
}
# =========================
# 4. 创建 Tool
# =========================
calculator_tool = Tool(
name="calculator",
description="计算两个数字的乘积",
args_model=CalculatorArgs,
function=calculator
)
weather_tool = Tool(
name="get_weather",
description="查询指定城市的天气",
args_model=WeatherArgs,
function=get_weather
)
# =========================
# 5. Tool Registry
# =========================
tool_registry = {
calculator_tool.name: calculator_tool,
weather_tool.name: weather_tool
}
# =========================
# 6. 测试
# =========================
tool = tool_registry["calculator"]
print("工具名称:", tool.name)
print("工具描述:", tool.description)
print("========== Schema ==========")
print(tool.schema())
print("========== Execute ==========")
result = tool.execute({
"a": 123,
"b": 456
})
print("结果:", result)
一、Tool 类
封装成对象
Tool
├── name
├── description
├── args_model
└── function
所以
calculator_tool = Tool(
name="calculator",
description="计算两个数字的乘积",
args_model=CalculatorArgs,
function=calculator
)
表示创建一个叫 calculator 的工具,它的参数由 CalculatorArgs 定义,真正执行的时候调用 calculator 函数。
二、execute()
python
def execute(self, arguments):
args = self.args_model(**arguments)
result = self.function(**args.model_dump())
return result
LLM 传来的参数
↓
Pydantic 验证
↓
转换成合法参数
↓
执行 Python 函数
↓
返回结果
例如
tool.execute({
"a": 123,
"b": 456
})根据定义的execute函数
内部相当于:先CalculatorArgs( a=123, b=456 ),然后calculator( a=123, b=456 )。
三、schema()
python
def schema(self):
return {
"type": "function",
"name": self.name,
"description": self.description,
"parameters": self.args_model.model_json_schema()
}
所以calculator_tool.schema()得到
{
"type": "function",
"name": "calculator",
"description": "计算两个数字的乘积",
"parameters": { ... }
}
正好就是我们传给client.responses.create( tools=tools )的tools。
所以现在形成了:
Tool
│
┌─────────┴─────────┐
↓ ↓
schema() execute()
↓ ↓
给 LLM 看 给 Python 执行
↓ ↓
Tool Schema Pydantic验证
↓
Python函数
四、Agent框架
┌──────────────┐
│ LLM │
└──────┬───────┘
│
Tool Call
│
↓
┌─────────────────┐
│ Tool Registry │
└────────┬────────┘
│
找到对应 Tool
│
↓
┌─────────────────┐
│ Tool │
├─────────────────┤
│ Schema │
│ Pydantic │
│ Python Function │
└────────┬────────┘
│
↓
Tool Result
│
↓
LLM
│
↓
Final Answer
五、Agent Loop
可能执行多个 Tool Call,但我们的代码只做了一轮!
解决方法是:Agent Loop!
核心是:
while True:
response = call_llm()
if 有 tool call:
执行 tool
把结果交回 LLM
continue
else:
输出最终答案
break
因为"Agent"和"普通的 Tool Calling Demo"的真正分水岭,就是这个循环