Dayward AI
Week 1 · D4About 4 hours

Long-Running Sessions: Compression, Notes and Memory Files, Subagent Isolation and Handoff Summaries

A window will always fill up once a task runs for tens of minutes. Today implement a measurable compression strategy, and draw a clear line between when notes-and-memory-files and when subagent isolation each fit.

Today's goals 0/3

Sign in to tick these off and save your progress.

今日目标

  1. 能实现一个压缩策略,并用压缩前后 token 数与关键信息保留检查验证它
  2. 能说出压缩、笔记与记忆文件、子代理隔离三种手段各适合什么任务
  3. 能写出一份交接摘要模板,并解释子代理为什么只回传摘要而不回传全过程

前三天治的都是「每一轮长度基本可控」的东西。今天治最后一块:对话历史。它的特点是只涨不跌,任务跑上几十分钟必然撑满。读完回来把三条目标勾掉。

小白版讲解

转机的时候,把箱子重新收拾一遍

长途出差要转机。在中转机场的三小时里,有经验的人会做一件事:把箱子打开重新收拾一遍。 前半程穿过的衣服塞进脏衣袋压到最底下,登机牌存根扔掉,下半程要用的合同挪到最上面。箱子还是那只箱子,但可用空间回来了一大半。

压缩(compaction)就是这件事。当会话接近窗口上限时,把前面的内容摘要成一段更短的文字,用它替换掉原文,然后带着这段摘要继续跑。

它和昨天的裁剪有一个本质区别,这个区别决定了它更危险:裁剪动的是结构,压缩动的是语言。 裁剪删掉一个 audit_log 字段,你知道自己删掉了什么,随时能取回来。压缩把三十轮对话变成一段三百字的摘要,丢掉了什么是模型决定的,而且丢掉之后没有任何标识告诉你它丢了。

所以这门手艺的全部难点不在「怎么压」——调一次模型让它总结一下,谁都会写。难点在于怎么证明你没压错。今天的实验里,压缩器有两张输出:一张是压缩率,另一张是关键事实存活检查。只有第二张才让第一张有意义。

那到底该留什么、扔什么,什么时候该压缩、什么时候压缩根本不是正确答案?下面挨个讲清楚。

压缩的手艺:留什么、扔什么、怎么验

先说触发时机。最常见的错误做法是按轮数:每 20 轮压一次。这条规则一定会出事,因为轮数和 token 数不成正比——一次工具返回顶得上二十轮闲聊。要盯的是窗口占用率。

一个可以直接用的实现:

compact.js
// 触发看占用率,不看轮数:一次工具返回顶得上二十轮闲聊
export function shouldCompact(turns, window, threshold) {
  return estimateTokens(turnsToText(turns)) / window >= threshold
}
 
// 切分:最近 keepTurns 轮必须逐字保留
// 正在进行的那件事一旦被摘要,模型会立刻失去指代对象,下一句就开始问「你说的是哪一单」
export function splitKeepAndFold(turns, keepTurns) {
  const cut = Math.max(0, turns.length - keepTurns)
  return { fold: turns.slice(0, cut), keep: turns.slice(cut) }
}

再说摘要写什么。自由发挥的「请总结上面的对话」会得到一段读起来很顺、但把订单号写成「相关订单」的文字。标识符是摘要最容易丢的东西,因为它们在语言上不重要、在工程上却是全部。所以摘要提示词要做两件事:分段,以及点名要求逐字保留标识。今天用的是三段式:

  • 已定结论:已经确认、不会再变的事实,逐条列,保留订单号、金额、单号、政策条目编号等原文标识。
  • 待办事项:还没完成、后面要接着做的事。
  • 硬约束:不能违反的规则,以及用户提出的硬性要求。

最后是验证,也是这一天真正的重点。实验里预置了四条「压缩后必须还能找到」的事实,压完逐条核对。默认配置下 2199 token 压到 701,压缩率 68.1%,四条全部存活;把保留轮数从 6 调到 1,压缩率涨到 87.3%,但「用户要求周五 18:00 前答复」这条直接消失——因为它只活在最近几轮原文里,而且它在语言上不像一条结论,摘要器不会主动捞它。

