模型: openai/gpt-5.4
生成日期: 2026-04-01
书名: Claude Code VS OpenCode:架构、设计与未来
章节: 第4章 — 工具系统设计
Token用量: 约 13,500 input + 2,200 output
4.4 工具输出处理
对 Agent 而言,工具调用的难点不只是“能不能执行”,更是“执行结果怎么喂回模型”。如果输出过长,context window 会被迅速吃空;如果输出过散,模型会抓不住重点;如果输出完全非结构化,后续推理会变得昂贵而脆弱。因此,tool output handling 是工具系统设计中的第二战场。
OpenCode 在 packages/opencode/src/tool/truncation.ts 中实现了非常典型的截断策略:默认上限约为 2000 行或 50KB,超过后把完整结果写入外部文件,并把摘要提示返回给模型,同时在 metadata 中标记 truncated 与 outputPath。这是一种很朴素但非常有效的做法:让模型只消费“当前需要看的局部”,而不是每次把海量日志全部塞回上下文。更重要的是,OpenCode 会在提示中建议使用 Read 的 offset/limit 或 Grep 做二次定位,这相当于把长输出重新转化为可导航的数据源。
Claude Code 的做法更产品化。在很多工具中都可以看到 maxResultSizeChars 这一显式上限;超过阈值时,完整内容被保存到本地 tool-output 存储,模型收到的是 preview + path,而不是全量正文。与此同时,Claude Code 还要求工具把结果映射成 ToolResultBlockParam 之类的结构化块,支持 text、image、document 等多种 content type,并可附带 MCP metadata 或 structured content。换言之,Claude Code 的输出处理不是单纯“截断文本”,而是把结果对象化、分块化、可渲染化。这样做的直接收益是:同一份工具结果既能被模型继续消费,也能被 UI 层友好展示。
OMO 在这方面采取了“宿主机制 + 钩子增强”的策略。它既复用 OpenCode 的基本输出模型,又在 src/hooks/tool-output-truncator.ts 中按工具类型施加不同的截断预算,例如对 webfetch 给出更紧的限制,对搜索与诊断类工具做动态压缩。同时,它通过 metadata store 在前后钩子之间传递标题、上下文与额外信息。也就是说,OMO 的输出处理不是一个固定函数,而是一个可编排 pipeline:原始输出先生成,再格式化,再截断,再注入额外元数据,最后返回给模型。
这里牵涉一个很重要但常被忽略的概念:认知带宽(cognitive bandwidth)。这不是标准 CS 教材里的经典术语,但在 Agent 设计里非常实用。它指的是模型在单轮推理中真正能高质量吸收和利用的信息量。context window 是硬上限,认知带宽则更像软上限:即使窗口还能装下更多 token,模型也未必能高效利用一大坨无结构日志。因此,优秀的工具输出处理并不是追求“少丢信息”,而是追求“把信息压缩成最适合继续思考的形式”。
可以把三者对比为下表:
| 维度 | OpenCode | Claude Code | OMO |
|---|---|---|---|
| 截断策略 | 行数/字节双阈值 | 字符数阈值 + 预览 | 宿主截断 + 工具特定钩子 |
| 完整输出保存 | 是,写入文件 | 是,写入 tool-output | 是,结合宿主与扩展逻辑 |
| 元数据 | truncated、outputPath | 结构化 result block、MCP meta | metadata store + hook 注入 |
| 内容类型 | 以文本为主 | text/image/document 多模态 | 以文本为主,支持增强格式化 |
| 设计重点 | 简洁、可导航 | 产品化、对象化、可渲染 | 可编排、可干预、可扩展 |
归根结底,工具输出处理决定了 Agent 是在“消化结果”,还是在“淹没于结果”。OpenCode 通过统一截断建立最小可用秩序,Claude Code 通过结构化结果提升消费质量,OMO 则通过 hook pipeline 把输出处理纳入编排系统。三者共同说明:工具不是调完就结束,真正的设计功夫,往往体现在结果返回给模型的那一瞬间。