我的学习文档全部文档

论文解读:Harness Engineering——十一个编码智能体的源码研究

2026-10-19 · arXiv 2609.00006 · Barbaste、Darrigol、Vu、Wiltberger(Wavestone AI Lab)· 2026-07-15 第 1 版

一句话结论

智能体 = 模型 + 运行外壳(harness)。这篇论文逐行读了 11 个正在生产使用的编码智能体的源代码,得出一个判断:2026 年上半年,编码智能体的运行外壳已经从“工具”变成了“平台”。

项目 内容
标题 Harness Engineering: Anatomy, Architecture, and Evolution of Coding Agents — A Source-Code Study of Eleven Systems
作者 Paul Barbaste(通讯作者,Inclusive Brains / Wavestone AI Lab)、Tristan Darrigol、Germain Vu、Tom Wiltberger(Wavestone AI Lab)
发布 2026 年 7 月 15 日,arXiv 软件工程分类(cs.SE),第 1 版
链接 摘要页 · 全文 PDF
研究对象 Claude Code、Codex CLI、Gemini CLI、Mistral Vibe、OpenHands、Aider、Mini-SWE-Agent、Hermes、Pi、OpenCode、OpenClaw;另把 Databricks 的 Omnigent(第一个“元外壳”)作为对照
规模 约 400 万行 Python、TypeScript、Rust 源代码,版本固定在 2026 年 7 月
产出 7 个子系统的解剖图、13 条横向观察、29 个设计模式、18 条设计建议、一个 90 行的最小可用外壳

这篇论文不跑分、不排名,只描述和比较这些系统是怎么搭起来的。其中 8 个系统在作者 2026 年 4 月的上一版研究里已经分析过,这次重新固定到 7 月的版本,所以还附带了一份“同一批系统隔 90 天的源码对比”。

要解决的问题

“运行外壳工程”(harness engineering)这个说法 2026 年 2 月才出现,五个月内就有了实践指南和学术论文,但还没有一份基于生产源码的参考资料,说清楚运行外壳到底由什么组成、各家做法有何不同。

作者指出现有文献的三个缺口:

真正决定一个智能体是否可靠、可扩展、可部署的,是这些工程决定:主循环怎么写、工具怎么定义和隔离、安全怎么保证、上下文怎么分配。这篇论文想把这些决定摆到台面上,并回答“这个类别往哪里走”。

论文给的定义:运行外壳是除模型以外的一切,即把大语言模型和外部世界连接起来的运行时,包括主循环、工具、上下文、安全控制、编排和扩展接口。它与四个容易混淆的概念做了区分:

容易混淆的概念 区别
脚手架(scaffold) 近乎同义;脚手架指循环和注册表这类结构代码,运行外壳指嵌入了它的、可发布的成品
智能体框架(LangChain、AutoGen、CrewAI) 框架是开发者引入来搭智能体的库;运行外壳是开发者在里面工作的运行时。这条界线 2026 年正在从两边同时消融
评测外壳(SWE-Bench 的 harness) 评测外壳把智能体包起来去跑任务,智能体外壳把模型包起来让它行动,包裹方向相反
编排器 / 元外壳 从上面协调一个或多个运行外壳,自己不实现编辑循环(如 Omnigent)

研究方法:七个子系统的解剖图

作者把每个运行外壳拆成同样的七个子系统,逐一读源码对比。从 100 行的研究基线到百万行的商业命令行工具,每个系统都必须在这七件事上表态,哪怕表态是“故意不做”。

