要搞清楚:实际 Agent 项目里,为什么不建议一直手写 JSON Schema
一、环境配置
执行
bash
pip install pydantic
然后验证:
bash
python -c "import pydantic; print(pydantic.__version__)"
二、Pydantic 模型
新建一个新的py
bash
from pydantic import BaseModel
class CalculatorArgs(BaseModel):
a: float
b: float
args = CalculatorArgs(
a=123,
b=456
)
print(args)
print(args.a)
print(args.b)
print("========== JSON Schema ==========")
print(CalculatorArgs.model_json_schema())
【注意】文件名称别叫 pydantic.py ,会报错。
不是 Pydantic 安装坏了,而是你的文件名导致了 Python 的模块名冲突。
运行结果为:

原来手写的
"parameters": {
"type": "object",
"properties": {
"a": {"type": "number"},
"b": { "type": "number"}
},
"required": "a", "b"
}
现在只需要:
class CalculatorArgs(BaseModel):
a: float
b: float
CalculatorArgs.model_json_schema()
也就是
Python 类型定义
↓
Pydantic
↓
JSON Schema
↓
LLM Tool
这就是 Pydantic 在 Agent 里的第一个重要作用。
三、校验
将任一一个参数修改为字符串类型,重新运行函数,出现了ValidationError,说明成功验证了 Pydantic 最核心的能力:参数校验。
LLM
↓
Tool Call
↓
JSON
↓
Pydantic
↓
参数验证(√)
↓
通过 ─────→ 执行工具
↓
失败
↓
拒绝执行 / 返回错误
这就是 Agent 中非常重要的一个思想:LLM 负责决策,但不能直接获得程序的执行权。
四、加入整体运行
中间多了一层Pydantic 参数验证。
这就是你以后做 Agent 时非常重要的边界意识:
LLM 输出属于"不完全可信的外部输入",工具执行属于你的程序权限边界。
python
import json
from openai import OpenAI
from pydantic import BaseModel
client = OpenAI()
# =========================
# 1. 定义工具参数
# =========================
class CalculatorArgs(BaseModel):
a: float
b: float
class WeatherArgs(BaseModel):
city: str
# =========================
# 2. 真正执行工具的 Python 函数
# =========================
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_map = {
"calculator": calculator,
"get_weather": get_weather
}
# =========================
# 4. Tool Schema
# =========================
tools = [
{
"type": "function",
"name": "calculator",
"description": "计算两个数字的乘积",
"parameters": CalculatorArgs.model_json_schema()
},
{
"type": "function",
"name": "get_weather",
"description": "查询指定城市的天气",
"parameters": WeatherArgs.model_json_schema()
}
]
# =========================
# 5. 请求 LLM
# =========================
response = client.responses.create(
model="gpt-5.6-sol",
input="请计算 123 × 456",
tools=tools,
tool_choice="required"
)
# =========================
# 6. 执行 Tool Call
# =========================
for item in response.output:
if item.type != "function_call":
continue
print("========== Tool Call ==========")
print("工具名称:", item.name)
print("参数:", item.arguments)
print("Call ID:", item.call_id)
# JSON → Python dict
arguments = json.loads(item.arguments)
# =========================
# 7. Pydantic 参数验证
# =========================
if item.name == "calculator":
args = CalculatorArgs(**arguments)
elif item.name == "get_weather":
args = WeatherArgs(**arguments)
else:
raise ValueError(f"未知工具: {item.name}")
print("========== Validated Args ==========")
print(args)
# =========================
# 8. 找到真正的 Python 函数
# =========================
function = tool_map[item.name]
# Pydantic Model → dict → 函数参数
result = function(**args.model_dump())
print("========== Tool Result ==========")
print(result)
# =========================
# 9. 把结果交给 LLM
# =========================
response2 = client.responses.create(
model="gpt-5.6-sol",
input=[
*response.output,
{
"type": "function_call_output",
"call_id": item.call_id,
"output": str(result)
}
],
tools=tools
)
print("========== Final Answer ==========")
print(response2.output_text)
运行结果

