Skip to content

[Bug]: Auto-compaction 丢失最新用户诉求并保留过期待办,导致压缩后 Agent 持续漂移 #480

Description

@worksyang

Summary (EN): Auto-compaction drops the user's newest ask and keeps stale ones, which makes the agent drift further off-target after every compaction. Root cause is in the hardcoded checkpoint prompt; OpenCode solves the same problem with two mechanisms we don't have. Suggested fix inside.


我遇到的困难

我是 MiniMax Code 的重度用户,长时间跑一个任务会话是常态。遇到一个反复出现、而且我没法自己修的问题:

上下文满触发自动压缩后,Agent 经常不再处理我最新提的需求,转而去处理上一轮甚至更早之前的需求。而那些旧需求其实早就做完了。

更麻烦的是这不只是一次跑偏。压缩之后历史就只剩那份摘要,Agent 拿着摘要里的过期待办继续干,干出来的决策、改动又变成新的历史;下次压缩时,这些基于错误前提的产出还会被写进「已完成工作」里被固化下来。偏差会一轮一轮累积、放大,越漂越远,最后我得手动把会话掰回来,有时候干脆重开会话。对一个定位是长程 Coding Agent 的产品来说,这个损失挺大的。

我发现的问题

我读了 app.asar 里的源码,定位到根因在压缩提示词,是硬编码的常量:

packages/local-runtime-v2/src/service/turn-system/compaction/execution/checkpoint-prompt.ts

export const CHECKPOINT_SYSTEM_PROMPT = `You are creating a loss-aware checkpoint of a coding-agent conversation.
...
## Pending User Asks
## Critical Context & Relevant Files`;

## Pending User Asks 是一个不分时序的收集桶。整份提示词里没有任何一条时效规则:

  • 没有「只保留仍未回答或仍需行动的用户诉求」
  • 没有「更新的历史优先于旧检查点」
  • 没有「已解决的从待办移到已完成」

而提示词里恰恰写了一句反效果的话:Do not generate recent-query, Todo, or Plan state; the host appends verified state separately——它明确禁止摘要模型输出最近一轮状态,说这部分由宿主单独补。但宿主没有补。

我翻了自己机器上真实压缩过的会话(~/.minimax/v2/sessions/2026/10/09/.../messages.jsonl),摘要里是一长串 Pending User Asks,后面没有任何 recent-query 段落。这句话的两端都没兑现:模型不许写,宿主也不写。于是最新一轮就这么凭空消失了。

这就是漂移的起点:一份摘要里同时躺着过期待办和缺失的当前诉求,Agent 没有任何依据去偏好后者。

OpenCode 为什么做得更好

OpenCode 是开源的(packages/core/src/session/compaction.ts),同样的问题它用三个机制解决了:

一、它从物理上保住最新几轮原文。 splitConversation() 把对话切成两半,老的那半交给模型总结,最新约 15000 token 的内容原样保留,包在 <recent-context> 标签里跟摘要一起交给下一个 Agent。最新那一轮根本不经过摘要模型,自然不可能被误判成「已完成」。

二、它的摘要提示词明写了时效规则。 SUMMARY_RULES 原文:

Carry forward only user questions or requests that remain unanswered or require further action. Do not repeat ones that newer history has answered or resolved.

增量压缩时还有一条:

Newer history always takes precedence over the existing checkpoint.

三、它输出不合格会重问一次。 回复没填模板就补一句提醒再试,两次都不合格才算失败,不会让一次抽风直接毁掉整次压缩。

代码里的具体问题

按影响排序:

  1. checkpoint-prompt.ts 的八节模板缺时效规则,Pending User Asks 没有出口。
  2. 同一文件里 Do not generate recent-query ... the host appends verified state separately 是未兑现的承诺——我通读了 compaction 相关代码,没找到宿主补这段的实现。
  3. 自动压缩路径完全没有注入自定义指令的入口。手动压缩有 customInstructions(/compact <文本> 可用),但 AutomaticContextCompactor 那边连这个字段都没有,所以我连绕都没法绕。
  4. 提示词覆盖机制在生产里被关掉了。runtime-prompt-support.ts 里 enabled: false 写死,注释说是热修复;另一条 frozenPromptSource 入口需要 promptMode 或 freezeLocalPrompts,实际都没传。用户想自己修这份提示词都做不到。

我希望怎么改

按优先级:

P0 — 给 Pending User Asks 加时效规则。 一句话的事,比如「只保留仍未回答或仍需行动的用户诉求;更新的历史已回答、解决或取代的,移到 Completed Work」。这是性价比最高的一步,直接止住漂移。

P1 — 补上或者删掉那句承诺。 要么真的实现宿主追加 recent-query,要么把 Do not generate recent-query ... the host appends verified state separately 这句删掉。现在这样是提示词在骗模型,也让用户误以为有保障。

P2 — 增量压缩时声明新历史优先。 照 OpenCode 那句 Newer history always takes precedence over the existing checkpoint 加进去。

P3 — 学 <recent-context>,从物理上保住最新几轮。 这个改动大一些,但它是唯一能让「最新一轮被误判」在结构上不可能发生的方案。OpenCode 已经验证过可行。

另外两个不算 bug 但很想请求的:

  • 打开提示词覆盖入口,至少让压缩提示词可以本地替换。现在用户遇到这种问题只能干等版本。
  • 自动压缩也支持 customInstructions,让手动压缩已有的能力不要只留给 /compact。

