前面介绍了 Deep Agents 的 Planning、Tools 和 Filesystem。这些能力让 Agent 能够处理复杂任务,也带来了新的问题。

随着执行轮次增加,消息历史、工具结果和中间产物不断累积。模型调用越来越慢,Token 成本持续上升,还可能遗漏早期要求。

尽管更大的上下文窗口只能缓解长度限制,却无法消除信息冗余。

Deep Agents 主要通过三种机制解决这些问题:文件卸载(Offloading)、历史摘要(Summarization)和上下文隔离(Isolation),分别处理大型工具结果、冗长的消息历史和子任务产生的中间信息。

一、上下文膨胀的代价

普通 Agent 通过模型调用和工具执行不断循环:

代码片段Text
Model → Tool → Result → Model → ...

每轮都会产生新消息。如果完整保留历史,后续调用需要处理的内容就会持续增加。

假设连续五轮模型调用的输入分别为:

代码片段Text
第 1 轮: 3,000 Token
第 2 轮: 8,000 Token
第 3 轮:15,000 Token
第 4 轮:24,000 Token
第 5 轮:36,000 Token

累计输入达到 86000 Token。即使支持 Prompt Caching,不断新增的内容仍会带来额外开销。

除了成本和耗时,还有两个问题:

第一,关键要求可能被忽略。例如,用户要求兼容 Python 3.11,但经过数十轮搜索和代码修改后,这条约束可能已经被淹没在大量工具结果中。

第二,无用信息反复处理。如,有些场景中,一次测试输出数百行日志,真正需要的可能只有失败用例和异常堆栈。完整保留这些内容,只会增加后续调用的负担。

上下文管理需要解决的,就是哪些信息应该保留、暂时移出,以及何时重新读取。

二、上下文的使用边界

Deep Agents 不要求所有信息始终进入模型提示词。

类型主要内容管理方式
Input Context系统提示词、Memory、Skills、工具描述精简、按需加载
Runtime Context用户信息、连接配置、运行参数运行时传递
Working Context消息历史、工具结果、分析记录卸载、摘要
Long-term Memory跨会话知识、项目约定持久化存储

首先,简要区分一下 Context、State 和 Memory。

Context 是当前模型调用实际接收的信息;State 保存 Agent 的执行状态,不必全部传给模型;Memory 保存需要长期复用的知识。

例如,代码分析任务中,当前函数属于工作上下文,任务进度记录在 State 中,项目编码规范则适合保存在 Memory 中。

另外,Runtime Context 不会自动进入模型提示词,但工具和 Middleware 可以使用这些数据。

三、大型工具结果的处理

Deep Agents 通过 FilesystemMiddleware 管理文件,并自动处理或卸载(Offloading)大型工具结果。

假设搜索工具返回 30000 Token 的技术文档。直接保留全文,会增加后续模型调用的负担。

默认情况下,工具结果超过约 20000 Token 时,框架会将完整内容写入 Backend,并在工具消息中保留文件路径和前 10 行预览。

代码片段Text
Tool Result(30,000 Tokens)
            ↓
     FilesystemMiddleware
            ↓
       Backend 存储
            ↓
ToolMessage:路径 + 前10行
            ↓
       按需读取原文

Agent 后续可以通过 read_file、grep 等工具读取或搜索内容。read_file 还支持 offset 和 limit,可以分段读取长文件。

这就是 Offloading:数据仍然保留,只是不再反复进入模型上下文。

文件操作也可能产生冗余。例如,write_file 已经保存了完整文档,历史消息中就没必要始终保留同样的写入参数。

当上下文接近容量限制时,Deep Agents 可以截短较早的大型文件操作参数,保留文件引用。

需要注意,Backend 不一定是磁盘。默认 StateBackend 使用 Agent State 中的虚拟文件系统。文件能否持久保存,取决于 Backend 和状态持久化配置。

四、消息历史的自动摘要

文件卸载解决了大型工具结果的问题,但无法阻止消息历史持续增长。

Deep Agents 默认集成 SummarizationMiddleware,在上下文接近限制时自动压缩较早的消息。

例如,Agent 已完成资料收集、方案设计和代码实现,目前正在修复测试问题。

此时,模型主要需要任务目标、关键约束、已完成工作、重要决策和当前问题,不必重新读取全部搜索记录。

SummarizationMiddleware 会将早期历史整理成摘要,同时保留近期消息。

默认压缩策略

当前 Deep Agents 的默认策略如下:

配置默认行为
触发阈值模型 max_input_tokens 的约 85%
近期保留约 10% Token
缺少模型容量信息170000 Token 触发,保留 6 条消息
上下文溢出尝试摘要并重试
原始历史写入 Backend

框架会先尝试卸载可移出的冗余内容,再对历史消息进行摘要。

摘要会损失一些细节信息。例如,原始记录包含多个接口异常,摘要可能只保留“接口问题已修复”。

因此,Deep Agents 会将压缩前的历史保存到 Backend,默认位于:

代码片段Text
/conversation_history/

需要追溯时,Agent 可以重新读取原始记录。

因此,摘要适合保留任务进度和关键结论,并不能代替原始证据。

五、摘要机制的配置

通过 create_deep_agent() 创建 Agent 时,文件卸载和历史摘要已经默认启用,无需手动注册。

代码片段Python
from deepagents import create_deep_agent
 
agent = create_deep_agent(
    model="openai:gpt-5.5",
    system_prompt="你是一名技术研究助手。",
)