轻量压缩优先:先清工具结果,再考虑摘要

有一件事要在动手写摘要之前想清楚:很多时候你根本不需要摘要。

昨天的剖面已经说明,历史往往不是四块里最大的一块。一次会话里真正把窗口撑满的,通常是攒下来的一堆工具结果——而它们有一个摘要没有的优势:旧的工具结果可以直接删,因为模型早就读过并且已经用掉了。 一次订单查询的原始 JSON,在模型说完「你的订单已发货」之后就再没有价值了。

这就是「轻量压缩」:不调模型、不理解语义,纯按位置把旧的工具结果换成占位说明。它便宜、确定、可逆(占位里留着 ref),而且不会丢语言信息。

Claude 的接口把这条策略做成了托管能力:开启之后,输入超过设定的阈值就自动清理最早的工具结果,默认在十万 token 时触发、保留最近 3 次工具调用,并在响应里告诉你清掉了几次、省了多少 token。它还能和记忆工具配合——清理触发之前,模型会先收到一个提醒,让它把还需要的信息写进记忆文件,然后才清。

所以正确的顺序是:先清工具结果,不够再摘要历史。 反过来做的人很多,因为摘要听起来更高级;但摘要要多花一次模型调用、要承担丢信息的风险,而它治的往往还不是大头。

这里还有一个和缓存有关的取舍,很少有人提前想到:清理会打掉缓存前缀。 被清掉的工具结果排在消息序列的中间,一动,它后面的全部内容都要重新写入缓存。所以清理不能太频繁、也不能一次只清一点——托管能力提供了一个「至少清掉多少 token 才动手」的参数,就是为了保证这次清理省下的钱足够抵消重建缓存的代价。自己手写策略时同样要设这个下限,否则你会得到一个每轮都在清、每轮都在重建缓存的程序,token 数漂亮,账单更贵。

笔记与记忆文件:把状态写到窗口外面

压缩解决的是「窗口里装不下」,但它有个天花板:摘要本身也在窗口里,会话足够长的时候,摘要的摘要也会满。

另一条路是把状态写到窗口外面去。模型在跑的过程中主动把重要信息写进文件——待办清单、已经确认的事实、下一步计划——需要的时候再读回来。这套做法有个名字叫结构化笔记(structured note-taking),也叫 Agent 记忆。

它和压缩的分工很清楚:

压缩笔记与记忆文件
存在哪上下文里上下文外的文件里
谁决定留什么摘要那一次调用模型在过程中随时决定
会不会二次丢失会,摘要的摘要不会,文件一直在
适合什么一条主线跑下去的会话反复迭代、要跨会话续上的任务

Anthropic 公开过一个很能说明问题的例子:让模型玩宝可梦,它靠持续写笔记,在几千步之后仍然能维持精确的计数、画出地图、记住自己的长期策略——这些东西没有一样能靠压缩保住,因为它们是渐进积累的状态,不是可以被总结的结论。他们也把这套能力做成了记忆工具的公开测试版,让模型能自己维护一套基于文件的知识库。

笔记这条路还有一个压缩给不了的好处:跨会话。 压缩的产物活在这一次会话的上下文里,会话一结束就没了;写进文件的笔记下次开工还能读回来。所以凡是「今天做一半、明天接着做」的任务,笔记不是可选项而是必需项——否则每天早上都要重新把昨天的结论说一遍,而每一次复述都在丢东西。

判断该用哪条路,问一个问题就够了:这件事的状态是「结论」还是「账本」? 结论可以摘要,账本必须存文件——你没法把一本流水账「总结」成一句话还指望它还能对账。

子代理隔离:各带各的箱子

第三条路更彻底:换一只箱子。

主 Agent 负责规划,遇到一个需要大量探索的子任务时,起一个子代理(subagent)去做。子代理有自己干净的上下文窗口,可以在里面烧掉几万 token 反复搜索、试错、读文件,做完之后只往主线交回一份浓缩摘要,通常一两千 token。主 Agent 的上下文里从头到尾只多了这一两千 token,中间那几万它一个字都没看见。

