【Claude Code-上下文实测】撑爆 Coding Agent 上下文的,往往不是聊天历史,而是工具输出

非线智能API经验 [Claude Code-上下文实测] 第18篇

摘要

长会话 agent 的上下文压力,常常不是用户和模型聊太久造成的,而是文件读取、搜索结果、测试日志、构建输出、MCP 工具结果、工具定义和错误信息造成的。一次失败测试、一段大 JSON、一份长文件,可能比几十轮自然语言对话更占 token。

截断机制可以防止单次输出无限膨胀,但它也会引入新的风险:模型可能基于不完整文件或不完整工具结果继续推理,形成“我已经读完了”的错误信念。因此,上下文治理不能只做历史消息摘要,必须把工具输出当成一等对象来预算、压缩、标记完整性和归档。

数据来源:非线智能Nonlinear 官网

证据层级

Claude Code MCP 文档可以支撑 MCP 输出告警和默认最大输出限制等机制事实。AkitaOnRails 的源码逆向文章可作为社区观察,用于说明文件读取和工具结果截断的可能实现细节,但不能写成官方保证。Claude Code GitHub issue 适合支撑 Read tool 截断、文件 token 超限、工具 / MCP 描述启动开销等真实用户问题。Start Debugging 和 dev.to 文章适合作为实践补充。

本文把“截断”视为必要保护机制,而不是简单 bug。真正的问题是截断是否显式、是否可继续读取、是否被模型误解为完整事实。

从聊天历史太长到工具输出太胖

传统聊天系统里,上下文增长主要来自用户和助手的自然语言轮次。coding agent 的上下文增长则更像一个运行日志:

来源 典型内容 特点
文件读取 源码、配置、文档、日志 体积大,局部相关性强
搜索结果 rg 命中、路径、上下文片段 重复多,噪声高
测试输出 失败断言、stack trace、覆盖率 单次可能数万字符
构建输出 编译错误、依赖日志、warning 关键错误常埋在噪声中
MCP 工具结果 外部系统数据、JSON、表格 schema 和数据都可能很大
浏览器结果 DOM、console、截图描述 页面状态容易过期
错误信息 API 400、权限失败、网络错误 容易污染后续推理

这些内容进入上下文后,不只是增加 token,还会改变模型注意力分布。旧错误日志、过期文件片段、重复搜索结果会和当前事实竞争注意力,让模型更容易围绕已经解决的问题继续推理。

MCP 是高价值入口,也是高风险入口

MCP 的价值是让 agent 连接外部工具和数据源。但 MCP 也会放大上下文体积,原因有三类:

1、工具定义和描述本身会进入上下文预算。
2、工具数量增加后,模型每轮都要在更多能力之间选择。
3、MCP tool output 可能返回大量结构化数据。

Claude Code MCP 文档提到,MCP tool output 超过一定 token 会告警,并有默认最大输出限制。这说明 MCP 输出已经被视为上下文风险源。问题不只是“返回太多会被截断”,而是工具设计者是否能让返回结果天然适合 agent 使用。

一个不适合 agent 的 MCP 工具通常这样返回:

{
  "rows": [
    {"hundreds": "of", "fields": "..." }
  ],
  "debug": "...",
  "raw_response": "..."
}

更适合 agent 的工具应返回:

{
  "status": "ok",
  "summary": "查询到 3 个失败任务,最早失败发生在 deploy step。",
  "items": [
    {
      "id": "job_123",
      "state": "failed",
      "reason": "missing env var API_KEY",
      "url": "..."
    }
  ],
  "truncated": false,
  "next_page": null
}

上下文友好的工具结果应当默认摘要、分页、字段过滤,并显式标注是否完整。

截断不是纯收益

为了保护上下文,工具宿主通常会截断超大输出。截断可以避免单次工具调用耗尽上下文,但它也有副作用。

截断风险 表现
完整性误判 模型以为已经读完整文件或完整日志
关键片段丢失 错误根因刚好在截断后半段
计划错误 基于不完整依赖关系做修改
重复调用 模型反复读取同一大文件,浪费 token
摘要污染 截断结果被写入压缩摘要,变成长期错误事实

GitHub issue 中关于 Read tool truncation 的反馈,正好说明这个问题:如果工具只给预览而没有强烈标注完整性,agent 可能把预览当成完整文件。对代码修改任务来说,这会造成非常具体的风险,比如遗漏后半段函数、忽略同名实现、误删未看到的配置。

工具结果完整性 metadata

每个可能截断的工具结果都应该带完整性信息:

