当 LLM 遇见大文档:主流开源项目如何处理上下文超限

当 LLM 遇见大文档:主流开源项目如何处理上下文超限

从 Agentic Loop 到 Repo Map,七种策略与六类陷阱

引言:128K vs 10MB 的硬冲突

2026 年的 LLM 上下文窗口已达到 128K ~ 1M token(≈ 0.5MB ~ 4MB 文本),但 LLM 想要处理的真实数据规模远远超过这个量级:

真实场景数据量级与 200K context 的比值
一个 10MB 的代码文件~2.5M token12 倍
一份 50MB 的日志~12M token60 倍
一个代码仓库的全量源码数百 MB ~ 数 GB千倍 ~ 万倍

这是几乎所有 agent 系统的通病。本文盘点主流开源项目如何应对,并提炼出一套可落地的工程模式。


一、七种主流应对策略(建立坐标系)

应对上下文超限,业界的方法论可归纳为七类。它们常常组合使用,很少单独生效:

#策略一句话定义典型使用者
1硬截断(Truncate)工具输出只保留前 N 字节/行,剩余换成[truncated]指针OpenCode、Vercel AI SDK 应用层
2结构化摘要(Summarize)用 LLM 把工具输出重写成短摘要Claude Code/compact、LangChain SummarizationMiddleware
3动态剪枝(Prune)按"陈旧度 / 引用次数"删除已"消费过"的旧工具消息OpenCode DCP 插件、MemGPT
4外部化 + 按需检索(Offload + RAG)大文本存文件/向量库,prompt 里只放指针 + 检索片段LangChain offload、Letta OS-style 虚拟内存
5替换为引用(Reference Replacement)工具消息替换为短 metadata(行数 / 字节 / 路径)Claude CodeFile unchanged去重机制
6分块延迟回填(Chunked Backfill)工具返回立刻切片 + 嵌入;LLM 想看更多时再调检索OpenCode@enowdev/mnemosyne、LangChain Deep Agents
7上下文重置(Periodic Reset)不压缩,而是定期丢弃整个对话历史,从结构化文档重建CoordClaw

二、主流方案的实际坐标

2.1 CoordClaw——以外化记忆做根因规避

CoordClaw 的设计哲学与其他项目有根本性差异。它不试图压缩或检索,而是让对话历史根本不必要长期保留。

核心机制:

  • 每轮上下文完全重置——Agent 下次启动时重新跑task_start.py(T2 标准动作),只加载"角色定义 + 上一轮工作日志"
  • 工作日志外化——通过task_report.py(T3)编写结构化工作日志到项目目录,它是项目记忆,而不是对话历史
  • 配套context_optimization配置项——team.json中可配置保留轮数、丢弃/压缩策略,压缩历史工具消息
  • llm_error阻断机制——team.jsonllm_error.enabled+endcode配置,在 LLM 报错超阈值时阻断,防止对话失控
  • 点对点消息——Agent 之间通过chat_manager.py send精确路由,非广播,避免上下文污染扩散

为什么有效:真相在文件里,不在 prompt 里。LLM 看不到"上一次说了什么",但能看到"上一次的结论写在哪个文件里"——这是主动遗忘换取可审计。

代价:每轮需要花 token 重建上下文;Agent 不能做"基于对话氛围"的连续推理。


2.2 OpenCode——原生机制 + 插件生态

OpenCode 的官方钩子提供手动触发点:

  • experimental.session.compacting—— 上下文压缩钩子,允许插件在 LLM 生成续接摘要前注入自定义上下文或完全替换压缩提示词
  • tool.execute.before/tool.execute.after—— 工具调用拦截

但 OpenCode默认不主动压缩。真正活跃的是它的第三方插件生态:

插件功能状态
opencode-dynamic-context-pruning按"已无引用 / 超过轮数"自动移除 obsolete tool outputs官方生态收录
@enowdev/mnemosyne组合插件:命令过滤 + 上下文剪枝 + 持久记忆 + 自动代码索引npm 已发布
opencode-mnemosyne本地持久记忆(基于 SQLite + 向量搜索),跨会话保留社区维护

2026 年的事实:OpenCode 的 token 优化方向是"插件化裁剪",而非"runtime 内置智能压缩"。这是一个清晰的设计分工——核心 runtime 保持精简,社区围绕它做策略创新。


2.3 Claude Code——三件套 + 隐式预读

