首页
/ 计划模式上下文压缩蒸馏:oh-my-pi "批准并压缩上下文"流程的设计与实现

计划模式上下文压缩蒸馏:oh-my-pi "批准并压缩上下文"流程的设计与实现

2026-09-09 22:37:57作者:苗圣禹Peter

导读

在 oh-my-pi(⌥ Coding agent with the IDE wired in)的计划模式(Plan Mode)中,当用户批准计划后可以选择"批准并压缩上下文(Approve and compact context)":系统将长达数十轮的规划讨论蒸馏为一份精炼摘要,再以全新上下文继续执行。本文以 plan-mode-compact-instructions.md 为核心,讲解这条蒸馏指令的完整取舍契约——哪些信息必须保留、哪些必须丢弃、计划文件为何是唯一权威来源,以及它如何通过 internalGuidance 通道到达原生摘要器而不泄露给公共扩展钩子。读完本文,你将理解 oh-my-pi 计划模式的完整生命周期,并能据此为自己的 Agent 产品设计类似的"讨论 → 批准 → 压缩 → 执行"上下文策略。

一、指令文件的定位:一次压缩调用的"蒸馏宪法"

plan-mode-compact-instructions.md 是 oh-my-pi 计划模式专属的系统提示模板,全文围绕一个核心命令展开:

Prepare to execute approved plan.(准备执行已批准的计划。) MUST distill plan-mode discussion.(必须蒸馏计划模式的讨论。)

它不负责描述计划本身,而是规定在压缩发生时,摘要器如何从计划讨论中筛选信息。它属于 oh-my-pi 计划模式提示族中的一员,同族文件还包括:

  • plan-mode-active.md:计划模式下系统提示的完整内容,规定工作树只读、通过 xd://propose 写入计划标题以请求批准、计划文件必须命名为 local://<slug>-plan.md 等;
  • plan-mode-approved.md:批准后执行阶段的系统提示,把完整计划内联进提示并保留 local:// 持久副本;
  • plan-filename.md:为计划文件命名的小型提示(1~3 个词的主题)。

plan-mode-active.md 的批准选项中,"Approve and compact context"(批准并压缩上下文)被描述为 "discussion distilled, then executes here"(讨论被蒸馏,然后在当前会话执行)。而本次讨论的这条指令,正是驱动这次蒸馏的提示文本。

二、指令的取舍契约:Preserve 与 Drop

指令正文将蒸馏行为明确划分为"必须保留"与"必须丢弃"两组,这是整个提示的灵魂,也是执行阶段(executor)能否脱离对话上下文独立工作的关键。

必须保留(Preserve)

  1. 计划理由(Plan rationale)与明确被否决的备选方案(explicitly rejected alternatives):执行者需要知道"为什么选择这条路线",以及"为什么没有走另一条路线"。被否决的方案往往记录了对约束条件的理解,丢弃它们会导致执行者面对类似岔路时重复做设计决策。
  2. 关键决策与驱动约束(Key decisions; driving constraints):决策本身以及促成决策的约束条件必须成对保留。只有结论没有原因,执行者无法判断约束变化后是否仍然适用。
  3. 执行者需要的已发现文件、符号与代码路径(Discovered files, symbols, code paths executor needs):规划阶段通过探索得到的文件位置、符号签名、关键代码路径,是执行阶段最昂贵的信息——它们无法从计划正文重新推导,一旦丢失执行者只能重新探索。
  4. 规划期间用户表达过的偏好(User preferences expressed during planning):用户在规划对话中提出的明确偏好,代表了不可从代码推导的需求,属于 plan-mode-active.md 中定义的"Preferences/tradeoffs"一类信息,必须原样进入摘要。

必须丢弃(Drop)

  1. 工具调用噪音(Tool-call noise):文件读取、搜索等工具调用的原始记录,如果其结果已经被计划正文或计划讨论所吸收,就不再需要保留。这是蒸馏中最主要的体积削减来源——规划阶段可能产生几十轮 read/grep 调用,但真正有价值的是它们"发现了什么",而不是"调用了几次"。
  2. 被取代的计划草稿(Superseded plan drafts):规划是迭代的,早期草稿会被后续版本覆盖。保留旧草稿只会稀释执行者对最终版本的信赖。
  3. 计划文件中已重申的上下文(Context restated in plan file):凡是在计划文件中已经出现的上下文,摘要中不得重复——这既避免了冗余,也保证了"计划文件是唯一权威"这一原则不被破坏。