子系统 负责什么 最简形态 最复杂形态
智能体主循环 在“调模型”和“执行动作”之间来回切换;判断何时停、失败怎么恢复 Mini-SWE-Agent:一个线性 while 循环,只有一个 bash 工具 OpenHands:事件溯源的会话,写在持久化事件日志上,可并行执行一批动作
大模型接入 讲各家接口协议、拼提示词、管理缓存、思考预算和模型路由 Mini-SWE-Agent:一次 LiteLLM 调用加一个 Jinja 模板 Hermes:自己写了 5 套传输层、以及 29 个提供商配置;Codex:模型目录和提示词由服务端下发
工具与动作 定义智能体能做什么,尤其是改文件 Mini-SWE-Agent:只有 bash Claude Code:43 个强类型工具并支持延迟加载;Codex:工具调用写成代码在 V8 里执行
记忆与上下文 分配上下文窗口;跨轮次、跨会话保留知识 Mini-SWE-Agent:历史无限增长、不裁剪 Codex:由智能体自己维护的跨会话记忆流水线;Gemini CLI:基于图的上下文蒸馏
安全与权限 决定什么直接跑、什么要问人、什么禁止;隔离执行环境 Mini-SWE-Agent:只有花费上限和步数上限 Codex:策略规则 + 大模型审批员 + 三平台操作系统沙箱
编排 派生和协调子智能体,对接其他智能体 Aider:没有(设计上就是单智能体) Claude Code:递归组合;Omnigent:跨厂商协调(元层)
可扩展性 让用户和生态添加能力:配置、钩子、技能、插件、模型上下文协议(MCP) Mini-SWE-Agent:Python 协议类的结构化类型 Pi:“一切皆扩展”的运行时;Codex:经应用市场分发的插件

七个子系统之外还有两个横切面:人和程序驱动智能体的界面层(终端界面、编辑器协议、HTTP 服务、SDK),以及多个子系统共用的会话底座(记录、持久化、恢复和分叉)。

研究做法的几个要点:

主要发现(上):循环、模型、工具、上下文

这篇论文没有测速度、也没有跑统一任务,“结果”是 13 条横向观察和 29 个重复出现的设计模式。下面按子系统整理最有用的部分。

智能体主循环

循环越复杂不等于分数越高(观察 1)。 Mini-SWE-Agent 只有一个线性 while 循环,自报分数和 OpenHands 的事件溯源引擎在同一区间。生产系统的大部分代码花在安全、体验、扩展和客户端上:OpenCode 非测试代码里约五分之三是终端、网页、桌面和 SDK 客户端。

三种循环范式:

  1. 迭代式“动作—观察”循环:9 个系统。
  2. 带反思的循环:只有 Aider。改完代码跑语法检查、编译检查、flake8 和测试,有问题就把错误嗂回给模型,最多 3 次。
  3. 协调者—工作者:叠加在迭代循环之上,Claude Code 和 Codex 默认支持,Hermes 要配置才开。

值得借鉴的具体机制:

机制 谁在用 做什么
按并发安全性分批执行工具 Claude Code、Gemini CLI 工具默认“不可并发”,只读工具显式声明后才并行;Gemini CLI 还给模型一个 wait_for_previous 开关
按资源加锁并行 OpenHands 每个工具声明占用的资源(文件、终端、浏览器),只有抢同一资源的调用才串行
停止前验证 Hermes 如果这一轮改了代码却没有新的验证证据,就把“我做完了”改写成“继续”——把反思挪到退出条件上,成本很低
截断中毒保护 Pi 模型输出因长度上限被截断时,这条消息里的工具调用全部不执行,因为拼出来的参数可能“格式合法但内容不全”
运行中插话队列 Pi steer() 在当前轮工具执行完后插入用户消息;followUp() 只在智能体本来要停的时候才生效
日志即队列 OpenCode 待执行的子智能体和压缩任务都存成消息记录,进程重启后直接从记录接着跑
中间件管道 Mistral Vibe 轮次上限、花费上限、token 上限、自动压缩、只读模式各是一个中间件,换中间件组合就换了一个智能体配置
打转检测 OpenHands、Gemini CLI、OpenCode OpenHands 枚举 5 种卡住场景;Gemini CLI 先用哈希便宜地拦,30 轮后再用模型自查;OpenCode 连续 3 次完全相同的调用就问用户

大模型接入