{
  "tool": "read_file",
  "path": "src/example.ts",
  "status": "ok",
  "content": "...",
  "completeness": {
    "is_complete": false,
    "original_size_bytes": 184320,
    "returned_size_bytes": 32000,
    "truncation_reason": "token_budget",
    "range": {
      "start_line": 1,
      "end_line": 800
    },
    "continue_options": [
      {"start_line": 801, "end_line": 1600},
      {"query": "function targetName"}
    ]
  }
}

不要只把截断写进工具宿主日志。模型上下文里也要出现“未完整读取”的事实,否则模型没有理由主动怀疑自己看到的是片段。

测试日志和构建日志应结构化摘要

测试输出是最常见的上下文膨胀源。完整日志通常包含大量重复 stack trace、warning、依赖输出和无关测试。但修复 bug 所需的信息往往可以压成很小:

{
  "command": "npm test",
  "exit_code": 1,
  "failed_tests": [
    {
      "name": "maps tool_use to tool_calls",
      "file": "tests/tool_mapper.test.ts",
      "error": "expected tool_call_id to equal toolu_123",
      "first_relevant_stack": "src/mapper.ts:84"
    }
  ],
  "full_log_ref": "artifacts/test-runs/2026-06-18/npm-test.log",
  "truncated": false
}

这种摘要比完整日志更适合模型继续推理,也更适合压缩后保留。完整日志仍然要归档,以便复现和审计。

文件读取应定位式,而不是全文式

文件读取也要从“先读完整文件”变成“先定位再读取”。推荐流程:

1、用 rg 找符号、错误字符串、测试名。
2、读取命中附近的函数或配置块。
3、如果需要跨文件理解,再读取导入链和调用点。
4、只有在文件本身很短或结构未知时,才读取全文。
5、对长文件读取必须显示行号范围和完整性状态。

这并不是为了节省一点 token,而是为了减少模型接收低相关上下文的概率。代码理解任务里,高信号局部片段通常比低信号全文更可靠。

工具输出生命周期

工具输出不应该永久以原文形式留在模型上下文里。更合理的生命周期是:

阶段 上下文形态
刚返回 原始关键片段 + 完整性 metadata
被模型使用后 结构化结论 + 原始引用
阶段结束 压缩进任务摘要
任务完成或过期 移出 live context,只留 audit ref

这要求工具层、记忆层和审计层协同,而不是把工具返回字符串直接 append 到 messages。

工程策略

问题 策略
MCP 工具太多 按任务暴露工具子集,懒加载 server
MCP 输出太大 分页、字段过滤、返回摘要优先
文件读取太大 定位式读取、行号范围、完整性标记
测试日志太长 提取失败测试、退出码、关键 stack
构建日志噪声 保留首个有效错误和依赖版本
错误日志过期 标注 resolved / unresolved / stale
截断误导模型 is_complete=false 必须进入上下文
原文无法复盘 外置 artifact,摘要记录 hash/ref

失败模式

失败模式 触发原因 修复策略
模型基于半个文件改代码 Read result 被截断但未显式标记 强制完整性 metadata
上下文突然爆掉 测试 / MCP 一次返回巨大输出 工具层分页和摘要
已解决错误反复出现 旧日志长期留在上下文 工具结果生命周期管理
prompt cache 下降 动态工具结果进入稳定前缀 工具结果放入 dynamic tail
MCP 启动成本过高 所有 server/tool schema 全量暴露 工具能力索引和按需暴露
摘要无法审计 原始输出被丢弃 raw_ref + hash + retention policy

验证清单

• 构造超过工具输出限制的大 MCP 结果,确认告警、截断和分页行为。
• 构造长文件读取,检查模型上下文里是否明确出现 is_complete=false
• 跑一次失败测试,确认上下文只保留失败摘要,完整日志进入 artifact。
• 构造已解决错误,确认后续摘要标注 resolved,不再污染下一阶段。
• 比较“全文读取”和“定位式读取”的 token 消耗与修复成功率。
• 启用多个 MCP server,统计 tool schema、tool count、MCP output 对输入 token 的贡献。

工程结论

coding agent 的上下文治理不能只盯着聊天历史。真正高频、高体积、高噪声的入口是工具输出、文件读取和 MCP。截断只是保护机制,不是治理策略;可靠的做法是让每个工具结果可预算、可摘要、可分页、可标记完整性、可复盘。只有这样,compact 才不会把不完整事实压缩成长期记忆。

参考链接

Claude Code MCP Docs
AkitaOnRails: Claude Code's Source Code Leaked. Here's What We Found Inside
anthropics/claude-code #28783
anthropics/claude-code #4002
anthropics/claude-code #3406
Start Debugging: How to Reduce the Number of MCP Tools Claude Loads
dev.to: Tool-Result Truncation: The Silent Bug That Makes Agents Lie

本文由非线智能API Claude Code 行业专家整理编写