这三条"丢弃"规则共同指向一个目标:摘要中不出现任何一条可以从计划文件本身获得的信息,从而把压缩后残留的上下文体积压缩到最小。

三、计划文件:权威真相的唯一来源

指令中的条件模板块(Handlebars 语法)揭示了整条蒸馏逻辑的锚点:

{{#if planFilePath}}
Approved plan file: `{{planFilePath}}`; authoritative source of truth.
MUST preserve this durable path; the plan body is re-inlined for the
executor after compaction, so NEVER restate it in the summary.
{{/if}}

当渲染时提供了 planFilePath(即"批准并压缩上下文"场景,必然存在已批准的计划文件),摘要器必须遵守三条规则:

  1. 计划文件是权威真相(authoritative source of truth):一切以 local://<slug>-plan.md 的内容为准;
  2. 必须保留持久路径planFilePath 这个路径本身必须被保留进摘要,因为它是指向完整计划的唯一句柄;
  3. 绝不重申计划正文:压缩完成后,计划正文会由执行阶段系统提示重新内联(re-inlined)给执行者,因此摘要中永远不要重复计划正文

第三条规则与 plan-mode-approved.md 的执行阶段设计精确对应:批准后提示会携带 <plan path="{{planFilePath}}">{{planContent}}</plan> 的内联副本,并明确 "NEVER re-read {{planFilePath}} while the inline plan is intact; the path is for subagent handoff and recovery only"(内联计划完好时绝不重读计划文件,该路径仅供子代理交接与恢复使用)。也就是说:压缩阶段负责保留路径、丢弃正文;执行阶段负责内联正文、仅在副本失效时才回读文件。两者互补,构成完整的上下文管理闭环。

四、实现链路:指令如何在代码中被渲染与传递

这条提示并非停留在文档层面,它被真实地接入 oh-my-pi 的会话流程。在 interactive-mode.ts 中可以看到完整调用链:

const compactionPrompt = prompt.render(planModeCompactInstructionsPrompt, {
    planFilePath: options.planFilePath,
});

渲染时唯一注入的变量正是 planFilePath——即上一节条件块的输入。随后该提示通过 handleCompactCommand(...) 的第四个参数被传入压缩流程,源码注释明确说明了设计意图:

Ride the plan-mode distillation prompt through as internalGuidance so it reaches native summarization without leaking into the public customInstructions channel on session_before_compact — extensions there treat that field as user focus and would query-bias the summary toward the plan boilerplate (issue #4359).

即:这条内部蒸馏指令走 internalGuidance 专用通道,只到达原生摘要器(native summarizer),绝不进入公共的 customInstructions 通道。

关于压缩管道的整体背景,可参考 docs/compaction.md:它详细记录了 CompactionEntry 会话条目模型、prepareCompaction() 的边界与切点逻辑、软/远程/快照(snapcompact)等多种压缩方法,以及摘要生成后如何重建 LLM 上下文。其中明确写道:

The hook's customInstructions carries only the public user focus. Internal summarizer guidance — currently the plan-mode "Approve and compact context" distillation prompt — travels a separate internalGuidance channel on CompactOptions that reaches only native summarization, never this hook or session.compacting; when both are set the summarizer uses internalGuidance while hooks still see the public customInstructions (issue #4359).

五、钩子隔离契约:为什么不能走 customInstructions

plan-mode-compact-instructions.md 虽然只有短短 17 行,却牵动了一个真实的生产问题(issue #4359),并有专门的回归测试守护。

问题背景:早期的实现曾把这条蒸馏指令通过公共的 customInstructions 参数传给 AgentSession.compact(...),结果它顺着 session_before_compact 扩展钩子流到了扩展侧。而扩展(例如基于查询聚焦摘要的扩展)会把该字段当作"用户关注点"来使用,于是计划模式的样板文本(plan-mode boilerplate)会取代操作者的真实意图,导致摘要被错误地引导(query-biased)。

针对该问题的回归测试位于 agent-session-plan-compact-hook-instructions.test.ts,测试契约明确列出三条:

  1. 计划模式压缩必须调用 AgentSession.compact 时传 customInstructions: undefined,指令通过 CompactOptions.internalGuidance 传递;
  2. session_before_compact 钩子事件对内部指令压缩必须看到 customInstructions: undefined
  3. 原生摘要器(经 @oh-my-pi/pi-agent-core/compaction 调用)仍必须收到该指令以引导摘要方向。

测试用例逐一验证:

  • 内部指令不进公共钩子session.compact(undefined, { internalGuidance: planGuidance }) 后,session_before_compact 事件中的 customInstructionsundefined,而摘要器收到的指令正是 planGuidance
  • 用户焦点原样进公共通道session.compact("focus on the auth refactor") 时,钩子与摘要器都能看到用户焦点字符串,因为它是公共信息;
  • 两者同时存在时内部指令优先:同时传用户焦点与 internalGuidance 时,摘要器使用 internalGuidance,钩子仍只见用户焦点——防止调用方误把计划提示当作用户焦点泄漏出去。

六、从指令看设计哲学:面向未知执行者的自包含计划

综合 plan-mode-active.md 与本次指令,可以提炼出 oh-my-pi 计划模式压缩机制背后的一贯原则:

  1. 计划是执行规格,不是设计文档:一份合格的计划必须让"对对话一无所知的称职工程师"能够自上而下零设计决策地执行。压缩蒸馏正是为了让批准后的执行从干净的上下文开始,同时不丢失任何决策信息。
  2. 细节服务于"消除执行者决策",而非凑篇幅:Preserve 列表中的"已否决方案"和"驱动约束"看似多余,实则是消除执行者面临岔路时再做判断的必要信息;Drop 列表中的"计划草稿"和"已重申上下文"看似无害,实则是让执行者重新做设计的温床。
  3. 单一权威来源:计划文件 local://<slug>-plan.md 是唯一真相;摘要只携带它的路径,正文由执行阶段重新内联。两个阶段各司其职,避免同一份信息在多个地方以不一致的形态出现。
  4. 内部机制与公共扩展面严格隔离internalGuidance 通道的存在,让内部提示可以引导摘要方向,同时保持扩展钩子的语义纯净——钩子看到的 customInstructions 永远只代表用户意图。

七、实践启示

对于使用或扩展 oh-my-pi 的开发者,以下几点值得留意:

  • 使用计划模式的长任务:"批准并压缩上下文"适合规划讨论很长、但执行路径明确的场景。规划阶段的探索越多,压缩收益越大——前提是计划文件本身足够决策完整(decision-complete),否则压缩后的执行者将无据可依。
  • 编写扩展时:如果你的扩展消费 session_before_compact 事件并把 customInstructions 解释为用户意图,那么 oh-my-pi 当前的实现已经保证你不会看到计划模式的内部样板文本;若你仍观测到意外内容,可对照 agent-session-plan-compact-hook-instructions.test.ts 中定义的契约排查。
  • 深入阅读:完整的压缩管道(触发条件、边界切点、方法链、快照压缩等)见 docs/compaction.md;计划模式的完整行为约束见 plan-mode-active.mdplan-mode-approved.md

小结

plan-mode-compact-instructions.md 虽然是一份 17 行的提示模板,却是 oh-my-pi 计划模式压缩机制中承上启下的关键节点:它以"Preserve/Drop"二元清单定义了蒸馏的信息边界,以计划文件路径锚定了唯一权威来源,并通过 internalGuidance 通道在"引导摘要"与"隔离公共扩展面"之间取得平衡。理解这份指令,就等于理解了 oh-my-pi 如何让一次长达数十轮的计划讨论,以最小的信息损失、最干净的上下文,无缝过渡到执行阶段。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
927
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
397
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525