/compact 命令解读
文件位置:src/services/compact/prompt.ts
这部分主要看 /compact 的 Prompt 设计、Scratchpad 机制,以及摘要最终是如何格式化的。
1. Prompt 的核心约束
/compact 的 Prompt 一开始就限制得很严格:
CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.
Do NOT use Read, Bash, Grep, Glob, Edit, Write, or ANY other tool.
You already have all the context you need in the conversation above.
Tool calls will be REJECTED and will waste your only turn — you will fail the task.
Your entire response must be plain text: an <analysis> block followed by a <summary> block.
意思很明确:
- 只能输出纯文本
- 不能调用任何工具
- 所需上下文都已经在当前对话里
- 一旦调用工具,请求会被拒绝
- 输出格式必须是:
<analysis><summary>
这说明 /compact 的目标不是继续执行任务,而是基于现有上下文做一次压缩总结。
2. 为什么反复强调“不要调工具”
源码里有这样一段说明:
on Sonnet 4.6+ adaptive-thinking models the model sometimes attempts a tool call despite the weaker trailer instruction. With maxTurns: 1, a denied tool call means no text output → falls through to the streaming fallback (2.79% on 4.6 vs 0.01% on 4.5)
大意是:
- 在 Sonnet 4.6+ 上,即使 Prompt 已经提示“不要调工具”,模型有时还是会尝试调用工具
- 而
/compact的maxTurns: 1,只有一轮机会 - 一旦工具调用被拒绝,这轮就直接废掉
- 结果可能连文本都输出不了,只能走 fallback
失败率对比:
- 4.5:
0.01% - 4.6:
2.79%
所以这里的“不要调工具”不是普通提醒,而是一个和成功率直接相关的硬约束。
3. Scratchpad 机制
Prompt 还要求模型先输出 <analysis>,再输出 <summary>:
Before providing your final summary, wrap your analysis in tags to
organize your thoughts and ensure you’ve covered all necessary points. In your
analysis process:
Chronologically analyze each message and section of the conversation. For
each section thoroughly identify:
The user’s explicit requests and intents
Your approach to addressing the user’s requests
Key decisions, technical concepts and code patterns
Specific details like:
file names
full code snippets
function signatures
file edits
Errors that you ran into and how you fixed them
Pay special attention to specific user feedback that you received,
especially if the user told you to do something differently.
Double-check for technical accuracy and completeness, addressing each
required element thoroughly.
这里的要求主要有几类:
- 按时间顺序梳理对话
- 识别用户请求和真实意图
- 总结关键决策、技术概念、代码模式
- 记录具体细节:
- 文件名
- 完整代码片段
- 函数签名
- 文件修改内容
- 错误及修复方式
- 特别关注用户反馈
- 再次检查准确性和完整性
所以 <analysis> 本质上就是一个 Scratchpad(草稿区),作用是帮助模型先整理,再输出更完整的摘要。
4. formatCompactSummary() 的作用
对应的格式化函数如下:
export function formatCompactSummary(summary: string): string {
let formattedSummary = summary;
// Strip analysis section — it's a drafting scratchpad that improves summary
// quality but has no informational value once the summary is written.
formattedSummary = formattedSummary.replace(
/<analysis>[\s\S]*?<\/analysis>/,
"",
);
// Extract and format summary section
const summaryMatch = formattedSummary.match(/<summary>([\s\S]*?)<\/summary>/);
if (summaryMatch) {
const content = summaryMatch[1] || "";
formattedSummary = formattedSummary.replace(
/<summary>[\s\S]*?<\/summary>/,
`Summary:\n${content.trim()}`,
);
}
// Clean up extra whitespace between sections
formattedSummary = formattedSummary.replace(/\n\n+/g, "\n\n");
return formattedSummary.trim();
}
这个函数做了三件事:
1)删除 <analysis>
formattedSummary = formattedSummary.replace(
/<analysis>[\s\S]*?<\/analysis>/,
"",
);
<analysis> 只是中间草稿,最终不会保留。
2)提取 <summary>
const summaryMatch = formattedSummary.match(/<summary>([\s\S]*?)<\/summary>/);
if (summaryMatch) {
const content = summaryMatch[1] || "";
formattedSummary = formattedSummary.replace(
/<summary>[\s\S]*?<\/summary>/,
`Summary:\n${content.trim()}`,
);
}
这里会把 <summary> 中的内容提取出来,并转换成:
Summary:
...
3)清理多余空行
formattedSummary = formattedSummary.replace(/\n\n+/g, "\n\n");
最后统一整理格式,避免空行太多。
5. 最终续写时的行为约束
生成出来的 summary,后面会作为新会话的上下文继续使用。
源码中的提示大致是:
This session is being continued from a previous conversation that ran out of
context. The summary below covers the earlier portion of the conversation.
如果设置了 suppressFollowUpQuestions,还会追加要求:
Continue the conversation from where it left off without asking the user any
further questions. Resume directly — do not acknowledge the summary, do not
recap what was happening, do not preface with “I’ll continue” or similar.
也就是说:
- 直接从中断处继续
- 不要继续追问
- 不要确认“这是摘要”
- 不要回顾上下文
- 不要说“我继续”之类的话
这说明 /compact 的目标不只是压缩内容,而是让新会话尽可能无缝接上旧会话。
6. 我的理解
/compact 的整体思路可以概括成四步:
-
强约束输出形式 禁止工具调用,降低单轮失败概率
-
用
<analysis>做内部整理 让模型系统性梳理上下文 -
只保留
<summary>通过formatCompactSummary()去掉草稿内容 -
把摘要交给后续会话继续使用 实现上下文耗尽后的续写
所以它本质上不是简单地“缩短聊天记录”,而是压缩对后续最有价值的信息。