智能体重复调用工具无结果:循环检测与退出机制设计
某企业的采购智能体接到任务,查询三家供应商的报价并生成比价单。智能体调用了供应商查询接口,输入"轴承",返回了两条记录。接口返回有效——HTTP状态码200、数据非空——但任务结果不充分:比价单需要供应商名称、产品型号、单价、交货期和有效期五个字段,而返回数据缺少价格字段。智能体认为结果不够完整,把关键词换成"滚动轴承"再查,返回了一条新记录但同样缺少价格。接着又换成"轴承SKF"查,返回三条记录,其中两条与之前重复。十五分钟内,智能体连续调用十七次供应商查询接口,每次都拿到部分数据,每次都觉得"还差一点",直到会话超时被系统强制终止。整个过程没有报错,日志里全是HTTP 200响应,但比价单始终没有生成。
运维人员排查时发现,智能体的调用链看起来每一步都合理——它在尝试不同关键词,在补充缺失字段,在扩大检索范围。问题在于,没有任何环节告诉它"你已经查得够多了"或者"你查到的数据已经足够生成一份标注了缺失项的比价单"。接口每次都返回有效数据,系统无从区分"正常查询"和"已经陷入循环"。
很多团队遇到这类问题的直觉反应是模型不够聪明,于是切换到参数量更大的模型。但换模型后循环依然存在,因为这不是模型推理能力的问题,而是编排层缺少对工具调用行为的约束机制。模型再强大,如果不知道"什么算够了",就会一直尝试下去。也有团队尝试在Prompt里写"不要重复调用同一工具",但这类指令的执行依赖模型自身判断,在结果确实不完整时模型会认为这不是重复调用而是补充查询,指令几乎没有约束力。
问题可以从三个层面拆解。
一类是结果充分性定义缺失。这里需要区分两个概念:工具返回有效性指的是接口是否正常返回了数据,任务结果充分性指的是返回的数据是否足以完成当前任务。编排层目前只检查有效性,不检查充分性。以三家供应商比价为例,充分的结果应该包含三家供应商各自的名称、型号、单价、交货期和有效期,合计十五个字段。智能体首次调用返回了两条记录的名称和型号——返回有效,但距离任务完成还差十一个字段。编排层没有定义"一次充分的供应商查询应该返回哪些字段、多少条记录",只要接口返回了非空结果就认为调用成功,把判断"够不够"的责任完全推给了模型。模型面对不完整的数据,自然会倾向于再查一次而不是基于已有信息做降级处理。
另一类是循环检测维度单一。目前的检测只按工具维度做连续调用计数——同一个工具被连续调用几次,超过阈值就熔断。这漏掉了三种情况。一是参数振荡:同一工具用不同关键词反复调用,关键词变化但返回结果高度相似。二是A—B—A工具回路:智能体先调工具A,再调工具B,又回到工具A,参数与首次几乎相同。这种交替调用在单一工具计数器看来每次都是新一轮,因为中间插入了其他工具,连续计数被清零。三是信息增量缺失:每次调用返回的数据与之前已有的数据完全重叠,没有新增任何字段或记录,但系统没有机制检测这一点。
还有一类是退出路径缺失。当工具返回的结果确实不完整时,智能体没有定义好的降级路径。它不知道"在查了多次仍然缺少价格字段的情况下,应该用已有数据生成比价单并标注价格待补充,还是应该转入人工处理"。没有退出条件,没有降级策略,智能体只能在"再试一次"和"放弃任务"之间二选一,而缺少明确退出条件时,模型往往倾向于继续寻找解决路径。
针对智能体因结果不完整而重复调用工具的问题,青山不语AI工作室采用"工具调用循环检测与结果充分性判断"框架,通过任务完成条件、调用指纹、信息增量、任务级预算和退出路径共同约束工具调用行为。
起始环节是结果充分性定义。每个工具在注册时需要声明两类信息:必需字段列表和最小有效结果数。以供应商查询工具为例,必需字段包括供应商名称和产品型号,最小有效结果数为一。调用返回后,编排层检查返回数据是否包含所有必需字段且达到最小结果数。如果满足,标记为"充分",直接进入下一步;如果不满足,标记为"部分有效",记录缺失的字段和差距。这层校验由编排层执行而非模型判断,避免模型对"够不够"的评估因上下文不同而漂移。需要强调的是,工具返回有效不等于任务结果充分:接口返回了一条名称和型号,工具层面是有效的,但比价任务需要的十五个字段还差十一个,任务层面是不充分的。
第二个环节是循环检测。这个环节有三个维度。起始维度是任务级总调用预算:编排层为整个任务设定一个总调用次数上限,覆盖所有工具的调用总和。无论智能体调用的是工具A还是工具B,都从同一个预算池扣减。调用其他工具不会清空任务预算,避免通过工具切换来重置计数器。下一个维度是调用指纹:每次工具调用生成一个指纹,由工具ID和参数哈希组成。编排层维护一张指纹表,新调用生成指纹后与历史指纹比对。指纹完全匹配说明是重复调用;指纹高度相似——参数仅微小变化——标记为参数振荡。A—B—A回路通过指纹序列检测:当最近的若干次调用指纹与更早的指纹形成重复模式时,判定为工具回路。还有一个维度是信息增量:调用返回后,将结果数据与任务已有数据做差集运算。新增字段或新增记录数为零时标记为零增量调用。零增量调用连续出现时,即使任务预算未耗尽也应当触发退出决策。
第三个环节是退出决策。循环检测触发后,编排层根据已有数据的充分性等级决定下一步。如果已有数据达到"部分有效"标准——至少包含必需字段但缺少非关键字段——编排层允许智能体使用已有数据继续执行任务,在输出中标注数据不完整的部分。如果已有数据连"部分有效"都不满足,编排层将任务转入人工处理队列,同时附上已调用的参数和返回结果供人工参考。这个环节的关键在于:系统必须具备"用不完整数据继续"的能力,而不是非要等到数据完美才往下走。
第四个环节是替代路径。除了循环熔断,编排层还可以在结果不完整时主动建议智能体更换工具或调整查询策略。比如供应商查询缺少价格字段时,编排层可以提示智能体尝试调用报价查询工具,而不是反复用不同关键词查供应商库。这需要一个工具间的关联映射表,定义"当工具A返回不完整结果时可以尝试工具B"的替代关系,由工程团队在工具注册阶段维护。替代路径设置最大跳转次数,超过限制后不再允许工具切换,直接进入退出决策。替代路径还禁止无新增信息的回路:如果跳转到替代工具后返回的数据与已有数据重叠,不允许跳回原工具再试,因为这条路已经被验证为低增量。替代关系需要人工配置和测试,不能由模型临时创造新的工具调用链。
工具调用循环的问题核心不在于模型能力,而在于编排层是否具备行为约束能力。结果充分性定义解决了"什么算够"的问题,调用指纹和信息增量解决了"什么算重复"的问题,任务级预算解决了"什么时候该停"的问题,退出决策和替代路径解决了"停下来之后怎么办"的问题。四个环节中任何一个缺失,智能体都有可能在某个边界条件下重新陷入循环。对于实际部署的智能体项目而言,工具调用的行为约束和工具能力本身同等重要——不能只关注工具能不能调通,还要关注调不通时系统怎么处理,以及调通但结果不完整时系统会不会知道该停下来。
