compress 摘要双重转义(\uXXXX)直接入库+渲染进 prompt;幻觉用户原话被摘要永久化为 "CURRENT TASK" 导致循环复发
同一会话(01a071dc-e334-76ea-98a9-115e48061ac9,0.1.54)调查中发现的两个摘要保真度 bug。与 #250/#199 同源环境(本地 27B 量化模型)。
现象 A:摘要双重转义入库
Sidecar 对比:
- 早期块 b8/b9/b10 存储真中文 verbatim 引用:
"合并了295 继续下一个rebase"
- 14:55:01 起该会话所有 compress 调用(jsonl line 923 之后,含 b58/b59/b60/b61):模型参数里的中文全部变成字面
\u5408\u5e76... 转义序列(原始 wire 上是双重转义 \\u5408,外层 JSON.parse 后残留字面 \u5408 6 字符序列)
- kernel
renderSummary() 不做任何 unescape,原样渲染 → 模型 prompt 里出现大段 \uXXXX ASCII
诱因:模型模仿上下文中(工具输出里)转义过的 JSON —— 少样本污染,中途切换风格,之后自我强化。每次二级蒸馏把转义再复制一层(b61 也是转义的)。
影响
- 摘要保真度下降(qwen 能部分读懂
\uXXXX,但不再是可靠的历史记录)
- 双重转义写回 prompt 可能进一步污染模型后续输出风格
修复建议
- compress content 入库前规范化:解析后的 summary 文本中
(?:^|[^\\])\\u[0-9a-fA-F]{4} 命中数超过阈值(如 20 处)→ 做一次 unescape(JSON.parse('"'+s.replace(/\\/g,'\\\\').replace(/"/g,'\\"')+'"') 或逐段解码),写 debug log summary-unescaped
- tests/ 增加双转义样本用例(输入含
\u5408\u5e76 字面序列,断言入库后为真中文)
现象 B:幻觉用户原话被摘要永久化 → 循环复发的直接原因
时间线(全部来自 sidecar 与原始 jsonl):
- 会话节奏 = 用户在每次 PR 合并后说"合并了…"(真实话语被 b8/b58 等摘要 verbatim 保留)
- 11:03:08 UTC 模型幻觉出不存在的用户消息
合并了 下一个(两句话的混合体;全文检索证实该短语此前从未出现),进入 30× acp_status 死循环(另开 issue 详述)
- 11:18:13 用户打断后,模型压缩生成 b60,把幻觉写成事实:
CURRENT TASK: user '合并了 下一个' = proceed to NEXT open issue. Remaining: #305,#299,#271...
- 11:21:56 二级蒸馏 b61(active)继承:
CURRENT TASK (user verbatim '合并了 下一个'): pick NEXT open issue...
- → 打断后模型每次读到 b61 都会"恢复任务" → 两次复发,直到用户放弃会话
ACP 把一句幻觉标注为 user verbatim 写进存储,是循环从"一次事故"变成"持续复发"的放大器。
修复建议
- 压缩提示词加规则(
src/system-prompt.ts):引用用户原话必须带消息 ref(mNNNNN);没有 ref 的改为转述("user previously said (paraphrased) ...")。禁止在摘要中用现在时把引用写成当前指令
- kernel 入库校验:新摘要中出现
user verbatim/直接引号声称用户原话但缺 mNNNNN ref → [warn] summary-unverifiable-quote 日志(不自动改写,留证据)
- 摘要模板措辞:"CURRENT TASK" 一律改为 "TASK AS OF BLOCK CREATION(历史状态,截至本块创建时)"——摘要描述的是压缩时刻的过去,不是现在的指令
compress 摘要双重转义(\uXXXX)直接入库+渲染进 prompt;幻觉用户原话被摘要永久化为 "CURRENT TASK" 导致循环复发
现象 A:摘要双重转义入库
Sidecar 对比:
"合并了295 继续下一个rebase"\u5408\u5e76...转义序列(原始 wire 上是双重转义\\u5408,外层 JSON.parse 后残留字面\u54086 字符序列)renderSummary()不做任何 unescape,原样渲染 → 模型 prompt 里出现大段\uXXXXASCII诱因:模型模仿上下文中(工具输出里)转义过的 JSON —— 少样本污染,中途切换风格,之后自我强化。每次二级蒸馏把转义再复制一层(b61 也是转义的)。
影响
\uXXXX,但不再是可靠的历史记录)修复建议
(?:^|[^\\])\\u[0-9a-fA-F]{4}命中数超过阈值(如 20 处)→ 做一次 unescape(JSON.parse('"'+s.replace(/\\/g,'\\\\').replace(/"/g,'\\"')+'"')或逐段解码),写 debug logsummary-unescaped\u5408\u5e76字面序列,断言入库后为真中文)现象 B:幻觉用户原话被摘要永久化 → 循环复发的直接原因
时间线(全部来自 sidecar 与原始 jsonl):
合并了 下一个(两句话的混合体;全文检索证实该短语此前从未出现),进入 30× acp_status 死循环(另开 issue 详述)CURRENT TASK: user '合并了 下一个' = proceed to NEXT open issue. Remaining: #305,#299,#271...CURRENT TASK (user verbatim '合并了 下一个'): pick NEXT open issue...ACP 把一句幻觉标注为
user verbatim写进存储,是循环从"一次事故"变成"持续复发"的放大器。修复建议
src/system-prompt.ts):引用用户原话必须带消息 ref(mNNNNN);没有 ref 的改为转述("user previously said (paraphrased) ...")。禁止在摘要中用现在时把引用写成当前指令user verbatim/直接引号声称用户原话但缺 mNNNNN ref →[warn] summary-unverifiable-quote日志(不自动改写,留证据)