Agent Engineering 课程阅读
首页/课程十一 · Agent 执行骨架/压缩:有损但有纪律

在 GitHub 查看原文

本页目录

Lesson 02 — 压缩:有损但有纪律

本课目标:给窗口装「有纪律的收房机制」——水位触发、登记-摘要-验证三步、分层可压性、每压必审计。同样的 8k 窗口:裸奔死于 S11,登记压缩 30 源完赛且关键事实 20/20 在场;同样是压缩:不登记只剩 1/20——差别不是丢不丢信息,是丢什么由谁决定。


1. 何时压:水位驱动,进警戒区就动手

L01 的账本给了触发依据:compact_threshold_pct=0.60——总量到 60% 就压,压到 compact_target_pct=0.50 以下。为什么不等 danger(85%):

  • 太早(比如 30%):摘要调用本身花钱花窗口,压得勤=持续交「整理税」,且递归失真更快(见 §5);
  • 太晚(85%+):一次要压掉更多内容(丢得多)、danger 区余量可能装不下「压缩过程」本身(摘要指令+被压内容还要同窗一次)——太晚动手连自救动作都放不下

60/85 是课程起点不是真理——L00 练习 2 与本课练习 1 都在扫这个参数。

2. 压什么:分层可压性——可再生度决定可压性

最先压   tool_result   工具原文:已被提炼过,且(L06 后)可从文件再生
其次压   note          过程笔记:可从结论反推,损失有限
不可压   conclusion    结论:研究的资产,不是缓存——宁可压不到目标也不丢
不可压   pinned        登记块:契约本体
不可压   summary       摘要:已经是压缩产物,再压=摘要的摘要(失真放大器)

同层内 oldest-first:越老的工具原文越可能已被消化进结论。这个顺序在测试里锁死(test_tool_results_dropped_first_oldest_first / test_conclusion_never_dropped)。

3. 怎么压:登记-摘要-验证(「判断交给模型、纪律交给代码」的窗口版)

课程十的这句话在本课的形态:

步骤 谁负责 内容
登记 代码(纪律) 压缩前把 must-survive 事实登记 pinned;pinned 块永不进摘要器、永不可压——机械保证,不依赖任何模型的善意
摘要 模型(判断) 其余被丢内容交摘要器提炼(生产=LLM make_llm_summarizer;测试=确定性 head_summarizer
验证 代码(纪律) 压缩后逐条验证登记项原文在场;构造上已保证——验证是「带子加背带」,任何实现回归当场被抓

Part 1 的演示是这条纪律的极端测试:恶意摘要器(什么都不保留)压缩 757→16 token,登记项照样在场 ✅。关键事实的存活是契约不是运气。

⚠️ 诚实边界(两条,README 必须分开陈述): 1. mock 测不了摘要语义保真——FakeLLM 的摘要没有语义。本课锁死的是机械纪律(登记 100% 存活、审计 100% 完整);「摘要写得好不好」在 L09 可选真模型章抽查。 2. 登记质量是另一个战场——真实系统里「哪些值得登记」是 LLM 的判断(判断交给模型),本课试金石用剧本代演(研读某源即登记该源 KEY_FACTS)。登记漏了的事实同样会丢:纪律保证「登记的必活」,不保证「该登记的都登记了」(练习 3 专门拷问这一点)。

4. 压缩必须留审计:无痕压缩=篡史

每次压缩落一行 CompactionRecord:压掉多少 token、丢了哪些 item(id 可追溯)、摘要多长、登记验证结果。这是本课程第二条诚实纪律(与 L04 的「省略必须显式」并列),与课程十「没能看到 ≠ 没有变化」同宗:任何信息损失都必须显式、可见、可追溯

为什么这不是仪式:没有审计的压缩,模型会引用自己已经丢掉的东西而不自知(「如 S03 所述……」——S03 三轮前就被压了,窗口里只剩它的 80 字残影);有审计,下游至少能回答「这个引用还可信吗」,而 L06 之后审计里的 item id 能直接指回落盘原文。

5. 递归漂移与全量校准

摘要的摘要会累积失真——每轮压缩都在残片上再切一刀(Part 4 审计里能看到 summary 也被后续压缩吞进更高阶摘要)。解药不是「不压」,是校准锚点:审计行保留了被丢内容的身份(dropped_items),配合 L06 工作区(原文落盘),可以定期从原文重建认知,而不是在 N 阶残片上继续推理。这与课程十「增量漂移 → 全量校准周期」是同一个思想在窗口维度的投影。

6. 流派对比:装不下的四种处理

流派 思路 取舍
滑窗硬丢 只留最近 N 轮 免费;失忆无感知、无审计——L00 的 A3 就是它的变体
纯 LLM 摘要 全部交给模型压 灵活;有损无保证——本课对照组实测 1/20,关键事实的死活取决于摘要器心情
登记 + 摘要混合 关键零损(机械)+ 其余有损(可审计) 本课选择:契约与灵活各得其所;代价是要维护登记判定
外置换入 原文落盘,窗口只留指针 与压缩互补不竞争——能外置的别压缩(L06);但对话过程本身回不去,仍需压缩

业界锚点:Claude Code 的 /compact 就是「摘要+结构化保留」路线(你在本课程学习期间大概率见过它触发);Manus 强调「可恢复的压缩」——文件系统兜底原文,窗口内只做可逆瘦身,与本课 §5 的校准锚点同思路。

7. 跑起来

cd harness-lessons/02_compaction
python code.py     # 恶意摘要器 → 长途五行对照 → 分层演示 → 审计报表
配置 完成 峰值窗口 在场率 矛盾 计费token 结局
长程裸奔(L00 A2) 10/30 0/20 44,203 死于 S11
硬截断(L00 A3) 30/30 4,292 8/20 74,981 活着但失忆
压缩·不登记(对照) 30/30 4,800 1/20 103,019 无契约=运气
压缩·登记(本课) 30/30 5,272 20/20 106,844 完赛且记得

三个读点:①同一 8k 窗口,压缩让完赛从不可能变成常规(10 次压缩,审计全绿);②「不登记」对照比硬截断更惨(1/20 < 8/20)——盲目信任摘要器比盲目截断更危险,因为它连「按位置保留开头」的可预测性都没有;③计费 token 压缩档更高(106,844 vs 74,981)——压缩不省钱,省的是空间与记忆;省钱靠控源(L04)与缓存友好(练习 4)。

8. 落地清单

文件 改动
src/research_assistant/compactor.py 新增:PinnedFact/WindowItem/CompactionRecord + Compactor(登记-摘要-验证+分层+审计)+ make_llm_summarizer/head_summarizer
src/research_assistant/config.py enable_compaction(默认 off)、compact_threshold_pct=0.60compact_target_pct=0.50
eval_agent/harness_runs.py 新增:run_compacted_longhaul(登记/不登记两跑法;L09 收益矩阵的原料库从此逐课生长)
tests/test_compactor.py 新增 14 测试(三步纪律/分层/审计/长途两跑法/确定性)

与任务书的一处诚实偏差:任务书原计划「nodes 在开关下挂钩」;通读 v4 后确认主链路(map-reduce)各调用无跨调用累积——压缩的运行时消费方是长程单窗形态,故先落 eval 侧跑法,v5 长途模式(L09)接管运行时集成。enable_compaction 开关为 L09 预留(语义对齐 ambient 的 enable_source_watch:「模块随时可独立调用,daemon 后课接管」)。

验收

cd portfolio-projects/research-assistant
python -m pytest tests/test_compactor.py -q   # 14 passed
python -m pytest -q                            # 372 passed(358 + 14)
cd ../../harness-lessons/02_compaction && python code.py

9. 本课在两条主线上的位置

窗口经济:压缩是「收房」——把租金最高的工具原文换成摘要+登记块;水位到 60% 就动手,太晚连自救动作都放不下。外置化:压缩是有损的窗口内自救;L04/L06 会证明能外置的别压缩——原文落盘后,压缩只需处理真正回不去的对话过程。

🎯 面试话术

「我的压缩是登记-摘要-验证三步纪律:must-survive 事实登记后机械保留——pinned 块永不进摘要器永不可压,我用『恶意摘要器』测试过这个保证;其余内容 LLM 摘要,压完逐条验证,每压一次留审计行,丢弃内容 id 可追溯。数字:8k 窗口裸奔死于第 11 源,登记压缩 30 源完赛、20 个关键事实全在场;对照组只去掉登记这一步,在场率掉到 1/20——所以压缩的关键不是摘要写得多好,是丢什么由契约决定而不是由运气决定。另外压缩不省钱(计费反而略涨),它省的是空间;省钱是控源和缓存的事。」