Anthropic 的多 Agent 研究系统就是这么搭的:一个主导 Agent 定策略并派发,多个子代理带着各自独立的上下文窗口并行探索。这套架构在他们的内部研究评测上比单 Agent 高出 90.2%。

但它的代价必须说清楚,而且是个很大的数字:Agent 类应用本来就比聊天多用约 4 倍的 token,多 Agent 系统是约 15 倍。 子代理隔离买的不是省钱,是用钱换主线上下文的干净。所以它的适用面很窄:

  1. 子任务的探索量大、但产出可以浓缩成一页纸——比如「在这个代码库里找出所有调用了某个接口的地方」。
  2. 子任务之间彼此独立,可以并行——串行的子任务用隔离只会更慢更贵。
  3. 主线确实不需要看中间过程——如果主 Agent 后面还要追问细节,隔离反而制造了信息断层。

三条有一条不满足,就老老实实用压缩。不要因为多 Agent 听起来更厉害就上它,15 倍的账单不是抽象数字。

交接摘要该写什么

子代理回传的那一页纸,质量决定了整套架构成不成立。它不是「总结一下你做了什么」,而是一份让主线不用回看过程也能继续做决定的交接材料。用和压缩同一套三段式就够了,但每一段的要求更严:

handoff.js
// 交接摘要的三段式:给子代理的输出契约,不是给它的建议
export const HANDOFF_CONTRACT = `完成后只回传下面三段,不要复述过程:
 
已定结论:你查证过、可以直接被采信的事实。每条必须带来源标识(文件路径、订单号、URL),
主线要能凭这个标识自己复查,而不是相信你的转述。
待办事项:你没做完或没权限做的事,每条写清卡在哪一步。
硬约束:你在过程中发现的、主线后续必须遵守的限制。没有就写「无」,不要省略这一段。`
 
export function validateHandoff(text) {
  const missing = ['已定结论', '待办事项', '硬约束'].filter((s) => !text.includes(s))
  if (missing.length > 0) throw new Error(`交接摘要缺少段落:${missing.join('、')}`)
  return text
}

「每条必须带来源标识」这一条是整份契约里最关键的。没有标识的结论是不可复查的,主线只能选择全盘相信或者全盘重做,两个都很糟。带上标识之后,主线可以只对存疑的那一条做一次定点核实,成本是可控的。

最后提一个容易被忽略的场景:主 Agent 自己的计划也该写到窗口外面。 长任务跑到后期,上下文一旦被截断或压缩,最先丢的往往就是最开始那份计划——而它恰恰是最不该丢的。把计划先写进文件或记忆,是个便宜到没有理由不做的保险。

源码导读

动手实验

🧪 D4 实验:压缩策略

Code location: labs/context-engineering-5days/day-04-compaction-strategy

验收标准:

  1. MOCK=1 pnpm start 先打印占用率,达到阈值才进入压缩,把阈值调到 0.9 时会直接打印未达到触发阈值并退出。
  2. 压缩后的上下文明显分成两段:三段式的前情摘要,加上逐字保留的最近若干轮原文。
  3. 压缩率打印出来且在 65% 到 90% 之间,参考答案的默认配置是 68.1%。
  4. 四条关键事实的存活检查全部为 ✅,脚本以 0 退出。
  5. 把保留轮数调到 1 时,用户要求的答复时限那一条变成 ❌ 且脚本以 1 退出。

这个实验的 MOCK=1 走的是本地抽取式摘要,形状和模型输出一致,所以触发、切分、拼接、检查四步在离线下都是真跑的。做的时候把注意力放在第五条:亲眼看到某条事实因为压缩而消失,比读十遍「压缩会丢信息」有用得多。

  1. 跑通 solution 的 MOCK=1 pnpm start,看清占用率、压缩率与四条存活检查。
  2. 回到 starter 补全练习 1 的触发判据,验证阈值调到 0.9 时它会拒绝压缩。
  3. 补全练习 2 的切分,让最近 6 轮原文回到上下文里,观察最后那条时限要求重新出现。
  4. 补全练习 3 的三段式摘要提示词与练习 4 的存活检查,确认检查是真的在核对而不是恒真。
  5. 用保留轮数 1 跑一遍,记下丢掉的是哪一条、为什么是它,再想一条能救回它的改法。

