
❝让 Agent 干一件长活——写一个项目、做一轮深度研究——它会越聊越"重",对话历史像滚雪球一样越滚越大,直到把模型的上下文窗口撑爆。这时候要么报错、要么烧钱、要么粗暴丢掉早期信息。DeepAgents 给出的解法既聪明又克制:「压缩,但不删原稿;瘦身,但留得回得来。」 这篇文章用 6 张图,把它的实现拆给你看。 ❞
大模型有个硬约束——「上下文窗口」:一次能"看"的 token 数是有限的。
短对话无所谓。但当你让 Agent 干长活时,每一轮"调用工具 → 拿到结果 → 再思考"都会往历史里追加一大坨内容:读了哪些文件、跑了哪些命令、命令吐了多长的日志……几十轮下来,历史轻松膨胀到几十万 token。

撞上窗口上限会发生三件糟心事:
所以长任务型 Agent 必须有一套**上下文压缩(Summarization / Compaction)**机制:把"旧的、暂时用不上的"折叠成摘要,腾出空间继续干活。
这件事说起来简单——"把旧消息总结一下嘛"——但真要做对、做稳、做得不丢信息,里头的讲究比你想的多。我们就以 DeepAgents 的实现为样本,一层层剥开。
DeepAgents 的压缩有个很"工程师"的特点:「它没有重造轮子。」
它直接复用了 LangChain 自带的压缩内核——"判阈值 → 选切点 → 切分 → 生成摘要"这套核心逻辑原封不动地委托给上游。DeepAgents 自己只在外层加了「四件长任务 Agent 真正需要的增强」:
再加一个「手动压缩工具」,让模型能自己喊"我要清场"。
记住这个骨架,下面逐条展开。
DeepAgents 把压缩逻辑挂在"每次调用大模型之前"这个时机上。每次要调模型,它都会先跑一条三步流水线:

「第 0 步|重建有效消息」:先看看上一次有没有压缩过,如果有,就把"摘要 + 后面的新消息"拼成这次实际要用的视图(原稿不动,这点很关键,第四节细说)。
「第 1 步|截断大工具参数」:这是最便宜的一招。把历史里那些超长的 write_file / edit_file 参数(比如一次写了几千行的文件内容)裁短成"前 20 个字符 + (已截断)"。很多时候光这一步省下的 token 就够了,根本不用惊动大模型。
「第 2 步|判阈值」:算一下当前 token,看有没有超过触发线。「没超就直接发给模型」——但这里藏了个巧思:万一模型还是返回了"上下文溢出"错误,它不会把错误抛给你,而是「就地转入压缩路径重试」。相当于给阈值估算留了个安全气囊。
「第 3 步|真正压缩」:超阈值了,才走完整压缩。顺序很讲究——「先选安全切点 → 再把旧历史落盘 → 最后才让 LLM 生成摘要」,然后用"摘要 + 近期消息"替代原来那一长串发给模型。
❝小彩蛋:异步版本里,"落盘"和"生成摘要"这两件互不依赖的事是「并发」跑的(
asyncio.gather),能省一点墙上时间。细节控的快乐。 ❞
"把旧消息总结掉"听着简单,但「从哪儿下刀」是个技术活。
Agent 的历史里有大量"工具调用对":AI 说"我要调用 bash 跑个命令"(一条 AI 消息),紧跟着是"命令的返回结果"(一条 Tool 消息)。这俩是一对,「谁也离不开谁」。
如果切点不小心落在它们中间,就会留下一条"没有提问的答案"——一个孤儿 Tool 消息。绝大多数模型看到这种残缺结构会「直接报错」。

DeepAgents(借助 LangChain 内核)的处理很优雅:如果发现切点正好压在一条 Tool 消息上,就「向前回溯」,找到发起这次调用的那条 AI 消息,把切点提前,让整对要么一起被摘要、要么一起被保留。token 预算用二分查找精确逼近,但「绝不以切断工具对为代价」。
❝这就是为什么"保留最近 N 条"听着是个简单的数组切片,实际实现却有几十行——它得时刻护着这些成对结构。 ❞
这是 DeepAgents 相比 LangChain 原生实现「最本质的一处分歧」,也是最值得记一笔的设计。
LangChain 原生怎么做?简单粗暴:在压缩节点里「直接重写对话状态」——把原始消息全删掉(RemoveMessage(REMOVE_ALL_MESSAGES)),换成"摘要 + 近期消息"。干净,但原稿没了。
DeepAgents 偏不。它「一个字都不删」原始消息,只在一个私有字段 _summarization_event 里记三样东西:「在哪儿切的、摘要内容是什么、旧历史归档到哪个文件了」。每次要调模型时,再根据这个"事件"临时算出精简后的视图喂给模型。

为什么要这么"轴"?因为保留原稿能换来一堆好处:
代价当然有:每次调用都要"临时重建视图",还要做一点切点坐标的换算。但对一个要长期、可观测、可调试运行的 Agent 平台来说,「留住原稿的价值远大于这点开销」。
很多人以为"压缩"就是"把旧的扔了换个摘要"。DeepAgents 的理解更高级一层:「压缩是折叠,旧内容要归档,还要让 Agent 知道去哪儿找。」
正式压缩前,它会先把要丢弃的那批消息「追加写入一个 Markdown 存档文件」(按线程一个文件,每次压缩追加一节,带时间戳)。然后——这步最妙——「让摘要消息里带上这个存档文件的路径」。