Claude Code 的 Read 工具默认最多读2000 行,单行超过2000 字符会被自动截断。它暴露三个相互配合的工具:

工具作用LLM 何时调用
Read分页读窗口(offset + limit)已知位置,读具体内容
Grep按模式找位置不知道在哪,让 grep 定位
Glob按文件名 pattern 找文件不知道文件叫啥

LLM 的典型工作流:

Glob("**/*.ts") → 找到 50 个 Grep("handleAuth", path="src/") → 精确定位到 src/auth.ts:42 Read(file_path, offset=42, limit=50)

核心技巧:Read 返回的内容带显式行号——“我在第 42 行看到 function handleAuth()”,下次 LLM 可以精确地说"修改第 50 行的 return 语句"。

预读不变量(pre-read invariant):Edit / Write 工具强制要求目标文件此前被 Read 读取过——否则报错。防止 LLM 盲目覆盖。

File unchanged去重:同一文件被读过且未修改(通过 mtime 判断),第二次 Read 直接返回"File unchanged"字符串——deduplication 节省 token。官方测算命中率约18%,每次省约25K tokens


2.4 Claude Code 的/compact:自动压缩与手动触发

当 Claude Code 接近上下文窗口限制(约 95%)时,会自动压缩对话历史。/compact命令可手动触发这一过程。

压缩后,以下内容易丢失:

  • 会话早期的指令(如"不要碰这个文件")
  • 中间决策(为什么选择方案 A 而非 B)
  • 50 条消息前讨论的具体代码片段

而以下内容通常保留:

  • 当前任务和即时上下文
  • 最近修改的文件名
  • 最近的错误及解决方案

关键洞察:项目根目录的CLAUDE.md在压缩后会被重新加载——它是唯一保证能幸存任何压缩的地方


2.5 LangChain / LangGraph——Middleware 抽象

LangGraph 把"上下文管理"做成可插拔 middleware。Deep Agents 项目(基于 LangGraph)提供了SummarizationMiddlewareFilesystemMiddleware等组件。

# 概念示例(基于 LangGraph 中间件模式)app.add_middleware(SummarizationMiddleware(trigger={"messages":50},# 触发阈值keep={"messages":10},# 保留多少summarization_model="gpt-4o-mini",))

这种设计的真正价值:把策略和 runtime 解耦。同一份 LangGraph 应用可以挂不同 middleware:“开发环境保留全部” / “生产环境三级压缩” / “演示模式 50% 截断”。


2.6 Aider——Repo Map(代码地图)

Aider 不分页读取,而是自动生成仓库地图:用 tree-sitter 抽出所有文件的类签名、函数签名、关键调用关系,喂给 LLM 一个"代码地图"。

src/auth/auth.service.ts: class AuthService +login(email: str, password: str) -> Token # line 35 +validateToken(token: str) -> User | null # line 230 +hashPassword(plain: str) -> str # line 1500

LLM 看地图选位置,再精确读具体文件。地图大小固定(默认约 1,024 tokens),不随代码量线性增长——这是它能处理整个代码仓库的关键。

局限:只对结构化代码文件有效(.ts / .py / .go 等 50+ 语言)。对散文、日志、配置文件无效。


2.7 MemGPT / Letta——OS 风格虚拟内存

把 LLM 的 context window 类比为 RAM,大文档类比为磁盘:

OS 概念Letta 等价物
RAMCore Memory(始终保留在上下文中的关键信息)
磁盘缓存Recall Memory(可搜索的近期历史)
冷存储Archival Memory(长期向量数据库存储)

LLM 在两套内存之间主动换页——这是 OS 虚拟内存思想在 LLM 上的应用。优势是 LLM 显式掌控记忆,劣势是 LLM 要学会这个换页 API(认知负担)。

2026 年的现状:MemGPT 已演变为商业平台Letta,开源核心 + 商业云服务。对于生产环境,Letta 是更成熟的选择;MemGPT 原始仓库更适合研究和自定义。


2.8 Clawith——数字员工的 Aware 系统

Clawith(由 dataelement 团队开发的企业级 AI 员工框架)的创新是Aware 自主感知系统,三组件协同:

组件作用
Focus当前注意力焦点——结构化工作记忆列表
Trigger触发新任务的信号——六种类型(cron / once / interval / poll / on_message / webhook)
Heartbeat周期性自我检查——默认 15 秒一次轻量扫描

