Python 复刻:agents/s06_context_compact.py
跟 Claude 长时间对话会把对话历史撑得越来越长。Claude 的"工作内存"装得下的内容有上限,撞到上限就装不下后面的对话。Claude Code 自动把前面那些"已经做完确认过"的片段压缩成一段摘要,腾出空间让后面的对话继续装得下。
6.1 工作内存与对话历史
Claude 的工作内存是它一次性能读到的文字总量。当前 Claude 的工作内存上限在 20 万到 100 万字之间,看用的是哪个版本。再大的工作内存也是有限的。
对话历史是从你打开会话到现在所有交互的总和。你的每条指令、Claude 的每条回复、每次工具调用产生的结果都按顺序累积进去。一次三个小时的实证执行会话——读 docs/01_实证研究设计.md 设计、跑 do0–do6、看 Stata log、整理三线表——产生的对话历史可能就到几十万字。phase 1 那次实际跑下来:do4 拼面板时 stata-mcp 返回了 76305 行原始 PC 七合一的描述统计、winsor 之后的 8 个 PC 字段各跑了一次 sum detail(每次 30+ 行)、合并 ESG 与 CSMAR 之后的 codebook 几千行、do5 描述统计的 23 个变量 sum detail、do6 三张表的 reghdfe iteration log——光是工具结果就 12–18 万字。
工作内存有限、对话历史可以越长越多,两者之间必然有矛盾。压缩就是为了让对话历史远大于工作内存的同时仍能继续推进。
6.2 三个粒度的压缩
最细的一层叫 microcompact,作用于单个工具结果。让 Claude 调 mcp__stata-mcp__get_data_info 读 04_中间数据/main_panel.dta 的 codebook,stata-mcp 返回的内容可能就是几万字——含 26441 obs × 60+ 字段的逐字段统计。Claude 实际用得到的可能只是 PC、esg_score、Size 等十几个核心字段的字段定义。microcompact 把它没用到的部分换成占位说明,只保留实际引用的那几条。这一层在每次工具调用后自动跑,你看不见。
中间一层叫 auto-compact,作用于对话历史的前段。当对话总长接近工作内存的上限,默认在 75% 到 85% 之间触发,Claude Code 把对话历史最前面那一段打包,比如最早的 30 条消息,额外调一次模型生成一段几百字的摘要,然后用这段摘要替换掉前面 30 条消息。摘要的写法专门要求保留关键决定、约定、变量定义,丢弃过程数据。
最粗的一层叫 manual compact,由你在终端输入 /compact 主动触发。算法与 auto-compact 相同,区别是不等系统自动触发,你想在某个干净的状态点强制压一次。phase 1 跑完想进 phase 2 时跑一次 /compact,把 phase 1 累积的散碎 Stata log 压成一段干净摘要,进 phase 2 时上下文干净。
6.3 一次真实压缩里摘要保留了什么、丢了什么
下面是 phase 1 收尾那次 /compact 实际生成的摘要片段,约 600 字。原始对话历史 17 万字。
项目:耐心资本对企业 ESG 表现的影响。主口径决策(do0_setup 确认):PC = A2(z(SD_A2_ln) + z(Bank)),ESG 主测度 = 华证连续得分 0-1 标准化,机制变量 = MDA 版管理者短视,融资约束 = KZ(WW 不可得替代)。样本期 2009-2023。
主面板(04_中间数据/main_panel.dta):PC 七合一原始 76305 obs,与 ESG/CSMAR/Myopia 合并、剔金融业 J、剔 ST、关键变量非缺失、控制变量 1%/99% winsor 后最终 26441 obs,3608 家公司,15 年面板。stkcd 已 destring 为 firmid,xtset firmid year。
数据缺口:ROA 不可得(FS_Comins 仅含营业收入未含净利润,用 Cash=经营现金流/总资产替代);WW 不可得用 KZ 替代;迪博内部控制不可得(中介 IC 暂搁);Wind 银行长贷明细未取,A2 债权侧用 CSMAR 替代字段构造。
表 1-5 已生成:描述统计、Pearson 相关、基准回归 4 列、ESG 三分项、PC 内部分解 5 列。关键发现:PC(A2 主) β=0.0004(不显著),PC(A1) β=0.0018***,PC(C 熵值法) β=-0.0024(不显著)。ESG 三分项 E/S/G 三组 PC 系数均不显著。PC 内部分解:H1c 系数差异检验 F=13.57, p=0.0002(拒绝股权=债权);股权侧 Stequity_A1 单独不显著,债权侧 Bank(A2)β=0.0036**、Rdebt_A1 β=0.0159*** 显著。
待解决(暂搁 phase 2 前决策):A2 主口径在主回归 OLS 不显著是否切到 A1。
摘要把 phase 1 三小时里的所有过程数据(76305 → 26441 的逐步样本剔除日志、八个 PC 字段缩尾分位数、20+ 控制变量的 sum detail、三张表的 reghdfe iteration)全部丢掉,留下的是后续 phase 2 一定还会被引用的几条东西:主口径决策、样本规模、数据缺口替代方案、五张表的核心系数、待解决问题。
压缩之后进 phase 2 第一句话"现在跑 do7 IV/PSM",模型靠这段摘要就能正确选 PC 解释变量名(PC,不是 PC_A1)、正确读 main_panel.dta(不是别的版本)、正确选 IV 工具变量(按 docs/01 设计:IV1 同行业均值、IV2 前十大股东、IV3 PC 滞后)。原始那 17 万字的对话历史已经被一段 600 字摘要替代,上下文重新干净。
6.4 压缩比直接截断好在哪
模型的工作内存物理上有上限。实证研究从设计到投稿可能延续几个月,期间累积的对话量轻易突破任何工作内存上限。不压缩就一定撞墙。
每次模型调用要为整份工作内存的内容付费。一份 18 万字的对话历史跑一次模型调用就比一份 8 万字的贵两倍多。压缩让长会话的平均成本回到可控范围。
选保留摘要替换前段,不直接截断。前段包含的关键决定与约束——PC_A2 主测度、华证 ESG 0-1 标准化、KZ 替代 WW、样本期 2009-2023、剔除金融业 J、剔除 ST、连续控制变量 1%/99% 缩尾——在后续轮次仍需访问。如果直接截断,模型回到后段时可能违反前段约定,比如把 PC_A1 当主测度回归。摘要保留这些约束让会话语义连续。
6.5 容易踩的坑
压缩是有损的。摘要不可能保留前段的全部细节。当你在后段问起"上周二我们具体怎么决定用 KZ 代替 WW"这种细节时,压缩后可能只剩"决定了用 KZ"而没有当初的理由。重要细节应该写进 CLAUDE.md 或 checkpoint.md,那两份文件每次会话开头都重新加载,不受压缩影响。phase 1 那次 checkpoint.md 里就把"WW 不可得用 KZ 替代"的理由(CSMAR 子库不含 WW 的输入项)写明白,所以即使压缩丢掉了对话细节,新会话开会时仍读得到。
压缩本身要消耗资源——一次额外的模型调用来生成摘要。auto-compact 默认在 75% 到 85% 触发,留出空间给压缩调用本身。如果触发设置得太晚,可能在生成摘要时已经溢出。
microcompact 的去噪有时会误删模型后续需要的内容。这种情况下模型在后续轮次会重新调用工具读完整的文件,多花一次工具调用的代价。这种代价通常比省下的工作内存空间更划算。
6.6 知识地图
| 关键词 | 含义 | 容易误会的点 |
|---|---|---|
| 工作内存 | 模型一次能读到的文字总量上限 | 不等于对话历史;工作内存固定,对话历史可以远大于它 |
| 压缩阈值 | 触发自动压缩的占用比例 | 默认 75-85%,留出空间给压缩本身用 |
| 摘要替换 | 用一段短摘要替换掉前面一长段对话 | 是模型生成的有损压缩;重要约定保留,过程细节丢失 |
| CLAUDE.md | 每次会话重新加载的项目级配置 | 不受压缩影响,关键规则放这里最稳 |