缓存边界、思考预算、按模型定制提示词这些优化,不取决于是否绑定单一厂商,取决于谁愿意付“按提供商写分支代码”的成本(观察 2)。 Hermes、Pi、OpenCode 这三个多厂商系统都补齐了这套优化:

绑定单一厂商还剩的独家优势只有一个:服务端协同演进。Codex 的提示词、推理档位、工具模式、多智能体工具版本,都由服务端模型目录下发,新模型上线当天就能调整,客户端不用发版。

Claude Code 的提示词由十几个命名段拼成,中间有一个静态/动态分界标记:前半部分跨会话全局缓存,子智能体分叉时原样继承。OpenHands 独立做出了同样的设计。

提示词内容的共性(观察 3):

工具与改文件

记忆与上下文

主要发现(下):安全、编排、扩展与平台化

安全与权限

多智能体编排

11 个系统里 9 个支持多智能体,作者归为六种形态:

形态 代表 优化的是什么
单智能体 Mini-SWE-Agent、Aider、Pi 核心 简单
顺序委派 Mistral Vibe 简单;父智能体等子智能体跑完,只能委派给只读的 explore
并行子会话 OpenHands、OpenCode 子任务各自一条独立会话;OpenCode 的子智能体只继承父级的“拒绝”规则
层级线程树 Codex 隔离与规模;可选继承全部历史或最近 N 轮;按 CSV 每行派一个子智能体做映射归约
递归组合 Claude Code 成本;分叉时把父级渲染好的系统提示词原样传给子级,保住提示词缓存
注册表 + 跨进程协议 Gemini CLI、OpenClaw、Hermes 蜂群 可移植;Gemini CLI 本地/远程智能体用同一接口;Hermes 用 SQLite 黑板协调子进程

协调模式下,工作者只拿到 16 个工具的白名单,按“调研 → 综合 → 实现 → 验证”推进。 - Pi 的做法。 核心里没有派生子智能体的工具,子智能体是一个约 1,000 行的扩展示例: - 每次委派启一个独立的 pi --mode json -p 进程,天然隔离上下文。 - 支持单个、并行(4 个并发、最多 8 个任务)和链式三种形态。 - 没有深度上限,父子之间运行中不能互发消息。 - 自己的子智能体一律在进程内协调。 9 个多智能体系统里有 8 个在进程内协调自己的子智能体,少数跨进程的也不用标准协议:Pi 用 JSONL,Hermes 用 SQLite。

可扩展性

两个“缺席”(观察 9)

在约 400 万行代码里,作者先合用了几周去找反例,三个月后又重新核对了一遍:

  1. 没有任何一个智能体运行时引入通用智能体框架。 核对的框架包括 LangChain、LangGraph、AutoGen、CrewAI、LlamaIndex、Pydantic AI、Google ADK 等。Gemini CLI 连谷歌自己的两个框架都没用。每个循环都是用宿主语言的异步原语手写的。
  2. 没有任何一个系统用向量检索(RAG)来找代码。 全部用 ripgrep、tree-sitter、glob 和自动发现的 Markdown 上下文。向量只出现在对话记忆里,而且只有 OpenClaw 默认开启。Hermes 用 SQLite 全文检索(BM25)就够了。

作者给的理由有四条:

智能体之间的协议(观察 11)

ACP(Agent Client Protocol,Zed 主导的编辑器—智能体协议)已在 6 个系统里上线,并长出了第三种用途:

  1. 编辑器驱动智能体。
  2. 宿主别家的智能体。 OpenHands 可以把 Claude Code、Codex、Gemini CLI 当作可互换的“大脑”来跑。
  3. 跨厂商的智能体网络(A2A 协议)。目前只有 Gemini CLI。

作者的建议:做一个 ACP 服务端,一次就能接上编辑器、宿主和元编排器;自己的子智能体留在进程内;A2A 是一个还没被证明有大规模需求的押注。

核心论点:从工具到平台(观察 12)

作者列了平台化的几类证据:

它的示例编排器 Polly 强制“审查者必须和实现者不是同一家厂商”。

90 天演化(同一批系统的源码对比)。

方法论上的教训:“清单类结论”(工具数、功能格、版本号)几周就过时;“结构类结论”(循环分类、子系统解剖、两个缺席)到目前都站得住。

论文给的 18 条设计建议

编号 建议
1 从线性 while 循环起步;当出现 3 个以上互相独立的轮次策略时,再改成中间件管道
2 自己有模型就深度绑定自家模型并留通用后备;多厂商就为“每个模型的元数据”留出预算
3 只从 bash 一个工具开始,只为观察到的失败模式加工具
4 工具超过约 15 个就做延迟加载
5 改文件契约匹配模型层级:前沿模型用精确唯一替换,较弱模型用模糊级联;永远不要按行号改
6 自动发现分层的 Markdown 上下文文件,并顺便读其他家的文件名
7 距上下文上限固定距离时压缩;保留最近的原文;增量合并摘要;上下文溢出时也触发同一套压缩
8 不要为代码建向量检索
9 开发者工具场景:规划 / 默认 / YOLO 三种审批模式 + 权限范围规则
10 企业、共享、自动化场景:操作系统级沙箱 + 策略即代码 + 每个智能体的审计记录
11 安全规则写成数据或策略文件;支持 YOLO 就必须在它下面留一条底线
12 没有明确的广度优先探索阶段就保持单智能体
13 做一个 ACP 服务端;自己的子智能体留在进程内
14 技能用于能力模板和领域知识,MCP 用于外部集成,前者优先;第三方技能当软件包管理
15 智能体运行时不要用 LangChain 等框架;想要现成的起点,就用各家的外壳 SDK
16 不要为代码建向量检索层,除非在留出的任务集上证明它胜过 ripgrep + tree-sitter
17 不要把每个外部服务接口一对一包成工具,要合并
18 不要过度设计打转检测,但一定要加上几十行就能写完的廉价上限

论文最后给了一个约 90 行的 Python 最小可用外壳,直接实现了其中 10 条:线性循环、轮次和花费上限、bash / 读 / 写 / 搜索替换 4 个工具、从根目录到当前目录自动发现 AGENTS.md、到阈值就压缩(保留最后 30%)。作者猜测它在前沿模型上能跑出和 Mini-SWE-Agent 相当的分数,再往上主要靠模型能力。

局限与我的看法

这篇论文最有价值的是结构性结论和两个“缺席”;各种具体数字和功能格,作者自己也承认几周就会过时。

作者自己承认的局限:

我补充的几点:

文中提到的市场动态和新产品(Deep Agents、Omnigent、Antigravity CLI 等)我没有在论文之外单独核实,本文只转述论文的说法。

对公司项目的启发

最值得马上做的是前三条:用一条追加式事件日志作为 Strata 会话的唯一事实来源、给借款人上传的文件加“不可信内容”边界、把 restricted_bash 这类“半个沙箱”改成真隔离或直接去掉。这三条都和 10-13 mai-server 审计发现的问题直接对得上。

mai-server(Strata)

