通用工具重复熔断缺失:acp_status 30× 字节级相同调用死循环 —— 贪心模型下任何工具都可成环,compress 熔断器覆盖不到
与 #250 (compress 同参失败空转,已修)互补的形态:这次是永远成功的工具 的重复循环。#250 的熔断器只统计 compress 失败,对此零计数。#269 (模型无视 nudge)的另一变种。
环境
插件:billion-context-pi 0.1.54 (~/.pi/agent/npm/node_modules/billion-context-pi)
宿主:pi coding agent,Linux
模型:qwen3.8-27b-w8a16,SGLang 0.5.17(:8199),贪心解码 (模型目录 generation_config.json do_sample:false, temperature:0),thinking off
会话:01a071dc-e334-76ea-98a9-115e48061ac9(2026-09-05 13:58 → 09-06 11:23 UTC,21.5h,1066 条消息,61 次压缩,累计压缩 414K tokens)
证据:~/.pi/agent/sessions/--home-dog-projects-billion-context-pi--/2026-09-05T13-58-16-628Z_01a071dc-e334-76ea-98a9-115e48061ac9.jsonl + 同名 .acp.json sidecar + ~/.pi/acp.log
现象
2026-09-06 11:03:08–11:23:08 UTC,模型进入死循环,30 轮字节级完全相同 :
thinking md5 恒定、正文 md5 恒定(30 次全部一致)
每轮唯一工具调用:acp_status {"scope":"uncompressed","view":"ranges"},每次输出恰好 2635 tokens,~30s/轮
上下文每轮净增 ~2980 tokens,57K → 130K(有效上限 131072 = 262144 − maxOutput)
触发时序:11:01:07 nudge 注入一次 → 11:02:22 模型 compress 成功(27.8K→6.6K,blocks b58+b59)→ 11:03:08(下一轮)立即进入循环 ,thinking 声称 The user says "合并了 下一个" —— 该消息在全部 1069 条原始消息和所有压缩块中均不存在 (幻觉,是两句真实用户口头禅的混合;turnKey 全程未变,证明无新用户输入)
用户打断两次(11:16:59、11:21:18):模型道歉 + compress 一次 → 下一轮立刻复发同 think hash
11:15:01 emergency nudge(96%)注入也未能打破吸引子
为什么现有防线全部失效
compress-retry-capped 熔断器只统计 compress 失败 (src/index.ts:321,小模型(本地 27B 量化)compress 循环空转:同参数重复失败 + 幻觉 ref(0.1.52 完整日志证据) #250 的修复):本循环调的是 acp_status,永远成功 → 熔断器零计数、永不触发
nudge 去重按 turnKey :循环期间没有新用户消息,turnKey 恒定 → 76%→96% 全程 nudge-suppressed,emergency(≥96%)才注入,太晚
src/tool-guardrails.ts 只有 bash 输出上限 + timeout 检测 ,没有任何"连续相同调用"检测
保护带保护了循环自己 :循环产生的 ~60 条消息全在 recent/last-user zone,打断后的 compress 显示 Excluded 42 protected message(s),回收寥寥
复发性(本机 80 个近期会话扫描,3 个中招)
会话
模型
形态
01a071dc
qwen3.8-27b
24× acp_status + 打断后 2 次复发
01a02d90
同上 27B
7× compress(#250 形态)+ 17× 相同 bash (gitlab 命令)
01a06110
qwen3.8-flash W4A16
21× 相同 bash (sleep 轮询,17 分钟)
→ 任何工具都可成为吸引子;两代 qwen3.8(27B 与 flash)都有;贪心解码是共同条件。 循环是序列级的(上下文尾部 N 个相同 (assistant,toolResult) 对自我强化),token 级 penalties(presence/frequency/repetition)对跨轮重复完全无效。
修复建议(按优先级)
1. 通用重复指纹熔断(核心,挂 src/tool-guardrails.ts)
指纹 = sha1(toolName + 稳定序列化(args 键排序后的 JSON))
会话级滑动窗口记录最近指纹
连续 ≥3 次相同 → 在该次 toolResult 尾部注入强警告:你已连续 N 次发出完全相同的工具调用(name+参数逐字节一致)。禁止再次发出相同调用;必须改变策略、换参数,或停止并等待用户。
连续 ≥5 次相同 → 拒绝执行该调用(返回错误 toolResult)+ abort 当前 turn + 终端 echo(参照现有 bash timeout 的处理路径)
注意:只比对参数 ,不看结果 —— acp_status 结果里可见消息数会微变(24→26→28),但参数相同就算命中
阈值可配:acp.json { "repetitionGuard": { "warn": 3, "abort": 5 } },默认开启
tests/ 增加:连续同参调用触发 warn(3 次)、触发 abort(5 次)、参数变化即重置计数的用例
2. 熔断器泛化(src/index.ts:321 一带)
per-turn cap 除 compress 失败外,同时计入"无进展工具调用"(acp_status/decompress/search_context 反复调用且 tokenCount 无下降),达到上限同样 no-progress-capped 告警。
3. nudge 去重放宽
同一 turnKey 内,若距上次注入后上下文相对增长 >10% ,允许再注入一次(仍设每档位上限,防止重蹈 #223 无限追加)。
4. 循环消息可压缩
检测到重复指纹时,将循环产生的 assistant/toolResult 消息移出保护带(或显式标记为可压缩),让用户打断后的 compress 能真正回收它们(本例 60 条 × ~3K tokens 全被保护)。
通用工具重复熔断缺失:acp_status 30× 字节级相同调用死循环 —— 贪心模型下任何工具都可成环,compress 熔断器覆盖不到
环境
~/.pi/agent/npm/node_modules/billion-context-pi)do_sample:false, temperature:0),thinking off01a071dc-e334-76ea-98a9-115e48061ac9(2026-09-05 13:58 → 09-06 11:23 UTC,21.5h,1066 条消息,61 次压缩,累计压缩 414K tokens)~/.pi/agent/sessions/--home-dog-projects-billion-context-pi--/2026-09-05T13-58-16-628Z_01a071dc-e334-76ea-98a9-115e48061ac9.jsonl+ 同名.acp.jsonsidecar +~/.pi/acp.log现象
2026-09-06 11:03:08–11:23:08 UTC,模型进入死循环,30 轮字节级完全相同:
acp_status {"scope":"uncompressed","view":"ranges"},每次输出恰好 2635 tokens,~30s/轮The user says "合并了 下一个"—— 该消息在全部 1069 条原始消息和所有压缩块中均不存在(幻觉,是两句真实用户口头禅的混合;turnKey 全程未变,证明无新用户输入)为什么现有防线全部失效
src/index.ts:321,小模型(本地 27B 量化)compress 循环空转:同参数重复失败 + 幻觉 ref(0.1.52 完整日志证据) #250 的修复):本循环调的是 acp_status,永远成功 → 熔断器零计数、永不触发nudge-suppressed,emergency(≥96%)才注入,太晚src/tool-guardrails.ts只有 bash 输出上限 + timeout 检测,没有任何"连续相同调用"检测Excluded 42 protected message(s),回收寥寥复发性(本机 80 个近期会话扫描,3 个中招)
→ 任何工具都可成为吸引子;两代 qwen3.8(27B 与 flash)都有;贪心解码是共同条件。 循环是序列级的(上下文尾部 N 个相同 (assistant,toolResult) 对自我强化),token 级 penalties(presence/frequency/repetition)对跨轮重复完全无效。
修复建议(按优先级)
1. 通用重复指纹熔断(核心,挂
src/tool-guardrails.ts)sha1(toolName + 稳定序列化(args 键排序后的 JSON))你已连续 N 次发出完全相同的工具调用(name+参数逐字节一致)。禁止再次发出相同调用;必须改变策略、换参数,或停止并等待用户。acp.json { "repetitionGuard": { "warn": 3, "abort": 5 } },默认开启2. 熔断器泛化(
src/index.ts:321一带)per-turn cap 除 compress 失败外,同时计入"无进展工具调用"(acp_status/decompress/search_context 反复调用且 tokenCount 无下降),达到上限同样
no-progress-capped告警。3. nudge 去重放宽
同一 turnKey 内,若距上次注入后上下文相对增长 >10%,允许再注入一次(仍设每档位上限,防止重蹈 #223 无限追加)。
4. 循环消息可压缩
检测到重复指纹时,将循环产生的 assistant/toolResult 消息移出保护带(或显式标记为可压缩),让用户打断后的 compress 能真正回收它们(本例 60 条 × ~3K tokens 全被保护)。