Skip to content

第三章 接口也是智能:Aider、SWE-agent 与 OpenHands ​

2023 年的通用自主 Agent 证明模型可以循环调用工具。它没有证明模型在大型代码仓库里就能稳定工作。软件工程要求 Agent 定位相关文件、理解跨模块关系、生成可可靠落盘的局部修改、运行测试并解释错误。模型可能知道如何写函数,却可能因为看错文件、破坏补丁格式或忽略仓库约定而失败。

这一阶段最重要的发现可以概括为:

裸模型单次问答的成绩不能直接当作带工具系统的上限。模型看见什么、能做什么、动作如何表达、反馈怎样返回,都会影响任务表现;收益大小取决于任务、模型和预算,需要实测。

1. Aider:上下文不是越多越好 ​

大型仓库无法完整塞进上下文窗口。即使窗口足够大,无差别注入也会增加费用、延迟和注意力干扰。Aider 的 repository map 选择另一条路线:提取仓库中的关键符号、类型和签名,以文件依赖关系构图,再在 token 预算内通过图排序选择最相关、最重要的部分。Aider Repository Map

它实际上为模型提供了两级观察:

text
Repo Map:低成本、全局但有损的符号地图
Full File:高成本、局部但更完整的源码观察

模型先借助地图理解大致结构,再请求具体文件。这比预先猜测所有相关上下文更接近主动感知:Harness 提供可导航地图,模型决定何时放大细节。

这套设计包含三个可迁移原则。

第一,摘要必须服务于后续定位。一个只“概括内容”的摘要可能读起来很好,却无法帮助 Agent 找到下一步需要读取的对象。符号名、路径、签名和依赖边是可操作的索引。

第二,上下文选择需要显式预算。不同信息不是简单的“相关/不相关”,而是在有限 token、延迟和缓存条件下竞争。Harness 应把 context assembly 看成带约束优化问题。

第三,模型应能按需深化观察。一次性静态 RAG 无法预知执行过程中产生的新问题。现代 Cursor 的动态上下文、Claude Code 的搜索工具和 Codex 的文件工具都延续了这一点。

2. 编辑格式:工具接口会占用模型能力 ​

让模型“给出正确代码”和让它“给出 Harness 能可靠应用的修改”是两个不同任务。Aider 为 whole file、search/replace block、unified diff 等多种编辑格式建立端到端 benchmark,测量代码是否正确、格式是否可解析、修改是否成功落盘并通过测试。Aider 编辑 benchmark

这些评测提示,不同模型对 whole、diff、diff-fenced 等格式的适应可能不同。本轮尚未固定早期 function calling 与文本格式比较的完整实验版本,因此不把“更严格的结构反而更差”作为已核验的历史结论。可保留的设计问题是:复杂格式增加了解析和生成约束,是否影响解题表现,应在同任务、同预算下比较。

因此,“结构化接口必然优于文本接口”不是普遍真理。正确问题是:

  • 模型是否在训练或后训练中见过这种接口?
  • schema 是否贴近任务的自然结构?
  • 参数生成需要多少转义、定位和重复内容?
  • 接口失败能否返回可修复的局部错误?
  • token、延迟、正确率和修改范围之间如何权衡?

这也是模型特定 Harness 的早期证据。同一工具为不同模型提供相同 schema,看似平台中立,实际可能让某些模型承担额外认知税。企业平台需要统一语义,但不必强迫所有模型使用完全相同的表面协议;适配层可以把模型原生动作映射到统一的内部命令。

3. SWE-agent:Agent-Computer Interface 成为设计对象 ​

SWE-agent 把接口明确命名为 Agent-Computer Interface(ACI)。它的论文结论不是只比较模型,而是说明定制 ACI 可以显著改善 Agent 浏览仓库、编辑文件、运行测试和处理程序输出的能力。SWE-agent

ACI 类似人机交互中的 UI,但用户是语言模型。好的 ACI 需要考虑模型的行为偏好和错误模式:

  • 命令集合是否小而正交;
  • 观察是否包含足够定位信息;
  • 大输出是否截断,截断点是否可理解;
  • 文件编辑是否容易精确寻址;
  • 语法或 lint 错误是否及时返回;
  • shell 状态是否跨步骤保持;
  • 错误消息是否告诉模型怎样恢复。

传统 API 设计主要面向确定性程序:调用者会严格遵循 schema,并能用代码处理错误。ACI 面向概率性调用者:工具说明本身是模型上下文的一部分,命令命名、示例、错误文本和输出长度都会改变策略。

所以工具质量至少有四层:

text
Capability   是否能完成所需动作
Semantics    输入、输出和副作用是否定义清楚
Learnability 模型能否从说明与反馈学会正确使用
Governance   动作能否授权、审计、隔离和撤销

很多 MCP 或内部工具只完成第一层:接口“能调用”,却没有为 Agent 的可学习性与企业治理设计。

4. CodeAct:代码作为动作语言 ​

JSON tool call 将动作限制为预定义函数及其参数。CodeAct 提出用可执行 Python 作为统一动作空间,使模型可以组合库调用、中间计算和控制流,并根据执行观察继续修订。CodeAct

