好文集ChatGPT Plus¥119

在一个接口下跑任意 agent harness

作者:Akshay Pachaar(@akshay_pachaar,Daily Dose of Data Science 联合创始人)

UHP 和 HarnessRouter 如何把 agent 执行在 Codex、Claude Code、Hermes 等运行时之间统一起来。

当一个 agent 产品直接集成某一个 harness 时,它的后端就开始依赖那个 harness 的任务格式、事件流、会话模型和文件系统行为。

不像模型路由,再加一个 harness 不是改个配置或者参数的事——你是在加入另一个运行时,它自己规划工作、调用工具、管理文件、决定任务何时算完成。

而支持多个运行时很关键,因为 harness 的构建方式各不相同。

正确的选择可能取决于任务、需要的工具、provider 访问权限、可用模型、成本、延迟或用量限制。就像模型一样,一个产品应该能做到增加或替换 harness,而不必围绕它重建功能。

模型路由解决不了这个问题。它选的是哪个模型处理一次推理请求,而 agent 循环本身没变。harness 路由选的是拥有整个任务的 agent 运行时。

今天我们讲第二种路由背后的工程。我们会理解为什么产品可能需要不同的 harness、它们之间必须标准化什么,以及统一 harness 协议(UHP)如何定义这份契约。

然后我们会用 HarnessRouter——UHP 的一个开源实现——把同一个工作流分别跑过 Codex 和 Claude Code。

一、为什么一个产品可能需要另一个 harness

harness 在工具执行、上下文管理、权限、技能和所支持模型上做出不同选择。同一个 harness 未必能为每个产品功能提供正确的工具或模型支持。

一个产品服务的客户也可能有不同的 provider 访问权限。有的客户已经在用 OpenAI 的模型,另一个客户整套环境是围绕 Anthropic 搭的。配额或者 provider 故障也可能让某个后端不可用。

评测是另一个原因。把同一个任务跑过两个 harness,它们的成本、延迟、工具使用和产出会更容易比较。而如果每个后端需要不同的任务和事件代码,这个比较就很难做。

目标不是每次会话都切换 harness,而是不要让产品依赖某一个运行时。

一个团队可以按功能选 harness、给客户提供受支持的选择,或者在不改动产品工作流的前提下替换后端。

二、一次模型调用并不能跑完整个任务

模型 API 接受输入、返回生成的输出。应用程序仍然要负责运行被请求的工具、发起后续的模型调用、管理文件、权限、重试和任务状态。

一个 agent harness 包含了这个控制循环。它可以检查文件、调用工具、编辑项目、运行命令、审查输出,并决定何时停止。

Codex 和 Claude Code 可以使用相似的模型但仍然表现不同。它们的指令、工具、上下文处理、权限和完成规则都会影响运行结果。

三、模型路由 vs harness 路由

模型路由发生在推理层内部。它根据价格、延迟、上下文长度、可用性或实测质量选一个端点。应用程序或 harness 仍然拥有 agent 循环。

harness 路由选的是拥有任务的运行时。这个选择会改变工具、技能、工作区、权限和事件流。

一个产品可以同时使用两层路由。在 UHP 里,model 选模型,而 metadata.harness_id 选配置好的 harness。

四、每个 harness 都要求产品自己处理什么

第一次集成往往是一个小适配器:启动一个进程,读取它的输出。但产品的 UI 还需要实时进度、会话连续性、文件上传、下载链接和访问规则。

取消需要一个定义好的路径,因为本地进程、远程任务和会话的停止方式各不相同。错误也需要足够结构化,好把 provider 故障、权限拒绝、时间限制、文件缺失和任务取消区分开。

在 Codex 旁边再加一个 Claude Code,意味着这些映射要重新构建和维护一遍。产品需要一个两个集成都能遵循的、统一的任务生命周期。

五、UHP 定义的任务生命周期

统一 harness 协议定义的是应用程序和 harness 服务器之间的 HTTP 契约。它覆盖任务创建、进度、会话、文件、取消和错误,但不定义 harness 如何做规划。

UHP 使用一个形状类似 OpenAI Responses API 的接口。客户端通过 POST /v1/responses 启动工作。请求里包含任务输入、模型、配置好的 Harness ID,以及可选的执行限制。

一个 response 记录一个任务。一个 session 把共享对话状态和工作目录的相关 response 归到一组。一个「配置好的 harness」把基础 harness 和它的模型、指令、技能、工具、MCP 服务器及限制组合在一起。

