Skip to content

11_05_Loop_Guard

Wyckoff edited this page Jun 21, 2026 · 1 revision

(五) Loop Guard 死循环拦截

模型偶尔会只输出计划、不调用工具。cli/loop_guard.py 把部分数据型任务从 prompt(提示词)约束提升为运行时约束。

6.1 必须工具识别机制

运行时会通过 resolve_turn_expectation(messages) 判断当前对话轮次是否必须调用某个工具(目前主要针对 portfolio 即持仓数据工具进行强制要求)。具体识别逻辑如下:

1. 意图匹配场景

系统定义了多组硬编码的关键词元组,通过在归一化(转小写、去除首尾空格)后的用户输入中检索子串进行意图推断:

  • 直接查询持仓(View Portfolio):用户输入中包含 "我有什么持仓", "我买了啥", "持仓情况" 等关键词。强制要求调用 portfolio(mode="view")
  • 直接持仓诊断(Diagnose Portfolio):用户输入中包含 "我持仓怎么样", "持仓健康吗", "帮我审一下持仓" 等关键词。强制要求调用 portfolio(mode="diagnose")
  • **上下文承接诊断(Contextual Follow-up) :用户输入为简短词(如 "体检", "健康吗")或带有指代关系(如 "分析这些", "这几只"),且在 ** 最近 4 条上下文消息 中检测到了持仓标记(如 "持仓", "成本价", "代码 | 名称 | 持股" 类似字样)。强制要求调用 portfolio(mode="diagnose")
  • 肯定答复承接诊断(Affirmative Response):用户输入为肯定词(如 "要", "好的", "可以", "行"),且在最近 4 条上下文消息中包含体检/分析的暗示及持仓标记。强制要求调用 portfolio(mode="diagnose")

2. 上下文判定范围与隔离性

  • 匹配范围:所谓的“最近 4 条上下文消息”(代码中为 messages[:-1] 并设定 limit=4),指的是当前对话会话(Session)中排除当前用户输入后,往前倒数的 4 个消息对象(包含 userassistanttool 执行结果,并非真正的 4 轮完整对话)。
  • **会话内累积 :在同一个会话(Session)中,用户的 Query 和助手的回复是 ** 不隔离的 。历史消息不断累积追加到上下文列表,因此后续的简短提问可以通过 previous_context 关联上前面的对话环境(例如检测到刚才助手展示的持仓表格特征)。
  • **会话间隔离 :不同会话(或清除历史、重启终端)之间是 ** 完全隔离的 。上下文重置为零,匹配逻辑无法跨会话追溯。

3. 剥离记忆文本干扰

为了防止系统在前序处理中自动召回并注入到用户消息中的长期记忆(包含在 `<relevant-memories>` 标签内)误触发敏感词匹配,匹配引擎在进行子串检索前会通过 _strip_recall_context() 函数 强行剥离记忆区域的文本 ,只留下用户手打输入的原始 Query(包含在 `<current-user-message>` 内)进行判定。

6.2 拦截与纠偏机制

如果模型漏调必需工具,runtime(运行时)会注入 retry user message(纠偏用户消息),最多重试 2 次;仍失败则把警告前置到最终回答里。

6.3 运行阈值与死循环检测

当前实际阈值:

常量 当前值 含义
MAX_TOOL_ROUNDS 15 单轮用户请求最多 15 轮模型-工具往返
MAX_INCOMPLETE_TOOL_RETRIES 2 漏调必需工具时最多纠偏 2 次
DOOM_LOOP_WINDOW 6 死循环检测看最近 6 次工具调用
DOOM_LOOP_THRESHOLD 3 同工具同参数出现 3 次即判定疑似死循环
DOOM_LOOP_EXEMPT check_background_tasks 后台任务状态查询允许重复

Doom-loop(死循环)防护用于阻止同一工具同参数反复调用:

  • 精确匹配:最近 6 次调用中同一 (tool_name, args_hash) 出现 3 次。
  • 模糊匹配:参数文本长度达到 50 字符后,3-gram Jaccard 相似度达到 0.8 的同工具调用出现 3 次。
  • check_background_tasks 这类轮询工具豁免。

触发后 runtime(运行时)会写入工具错误 observation(观察结果),并中止本轮剩余工具调用,避免模型把外部 API(应用程序接口)或本地任务打爆。


6.4 死循环拦截与相似度计算策略

  • 精确重复调用拦截 (Exact Match): 系统会在内存中维护最近的 DOOM_LOOP_WINDOW = 6 次工具调用记录。如果同名工具且参数 Hash 相同的调用累计达到 DOOM_LOOP_THRESHOLD = 3 次,则判定为发生死循环。
  • 模糊相似调用拦截 (Fuzzy Similarity): 如果工具调用参数较长($\ge 50$ 字符),精确 Hash 难以直接碰撞。系统会启动 3-gram Jaccard 相似度计算
    1. 将参数 JSON 序列化字符串按 3 字符片段切片,分别形成词袋集合 $S_1$$S_2$
    2. 计算两个集合的交并比(Jaccard Index): $$\text{Similarity} = \frac{|S_1 \cap S_2|}{|S_1 \cup S_2|}$$
    3. 若 Jaccard 相似度 $\ge 0.8$ 的同工具调用累计达到 3 次,系统将立即进行拦截。
  • 拦截处理: 一旦死循环被拦截,Runtime 将向 messages 中写入一条特定的 Observation,通知大模型该工具调用被拦截,且后续工具调用权限当场关闭,逼迫大模型改变推理方向或结束本轮对话。

返回 系列索引

Clone this wiki locally