环境

  • MiniMax Code 桌面端 0.1.1136,macOS arm64
  • 自动压缩与手动压缩都能复现,手动压缩时可我用 /compact 带指令临时缓解,自动压缩无解

很乐意帮你们测修复版,也可以补充更多会话样本。这个产品我天天在用它干活,真心希望它好——上面每一个点我都自己查过代码、确认过不是我的用法问题,但以用户身份能做的也就到这儿了。

Activity

  1. hetaoBackend commented on Oct 12, 2026

    @hetaoBackend
    Collaborator

    感谢这份细致的分析,我们对照源码逐条核实了:

    1. Pending User Asks 缺少时效规则:确认。已修复,checkpoint prompt 新增「较新历史优先(包括晚于旧 checkpoint 的内容)」「只保留仍未解决的诉求,最新的放最后」「已回答或被取代的移到 Completed Work」。
    2. 关于「宿主没有追加 recent-query」:宿主其实一直会在摘要末尾追加 mavis-context-appendix,其中 Recent user queries 段保留最近 2 条用户原文。但此前没有标明最后一条是当前诉求、优先于 Pending User Asks,所以它和过期待办处于同等地位,这正是你观察到的漂移。本次修复在 appendix 之前加了宿主说明,明确最新诉求优先,同时提示先核对是否已完成,避免手动压缩后重复执行。我们还发现子 agent / 后台任务会话里这一段会是 _None_,会单独跟进。方便的话请确认你看到的会话是不是子任务会话,或者贴一下摘要末尾那段 appendix(注意脱敏)。
    3. 原样保留最近几轮(P3)、自动压缩支持自定义指令、本地覆盖压缩 prompt:已记录,后续单独评估。

    修复会随下一个版本发布,届时欢迎帮忙验证。

  2. worksyang commented on Oct 12, 2026

    @worksyang
    Author

    逐条回复,其中第 2 点你们是对的,我原来的结论是错的。

    1. 关于「宿主没有追加 recent-query」— 我判断失误,更正

    我重查了本机会话数据,mavis-context-appendix version="5" 里的 ## Recent user queries 确实存在,保留最近 2 条用户原文。

    我当初的问题是只读了摘要末尾约 800 字符,而这段在 appendix 靠前的位置,被我截掉了。我据此下的「宿主没有实现」结论是错的,抱歉。

    2. 我的会话不是子任务会话

    复现用的会话:mvs_f977cf48b1fa4becb664ddabc1e78f50,manifest.json 里 source: "local-runtime",history-catalog.json 显示 1206 条消息,是主会话不是子任务会话。

    3. appendix 片段(已脱敏,保留结构)

    <mavis-context-appendix version="5">
    ## Recent user queries
    ### Query
    - Text: "远端按曝光量粗筛前 10 篇?这个不太对吧?之前不是说有一些什么权重之类
      的……这个你也研究一下,它好像有一个挺智能的权重体系的。"
    - Timestamp ms: 1791649195347
    
    ### Query
    - Text: "现在有一个比较纠结的问题。就是我有点想给它加一个额外的维度字段,比
      如图片数量。然后 M1 现有返回 10 篇可能少了点,返回 20/30 篇也可以……如果图片
      数量大于 30 张就被过滤掉再排前三名。我不想只对优惠这么搜索,希望全局生效。但
      我绞尽脑汁想不出什么样的文章可能大于 30 张同时信息量大、用户还愿意读,有点悖论。
      所以我可能需要你设计一个有意思的方式帮我筛选……"
    - Timestamp ms: 1791650276358
    
    ## Todo state
    ### Todo
    - Content: "第1步:读已有 Style/Hooks(查重与风格校准)"
    - Status: "completed"
    ...

    4. 一个补充观察,可能对你们的修复有帮助

    这个会话里,摘要的 ## Pending User Asks 开头写的是「用户最新要求」,而它列的几条(选 10–20 个关键词做实证、统计图片数 >30 的文章、查原始排名、判断全局 >30 图排除是否成立)内容上和上面第二条 Query 完全对应。

    也就是说摘要模型自己已经在试图标记「最新诉求」了,它甚至主动写了个「用户最新要求」的小标题。但因为:

    • Pending User Asks 在摘要正文里,是模型自己生成的推断;
    • Recent user queries 在 appendix 里,是宿主给的原文事实;

    这两者在提示词里没有任何显式关联,模型没有理由知道「我推断的『最新要求』必须以宿主给的最近两条原文为准」。当推断和事实冲突时,模型没有裁决依据。

    所以我认为你们加的那句宿主说明方向是对的——把优先级关系显式写出来,比让模型自己猜要可靠得多。如果还有余力,可以考虑让提示词直接引用 Recent user queries 而不是让模型重新归纳,避免推断与事实分叉。

    5. 补充澄清我的漂移现象

    需要说明的是:在这个具体会话里我没复现出漂移,Pending User Asks 和 Recent user queries 是一致的。我观察到的漂移来自日常更长的会话,特征是 Pending User Asks 里残留早已完成的旧诉求,而最新一轮诉求仅存在于 Recent user queries 一处。符合你说的「二者处于同等地位、缺少优先级说明」这个判断。

    等新版本发布我来验证,谢谢。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions