
在统一接口下运行任意智能体执行框架
UHP 用一套 HTTP 契约统一任务生命周期,让产品通过 HarnessRouter 在 Codex、Claude Code、Hermes 等运行时之间自由选
UHP 与 HarnessRouter 如何在 Codex、Claude Code、Hermes 及其他运行时之间统一智能体的执行。
当一个智能体产品直接集成某个 harness 时,它的后端就开始依赖该 harness 的任务格式、事件流、会话模型和文件系统行为。
与模型路由不同,添加另一个 harness 不是改配置或改参数那么简单,因为它引入的是另一个运行时——它会规划工作、调用工具、管理文件,并决定任务何时完成。

而支持多个运行时至关重要,因为各个 harness 的构建方式各不相同。
正确的选择可能取决于任务本身、所需工具、提供商访问权限、可用模型、成本、延迟或用量限制。就像模型一样,产品应当能够添加或替换 harness,而不必围绕它重建整个功能。
模型路由解决不了这个问题。它选择的是由哪个模型来处理一次推理请求,而同一个智能体循环保持不变。harness 路由选择的则是拥有整个任务的智能体运行时。

今天,我们来聊聊第二种路由形式背后的工程实现。我们将理解为什么产品可能需要不同的 harness、它们之间必须统一哪些内容,以及 Unified Harness Protocol 如何定义这一契约。
接下来,我们将使用 HarnessRouter——一个开源的 UHP 实现——让同一个工作流分别通过 Codex 和 Claude Code 运行。

为什么一个产品可能需要另一个 harness
不同的 harness 在工具执行、上下文管理、权限、技能以及支持的模型方面会做出不同的选择。同一个 harness 未必能为每个产品功能提供合适的工具或模型支持。

一个产品也可能服务于拥有不同提供商访问权限的客户。一个客户可能已经在使用 OpenAI 的模型,而另一个客户则是围绕 Anthropic 搭建的。配额限制或提供商故障也可能导致某个后端不可用。

评估是另一个原因。通过两个 harness 运行同一个任务,可以更容易地比较它们的成本、延迟、工具使用和输出。当每个后端都需要不同的任务和事件代码时,这种比较就会变得困难。
目标并不是在每次会话中都切换 harness,而是让产品不再依赖于某一个运行时。

团队可以按功能选择 harness,向客户提供受支持的选项,或者在不改变产品工作流的情况下替换后端。
一次模型调用并不运行整个任务
模型 API 接收输入并返回生成的输出。应用程序仍然负责运行所请求的工具、发起后续模型调用,以及管理文件、权限、重试和任务状态。

一个智能体执行框架(agent harness)包含这个控制循环。它可以检查文件、调用工具、编辑项目、运行命令、审查输出,并决定何时停止。
Codex 和 Claude Code 可以使用相似的模型,却仍然表现出不同的行为。它们的指令、工具、上下文处理、权限和完成规则都会影响运行过程。
模型路由 vs. 执行框架路由
模型路由发生在推理层内部。它根据价格、延迟、上下文长度、可用性或实测质量来选择端点。应用程序或执行框架仍然拥有智能体循环。
执行框架路由选择的是拥有该任务的运行时。这一选择可以改变工具、技能、工作区、权限和事件流。

一个产品可能同时使用两层路由。在 UHP 中,model 选择模型,而 metadata.harness_id 选择所配置的执行框架。
每个 harness 产品必须处理什么
第一次集成通常从一个小型适配器开始,它启动一个进程并读取其输出。产品 UI 还需要实时进度、会话连续性、文件上传、下载链接和访问规则。

取消操作需要一条明确的路径,因为本地进程、远程作业和会话的停止方式各不相同。错误也需要足够清晰的结构,以区分提供商故障、权限拒绝、时间限制、文件缺失和已取消的任务。
在 Codex 旁边加入 Claude Code 意味着要再次构建和维护这些映射。产品需要一条两个集成都能够遵循的任务生命周期。
UHP 定义的任务生命周期
统一 Harness 协议(Unified Harness Protocol)定义了应用程序与 harness 服务器之间的 HTTP 契约。它涵盖任务创建、进度、会话、文件、取消和错误,但不定义 harness 如何规划。

UHP 使用的 API 形态类似 OpenAI Responses API。客户端通过 POST /v1/responses 启动工作。请求包含任务输入、模型、配置的 Harness ID,以及可选的执行限制。
一个响应记录一个任务。一个会话将共享对话状态和工作目录的相关响应分组在一起。一个已配置的 harness 将一个基础 harness 与其模型、指令、技能、工具、MCP 服务器和限制组合在一起。

实时任务使用服务器发送事件(Server-Sent Events,简称 SSE)。每个事件都有一个类型和序列号,因此客户端可以按顺序处理流。
这些事件报告文本输出、工具活动、文件和任务状态。应用程序直接展示它们,而无需为每个事件去搜索原始终端行。
UHP 在请求中接受小文件,并通过上传接受较大的文件。生成的文件成为工件(artifacts),应用程序可以列出并下载它们。文件规范定义了这些操作。
后续任务使用 previous_response_id。服务器沿用同一会话继续,包括其对话、工作目录、文件和已配置的 harness。
你仍然可以把工作交接给另一个 harness。如果 Codex 启动了一个任务,而你想让 Claude Code 接手,就新建一个 Claude Code 会话,并把相关上下文传给它,比如目前工作的摘要、接下来的指令,以及它需要的任何文件。可以把它想象成把任务交给另一位开发者:工作可以继续,但 Claude Code 并不是在恢复 Codex 的会话。

作为对比,该应用会启动两个会话,并给两者相同的 PDF 和提示词。每个 harness 收到的是明确的输入,而不是由另一个运行时创建的隐藏状态。会话规范记录了这条规则。
当前的 UHP 版本是 2026-09-12。该项目发布了书面规范、OpenAPI 3.1 schema、JSON Schema 定义,以及可运行的符合性检查。
HarnessRouter 如何运行任务
HarnessRouter(GitHub 仓库)是一个自托管的 UHP 服务器。它接收 UHP 请求,读取 Harness ID,并启动所选的运行时。在 harness 工作过程中,HarnessRouter 将其输出记录为 UHP 事件、响应、会话、文件和错误。
该 Docker 镜像包含三个服务。
Console 提供浏览器 UI。Gateway 处理 UHP API 和 harness 配置。Runner 在会话工作区内启动 harness 进程。
一个名为 /data 的卷存储数据库、已安装的 harness CLI、提供商集成、会话文件和工作区。只有 Console 端口对外发布。Gateway 和 Runner 在容器内监听回环地址。

自托管指南列出了 Codex、Claude Code、Hermes、DeepSeek Harness、Gemini CLI、OpenCode、Qwen Code、Cline、Goose 及其他后端。
内置 harness 无需自定义配置即可运行。自定义 harness 从一个基础 harness 出发,添加默认模型、指令、工具、技能以及可选的 MCP 服务器。HarnessRouter 会为保存的配置分配一个 Harness ID。

产品会在每个新任务中携带这个 ID。它无需启动 harness CLI,也无需自行解析 harness 的输出。
在本地运行 HarnessRouter
社区版需要 Docker、约 4 GB 磁盘空间,以及受支持模型提供商的 API 密钥。
启动容器。
docker run -d --name harnessrouter \
-p 127.0.0.1:3000:3000 \
-v harnessrouter:/data \
harnessrouter/harnessrouter绑定到 127.0.0.1 可将控制台限制在本机。命名卷会在容器重启后保留其数据。
查看启动日志。
docker logs -f harnessrouter首次运行会安装已启用的 harness CLI:

等待出现以下消息:

[harnessrouter] ready on :3000打开 http://localhost:3000。

接下来,在左侧面板中打开 Integrations,然后选择 Add Integration。选择一个模型提供商并输入其 API 密钥:

此密钥用于授权模型请求。它独立于控制台密码,也独立于应用程序稍后使用的 API 密钥。

在左侧面板中打开 Agent harnesses。你会看到 11 个内置 harness,包括 Codex、Claude Code 和 Hermes。选择 Hermes 来创建任务。
然后在控制台中跟踪运行情况。