实时任务使用 Server-Sent Events(SSE)。每个事件带一个类型和序号,所以客户端可以按顺序处理这个流。

事件报告文本输出、工具活动、文件和任务状态。应用程序直接展示它们,不需要去逐行搜索原始终端输出来还原每个事件。

UHP 接受请求里的小文件,更大的文件走上传。生成的文件成为 artifact,应用程序可以列出并下载。这些操作由 files 规范定义。

后续任务用 previous_response_id。服务器在同一个会话里继续,带着它的对话、工作目录、文件和配置好的 harness。

你仍然可以把工作交接给另一个 harness。如果 Codex 开始了一个任务、你想让 Claude Code 接手,就用 Claude Code 起一个新 session,把相关上下文传给它——比如到目前为止的工作摘要、下一步指令,以及它需要的文件。把它当成把任务交给另一个开发者:工作可以继续,但 Claude Code 不是在恢复 Codex 的会话。

作为对比,应用程序起两个 session,给它们同一个 PDF 和同一个 prompt。每个 harness 收到的是明确的输入,而不是另一个运行时制造的隐藏状态。

六、HarnessRouter:一个可以自己跑的 UHP 实现

HarnessRouter 是 UHP 的实现,提供一个兼容 OpenAI Responses 的 API,负责持久会话、流式进度、文件、artifact、取消和结构化错误。

它对外的主张很清楚:在接入某一个 harness 之前,你的产品后端要处理的任务格式、事件流、会话模型、文件系统行为这些东西,现在都被这一层收走了。

可以在自己机器上跑社区版(Apache-2.0,Docker 一条命令):

docker run -d --name harnessrouter -p 127.0.0.1:3000:3000 -v harnessrouter:/data harnessrouter/harnessrouter

需要 Docker、大约 4GB 磁盘、一个 provider API key。不需要 HarnessRouter 账号,也不带试用 key。首次启动时会安装启用的 harness CLI,等日志出现 ready on :3000 就可以打开 localhost:3000(默认账号密码都是 harnessrouter,官方提醒先去 Profile 改掉)。

接自己产品的后端,就是调它的 Responses 兼容接口,用 metadata.harness_id 指定 harness:

curl --fail-with-body -sS "$HARNESSROUTER_BASE_URL/v1/responses" -H "Authorization: Bearer ${HARNESSROUTER_API_KEY:?}" -H 'content-type: application/json' -d '{"input":"Reply with exactly: it works.","metadata":{"harness_id":"codex"},"model":"gpt-5.4-mini","stream":false}'

流式就把 stream 设成 true。

他们给的对比数字值得记一下:八个 harness 与模型的配置跑在同一个任务上,每个指标比较最好和最差的结果——成本相差 99.8%(223 credits 对 0.47),端到端延迟相差 3.2 倍(4 分 36 秒对 1 分 25 秒)。而且他们注明:最低成本和最快的配置随任务而变。

七、这份协议的技术定位

UHP 是一个公开的、带版本号的契约,社区版和 HarnessRouter Cloud 都实现它。它的任务接口刻意做得兼容 OpenAI Responses API,所以现有的 Responses SDK、流式解析器和 UI 组件可以直接配合 UHP 服务器工作。

仓库里包含 Apache-2.0 的参考实现、机器可读的 schema,以及一致性测试套件。协议版本、OpenAPI/JSON Schema、治理方式都在仓库里公开。

架构上是三个进程:Console(:3000,唯一对外暴露的端口)、Gateway(:8080,Responses API 加 harness 生命周期)、Runner(:8081,在会话工作区里跑 harness)。会话之间用的是分开的工作区加分开的操作系统用户,而不是分开的容器。

要不要用,判断标准其实很简单:如果你在做的是一个要接入 agent 能力的产品,而不是给自己用的一次性脚本,那「支持第二个 harness」的成本现在是可以被收走的一层。 如果只是本地脚本,多装一个 CLI 就够了,不需要这层。

链接

原文(Akshay Pachaar):https://x.com/akshay_pachaar/article/2100888166219886818

HarnessRouter 仓库:https://github.com/HarnessRouter/harnessrouter

UHP 规范:https://unifiedharnessprotocol.org/

起手模板:https://github.com/HarnessRouter/starter-kit

#Agent工程 #协议 #自托管

全文完
查看原文