这套机制不直接解决"上下文超限",而是让 Agent 主动管理注意力——Focus 决定"现在看什么",Heartbeat 周期性评估"是否需要换页",Trigger 在"该换页时主动发起"。


三、工具层设计:让 Agentic Loop 健康运转

主流方案的工程实现都收敛到同一个事实:LLM 必须分页读取大文件。这种"LLM 始终只处理一小块"的模式叫Agentic LoopIterative Retrieval

┌─────────────────┐ │ LLM 拿到当前页 │ ← context window 里只有这一段 └────────┬────────┘ │ reasoning ▼ ┌─────────────────────────────┐ │ 决定下一步: │ │ A. 读下一段(offset+=N) │ │ B. grep 换位置 │ │ C. 已收集够,输出结论 │ └────────┬────────────────────┘ │ tool call ▼ ┌─────────────────┐ │ read_file 返回 │ ← 又是 200 行 └────────┬────────┘ │ 回到 LLM └──── 循环

3.1 read_file 的契约设计

一个健康的read_file工具应返回:

read_file(path:string,offset?:number,// 1-based 起始行limit?:number// 读多少行(默认 200,最大 2000)):{content:string,// 该窗口内容(每行带行号)total_lines:number,// 文件总行数(让 LLM 知道剩余多少)start_line:number,// 本次起始行号encoding:string,// 文件编码truncated:boolean,// 是否被截断}

建议的扩展字段(推荐设计,非所有工具统一实现):

  • next_offset?: number—— 建议的下一次 offset,避免 LLM 陷入 offset 计算循环
  • bytes_total?: number—— 总字节数,辅助 LLM 评估文件规模

3.2 配套工具——三个最少必须有

工具作用为什么必须有
read_file分页读窗口主力
grep按模式找位置效率工具——大多数时候是找特定模式,不是顺序读
outline看文件结构(类/函数/章节大纲)给 LLM 全局地图,避免"读了一段不知身在何处"

只有 read_file 会导致 LLM 盲目翻页;只有 grep 会让 LLM 缺乏全局感;三个配套才能形成健康工作流。

3.3 LLM 的工作流示例

假设架构师 Agent 审查src/auth/auth.service.ts(2400 行):

[Round 1] outline(path="src/auth/auth.service.ts") → { classes: [AuthService], functions: [login, validateToken, hashPassword] } [Round 1] reasoning: "login() 在 line 35,先看它 + 周围 100 行" read_file(path, offset=1, limit=100) [Round 2] reasoning: "看完 login(),跳到 validateToken() 在 line 230" read_file(path, offset=230, limit=100) [Round 3] reasoning: "重点关注 hashPassword 部分,在 line 1500-1600" read_file(path, offset=1500, limit=100) [Round 4] reasoning: "已收集够证据,写工作日志并交付" write_worklog(content="...") → done

每一轮 LLM context 里只看到 ~100 行,但逻辑上看完了 4 个关键区段。


四、六类陷阱(实战中会撞到的)

光说优势不够,这些坑决定了你工具设计的好坏:

#陷阱反模式表现解决方案
1翻页循环LLM 卡在"再 offset 几行确认一下",N 轮无结论max_steps上限 + 工作日志记录已读区段
2早期放弃前几页不像预期就跳走,错过关键章节提供 outline 工具给全局地图
3丢失全局视野只看局部,忘了"全局目标在哪一段"outline + 段摘要工具
4重复读取同一窗口被反复读File unchangeddeduplication + 已读区段记忆
5撑爆 window某段意外读到 10MB工具内置硬上限(单行 2000 字符截断、limit 上限 2000)
6多级压缩细节流失第一级压缩保留的细节在第二级被丢弃用 reference replacement 而非 summarize

其中#6是工业界最隐蔽的问题——Claude Code 的自动压缩设计巧妙,但学术研究反复指出"经过多级压缩后,关键决策细节会显著丢失"。

补充:Claude Code 的 Read 工具存在一个已知边界情况——在某些场景下会尝试读取整个文件而非严格遵守 2000 行限制,导致超出 25,000 token 上限而报错。这提醒我们:即使工具文档承诺了限制,实际实现也可能有漏洞,生产环境必须做二次校验。


五、提示词纪律——告诉 LLM 怎么读

光有好工具不够,LLM 需要"工作纪律"。建议在 Agent 系统 prompt 或角色卡里明示:

阅读大型文档的工作纪律: 1. 拿到文件路径后,先评估大小(read_file 返回的 total_lines) 2. 超过 1000 行:先用 outline 拿到结构,再 grep 定位关键区段,最后 read_file 取窗口 3. 超过 5000 行:禁止"从头顺序翻页",必须 grep + outline 组合 4. 每次 read_file 后,记录本段要点到工作日志,避免重复读 5. 累计读 5 次以上仍未得出结论,回退向用户澄清而非继续翻页

这条纪律直接解决了陷阱 1(翻页循环)和陷阱 2(早期放弃)。


六、场景适配:什么场景用什么方案

并非所有场景都适合 Agentic Loop。下表给出真实工程选择:

场景推荐策略理由
找特定关键字 / 函数Agentic Loop + grep极高效,token 节省 80%+
审查代码逻辑漏洞Agentic Loop + outlineLLM 可自主定位
通读散文 / 报告理解全局先 LLM 摘要预处理 + 再读一次性摘要比翻页更合适
写整篇论文 summary专门 transformer 工具不该让 LLM 翻页
大型仓库全局理解Aider Repo Map 思路固定大小 + 全局感
长对话历史保留LangGraph middleware策略可插拔
长期运行的数字员工Clawith Aware 系统主动注意力管理
严格可审计的多 Agent 协作CoordClaw 外化记忆真相在文件里

七、给工程团队的落地建议

7.1 工具层(必须做)

  • read_file建议返回next_offset—— 没这个字段,LLM 必然进入 offset 计算浪费循环
  • 单行 > 2000 字符自动截断(加...truncated...标记,不报错)
  • File unchanged机制做 deduplication(基于 mtime 或哈希)
  • 二进制文件直接拒绝(不暴露内容细节)
  • 强制预读不变性:Edit / Write 前必须 Read 一次

7.2 提示词层(强烈建议)

  • 在系统 prompt 里写入"阅读纪律"
  • 对不同角色给不同阅读风格——审查员严格(outline 必用)、快速决策者宽松(允许更大 limit)

7.3 监控层(生产必做)

  • 监控"连续 read_file 调用次数"——超过阈值算 agent 进入循环
  • 监控"重复读取"——同一 offset 范围被读多次算浪费
  • 监控"中途放弃"——读完 < 30% 就停止算早期放弃

7.4 架构层(进阶)

  • 记忆外化:重要结论写文件而非留对话(CoordClaw 模式)
  • 可插拔压缩策略:开发环境保留全部 / 生产环境多级压缩
  • Agentic Loop 与单次读取并存:简单查询走单次,复杂任务走 Loop

结论:核心心智模型

把上下文管理想成操作系统:

OS 概念LLM 等价物
RAM(有限、快)Context Window(128K ~ 1M token)
Disk(无限、慢)文件系统 + 向量数据库
虚拟内存(按需换页)Agentic Loop + grep + outline
进程间通信工具调用 + 工作日志
文件系统缓存Session 内已读区段记忆

主流开源项目的差异,本质上是"在这个心智模型下,谁来管理换页"的回答:

项目换页策略核心思想
CoordClaw用户(Agent 自己)主动写文件,让 OS 接管上下文重置 + 工作日志外化
OpenCode + DCP 插件插件按 LRU 自动剪枝社区创新,核心保持精简
Claude CodeRead + Grep + Glob 三件套显式换页应用层控制,人类可审计
AiderRepo Map 提供文件系统索引固定大小地图,按需寻址
Letta (MemGPT)LLM 本身学会系统调用换页LLM 自主管理三层内存
ClawithFocus / Trigger / Heartbeat 自主感知Agent 主动管理注意力

没有最好的方案,只有最适合场景的方案。一个工程团队真正需要决定的,是:让 LLM 学会"换页",还是让它"忘了也不心疼"。


附录:开源项目链接索引

项目链接
CoordClawhttps://github.com/CoordClaw/CoordClaw
OpenCodehttps://opencode.ai
OpenCode 插件生态https://opencode.ai/docs/ecosystem/
opencode-dcphttps://github.com/monotykamary/opencode-dynamic-context-pruning
Claude Codehttps://docs.claude.com/en/docs/claude-code
LangGraphhttps://langchain-ai.github.io/langgraph/
Aiderhttps://aider.chat
Letta (原 MemGPT)https://docs.letta.com
Clawithhttps://github.com/dataelement/Clawith