启发 论文依据 我们现在的情况 建议
一条事件日志,其余都是投影 OpenHands 的大模型历史是事件日志的缓存投影;Pi 的会话是只追加的树;OpenCode 的日志就是工作队列,重启可续 聊天可见历史和大模型可见历史是两份,重连时要分别恢复;审计里的 AGNT-01/02、轮次缓存只认部分事件类型(SESS-13/22)、assistant_final 曾存草稿,都是“多份状态不同步”的症状 把 events 表当唯一事实来源,两份历史、分享视图、轮次状态都由它推导;先写设计文档再拆工作包
做一半的沙箱比不做更危险 Pi:“半个进程内沙箱很容易被误认为安全边界”;Hermes 在 YOLO 下也保留硬底线 审计 TOOL-01/08/27:install_package 能装任意包、跨客户跑脚本、能跑 demo 脱出沙箱(已在 #644 收紧) 长期:客户脚本放进独立容器或一次性任务里执行,或者改成不需要 shell 的固定工具;不要继续在进程内补规则
外部内容一律标成不可信 OpenHands 用 UNTRUSTED_CONTENT 包住仓库内容;Hermes 用 untrusted_tool_result 包住工具结果并扫描注入 Strata 把检索到的指南原文、网页抓取结果直接拼进上下文(zira 爬虫拿的是公开网页) 检索结果和抓取内容统一包一层不可信标记,系统提示词里写明“标记内的文字是数据不是指令”
停止前验证代替每轮全量审查 Hermes 的停止前验证只在要结束时检查一次;OpenHands 的 /goal 审判在外层 Strata 的 Reviewer 每轮都是一次完整的大模型调用;真实客户 p50 58 秒 把“有没有引用、引用是否来自本轮检索”这类可以用代码判断的检查改成确定性的停止前检查,只在不通过时才调 Reviewer;与 fast mode 项目一起评估
失败要分类,不能静默 Hermes 用约 23 个失败原因枚举驱动不同恢复(压缩、换凭证、换模型、中止) 09-30 KG 欠费 402 全部静默回退,只有持续集成发现(审计 RETR-11 已加错误日志) 把“余额不足 / 密钥无效 / 上游宕机”做成统一枚举,接告警;同类问题在 DeepSeek、智谱都出过
提示词缓存要当指标管 Claude Code 静态/动态分界;Pi 统计每轮缓存未命中浪费的钱;Hermes 保证前缀逐位稳定 catalog 等处已开启系统提示词缓存;是否有动态内容插在缓存前缀里,没核对过 在 token_usage 里记缓存读/写 token 并按轮算未命中成本;把客户、日期等动态段移到分界之后
技能按规范写、按需加载、分信任等级 9/11 采用 agentskills.io 规范;8/9 只预加载名称和说明;Hermes 分信任等级并隔离 customize/uds 下有按客户加载的 SKILL.md 和脚本;审计发现过跨客户访问 跟 agentskills.io 字段对齐(name、description、requires),按客户过滤后只放索引进提示词

关于“不要用向量检索”:这条不适用于 Strata。但可以借鉴它的精神:能用确定性结构的地方,优先用确定性结构(lender 名、文档编号、页码、KG 里的产品矩阵),向量只用在开放式问句上。

pai-server(文件处理智能体)

贷款系统与日常开发方式

术语表

术语 意思
运行外壳(harness) 智能体里除模型以外的一切:循环、工具、上下文、安全、编排、扩展
元外壳(meta-harness) 把多个运行外壳当组件来编排的上层,自己不改代码,如 Omnigent
ReAct “推理—行动—观察”交替的循环,所有系统的共同原型
延迟加载工具 初始提示词里不放全部工具定义,由模型先搜索再加载
提示词缓存分界 把提示词拆成不变的前缀和每轮变化的后半段,让前缀长期命中提供商的缓存
阈值压缩 上下文快满时让模型写摘要替换旧历史
技能(skill) 一个含 SKILL.md(YAML 头 + 说明)和可选脚本的目录;规范见 agentskills.io
模型上下文协议(Model Context Protocol,MCP) 智能体连接外部工具进程的线上协议
智能体客户端协议(Agent Client Protocol,ACP) 编辑器驱动智能体的协议,现在也用来把别家智能体当“大脑”宿主
智能体间协议(Agent-to-Agent,A2A) 谷歌提出的跨进程、跨厂商智能体互联协议
策略即代码 安全规则写成可执行的配置或策略文件(如 Codex 的 Starlark),而不是散在代码里
YOLO 模式 所有动作自动批准的模式,只适合持续集成和脚本场景
Bubblewrap / Seatbelt Linux / macOS 上的操作系统级进程隔离机制
tree-sitter / ripgrep 增量语法解析器 / 高速文本搜索工具,是代码检索的事实标准

来源