← 返回 FEED
AGENT2026-04-27

Agent 骨架的上下文管理:四大框架如何处理上下文窗口耗尽

每个 Agent 骨架都会遇到同一个限制:上下文窗口太小,装不下模型可能需要记住的所有东西。随着会话增长、文件读取扩大、子 Agent 调用倍增、工具输出堆积,骨架必须决定:什么留在工作集里,什么被压缩,什么稍后检索。

两年的 Alyx( Arize 内部产品 Agent)构建经验,让我们踩遍了所有版本的上下文问题——会话大到模型失去任务追踪、文件读取用一半上下文窗口塞样板内容、工具结果挤掉了真正的对话。

核心问题已经不只是"往 Prompt 里塞什么",而是:骨架如何随时间管理上下文。 最好的系统不会把上下文窗口当作被动转录缓冲区,而是主动管理它:保持高价值状态贴近、按需分页数据、建立索引定位所需内容(grep 就是这么做的)、以提示"还有什么可访问"的方式截断内容。

文件读取的上下文管理

当模型需要读取大于上下文容量的文件时,必须有人决定保留什么。四个框架都支持 offset 和 limit 参数做分页。

Pi(pi-mono)

Pi 读取文件有硬上限:2000 行或 50KB,以先到为准,即使模型没有要求分段也不例外。内容从头截断,工具输出追加显式的续读提示:[Showing lines 1-2000 of 50000. Use offset=2001 to continue.] 工具描述也强调这一点。

Pi 的方式是骨架优先:骨架先保护你,再教模型分页。

OpenClaw

OpenClaw 继承了 Pi 的读取工具和 2K 行 / 50KB 截断。在此之上,又加了启动文件(session 启动时一次性加载的上下文文件)的额外上限:每个文件 12000 字符,总共 60000 字符。超预算时采用 75% 头 / 25% 尾的切分——让你看到开头和结尾,中间砍掉。

工具结果有独立预算:16000 字符或上下文窗口的 30%,取较小值。当尾部看起来"重要"时(错误、JSON 闭合括号、摘要关键词),切换到头+尾模式;否则只保留开头。

OpenClaw 是纵深防御:Pi 的截断作第一层,启动文件注入上限作第二层,工具结果预算作第三层。

Claude Code

Claude Code 对文件读取应用双层防御。第一道关卡是 256KB 字节上限,通过 stat 调用在文件打开前检查——超出则立即拒绝,并给出错误指引模型使用 offset/limit 或 grep。第二道关卡在读取后运行:输出对照 25000 token 预算做 token 计数,抓住那些字节量小但 token 密度高的文件。两个上限都可由 Anthropic 通过 GrowthBook 远程调节,无需发版。

即使文件在限额内,工具也默认只返回开头 2000 行;超过 2000 字符的行单独截断。模型必须用 offset 和 limit 参数显式请求更多内容。

文件去重系统也值得关注:如果模型在时间戳未变的情况下以相同范围重读同一文件,Claude Code 返回 stub 而不是完整内容,避免上下文中出现重复 token。

Claude Code 是带远程可调性的骨架优先:读前字节门 + 读后 token 门 + 行数/行长默认值 + 可操作错误提示 + 丰富工具 Prompt + 读取去重 + 服务端特性开关。

Letta

Letta 走了完全不同的路:每个上传文件都经过解析、分块、嵌入向量库,Agent 同时获得精确搜索和语义搜索能力。文件工具有三个:open_files(直接查看原始文本)、grep_files(精确模式匹配)、semantic_search_files(基于语义的检索)。

文件"打开"时,可见内容按模型的上下文窗口分五档做字符上限缩放:8K context 5000 字符、32K 15000、128K 25000、200K+ 40000。同时打开的文件数量也相应扩展:从小模型 3 个到超大模型 15 个,默认 5 个。LRU 策略驱逐最久未访问的文件。

Letta 是记忆优先:文件同时存在于原始文本和向量库(嵌入块),上下文窗口只展示受管理的视图,模型用工具访问更多内容。

Session 压缩策略

随着对话增长,每个骨架都要决定保留什么、丢弃什么。这才是设计差异最有意义的地方——因为压缩策略决定了长时运行的 Agent 是保持连贯还是逐渐降级。

Pi

Pi 使用压缩:基于 LLM 的摘要,由 token 阈值触发。

  • 触发条件:估算上下文 token 超过 contextWindow - reserveTokens(默认保留 16384 token)
  • 保留内容:从后往前走,保留最近约 20000 token 的消息
  • 摘要内容:更早的内容发给 LLM 做摘要
  • 摘要去向:变成合成用户消息,放在保留尾部的最前面
  • 工具调用安全:绝不在孤儿工具结果处切断,边界对齐保持工具调用/结果配对完整

OpenClaw

