第 10 章:用 Zod 定义工具参数
本章目标
这一章聚焦工具参数。Tool Calling 能不能稳定工作,关键不只在模型,也在 Schema 设计。
本章效果
工具参数会在调用轨迹中显示出来,方便确认模型是否按 Zod Schema 生成了正确参数。

为什么 Zod 很重要
模型调用工具时,需要知道:
- 工具有哪些参数
- 每个参数是什么类型
- 哪些参数必填
- 参数含义是什么
- 取值范围是什么
Zod 不只是 TypeScript 类型工具,也是给模型看的参数说明。
一个糟糕的 Schema
z.object({
value: z.string(),
type: z.string()
});
问题是字段太模糊。模型不知道 value 是价格、城市还是用户 ID,也不知道 type 有哪些选项。
一个更好的 Schema
const orderStatusSchema = z.object({
orderId: z.string().describe("订单编号,例如 SO202605190001"),
includeLogs: z
.boolean()
.default(false)
.describe("是否返回订单流转日志,默认 false")
});
字段名清楚,描述明确,默认值合理。
业务查询工具
import { tool } from "langchain";
import * as z from "zod";
export const getOrderStatus = tool(
async ({ orderId, includeLogs }) => {
const order = {
id: orderId,
status: "已发货",
carrier: "顺丰",
trackingNo: "SF1234567890",
logs: ["已付款", "仓库已出库", "已发货"]
};
return JSON.stringify({
id: order.id,
status: order.status,
carrier: order.carrier,
trackingNo: order.trackingNo,
logs: includeLogs ? order.logs : undefined
});
},
{
name: "get_order_status",
description: "根据订单编号查询订单状态和物流信息",
schema: z.object({
orderId: z.string().describe("订单编号,例如 SO202605190001"),
includeLogs: z.boolean().default(false).describe("是否包含订单流转日志")
})
}
);
Schema 设计原则
字段名要具体:
好:orderId, startDate, maxResults
差:id, value, data
枚举要收窄:
z.enum(["pending", "paid", "shipped", "done"])
可选字段要说明默认行为:
z.number().optional().describe("最多返回多少条,不传默认 10 条")
危险参数要避免开放:
不要让模型直接传 SQL
不要让模型直接传文件路径
不要让模型直接传任意 URL 并由服务端请求
参数校验失败怎么办
模型可能生成不合法参数。处理方式:
- 让 Zod 拦截
- 返回可理解的错误信息
- 必要时让模型重新生成
- 高风险动作不要自动重试
实战任务
完成:
get_order_status工具- 一个带枚举参数的
search_policy工具 - 对工具参数做边界限制
- 测试模型是否能正确选择工具
常见坑
不要把工具参数设计成“万能参数”。万能参数等于没有 Schema。
不要假设模型一定会填对。服务端必须校验。
不要把工具描述写得像注释。它是模型选择工具的重要依据。
本章小结
Zod Schema 是工具调用稳定性的核心。下一章会把多个工具组合成一个业务 Agent。