代码动作的优势来自组合性。假设 Agent 需要读取数据、过滤、聚合并画图。函数调用模式可能产生多轮 payload 往返;代码模式可以在沙箱内完成多个步骤,只把必要结果送回模型。

但代码动作也扩大了风险面:

  • 动作空间从有限 schema 扩大为通用程序;
  • 静态权限判断更困难;
  • 中间状态可能留在进程、文件或网络中;
  • 可重试性和幂等性更难保证;
  • 执行日志可能泄露秘密或产生巨大输出。

因此 CodeAct 不是 function calling 的普遍替代,而是一种适用于高组合性任务的 ACI。一个成熟 Harness 可以同时提供:高风险业务动作使用窄 schema 工具;数据转换和探索在受控代码沙箱中完成;确定性重复流程编译成普通程序或工作流。

5. OpenHands:把 Agent 与 Runtime 分开 ​

本节依据早期论文和历史0.62.0实现说明一种分工:Agent根据状态产生Action,Event Stream记录Action与Observation,Runtime执行动作并返回观察。当前SDK与Agent Server已经采用新的组件边界,见第十七章,不能拿此图代替当前产品接口。OpenHands论文

text
               Action
Agent/Controller ─────────→ Event Stream ─────────→ Runtime
       ↑                         │                    │
       │ State                   │ history            │ execute
       └──────── Observation ←───┴────────────────────┘

这个分离具有深远的工程意义。

Agent 是决策面:它可以替换模型、提示和策略。Runtime 是执行面:它负责进程、文件、浏览器和网络等真实副作用。Event Stream 则成为二者之间可追溯的协议事实。

如果 Agent 进程崩溃,Runtime 不一定必须销毁;如果 UI 断开,事件仍可持久化;如果要回放问题,可以重建动作—观察历史;如果要并行评估,同一 Agent 可以连接多个隔离 Runtime;如果要支持远程执行,控制面不必进入容器。

历史Docker Runtime在用户镜像中加入action-execution server,通过客户端—服务器接口传递动作和观察。它提供分离执行环境的部署接口,实际隔离取决于容器、挂载、网络和凭证配置;拆成客户端与服务器本身不证明建立了安全域。历史Runtime文档

6. Event Stream 不等于完整事件溯源 ​

按时间记录 Action 与 Observation 很有价值,但不能看到“event stream”就自动假设系统满足严格事件溯源语义。企业实现还要回答:

  • event 是否不可变,允许怎样的脱敏和删除?
  • 每个 event 是否有稳定 id、因果 id 和幂等键?
  • schema 如何版本化?旧 consumer 如何升级?
  • 大型输出存正文还是对象存储引用?
  • secret 在写日志之前还是之后脱敏?
  • 并发工具和 subagent event 如何排序?
  • projection 出错后能否从日志重建?
  • 用户数据删除与不可变审计如何协调?

因此,动作—观察日志是基础,不是终点。参考架构将在后文区分原始 execution event、面向模型的 observation、面向 UI 的 projection 与面向审计的 security record。它们可能源自同一动作,却有不同数据保留和访问策略。

7. Benchmark 开始评价“模型 × Harness” ​

Aider 的 benchmark 同时评价模型解题和编辑格式;SWE-agent 比较 ACI;OpenHands 将 Agent 和 Runtime 接入多个软件工程 benchmark。这意味着评价单位开始从裸模型转向系统组合。

可以将任务成功率表示为:

text
Success = f(Model, Harness, Environment, TaskDistribution, Budget)

如果只报告模型名称而不固定 Harness、环境镜像、工具版本、token 预算和重试策略,结果无法归因。反过来,如果 Harness 更新后分数提高,也不能立即说 Harness 本身更好:可能是评测污染、任务方差、模型后端变化或预算增加。

这为本书后面的 2×2 Model × Harness 评估奠定基础:固定任务集,交叉运行旧/新模型与旧/新 Harness,多次采样,并同时测量成功率、成本、延迟、安全违规和人工介入。只有这样才能区分模型收益、Harness 收益与交互效应。

8. 从接口工程得到的七条原则 ​

这一阶段留下七条稳定原则:

  1. 全量上下文不是默认答案;应提供可导航的低成本地图和按需深化机制。
  2. 工具接口是模型行为的一部分,必须用目标模型做端到端评估。
  3. 表面协议可以模型特定,内部动作语义必须稳定。
  4. 通用代码动作适合组合计算,但必须进入更强的沙箱与审计域。
  5. 决策控制面与副作用执行面应具有清晰协议边界。
  6. Action/Observation 应成为结构化、可关联、可回放的运行时事实。
  7. 评估对象应是模型、Harness、环境、预算与任务分布的组合。

这些原则为比较 Claude Code、Codex、Cursor 提供了具体问题:它们如何设计上下文、编辑、命令、权限、会话和验证接口。下一章转向真实仓库与产品运行时,再由原理篇系统展开这些责任,建立可用于产品分析和自研设计的统一模型。

公开阅读版本