面试题

今天 3 道题在下方题库区,侧重压缩的触发与验证、外部记忆的写法、以及子代理隔离与交接摘要的设计。展开后先看「分析过程」再看要点——照着推导练,比背要点管用。标注「国内高频 / 海外高频」方便按目标市场取舍。

检查清单与明日预告

  • 能实现一个压缩策略,并用压缩前后 token 数与关键信息保留检查验证它
  • 能说出压缩、笔记与记忆文件、子代理隔离三种手段各适合什么任务
  • 能写出一份交接摘要模板,并解释子代理为什么只回传摘要而不回传全过程
  • 能说清为什么该先清工具结果再考虑摘要历史
  • 实验的 5 条验收标准全部通过,包括亲眼看到一条事实因压缩而消失
  • 3 道面试题不看要点也能答出至少 2 道

明天(D5)我们收口:把这四天的手段变成一个可度量的循环。你会算清一次任务的完整 token 账单(包括缓存怎么改变这张账单,那里有一个反直觉的结论在等着),定义两个利用率指标,对照四种失败模式排查,最后过一遍上下文工程的面试专题。前四天教的是手段,明天教的是什么时候用哪个手段、以及什么时候该停手。

Interview questions

  • When should you compact the context, and when should you just move to a larger context window?什么时候该压缩上下文,什么时候该直接换一个更大的窗口?
    Common in ChinaCommon overseasIntermediate#compaction#context-rot

    How to reason about it · think before answering

    1. This checks whether you treat the window as capacity and attention as a budget. Answering only that you compact when it does not fit misses half the cases, since plenty of sessions should be compacted while the window is still mostly empty.
    2. Separate the two problems. Not fitting is capacity, and a bigger window fixes it. But a bigger window does not fix context rot: recall degrades as context grows, on a gradient, so a large nominal window is not a promise of stable behavior at that length. Fitting and being used well are different.
    3. Give the test: watch two signals, not one. High window occupancy means compact for capacity. Low occupancy with a low share of actually-useful tokens also means compact, for attention. The second is the one people miss because nothing looks urgent.
    4. Then order the tactics. Compaction is not the first move. Clear stale tool results first, since that needs no model call, is deterministic, and is reversible. Only then summarize history. Doing it the other way costs an extra call and risks losing information while usually treating the smaller bucket.
    5. Expect the follow-up: when is compaction itself not enough? When the state is an accumulating ledger rather than a summarizable conclusion, such as exact tallies, maps, or a long-term plan. Those belong in files outside the window.

    分析过程 · 先想清楚再作答

    1. 这题在考你有没有把窗口当容量、把注意力当预算。只回答「窗口不够就压缩」的人漏掉了一半——很多时候窗口还很空,但已经该压了。
    2. 怎么拆:先把两个问题分开。窗口不够是容量问题,换大窗口确实能解决;但换大窗口解决不了上下文腐烂——上下文越长模型准确回忆的能力越差,这是一条缓坡,标称窗口大不等于在那个长度上表现稳定。所以「装得下」和「用得好」是两件事。
    3. 给判据:看两个指标而不是一个。窗口占用率高就该压(容量问题);占用率不高但有效信息占比很低,也该压(注意力问题)——后者最容易被忽略,因为看起来毫无压力。
    4. 再给顺序上的结论:压缩不是第一手段。先清掉旧的工具结果(不用调模型、确定、可逆),不够再摘要历史。反过来做的人很多,因为摘要听起来更高级,但摘要要多花一次调用、要承担丢信息的风险,而它治的往往不是大头。
    5. 可预期的追问:那什么时候压缩也不够?当状态是渐进积累的账本而不是可总结的结论时——比如精确计数、地图、长期计划。这类东西要写到窗口外面的文件里,不能靠摘要保住。

    Key points

    • Not fitting is capacity and a larger window solves it; context rot is attention and a larger window does not.
    • Two triggers: high window occupancy, or low occupancy with a low share of useful tokens.
    • Clear stale tool results first (no model call, deterministic, reversible), then summarize history.
    • If the state is an accumulating ledger such as tallies, maps, or a plan, use external files instead of compaction.

    答题要点

    • 窗口不够是容量问题,换大窗口能解决;上下文腐烂是注意力问题,换大窗口解决不了。
    • 两个触发信号:窗口占用率高,或占用率不高但有效信息占比很低。
    • 顺序上先清旧工具结果(不调模型、确定、可逆),不够再摘要历史。
    • 如果状态是渐进积累的账本(计数、地图、长期计划),压缩救不了,要写到窗口外的文件里。
  • What does compaction lose most easily, and how do you verify that a given compaction kept what mattered?压缩最容易丢什么?你怎么验证一次压缩没有丢掉关键信息?
    Common in ChinaCommon overseasDeep dive#compaction#verification

    How to reason about it · think before answering

    1. The signal is entirely in the second half. Saying you keep the important parts is empty; interviewers want an executable verification step and evidence it has actually caught something.
    2. Explain why compaction is riskier than trimming. Trimming changes structure: you know which field you removed and you can fetch it back. Compaction changes language: what got dropped is the model's choice, and nothing marks the loss.
    3. Name the fragile categories. First, whatever is currently in flight in the last few turns, which loses its referent the moment it is folded. Second, hard requirements that do not look like conclusions, such as user-stated deadlines, emotional demands, or verbal commitments. Third, identifiers, which summaries happily rewrite from an order number into the relevant order.
    4. Conclusion: preset a list of facts that must remain findable after compaction and check them every time, rejecting the compaction or widening the verbatim window on failure. Support it with three measures: keep recent turns verbatim, give hard requirements their own section in the summary prompt, and demand verbatim preservation of identifiers.
    5. Expect the follow-up asking whether it ever caught you. A concrete case lands best: dropping the verbatim window from six turns to one raised the compression ratio from 68 to 87 percent but silently deleted a user's stated Friday deadline, because it lived only in recent turns and did not read like a conclusion.

    分析过程 · 先想清楚再作答

    1. 这题的区分度全在后半句。谈「要保留重要信息」是空话,面试官想听的是一个可执行的验证机制,以及你有没有真的被它拦下来过。
    2. 怎么拆:先说清压缩为什么比裁剪危险。裁剪动结构,删掉一个字段你知道删了什么、也能取回来;压缩动语言,丢掉了什么是模型决定的,而且丢完不留任何标识。
    3. 点出最脆弱的两类内容:一是最近几轮正在进行的事,一折叠就失去指代对象,模型下一句就会问你说的是哪一单;二是形式上不像结论的硬性要求,比如用户提出的时间点、情绪化诉求、口头承诺——它们在语言上不重要,在业务上是全部。还有一类是标识符,摘要很容易把订单号写成「相关订单」。
    4. 结论给验证机制:预置一组「压缩后必须还能找到」的关键事实,每次压完逐条核对,不通过就拒绝这次压缩或调大保留轮数。三条配套措施是:保留最近若干轮原文、在摘要提示词里让硬性要求单独成段、明确要求逐字保留标识符。
    5. 可预期的追问:你被这个检查拦下来过吗?给一个具体例子最有力,比如把保留轮数从 6 调到 1 时压缩率从 68% 涨到 87%,但「用户要求周五 18:00 前答复」这条直接消失——因为它只活在最近几轮原文里,而且它不像一条结论。

    Key points

    • Compaction is riskier than trimming: structure is recoverable, language loss is silent.
    • Three fragile categories: what is in flight in recent turns, hard requirements that do not look like conclusions, and identifiers.
    • Verification: preset facts that must survive and check each one after every compaction, rejecting it on failure.
    • Support with a verbatim recent window, a dedicated section for hard requirements, and explicit verbatim preservation of identifiers.

    答题要点

    • 压缩比裁剪危险:裁剪动结构可回溯,压缩动语言且丢失无标识。
    • 最容易丢的三类:最近几轮正在进行的事、不像结论的硬性要求、标识符。
    • 验证机制:预置一组必须存活的关键事实,每次压完逐条核对,不通过就不采纳这次压缩。
    • 配套三招:保留最近若干轮原文、硬性要求在摘要里单独成段、要求逐字保留标识符。
  • Why does a subagent return only a summary instead of its full transcript, and how should the lead agent specify the handoff?子代理为什么只回传摘要而不回传全过程?主代理该怎么写交接要求?
    Common in ChinaCommon overseasDeep dive#subagents#handoff#cost

    How to reason about it · think before answering

    1. This tests architectural intent. Saying it saves tokens is only half right, and the lesser half: multi-agent setups are more expensive overall, not cheaper.
    2. State the purpose. Subagent isolation buys a clean main context, not a smaller bill. A subagent can burn tens of thousands of tokens exploring in its own window while the main thread gains only a condensed result of one or two thousand tokens. It is separation of concerns applied to context.
    3. Put the cost on the table, which is where engineering experience shows: agentic applications use roughly four times the tokens of chat, and multi-agent systems roughly fifteen times. So the fit is narrow: heavy exploration with a condensable result, independent parallelizable subtasks, and a main thread that genuinely does not need the intermediate steps. Missing any one, fall back to compaction.
    4. Conclusion: specify a handoff contract of three sections (settled conclusions, open items, hard constraints), with every conclusion carrying a source identifier such as a file path, order id, or URL. Without identifiers the main thread can only trust everything or redo everything; with them it can spot-check the one claim it doubts. Require the constraints section even when empty, or the main thread cannot tell absent from forgotten.
    5. Expect the follow-up about the lead agent's own plan: write it outside the window too, since truncation or compaction late in a long task tends to eat the original plan first.

    分析过程 · 先想清楚再作答

    1. 这题在考架构意图。答「为了省 token」只对了一半,而且是次要的那一半——子代理架构整体上是更贵的,不是更省的。
    2. 怎么拆:先说清目的。子代理隔离买的不是省钱,是主线上下文的干净。子代理可以在自己独立的窗口里烧掉几万 token 反复探索,主线只多了一两千 token 的浓缩结论,中间过程一个字都没进主线。这是关注点分离在上下文层面的落地。
    3. 把代价摆出来,这是最能体现做过工程的地方:Agent 类应用本来就比聊天多用约 4 倍 token,多 Agent 系统约 15 倍。所以适用面很窄——探索量大但产出能浓缩、子任务彼此独立可并行、主线确实不需要看中间过程,三条缺一就该退回压缩。
    4. 结论给交接契约:三段式(已定结论、待办事项、硬约束),且每条结论必须带来源标识(文件路径、订单号、URL)。原因是没有标识的结论不可复查,主线只能全盘相信或全盘重做;带标识之后主线可以只对存疑的那条做定点核实。硬约束那一段没有也要写「无」,不能省略,否则主线分不清是没有还是忘了写。
    5. 可预期的追问:主代理自己的计划怎么办?也该写到窗口外面。长任务后期一旦触发截断或压缩,最先丢的往往就是最初那份计划,而它恰恰最不该丢。

    Key points

    • Isolation buys a clean main context, not savings; multi-agent is more expensive overall.
    • Magnitudes: agents use about four times chat tokens, multi-agent about fifteen times.
    • Fits when exploration is heavy but condensable, subtasks are independent and parallel, and the main thread does not need intermediate steps.
    • Handoff contract in three sections, every conclusion carrying a source identifier, and an explicit none when constraints are empty.
    • Persist the lead agent's plan outside the window, since it is the first casualty of truncation late in long tasks.

    答题要点

    • 隔离买的是主线上下文的干净,不是省钱;多 Agent 整体更贵。
    • 代价数量级:Agent 约为聊天的 4 倍 token,多 Agent 约 15 倍。
    • 适用三条:探索量大且产出可浓缩、子任务独立可并行、主线不需要中间过程;缺一就退回压缩。
    • 交接契约三段式,每条结论必须带来源标识,硬约束段即使为空也要显式写「无」。
    • 主代理自己的计划也要写到窗口外,长任务里它最容易被截断或压缩吃掉。

Comments

Sign in to join the discussion

No comments yet — be the first.