对于短任务,可能不会触发摘要。只有达到相应阈值时,框架才会压缩历史。

自定义压缩阈值

如果 Agent 的工具调用频繁、上下文增长较快,可以提前触发摘要。

Deep Agents 支持通过自定义 SummarizationMiddleware 覆盖默认配置:

代码片段Python
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.middleware import SummarizationMiddleware
 
model = "openai:gpt-5.5"
backend = StateBackend()
 
agent = create_deep_agent(
    model=model,
    backend=backend,
    middleware=[
        SummarizationMiddleware(
            model=model,
            backend=backend,
            trigger=("fraction", 0.75),
            keep=("messages", 12),
        )
    ],
)

两个参数决定压缩策略:

  • trigger=("fraction", 0.75):上下文达到模型输入容量的 75% 时触发。
  • keep=("messages", 12):尽量保留最近 12 条消息。

trigger 也支持固定 Token 阈值,例如 ("tokens", 100000)。

从 deepagents>=0.7 开始,传入同名 Middleware 实例可以替换默认配置。

需要注意的是,摘要并非越早越好。频繁压缩会增加模型调用,还可能丢失重要细节。

一般来说,可先使用默认策略,再根据实际运行情况调整。

主动压缩工具

有时上下文尚未达到阈值,任务已经进入新阶段。

例如,资料收集完成后,Agent 准备编写报告。此前的搜索过程可以提前压缩。

Deep Agents 提供 create_summarization_tool_middleware(),用于增加 compact_conversation 工具。

代码片段Python
from deepagents import create_deep_agent
from deepagents.backends import StateBackend
from deepagents.middleware.summarization import (
    create_summarization_tool_middleware,
)
 
model = "openai:gpt-5.5"
backend = StateBackend()
 
agent = create_deep_agent(
    model=model,
    backend=backend,
    middleware=[
        create_summarization_tool_middleware(
            model, backend
        )
    ],
)

Agent 可以主动调用 compact_conversation 整理历史,不必等待默认阈值。

注意:在主动调用压缩工具前,应先将关键结论、决策等内容写入文件。

六、子任务的上下文隔离

对于复杂任务,还可以通过 Subagent 隔离执行过程。

例如,研究型 Agent 需要比较 PostgreSQL、MySQL 和 MongoDB。如果全部由主 Agent 完成,搜索结果和分析记录就会混杂在同一份消息历史中。

Deep Agents 可以通过 task 工具委派研究任务。

代码片段Text
Main Agent
    │
    ├── PostgreSQL Research
    │      独立上下文
    │
    ├── MySQL Research
    │      独立上下文
    │
    └── MongoDB Research
           独立上下文
    │
    ↓
汇总研究结论

每个 Subagent 独立执行。主 Agent 只接收研究结果,不必保留子任务的全部工具调用。

实际开发中,应明确子任务的输出格式。例如,只返回结论、证据来源和未解决问题,原始资料另存文件。

不过,上下文隔离不等于降低总 Token 消耗。子 Agent 仍需调用模型,委派任务也有额外开销。

因此,子任务适合隔离执行过程较长、能够独立完成的任务。简单操作直接调用工具通常更高效。

七、工程实践中的优化

尽管框架提供了上下文管理的能力,要让 Agent 长时间稳定运行,还需注意以下几点:

1. 关键状态独立保存

不要只依赖摘要保存任务状态。可以建立简单的工作目录:

代码片段Text
/workspace/
├── brief.md        # 目标与约束
├── progress.md     # 当前进度
├── decisions.md    # 关键决策
├── evidence.md     # 证据索引
└── report.md       # 最终结果

每完成一个阶段,更新进度和关键决策。需要恢复上下文时,Agent 读取相关文件即可。

2. 精简基础上下文

上下文开销不仅来自执行历史,还包括系统提示词、工具描述、Memory 和 Skills。

这些信息可能在每轮调用中反复出现,应根据用途管理。

Memory 保存长期有效的项目约定和规则;Skills 保存特定任务的操作流程,按需加载;Tools 只暴露当前任务需要的能力。

基础输入越精简,留给实际任务的上下文就越充足。

3. 监控实际运行成本

Agent 变慢不一定是上下文造成的,也可能来自模型推理、外部 API 或工具执行。

可以通过 LangSmith Tracing 观察:

指标关注重点
Input Tokens上下文增长情况
Cached Tokens缓存利用情况
Model Latency模型调用耗时
Tool Latency工具执行瓶颈
Offloading Count文件卸载频率
Summarization Count历史压缩频率
Task Success Rate任务正确率

调优时,使用相同任务比较不同配置下的 Token 消耗、总耗时和结果正确率。

如果提前摘要节省了 30% Token,却导致 Agent 遗漏关键要求,就没有达到优化目的。

八、上下文管理的取舍

Deep Agents 的三种机制各有侧重:

机制主要作用代价
Offloading卸载大型工具结果存储与读取开销
Summarization压缩历史消息摘要成本、信息损失
Isolation隔离子任务上下文额外调用、协调成本

实际开发中,应先控制工具输出,再利用文件卸载和摘要管理历史。对于执行过程较长、相对独立的任务,可以使用 Subagent 隔离上下文。

上下文管理的关键,是让模型只处理当前需要的信息,同时保留找回历史信息的能力。

这样既能控制 Token 成本,也能让 Agent 在长任务中保持执行的连续性和可靠性。