Agent 效果不好,八成问题出在工具定义上,而不是模型上。这节是我们的五条原则。
可复现前提: 每条原则都附了 A/B 两版工具定义与 60 条测试 query,脚本 bench/tool-def。
1. 描述里写清"什么时候用我"
工具描述不是给人看的文档,是给模型的路由依据。
差: 查询订单信息
好: 按订单号或用户手机号查询订单详情。当用户提到订单号、"我的订单"、"上次买的东西"时使用。不要用于查询物流,物流请用 track_shipment。
加上"不要用于…"这一句,我们的工具误选率从 19% 降到 4%。
2. 参数要有默认值和枚举
{
status: z.enum(["pending", "shipped", "done"]).default("pending"),
limit: z.number().int().min(1).max(50).default(10),
}自由文本参数是幻觉重灾区。能枚举的一定枚举。
3. 一个工具只做一件事
我们曾经有个 manage_order 工具,靠 action 参数区分查询/取消/改地址。模型经常传错 action。拆成三个工具后,错误率降到接近 0。
4. 返回结果要精简
把整个 JSON 响应塞回去,模型会被无关字段带偏,还烧 token。我们现在的做法是每个工具都有一个投影层,只返回决策需要的字段。一次返回从平均 2400 token 降到 180 token。
5. 副作用工具要能回滚或需确认
// 有副作用的工具:先返回预览,拿到确认再执行
server.tool("cancel_order", "取消订单。会先返回确认信息,需用户明确同意后再传 confirm=true 执行。", {
order_id: z.string(),
confirm: z.boolean().default(false),
}, async ({ order_id, confirm }) => {
if (!confirm) return preview(order_id);
return doCancel(order_id);
});