# Function Calling 幻觉:防御、纠正、兜底

📅 2026/7/10 1:57:56
# Function Calling 幻觉:防御、纠正、兜底
先说一下问题做 AI 应用的时候Function Calling 有个很头疼的问题——模型会乱调工具。举个例子你定义了一个queryOrder用来查订单。用户说我要查订单它调了正常。但用户说我想退单它可能也调了queryOrder而不是cancelOrder。或者传参传了一个不存在的订单号然后告诉你查不到。这个问题在圈子里叫Function Calling 幻觉。不是模型坏了是它在猜应该用哪个工具而不是真的理解业务场景。我这段时间在折腾这个从各种资料和实验里整理了一套方案分三个层面。问题出在哪模型的 Function Calling 逻辑大致是这样的看了你写的 function 描述比对当前用户输入找语义上最匹配的那个工具调。但有两个问题第一描述是自然语言模型的理解有边界。你写查询用户信息它不知道查询和修改的区别。你写当用户想查看个人信息时调用它可能把查一下我的等级也匹配进来。第二工具越多准确率越低。我的测试结果10 个以内的 function准确率还行。超过 20 个模型开始频繁选错。跟人一样选项太多就容易纠结。防御层让模型少犯错防御层是在调用发生之前做的优化成本最低效果最明显。1. 描述里加负面约束最常见的错误写法查询用户的订单信息模型拿到的信息太少全靠猜。改一下当用户明确提供了用户ID或订单号并且意图是查询订单状态或详情时调用。 如果用户没有提供具体的查询条件不要调用先反问用户要查什么。 不要用于修改订单、取消订单、查询其他用户的信息。核心改动是加了“什么时候不要调”的说明。实测下来负面约束比正面描述更管用。2. Few-shot 示例在 System Prompt 里放几个调用示例效果比优化描述都好。正确的调用方式 用户我最近的订单到了吗 → queryOrder(statusRECENT) 用户你好 → 不调用任何工具直接回复 用户我的收货地址是什么 → queryUserAddress() 错误的调用方式 用户你们客服电话多少 → ❌ 不应该调任何工具3 到 5 个就够多了占上下文少了覆盖不全。3. 动态控制工具数量不要让模型一次面对几十个工具。先做意图分类判断用户大概想干什么只暴露相关的工具给模型。比如用户说帮我查一下快递系统判断属于物流类只给模型暴露物流相关的 3 个 function其他 20 个工具不进入这次上下文。工具数量从 20 降到 3模型选错的概率低很多。纠正层让模型错了能改防御层再怎么做模型还是会犯错。所以要在调用过程中加纠正机制。1. 参数校验 反馈闭环不直接信任模型生成的参数。在执行工具之前先校验参数格式和范围。比如orderId规定是ORD-开头模型传了个12345。这时候不要直接报错而是把校验失败的信息包装成一条系统反馈再发给模型系统提示你传入的 orderId 格式不对必须是 ORD- 开头请修正后重试。模型看到反馈后通常会自己修正参数重新调用。这个过程完全自动你只需要写校验规则和反馈模板。但要注意一点模型可能在同一个错误上反复循环所以要限制重试次数2 次差不多超过就走降级。2. 调用后的自反思工具执行完后让模型自己确认结果是不是正常。如果返回空数据或者报错模型可以决定怎么处理。比如模型调了天气查询接口传了城市中文名但接口只支持拼音返回为空。系统反馈异常信息模型意识到参数错了换成拼音重试。在 Prompt 里加一句调用工具后检查返回结果异常时可以修正参数重试就能启用这个能力。兜底层系统扛得住防御和纠正都失效的时候兜底保证业务不崩。1. 重试上限 降级同一个工具调用最多重试 2 次。超过了就走降级返回用户提示“暂时查不到请稍后再试”记录异常日志切到备选方案不用模型用关键词匹配2. 业务补偿如果模型调错了工具产生了副作用要有撤销能力。比如错误地发了一条通知、改了某个状态得有一个对应的撤销操作。这个比较复杂适合核心业务链路。非核心场景走降级就行。3. 人工确认涉及写操作、权限变更、支付类的场景可以做成半自动模型生成调用请求后先让用户确认再执行。形式上就是个确认弹窗但能挡住大部分误操作。实际项目怎么选不是所有场景都需要三层全上场景建议纯问答、信息查询防御 纠正数据查询和报表防御 纠正 重试降级涉及写操作三层全上 人工确认防御层的投入产出比最高。改改描述、加几个示例不需要改代码结构就能提升准确率。最后Function Calling 幻觉不会彻底消失模型迭代会改善但不会根除。把模型会犯错当作默认前提来设计比期待下一个模型版本能解决所有问题更实际。防御层让它少犯错纠正层让它错了能改兜底层让系统不崩——三层加起来多数场景就够用了。—— 焦虑的饼干