--- title: 别再把上下文当聊天记录 source_url: https://mp.weixin.qq.com/s/ajurJ3Vayd9qLIwh9M3Fnw publish_date: 2026-05-10 tags: [wechat, article, claude, agent, harness, coding, llm, openclaw] review_value: 7 review_confidence: 7 review_recommendation: neutral sha256: 0f75a896c4791ab5caa6f3fd689486bad5098e91b869d3abe7d9fab969c075ef --- --- source: wechat source_url: https://mp.weixin.qq.com/s/ajurJ3Vayd9qLIwh9M3Fnw ingested: 2026-05-09 feed_name: 高可用架构 wechat_mp_fakeid: MP_WXS_3000551159 source_published: 2026-04-26 --- # 别再把上下文当聊天记录 导读:本文详细比较了 Pi、OpenClaw、Claude Code 和 Letta 等 AI agent 框架如何应对上下文窗口限制,包括文件读取截断、分页、工具结果预算和会话压缩策略。 这些框架在文件硬上限、偏移量/限制分页、sub-agent 隔离和 LLM 驱动的会话修剪上表现出明显趋同,表明主动管理上下文已成为工程共识。 作者认为最佳设计应让模型自主管理上下文预算,类似于传统计算的内存管理系统,Arize 的 Alyx agent 也独立采用了类似模式。 > 作者 ** Aparna Dhinakaran ** 是 Arize AI 联合创始人兼 CPO,专注 AI agent 与评估领域。曾就职 Uber、YC 校友,伯克利 EECS 毕业,曾攻读康奈尔计算机视觉博士。 Image 每个 agent harness 都会遇到同一个限制:上下文窗口太小,装不下模型可能想记住的一切。随着会话变长,文件读取膨胀,子智能体调用增多,工具输出堆积,harness 必须决定哪些内容留在工作集里,哪些被压缩,哪些之后再检索。 过去两年,我们一直在构建 Alyx,Arize 的产品内 agent,也把这个问题的各种版本都踩了一遍。我们见过会话一路增长,直到模型忘了任务是什么;也见过文件读取用样板内容吃掉半个上下文窗口,工具结果把真正的对话挤出去。 关键问题已经不再只是 prompt 里放什么。真正的问题是,harness 如何随着时间管理上下文。最好的系统不会把上下文窗口当作被动的转录缓冲区。它们会主动管理:把高价值状态放近一点,按需分页读取数据,建立索引来找到需要的东西(grep 做的就是这个),并且用一种能提示还有什么内容可访问的方式截断内容。 Image 管理上下文窗口 Pi、OpenClaw、Claude Code 和 Letta 在这里做了不同选择,但它们正在收敛到相似的底层模式。上下文不再只是 transcript 里刚好能放下的内容。它变成了系统必须主动管理的对象。真正的设计问题是,这种管理有多少发生在 harness 内部,又有多少要交给模型自己完成。 ### 赌注:相信模型能管理自己的上下文 每个上下文管理决策都编码了一个关于模型行为的假设。关键问题是,harness 应该主动约束上下文用量,还是依赖模型自己正确管理这笔预算。 Image 大文件上下文管理 文件读取让这个问题变得很具体。当模型需要读取一个大到放不进上下文的文件时,必须有人决定保留什么。四个 harness 都支持用于分页的 offset 和 limit 参数。 ** Pi (pi-mono) ** Pi 读取文件时有硬上限:最多 2,000 行或 50KB,哪个先到就停,即使模型没有主动请求切片也一样。内容会从头部开始保留并截断,工具输出还会附加一个明确的继续提示:[Showing lines 1-2000 of 50000. Use offset=2001 to continue.] 工具描述也会强化这一点:"output is truncated to 2000 lines or 50KB. Use offset/limit for large files." Pi 的做法是 ** harness 优先 ** :harness 先保护你,再教模型分页。 ** OpenClaw ** OpenClaw 继承了 Pi 的 read 工具,以及它的 2K 行 / 50KB 截断。普通文件读取时行为相同。在此基础上,它还给 bootstrap 文件叠加了额外上限。bootstrap 文件是在会话开始时一次性加载的上下文文件:每个文件最多 12,000 个字符,总计最多 60,000 个字符。当 bootstrap 文件超过预算时,它使用 75% 头部 / 25% 尾部的切分:你能看到开头和结尾,中间被裁掉。 工具结果有单独预算: ** 16,000 个字符 ** ,或 ** 上下文窗口的 30% ** ,取较小值。当尾部看起来“重要”(错误、JSON 右括号、summary 关键词)时,它会切换到头部加尾部模式;否则只保留开头。 OpenClaw 的做法是 ** 纵深防御 ** :Pi 的截断作为第一层,然后对 bootstrap 注入加额外上限,再在上面叠加工具结果预算。 ** Claude Code ** Claude Code 对文件读取使用双层防线。第一道门是在文件打开之前,通过 stat 调用检查 ** 256KB 字节上限 ** 。如果文件超过这个限制,读取会立刻被拒绝,并返回错误,提示模型改用 ** offset/limit ** 或 ** grep ** 。第二道门在读取之后运行:输出会按 token 计数,并受 25,000 token 预算约束,用来兜住那些字节数没超限但 token 密度很高的文件。两个限制都可以由 Anthropic 通过 GrowthBook feature flag 远程调整,不需要发布新版本。 即使文件没有超过上限,工具默认也只返回开头的 2,000 行,任何超过 2,000 个字符的单行都会被截断。模型必须显式使用 offset 和 limit 参数请求更多内容。 工具描述是一段完整的多段 prompt,解释分页,提到大小上限,覆盖 image、PDF、notebook 支持,并鼓励并行读取多个文件。offset 和 limit 参数也有自己的描述,告诉模型它们适用于太大而无法一次读取的文件。还有一条条件指令,会根据 feature flag 在 prompt 中直接暴露 256KB 上限。 文件去重系统也值得注意。如果模型在同一范围重复读取同一个文件,并且文件修改时间没有变化,Claude Code 会返回一个 stub,而不是完整内容,从而避免上下文中出现重复 token。 Claude Code 的做法是 harness 优先,并且支持远程调参:读取前的字节门禁、读取后的 token 门禁、行数和行长默认值、可执行的错误消息、丰富的工具 prompt、读取去重,以及让 Anthropic 能在服务端调整所有这些行为的 feature flag。 ** Letta ** Letta 采用了根本不同的做法。每个上传文件都会被解析、分块,并嵌入到向量库中,所以 agent 同时获得精确搜索和语义搜索。这让它拥有三个文件工具:open_files 用于直接查看(读取原始文本),grep_files 用于精确模式匹配(同样是原始文本),semantic_search_files 用于基于已嵌入段落的语义检索。 当一个文件在 agent 的上下文中处于“打开”状态时,它可见的内容会被截断到一个按文件计算的字符上限,这个上限会随模型上下文窗口分为五档:8K 上下文对应 5,000 个字符,32K 对应 15,000,128K 对应 25,000,200K+ 对应 40,000。可同时打开的文件数量也会扩展,小模型为 3 个,超大模型最高 15 个,兜底默认值为 5。超过限制时,LRU 策略会驱逐最近最少访问的文件。 Letta 的做法是 memory 优先:文件同时存在于原始文本和向量库(嵌入分块)中,上下文窗口只显示一个受管理的视图,模型通过工具访问更多内容。 ### 真正的工程难点:会话剪枝 随着对话增长,每个 harness 都必须决定保留什么、丢弃什么。这里的设计差异最有意义,因为压缩策略决定了长时间运行的 agent 是保持连贯,还是慢慢退化。 Image 会话剪枝 ** Pi (pi-mono) ** Pi 使用 compaction:由 token 阈值触发、LLM 驱动的总结。 * ** 触发条件 ** :估算上下文 token 超过 contextWindow - reserveTokens(默认 reserve: ** 16,384 tokens ** ) * ** 保留内容 ** :从对话末尾向前遍历,保留最近约 ** 20,000 tokens ** 的消息(keepRecentTokens) * ** 总结内容 ** :更早的所有内容都会交给 LLM 总结 * ** 总结放在哪里 ** :变成一条合成的 ** user message ** ,前置到被保留的尾部之前 * ** 工具调用安全性: ** 永远不会切出孤立的工具结果。它会沿边界移动,保持 tool-call/tool-result 成对完整 ** OpenClaw ** OpenClaw 在 Pi 的 compaction 之上运行两套不同的上下文管理机制: * ** 触发条件: ** 历史超过上下文窗口的 50%(maxHistoryShare,默认 0.5) * ** 保留内容: ** 历史会被切成 token 质量相等的块;最老的块被丢弃,其余保留,并修复 tool-call/result 配对 * ** 总结内容: ** 被丢弃内容会经过分阶段的多轮 LLM 总结,并带有 merge 步骤 * ** 总结放在哪里: ** 和 Pi 一样,合成消息前置到保留的尾部之前 * ** 工具调用安全性: ** repairToolUseResultPairing 会修复块丢弃后产生的任何孤立工具结果;splitMessagesByTokenShare 避免切进 tool-call/result 对中间 * ** 压缩前 flush: ** 一个静默的 agentic turn 让 agent 在历史消失前把状态持久化到 memory 文件 * ** 第二层: ** 对工具结果做非破坏性的内存内剪枝(先 soft-trim,再 hard-clear),使用 5 分钟缓存 TTL,在保护持久对话的同时,为当前请求回收上下文 ** Claude Code ** Claude Code 通过查询前优化和 LLM 驱动的 compaction 管理上下文。 * ** 触发条件 ** :估算 token 超过有效上下文窗口减去 13,000-token buffer(对 200K 上下文模型,compaction 大约在 167K tokens 时触发) * ** 总结内容 ** :完整对话会被发给模型,并附带结构化的九段 prompt,覆盖 primary request、key technical concepts、files and code、errors and fixes、problem solving、all user messages、pending tasks、current work,以及可选的 next step * ** 总结放在哪里 ** :变成一条 user message,告诉模型这个会话是从上一个因上下文耗尽而中断的对话继续 * ** 压缩后恢复 ** :最近读取过的最多 5 个文件会在 compaction 后重新附加到上下文中,受 token 预算约束 * ** 总结器安全性: ** 模型会在分离的 tagged blocks 中生成 analysis scratchpad 和 final summary。scratchpad 会在 summary 进入上下文前被剥离,在不膨胀结果的前提下提升质量 * ** prompt-too-long 兜底: ** 如果 compaction 调用本身触发上下文限制,一个确定性的 head-drop 会移除最旧的 API-round groups(20% 的 groups,或足以补齐 token 缺口的数量) 查询前优化会在每次 API 调用前运行,不管当时是否有上下文压力。每次模型调用之前,Claude Code 都会运行一条 pipeline 来管理工具结果,但不触碰对话文本。超大的工具结果会被持久化到磁盘,并替换成 2KB preview。每个工具有 50,000 字符上限,每条消息聚合后有 200,000 字符上限,所以一个 60KB 的 grep 结果会在新会话第一轮就被 offload。 ** Letta ** Letta 通过多种 compaction 策略管理上下文,并在主路径溢出时使用两阶段 summarizer 兜底。 * ** 触发条件: ** 估算上下文使用量超过上下文窗口的 90% 时触发 compaction * ** 滑动窗口驱逐: ** 从 30% 的消息开始(不是 10%),然后每轮增加 10%,直到 token 使用量低于目标。保留最近消息,驱逐最老消息 * ** Self-compact 模式: ** 使用 agent 自己的模型来总结,所以不需要单独的 summarizer 成本或配置 * ** summarizer 溢出的两阶段兜底: ** 首先把工具返回钳制到 5,000 个字符并重试。如果仍然溢出,就对 transcript 做中间截断,保留 30% 头部和 30% 尾部,丢弃中间 * ** 警告阈值: ** 在 90% compaction 触发前,还有一个独立的 75% memory warning ### 子智能体上下文管理 在我们观察的这些 harness 中,子智能体通常与父会话隔离。这里没有任何一个例子会把完整父对话历史复制给子智能体。问题在于它们继承哪些 workspace context。 Image Subagent Pi 会为每个委派任务启动一个新进程,并创建一个内存中的会话。子智能体只收到任务字符串作为唯一的 user message。不会传入父对话历史。 OpenClaw 默认给子智能体 fresh isolated sessions,不带父 transcript。有一个 fork 模式会把父 transcript 复制给子智能体,但只适用于 same-agent spawns。Workspace context 会被过滤到最小 allowlist(AGENTS.md、TOOLS.md、SOUL.md)。 Claude Code 有两条路径。默认的 typed-agent 路径会创建空白对话:委派 prompt 成为唯一的 user message,没有父历史。较新的 fork 路径会把完整父消息历史传给子智能体,用于 prompt cache sharing,另外还会添加一条合成 assistant message 和 placeholder tool results。Worker 的工具会按自己的权限模式重建;async agents 会得到明确的 allowlist(Read、Grep、Glob、Shell、Edit、Write、WebSearch,以及少数其他工具)。agent definition 中引用的 skills 会被提前预加载。完整 skill 内容会作为 user messages 注入初始对话,而不是按需加载。 Letta 在普通工具执行时完全不 fork。工具运行在主 agent loop 中。历史上下文通过专用搜索工具访问:conversation search 用于 recall memory,archival memory search 用于 embedding store。 ### 设计在哪里收敛 比较这四个代码库后,最突出的发现并非差异有多大,而是共识有多强。 四个 harness 都对文件读取设置硬上限。四个都支持 offset/limit 分页。四个都限制工具结果大小。四个都隔离子智能体会话。四个都运行由 token 阈值触发、LLM 驱动的 compaction。四个都会估算上下文使用量并检测压力。这些都不是巧合。它们是同一个工程问题上的收敛解法:一个固定大小的工作集,却必须让人感觉近乎无限。 这种收敛不只停留在功能相同。具体设计选择也互相押韵。Pi 和 OpenClaw 都对文件读取做头部截断,并附加继续提示。Claude Code 和 OpenClaw 都把超大的工具结果持久化到磁盘。Pi、OpenClaw 和 Claude Code 都在 compaction 期间强制保持 tool-call/result 边界安全。四个里有三个支持把父 transcript fork 到子智能体。各个 harness 正在独立抵达同一组答案。 这些模式也不限于 coding agents。Arize 自己的 Alyx assistant 是为数据探索构建的,不是为代码编辑构建的,却也独立走到了同样的设计。Alyx 把工具结果限制在 10,000-token 预算内,并用二分搜索找到能放下的最大数据集切片。它会通过从对话历史中剪掉重复 preview 来去重幂等工具调用,只保留最新一次。它把大型 JSON payload 拆成 LLM 可见的压缩 preview 和服务端完整副本,模型可以通过 jq 深入查看。这和 Pi、OpenClaw、Claude Code 用于文件读取的“把超大结果持久化在上下文之外”是同一种模式。它会对长 cell value 做头尾截断,并带有指向完整内容的 back-reference。它用 char/4 启发式估算 token 压力,并在对话超过 50,000 tokens 时强制 checkpoint。 此时模型会在历史被剪枝前写下自己的状态总结,把 Claude Code 的确定性 compaction 触发和 OpenClaw 的压缩前状态 flush 结合起来。它的子智能体也使用四个 harness 都采用的隔离启动模式。一个为完全不同领域构建的产品,收敛到了同一套上下文管理 playbook。 Image 50 年计算机发展教会我们,最好的内存管理,是程序根本不用思考的那种。寄存器、缓存行、页表、交换空间。每一层都由系统管理,对上一层不可见。程序只管运行。 Agent harness 正在朝同一个方向移动。目标不是向模型展示一切。目标是在正确的时间给它正确的工作集,并允许它动态决策,管理自己的上下文。 ### 参考阅读: * [ Claude 发布官方报告,承认存在 3 处质量退化问题 ]() * [ 刚刚Opus 4.7发布,相比4.6核心变化,与Claude Code搭配最佳实践 ]() * [ 使用Claude Code:session管理与1M上下文 ]() * [ 很多企业做完 AI PoC,为什么还是上不了生产 ]() 如果你也在关注 AI 应用如何真正落地到生产环境,2026.6.26 - 6.27 GIAC 深圳站值得留意。这次大会会集中讨论智能应用开发、架构演进,以及来自一线实践的经验与案例,识别二维码可申请大会体验门票,点击阅读原文了解大会详细议程。