harness 创建的文件会保留在该会话中。
配置论文工作流
在控制台中创建两个自定义 harness。
Paper Explainer with DeepSeek Harness
Paper Explainer with Claude Code第一个配置使用 DeepSeek Harnes 作为其基础 harness。第二个使用 Codex。两者接收相同的指令和相同的论文讲解技能。
该技能定义了论文应用所期望的输出。
Read the uploaded research paper and identify its main mechanism.
Build a self-contained interactive explainer in index.html.
Include one controllable simulation with a short explanation beside it.
Use Three.js only when 3D interaction improves the explanation.
Create README.md with the source, assumptions, and run instructions.
Verify both files before completing the task.以下视频展示了此设置:

将同一篇论文上传到两个新会话。在两种配置中运行相同的提示词。
Turn the uploaded paper into an interactive visual explainer.
Recreate its main mechanism as a controllable simulation.
Return index.html and README.md.提示词、技能和所需文件保持不变。Codex 和 DeepSeek Harness 仍然可以选择不同的计划、工具和实现方式。

- 上述视频的第一部分展示了 HarnessRouter 仪表板,以及应用程序如何选择和运行 harness。
- 上述视频的最后一部分展示了 agent 生成的内容。
从应用程序调用 harness
任务在 Console 中运行成功后,打开 http://localhost:3000/keys。创建一个 HarnessRouter API 密钥,并将其保存到后端代码中。

设置本地 API 地址和 API 密钥
export HARNESSROUTER_BASE_URL=http://localhost:3000/api/harness
export HARNESSROUTER_API_KEY=sk-hr-...通过兼容 Responses 的端点发送任务。
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
}' |
jq -r '
"Status: \(.status)
Model: \(.model)
Reply: \([.output[].content[] | select(.type == "output_text") | .text] | join(" "))
Session: \(.metadata.session_id)
Tokens: \(.usage.total_tokens)"
'以下是该请求针对本地端点运行的情况,响应打印在终端中:

此调用使用仓库快速入门中内置的 codex 标识符。自定义配置则使用 Console 中显示的 Harness ID。
对于另一个新任务,更改 metadata.harness_id 即可选择另一个已配置的 harness。
以下是使用 Hermes 的演示:
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": "hermes"},
"model": "gpt-5.4-mini",
"stream": false
}' |
jq -r '
"Status: \(.status)
Model: \(.model)
Reply: \([.output[].content[] | select(.type == "output_text") | .text] | join(" "))
Session: \(.metadata.session_id)
Tokens: \(.usage.total_tokens)"
'如上所示,应用保持相同的端点和事件格式。同一客户端还可以继续会话、检索文件和取消任务。
会话与安全规则
统一执行框架协议(UHP)标准化了任务生命周期,但并不会让各个执行框架的行为变得一致。不同的运行时可以选择不同的计划、工具、文件和模型。该协议为产品提供了一种提交任务并查看结果的统一方式。
本地部署也有明确的隔离限制。会话使用独立的操作系统用户和工作区,但它们并不运行在独立的容器中。Runner 保留创建这些用户所需的权限,而每个执行框架进程则以分配给它的会话用户身份运行。
提供商凭据应存放在代理工具无法读取的环境之外。应用 API 密钥绝不应进入浏览器代码。在回环地址之外的部署还需要 TLS 以及 UHP 安全规范中描述的各项控制措施。
上面的两个 API 调用说明了,当代理成为产品的一部分时,这一点为何重要。用户可能希望用 Codex、Claude Code 或 Hermes 来运行任务。

如果没有共享的任务接口,支持每个执行框架就意味着要为进度、会话、文件和取消再写一套集成。
HarnessRouter 让产品可以在自己的 UI 中提供这种选择。
它通过 UHP 发送任务、选择执行框架,并通过同一个 API 接收结果。
团队可以在把工作流呈现给用户之前,先在本地进行测试。随着执行框架的变化,产品也有办法支持更多框架,而不必每次都重建自己的任务流程。
HarnessRouter 采用 Apache 2.0 许可。该仓库包含自托管实现、UHP schema 和一致性测试。
GitHub 仓库:github.com/HarnessRouter/harnessrouter。
(别忘了给它点个星 ⭐️)
祝好!