主题
上下文与压缩
长会话会变慢、变贵,最后突然"忘事"。这页讲清楚为什么,以及你能做什么。
一句话:**每次发消息,整段对话历史都要重新发一遍给模型。**历史越长, 单次请求越贵越慢。上下文窗口塞满之前,sid-code 会自动把旧对话压成摘要。
快速上手
想知道现在占了多少,会话里打:
text
/context会看到分类拆解 + 距自动压缩阈值还有多远。分类是固定这几项:
| 分类 | 是什么 |
|---|---|
| 系统提示词 | 内置指令,含记忆/CLAUDE.md 部分 |
| 工具定义 | 工具的 schema,MCP 工具和自定义代理会单列 |
| 记忆/CLAUDE.md | 你写的项目约定与已保存记忆索引 |
| 用户消息 / 助手回复 | 对话正文 |
| 工具调用 / 工具结果 | 它读的文件、跑的命令及输出——长会话里通常是最大头 |
| 结构开销 | 消息结构本身的固定成本 |
觉得占太多了,手动压一次:
text
/compact详细说明
什么时候该手动 /compact
自动压缩是兜底,不是最优解——它触发时你正在干活,压缩本身要花一次 LLM 往返。 主动压的时机更好选:
- 一个子任务刚做完,下一个不相关:这时候压最划算,旧上下文本来就没用了
/context显示工具结果占了大半:读过的文件内容留着没意义了- 准备切换到完全不同的模块
三种压法:
text
/compact 全量:除最近几条外全压成一份 LLM 摘要
/compact 0.5 只压最早的 50%,后半段原文保留
/compact 20 压到第 20 条消息为止
/compact focus on auth errors 压成摘要,但指导摘要器重点保留 auth 相关信息数字档(部分压缩)语义边界最清晰:前半段变摘要,后半段一字不动。 不确定压多少就先 /compact 0.5。
压缩走的是安全 round 边界 + 完整性双校验,不会把 tool_use / tool_result 对切碎。 摘要失败会提示并保持历史不变,不会把你的上下文搞丢。
自动压缩什么时候触发
按剩余 token 的绝对量判断,不是百分比。原因是百分比在不同窗口模型下行为不可预测: 32K 窗口的 50% 是 16K(压得太早),200K 窗口的 50% 是 100K(压得太晚)。
对 ≥ 80K 窗口的模型,三层渐进:
| 层 | 触发点(剩余) | 动作 |
|---|---|---|
| 遮罩 | ≤ 80K | 遮住旧的工具输出(信息损失最小) |
| 压缩 | ≤ 60K | LLM 摘要压缩 |
| 紧急 | ≤ 40K | 直接截断,保证最后 40K 内容不丢 |
同时还有一层相对系数,和绝对值取更早触发的那个——否则窗口越大压得越晚, 1M 窗口要到 88% 才压缩,那时候推理质量已经掉下去了。
窗口 ≤ 60K 的小模型只有紧急一档,在用到 90% 时触发轻量截断。前两层不开, 因为小窗口本来就紧张,过早压缩等于过早丢信息。
还有一条绝对底线:剩余 ≤ 3K 时强制截断,不调 LLM——那时候连一次摘要往返都危险。
自己定触发点
想让它更早压缩(比如你更在意响应速度而不是上下文完整度):
bash
SID_CODE_AUTOCOMPACT_PCT=0.6 sid-code语义是"用量到 60% 就触发 LLM 摘要压缩"。接受小数(0.6)或整数百分数(60), 两种写法等价。非法值(0 / 100 / abc)会被忽略并在日志里 warn,不会静默改行为。
兼容别名 CLAUDE_AUTOCOMPACT_PCT_OVERRIDE 也认,自有变量优先。
少花 token 的几个实际办法
按性价比排序:
- 让缓存命中。prompt cache 是这里最大的杠杆,细节见成本与用量。 关键点:别频繁改 CLAUDE.md 和工具集,前缀一变缓存全失效。
- CLAUDE.md 别写太长。它进系统提示词,每次请求都带。写一百行没人遵守的规则, 是每一次请求都在为它付费。见记忆与 CLAUDE.md。
- 子任务派给子代理。子代理有自己独立的上下文,跑完只把结论带回主会话, 探索过程中读的那一堆文件不进主上下文。见子代理。
- 该
/clear就/clear。任务真做完了,压缩不如清空。 - 按需加载工具。工具定义也占上下文,
toolSearch可以让工具 schema 延迟加载。 - 不常用的约定存进 Auto Memory,别堆进 CLAUDE.md。CLAUDE.md 全文每次请求都带, 而记忆系统是「索引进上下文 + 需要时按需 Read」——只把记忆的标题与摘要常驻 (实测每条约几十 token),具体内容等模型判断需要时才读回。所以「常用约定写 CLAUDE.md、 不常用但重要的约定让
save_memory存」能让系统提示词体积下来一截,又不丢信息。 见记忆与 CLAUDE.md。
旁路提问:/btw
模型正在跑一个长任务时,你顺手想问个不相关的小问题——又不想打断它、也不想这个问题污染主对话上下文。用 /btw:
text
/btw 刚才那个函数的返回值是什么类型?它做的事:fork 一个共享完整对话上下文的 agent 回答你的旁路问题,回答完直接展示给你。
三个关键行为:
- 不注入主对话——回答只是一锤子买卖,展示完就丢,不进对话历史、不占后续上下文。和正常发消息的本质区别就在这
- 不给工具权限——fork 出来的 agent 全部工具 deny,纯基于已有上下文回答,不会去读新文件、跑新命令
- 单轮回答——
maxTurns=1,不开循环,答完即止
所以它适合「基于刚才聊过的内容快速确认一个细节」,不适合「让它再去查一下」。没有对话上下文时(会话刚开始)它会直接提示「当前还没有对话上下文」。
/btw vs 子代理 vs 直接问
- 直接问:进主对话,占用后续上下文,模型会接着往下干活
/btw:不进主对话、不占上下文,但只能基于已有内容回答、不能用工具- 子代理:开新上下文、能用工具,但回答以结论形式带回主对话 三者解决「不想打断 + 不想污染上下文」的不同程度需求。
/btw是最轻的那档。
上下文窗口按模型算,不是固定值
窗口大小取自模型注册表,不同模型差别很大(32K 到 1M)。所以同一句 "用了 60%"在不同模型上是完全不同的绝对量。/status 和 /context 显示的百分比 都是按当前模型的真实窗口算的。
常见问题
它突然不记得前面说过的话了。 发生了自动压缩。压缩是有损的——摘要保留结论,丢掉过程细节。重要约定别指望它记住, 写进 CLAUDE.md(永久)或让它 save_memory(跨会话)。
/compact 说"对话历史太短,无需压缩"。 消息数 ≤ 4 时不压。这不是错误。
/compact 说"已有压缩流程在进行中"。 撞上了自动压缩。有互斥锁防竞态,等几秒再试。
响应越来越慢,但还没到压缩阈值。 输入 token 越多,首字延迟越高,这是正常的。/context 看看是不是工具结果堆积, 主动 /compact 0.5 通常立刻见效。
设了 SID_CODE_AUTOCOMPACT_PCT 但好像没用。 先确认值在 (0,1) 或 (0,100) 开区间内——0 和 100 都算非法会被忽略。 另外小窗口模型(≤60K)以前会静默忽略这个设置,现在已经生效。
Hook 能拦住压缩吗。 能。PreCompact 事件在压缩前触发(手动压缩也触发,trigger=manual), 可以 block,也可以往摘要 prompt 里注入额外指令。见Hook 指南。
相关
- 成本与用量 —— 缓存命中率怎么看、怎么提
- 记忆与 CLAUDE.md —— 什么该写进永久上下文
- 子代理 —— 把探索过程隔离出主上下文
- 环境变量 ——
SID_CODE_AUTOCOMPACT_PCT等
想知道「规则到底有没有进上下文」是怎么被决定的,读 JIT 上下文:让规则在正确的时刻进入上下文—— 拆开两条注入路径,附 19 个会话的实测基线和一条至今没修的边界。