于是模型收到的摘要长这样(大意):
❝"你正处在一段已被压缩的对话中。完整历史已保存到
/conversation_history/abc.md,需要细节时可以去翻。下面是浓缩摘要:……" ❞
这意味着:上下文瘦下来了,但「任何被折叠掉的细节,Agent 都能用 read_file 翻回来」。摘要漏掉了某个关键命令的输出?没关系,去存档里查。这一手把"有损压缩"变成了"无损归档 + 有损视图",是它最实用的增强。
顺带一提,摘要本身也不是随便写的。提示词强制 LLM 按四段 checklist 输出:「SESSION INTENT(这次到底要干嘛)/ SUMMARY(关键决策与结论)/ ARTIFACTS(动了哪些文件)/ NEXT STEPS(接下来做什么)」——专门防止压缩后 Agent 重复劳动或忘了产出物。
DeepAgents 给压缩配了「两套触发方式」,覆盖不同场景:

「自动层」(SummarizationMiddleware):后台兜底。token 一旦超过触发线(模型 profile 可用时默认是窗口的 「85%」)就自动压,全程不用模型或用户操心。
「手动层」(SummarizationToolMiddleware):给 Agent 装一个 compact_conversation 工具,并在系统提示里悄悄告诉它——"当你切换到全新任务、或已经拿到结果、旧上下文用不上时,可以主动调用它清场"。
手动层有个防呆设计:「50% 资格闸门」。如果上下文还没到自动触发线的一半,模型就算手贱调了 compact_conversation,也会被礼貌拒绝("还没到该压的时候"),避免过早压缩白白浪费一次 LLM 调用。
两层最聪明的地方在于:「它们共享同一个 _summarization_event 状态字段」。自动压的和手动压的写同一份账,互相可见、协同工作,不会出现"压了两遍""坐标对不上"的混乱。
DeepAgents 的每一处选择,背后都是一组取舍。一表看全:
权衡点 | DeepAgents 的选择 | 换来什么 / 代价 |
|---|---|---|
状态可变性 | 「非破坏式」:留原稿,压缩信息记私有字段 | 可回放 / 可评测 / 可与工具共享;代价是每次要重建视图 |
复用还是重写 | 复用 LangChain 内核,自己只做外壳 | 逻辑零重复、跟上游同步;代价是耦合上游私有方法 |
旧历史去向 | 压缩前「先落盘」,摘要内嵌路径 | 细节可 read_file 回查、不丢 artifact;代价是多一次 I/O |
压缩成本 | 先做「参数截断」这层廉价优化 | 常能省掉一次摘要 LLM 调用;代价是截断有损(但已落盘) |
撞墙处理 | 不超阈值也先试,溢出再压缩重试 | 阈值估松也不报错;代价是极端情况多一次失败往返 |
触发方式 | 「自动 + 手动」两层,共享状态 | 既能兜底又能主动清场;代价是要 50% 闸门防过早压 |
默认阈值 | 有 profile 用比例(85%)、无则用保守固定值 | 开箱即用、跨模型自适应;代价是依赖 profile 数据质量 |
一句话总结这张表:
❝「DeepAgents 把"压缩"当成长任务 Agent 的一项基础设施来做——不是把旧消息一删了事,而是"先归档、能回查、原稿留底、还分自动和手动两档"。」 ❞
读源码读到后面,有几处我自己也还存疑,放在这儿供同好讨论:
thread_id 命名——子代理是否复用了父线程 ID?若复用,多个代理的历史会不会追加到同一个文件里互相污染?write_file / edit_file」:那些会吐超长输出的自定义工具(比如某些 execute)的大参数不会被截,长输出工具多的场景这层优化收益就有限了,是否该开放工具名白名单?这些都不是 bug,更多是"在通用与精确之间怎么取舍"的开放问题。也欢迎读过源码的朋友评论区开聊。
回头看,DeepAgents 的上下文压缩给我最大的启发是这句话:
❝「真正难的不是"怎么压缩",而是"怎么压得让 Agent 既轻装上阵、又随时能找回过去"。」 ❞
它的答案是一组克制而周到的工程选择:复用成熟内核不炫技、先用最便宜的手段省 token、切点死守工具调用对、原稿一律留底、旧历史归档可回查、自动手动双保险。每一条单看都不惊艳,合在一起却构成了一个「能扛住长任务、又不丢信息」的压缩系统。
下次当你设计任何"需要长期运行、上下文会膨胀"的 AI 系统时,不妨借走这套思路——「忘记,也可以很优雅。」
notes/research/agent-frameworks/2026-06-04-deepagents-context-compaction-深读.mdnotes/research/agent-frameworks/2026-05-19-langchain-1.0-upgrade-深读.md(LangChain 中间件机制总览)涉及代码版本:
2ac7d415(langchain-ai/deepagents,middleware/summarization.py)SummarizationMiddleware 来源)