OpenClaw 在 Pi 压缩之上运行两套不同的上下文管理机制。

  • 触发条件:历史超过上下文窗口的 50%(maxHistoryShare,默认 0.5)
  • 保留内容:历史切分为等 token 量的块,丢弃最老的块,其余保留并修复工具调用/结果配对
  • 摘要内容:丢弃的内容经过多轮 LLM 摘要加合并步骤
  • 摘要去向:与 Pi 相同——合成消息放在保留尾部的最前面
  • 工具调用安全:repairToolUseResultPairing 修复块丢弃后的孤儿工具结果;splitMessagesByTokenShare 避免在工具调用/结果对内部切断
  • 压缩前冲洗:一次静默 Agent 轮次让 Agent 在历史消失前将状态持久化到记忆文件
  • 第二层:工具结果的非破坏性内存修剪(软修剪→硬清空),5 分钟缓存 TTL,在保护持续对话的同时为当前请求回收上下文

Claude Code

Claude Code 通过预查询优化和 LLM 压缩管理上下文。

  • 触发条件:估算 token 超过有效上下文窗口减去 13000 token buffer(200K 上下文模型约在 167K token 时触发压缩)
  • 摘要内容:整段对话以结构化 9 部分 Prompt 发送给模型,涵盖主要请求、关键技术概念、文件和代码、错误和修复、问题解决、所有用户消息、待处理任务、当前工作、可选的下一步
  • 摘要去向:变成用户消息,告诉模型"session 从之前的上下文耗尽对话继续"
  • 压缩后恢复:压缩后最多重新附上 5 个最近读取的文件,在 token 预算内
  • 摘要器安全:模型生成分析草稿和最终摘要,分开放置。草稿在摘要进入上下文前剥离,提升质量而不膨胀结果
  • Prompt 过长时的兜底:如果压缩调用本身触发上下文限制,确定性地从头丢弃最老的 API 轮次组(丢弃 20% 的组或足够关闭 token 缺口的量)

预查询优化:每次 API 调用都会运行(无论上下文是否有压力)。在每次模型调用前,Claude Code 运行一个管道,管理工具结果但不碰对话文本。超大的工具结果持久化到磁盘,替换为 2KB 预览,每个工具上限 50000 字符,每条消息聚合上限 200000 字符。

Letta

Letta 通过多种压缩策略管理上下文,当前述路径溢出时,有两级摘要器兜底。

  • 触发条件:估算上下文使用超过上下文窗口的 90%
  • 滑动窗口驱逐:从 30% 的消息开始(不是 10%),每次迭代增加 10%,直到 token 使用降到目标以下。保留最新消息,驱逐最老的
  • 自我压缩模式:用 Agent 自己的模型做摘要,不需要单独的摘要器成本或配置
  • 两级兜底:第一步,钳制工具返回到 5000 字符重试;如果还溢出,在保持 30% 头 + 30% 尾的同时中间截断,丢弃中间部分
  • 警告阈值:90% 压缩触发器之前有单独的 75% 内存警告

Subagent 模式

我们研究的四个框架里,子 Agent 都与父会话隔离。没有一个把完整的父对话历史复制到子 Agent。真正的问题是它们继承什么工作区上下文。

框架子 Agent 策略
Pi每个委托任务启动新进程,子进程只收到任务字符串作为用户消息,无父历史
OpenClaw默认全新隔离 session;fork 模式可复制父 transcript;工作区上下文过滤到最小 allowlist
Claude Code默认空白对话;新 fork 路径可复制完整父消息历史;引用的 Skills 预加载为初始用户消息
Letta正常工具执行不 fork;通过对话搜索工具访问历史记忆和归档记忆搜索

收敛才是关键发现

对比四个代码库,最惊人的发现不是它们有多不同,而是它们有多一致。

  • 四个都硬截断文件读取
  • 四个都支持 offset/limit 分页
  • 四个都限制工具结果大小
  • 四个都隔离子 Agent session
  • 四个都运行 LLM 驱动的 token 阈值触发压缩
  • 四个都估算上下文使用并检测压力

这些不是巧合,是同一工程问题的收敛解:必须让固定大小的工作集感觉无限。

收敛比共同功能更深——具体设计选择也在押韵。Pi 和 OpenClaw 都从文件头部截断并追加续读提示。Claude Code 和 OpenClaw 都将超大工具结果持久化到磁盘。Pi、OpenClaw 和 Claude Code 都在压缩期间执行工具调用/结果边界安全。四个里有三个支持 fork 父 transcript 到子 Agent。

这些模式不限于编程 Agent。 Arize 自家的 Alyx 助手(面向数据分析而非代码编辑)独立收敛到了相同设计:Alyx 工具结果上限 10000 token,用二分查找找到最大可加载数据集切片;通过修剪对话历史中的重复预览对幂等工具调用去重;将大 JSON 载荷切分为压缩的 LLM 可见预览和完整服务端副本,模型可通过 jq 深入;同样对长单元格值做头+尾截断并反向引用完整内容;用 char/4 启发式估算 token 压力;对话超过 50000 token 时强制检查点——结合了 Claude Code 的确定性压缩触发和 OpenClaw 的压缩前状态冲洗。

不同领域的系统,独立收敛到同一套上下文管理 playbook。 这是范式,不是技巧。

类比

50 年的计算历史教会我们:最好的内存管理是程序根本感知不到的那种。寄存器、缓存行、页表、swap。每层由系统管理,对上一层透明。程序只管运行。

Agent 骨架也在走向同一个方向。目标不是给模型展示一切,而是在对的时机给它对的工作集,并允许它动态决策来管理自己的上下文。