专栏 REA 解剖

预算:summary-first 是架构,不是优化

反编译一个函数可能几万字,一张调用图可能几十万个节点。REA 的做法不是截断,而是把"分析完整"和"交付多大"拆成两个问题。

预算:summary-first 是架构,不是优化

逆向工具的输出天然不适合直接塞进模型上下文:一个函数的伪代码几千字,一个 JavaScript bundle 的模块图几万个节点,一份 HAR 可能有几十万条请求记录。

多数工具的处理方式是截断:取前 N 条,加一句”还有更多”。REA 没有这么做。它把”分析完成”和”这次交付多少”拆成两个独立的状态。

完整结果先进账本

一次 analyze_function 的成功结果,不管多大,都会先变成 Evidence 存进账本。交付给模型的可以是摘要,但账本里始终是完整记录。

// 默认返回 summary,完整档案留在账本
analyze_function({ address: "0x100012340" })
// → normalized_result.parent_evidence_id = "ev_..."

摘要不是”从完整结果里切一段”,而是一个独立的、带 parent_evidence_id 的视图记录。后续要取细节,用 inspect_analysis_view:

{
  "source": { "kind": "retained-evidence", "evidence_id": "ev_..." },
  "view": { "kind": "native", "facet": "pseudocode", "offset": 0, "limit": 64 }
}

limit、offset、fields 都是视图参数;页面耗尽只说明这一页读完,不说明整个结果只有这些。

响应超限时的三步

MCP 的 stdio 接收缓冲有上限,REA 自己的单字符串长度也有上限(Node 的单字符串上限再减 1024 个 UTF-16 单元)。当一条完整结果放不下时,ToolResultDelivery 不会截断 JSON,而是走三步:

  1. 如果调用方已经选了一个分页,把 limit 减半,再试一次。
  2. 如果没选分页,给出这个操作类型的”第一页”:函数档案给伪代码第一页,批量反编译给 items 第一页,原生清单给 64 条第一页。
  3. 如果连第一页都放不下,返回 resource_constraint,并在 details 里给出下一步:换 inspect_analysis_view、导出 bundle,或者用 CLI 的流式输出。

源码里的分页续接很直白:

const smaller = smallerPage(selected);
const view = smaller ?? ownerFirstPage(evidence);
return continuationOf(
  { kind: "retained-evidence", evidence_id: evidence.evidence_id },
  view,
);

这里没有”截断”分支,只有”换一个更小的视图”。

为什么 summary-first 是架构

如果摘要只是可选的优化,调用方就会默认拿完整结果,然后由客户端截断——这时模型看到的是一段不完整的 JSON,它不知道自己看到的是全部还是前 10%。

REA 把默认值反过来:默认交付摘要,完整记录留在账本。这不是为了省 token,而是为了让”当前看到的是视图”成为协议的一部分。摘要记录里有:

  • parent_evidence_id:完整结果是谁。
  • 这份视图的 evidence_id:这一页本身也是一条可引用记录。
  • 视图的类型、偏移、限制、字段选择。

模型可以明确地说”我看的是第 0–63 条”,而不是”我猜这是全部”。

账本也有预算

证据不是无限存的。EvidenceLedger 的上限是当前 V8 可用堆的四分之一;超过就返回资源约束错误,要求导出或分页,而不是悄悄丢旧记录。

导出有两个层次:

  • get_evidence_bundle 可以只取摘要,按 operation、目标 SHA-256、profile digest、地址过滤。
  • export_evidence_bundle 写完整 bundle 到调用方指定的路径。

reset_investigation 可以带 save_path,在清空之前把完整 bundle 落盘;新进程再导入,Evidence ID 和未知项修订链都能复原。REA 明确说”保留是有界的,不是自动持久化”——这句话很重要,它避免了”以为工具记得住”的幻觉。

交付层还做了两件小事

一是 compact schema。 输入 schema 默认紧凑,只有需要完整字段说明时才打开 full。这把”工具目录本身”的上下文成本也纳入了预算。

二是给结果加来源标记。 带目标内容的回复会带 _meta.provenance.untrusted_content,提示模型这是数据不是指令。它不改变结果大小,但改变了模型解读结果的方式——也算一种预算:注意力预算。

一句话总结

REA 不假设上下文无限,也不接受”截断后假装完整”。它的做法是:分析结果完整落账,交付按视图分页,超限时给出可执行的下一步。

下一篇讲边界:当工具真的能启动进程、写文件、连网络、操作设备时,REA 用什么约束保证”能执行”不等于”随便执行”。