你启动Agent时只有3个工具。系统提示词里逐一命名,各给一行示例,告诉模型何时调用哪个。半年后工具膨胀到28个。产品陆续加了"查客户"工具、"查客户最近发票"工具,然后是6个"搜索文档"的变体。系统提示词从没更新,仍写着那3个工具的名字。
日志揭示了后果:模型调用了一个不存在的工具。它选了search_docs_v1,正确答案却是search_docs_legal。一半工具从未被调用,因为提示词里没有任何字符串引导模型走向它们。你没破坏任何东西,只是提示词和工具集分道扬镳了。
这是生产环境Agent中影响最大、又最容易被忽视的bug之一。工具集在代码里,提示词也在代码里。它们不是同一份代码,不在同一个文件,CI也不会在两者脱节时报错。
traces中呈现出几种典型形态,根因相同:
工具调用幻觉。模型输出tool_use,名称是调度器不认识的。往往是两个真实工具的合理拼接:你有search_customers和get_invoice_by_id,模型发明了search_customer_invoices。它在根据提示词示例泛化,填补空白。Anthropic API带着tool_use块返回响应,你的代码抛"无此工具"错误,用户看到通用失败。
孤儿工具。工具存在于注册表,每次请求都发给模型,生产环境中从未被调用。有时是合理的(边缘场景极少触发),更多时候是工具描述太弱,模型从不选它,或另一工具描述更强、总是胜出。无论如何,你都在为每次请求发送schema的输入token付费,却毫无回报。
选择模糊。两个工具都能回答同一问题。模型始终选一个、忽略另一个,更糟的是随机挑选。比如search_docs_v1和search_docs_legal,若提示词没说明哪个语料库是什么,选择就是抛硬币。用户看到的答案 inconsistently,取决于那一分钟模型挑了哪个文档库。
共同根因:提示词没有准确描述模型拥有的工具集。
第一步是机械性的。把工具集和提示词放进同一数据结构,做diff。你需要知道:注册表里的每个工具,系统提示词是否提及;系统提示词里的每个工具名,是否仍然存在。
热门跟贴