在讨论一个 coding agent 是否足够强时,我们通常首先问:它用了什么模型?

模型版本是什么,reasoning effort 开到了什么级别,上下文窗口有多大,工具调用能力是否足够稳定。这些当然重要,因为基础模型决定了智能体能力的重要边界。

但在实际构建 agent 系统时,很快会遇到一个更难解释的现象:

同一个模型,换一个 harness,表现可能完全不同。

这里的 harness,是位于模型与真实执行环境之间的系统层。它决定模型能看到什么上下文,可以调用哪些工具,工具以什么形式出现,执行结果怎样返回,什么时候压缩上下文,错误之后怎样恢复,以及一项任务如何从开始持续推进到结束。

在此前的 《Harness Engineering:模型之外的工程》 中,我把 harness 看成模型之外的执行结构:工具、权限、验证、观察、记忆和反馈共同决定一个 agent 能否可靠工作。继续沿着这个方向看,还会出现一个更具体的问题:即使两个 harness 提供了相同的能力,它们是否都以模型容易使用的方式提供了这些能力?

本文把这种匹配关系称为 模型易用性(Model ergonomics)

这还不是一个已经严格标准化的学术术语。现有研究更常使用智能体计算机接口(Agent-Computer Interface,ACI)、agent scaffolding、tool interface 或 harness design 等概念。但 Model ergonomics 很适合描述一个越来越重要的工程问题:

一个 harness 是否以某个模型容易理解、容易决策、容易行动和容易恢复的方式,把环境能力暴露给了它?

这个问题意味着,agent 的实际能力不能只归因于模型,也不能简单归因于 harness。真正需要研究的是两者之间的匹配。

Harness 不是模型外面的壳

早期的大语言模型应用很容易被理解成一条简单链路:

task

model

answer

但 agent 系统真正运行的过程更接近:

task

harness constructs observation

model reasons

harness exposes actions

model selects action

harness executes

harness transforms feedback

model reasons again

...

模型不是直接面对计算机,而是面对 harness 为它构造出来的世界。

SWE-agent 在 2024 年提出 Agent-Computer Interface 时,已经明确指出这一点:语言模型 agent 是一种新的计算机用户,因此为它设计怎样的接口,会显著影响软件工程任务中的行为和性能。1

这意味着 agent 的可观察能力更接近:

Capability = f(Model, Harness, Environment, Budget)

而不是:

Capability = f(Model)

其中尤其值得单独关注的是 Model × Harness 的交互项。

2026 年的 Harness-Bench 更直接地研究了这一问题。它把工具、上下文、状态、权限、约束和恢复机制都视为 harness 的组成部分,并比较不同 model-harness configuration 的执行轨迹。一个重要结论是:agent capability 更适合在 model-harness configuration 层面报告,而不能简单归因于 base model。2

因此,“这个模型有多强”在 agent 场景中本身就是一个不完整的问题。

更准确的问题应该是:

在什么 harness、什么工具环境、什么上下文策略和什么执行预算下,这个模型能够表现出怎样的能力?

Model ergonomics 关注的不是“能不能”,而是“是否容易发挥”

Model ergonomics 最容易被误解成“针对某个模型多写一些 prompt”。

它实际涉及的范围更广。

一个模型理论上能够完成某项操作,并不意味着当前 harness 给它的就是最合适的操作接口。

假设模型只有一个非常强的工具:

exec_command(command)

那么从 capability 的角度看,它几乎可以自己构造完整的本地工具集。模型可以通过 shell、Python、Perl、awk 或其他程序实现文件读取、目录遍历、搜索、批量处理、修改文件和运行测试。

因此,从“能否完成操作”的角度看,一个通用 shell 已经非常接近图灵完备。

但模型面对的问题并不只有表达能力。

它还需要决定下一步应该采取什么行动,构造正确参数,控制副作用,理解工具结果,并在失败后恢复。于是,harness 的质量还取决于:

  • 模型是否容易选择正确的 action;
  • action 的粒度是否合适;
  • 工具参数是否容易稳定生成;
  • 工具结果是否包含必要而不过量的信息;
  • 错误是否容易分类;
  • 上下文是否保留了下一步需要的状态;
  • 模型犯错后是否容易重新进入有效轨道。

因此:

capability completeness ≠ ergonomic fit

一个 interface 可以具有极高的理论表达能力,却让模型承担过多低层决策。

另一个 interface 可以提供许多方便的结构化工具,却因为工具过多、语义重叠,使模型面对更大的 action search space。

Model ergonomics 研究的正是两者之间的关系。

Grok 运行在 Codex 上:协议兼容之后还有什么

这个问题在 Grok 运行于 Codex harness 的实践中表现得很具体。

我们的目标不是重新实现一个 Grok coding agent,而是尽量保留 Codex 已经拥有的执行系统,包括 Thread 和 session 生命周期、context 和 history、sandbox 与 approval、MCP、Code Mode、Multi-Agent、ToolRouter,以及 App Server 和 UI contract。

对应的架构原则是:

Stock Codex owns the harness. Provider adaptation owns backend differences.

在当前设计中,Grok Provider 主要负责 Codex 与 Grok Responses API 之间真实存在的协议差异,例如 request/history projection、Grok Responses dialect,以及把 Codex 的 canonical namespaced tools 投影成 Grok 可以接受的 flat functions,再把返回的调用恢复成 Codex 的 canonical tool identity。3

这些都属于 Provider compatibility

它们回答的是:

Codex 的现有 harness 能不能通过 Grok API 正确工作?

但模型开始真正执行 coding task 之后,又出现了另一类问题。

例如,在需要一次读取多个文件时,我们观察到 Grok 经常通过 exec_command 临时生成 Python 程序:

python3 - <<'PY'
from pathlib import Path

for path in paths:
    print(Path(path).read_text())
PY

这并不意味着 Grok 无法使用 Codex。

相反,它成功使用了 Codex 提供的 shell,也通常可以完成任务。

真正值得问的是:

为什么模型会反复在 shell 内重新构造一个文件读取抽象?

这已经不是 Provider protocol 的问题。

它是 Model ergonomics。

Shell 是通用接口,但不是中性接口

在当前 Grok-enabled Codex release/rust-v0.151.0 中,Grok 4.6 的 model catalog 配置了 UnifiedExec,而 apply_patch_tool_typeNone4

Codex 的工具规划代码会为 Unified Exec 注册 exec_commandwrite_stdin;stock ApplyPatchHandler 则只有在 model_info.apply_patch_tool_type 存在时才会进入工具 registry。5

因此,在这个具体配置中,Grok 获得了一个表达能力很强的 shell,却没有获得 Codex 原生的 apply_patch 工具。

这个事实本身还不能证明 harness 设计有问题。

更不能直接证明:“给 Grok 增加更多文件工具,表现一定会更好。”

但它揭示了 generalized harness 一个容易被忽略的问题:

通用接口并不意味着没有设计偏置。

如果所有模型都统一获得:

shell(command: string)

看起来似乎非常 generalized,因为任何模型都能使用,而且大量计算机操作都能通过 shell 表达。

但选择 shell 作为 universal action representation,本身就是一个强烈的设计决策。它隐含假设模型能够稳定处理 shell syntax、quoting、batching、side effects、stdout,以及 grep、sed、find、Python 等不同工具之间的组合。

对于一个擅长这些操作的模型,这种自由度可能非常有效。

对于另一个模型,同样的自由度可能只是扩大 action space,并制造额外的执行 ceremony。

所以 generalized harness 并不是“没有 specialization”。

它往往只是把 specialization 隐藏进了一个被认为足够通用的 abstraction。

GrokBuild 是一个设计信号,而不是结论

xAI 自己开源的 GrokBuild 提供了一个很有意思的对照。

它的工具运行时中存在一组明确标记为 Codex-specific 的工具:

apply_patch
grep_files
list_dir
read_file

源码说明这些工具来自 Codex 实现的移植和修改。6

这很容易产生一个过强的推论:

GrokBuild 有 read_file,所以 Grok 在 Codex 中也必须有 read_file

目前没有足够证据支持这个结论。

GrokBuild 的设计只能证明:xAI 在构建自己的 Grok coding harness 时,选择了向模型提供这些结构化文件操作。

但这个对照仍然有价值。

因为两个都希望让 Grok 完成软件工程任务的 harness,可以选择完全不同的 action vocabulary:

Codex                  GrokBuild

exec_command           read_file
write_stdin            list_dir
...                    grep_files
                       apply_patch
                       ...

如果同一个模型在两种环境中的行为明显不同,那么差异至少不能全部归因于模型权重。

更值得注意的是,GrokBuild 的 ToolConfig 还把 canonical tool identity 与 client-facing presentation 分开:它支持工具名称、参数名称和 description 的 override。7

这暗示了一个重要的架构方向:

工具“是什么”,和模型“怎样看到这个工具”,不一定必须是同一层。

这比单纯复制 GrokBuild 的具体工具更值得借鉴。

Generalized harness 与 specialized harness 不是二选一

接受 Model ergonomics 之后,很容易走向另一个极端:既然不同模型喜欢不同的 interface,就为每个模型维护一套专用 harness。

例如:

Model A ToolRouter
Model B ToolRouter
Grok ToolRouter
...

短期这样做很容易提高 benchmark。

某个模型不会使用一种工具,就给它换一种工具;某种 context 组织效果不好,就加一条 model-specific branch;某个模型容易在特定地方停滞,就专门写一个 recovery rule。

如果一直这样发展,最终会产生另一种问题:

semantic divergence
test explosion
model-version drift
duplicate runtimes
upgrade difficulty

模型本身还在持续变化。

今天必要的 workaround,下一次模型升级以后可能已经毫无价值,甚至会反过来限制新模型的能力。

因此,真正的问题不是:

generalized harness 还是 specialized harness?

而是:

什么应该 generalized,什么可以 specialized?

我目前更倾向于把它拆成三个层次。

┌────────────────────────────────────┐
│ Model Ergonomic Profile            │
│                                    │
│ tool presentation                  │
│ observation granularity            │
│ context policy                     │
│ reasoning defaults                 │
│ guidance / recovery                │
└────────────────┬───────────────────┘

┌────────────────▼───────────────────┐
│ General Semantic Harness           │
│                                    │
│ canonical tools                    │
│ ToolRouter                         │
│ sandbox / approvals                │
│ history / context                  │
│ multi-agent                        │
│ lifecycle / state                  │
└────────────────┬───────────────────┘

┌────────────────▼───────────────────┐
│ Provider / Wire Adapter            │
│                                    │
│ auth / endpoint                    │
│ request dialect                    │
│ reasoning projection               │
│ tool wire encoding                 │
│ response normalization             │
└────────────────────────────────────┘

这三层分别解决不同的问题。

Semantic harness 应该保持通用

第一层是通用语义 harness。

这里应该尽可能避免 model-specific implementation。

例如 Read File、Apply Patch、Exec、MCP Call、Web Search、Spawn Agent 这些都可以被理解成 agent system 中的 canonical semantic operations。

同样,sandbox、permission、history、tool lifecycle、persistence 和 cancellation 也应该保持统一。

这一层最重要的不是让每个模型看到完全相同的界面,而是:

execution authority 必须保持唯一。

如果 Codex 已经拥有 ToolRegistry、ToolRouter、sandbox、history 和 extension runtime,那么为了支持 Grok 再创建一套 Grok ToolRouter,通常意味着架构开始分裂。

这也是目前 Codex Third-Party Provider North Star 所坚持的边界:Codex core 保持 canonical concepts,Provider-specific behavior 只在最窄的 backend boundary 上做 projection。8

Provider compatibility 只负责协议差异

第二层是 Provider compatibility。

这一层可以 specialized,因为不同 backend 确实存在真实协议差异。

以 Grok 为例,这里可以处理:

logical Codex reasoning

Grok wire reasoning

canonical namespaced tool

backend-safe function name

reverse projection

canonical Codex identity

canonical history

Grok-compatible request representation

这种 specialization 有明确来源:backend contract 不同。

它回答的是:

怎样让统一的 Codex semantics 正确穿过不同 Provider?

如果一个差异无法由 Provider API、wire protocol 或 backend behavior 解释,就应该谨慎判断它是否真的属于 Provider 层。

例如,“Grok 更喜欢 read_file 而不是 shell”即使最终被实验验证,也不是 Grok Responses API 的协议事实。

它属于另一层。

Model ergonomic profile 负责模型看到什么

第三层才是 Model ergonomics。

它解决的是:

当 harness 已经能够正确运行以后,应该怎样把这些能力呈现给当前模型?

这一层可以控制的内容可能包括:

  • 哪些 canonical tools 直接暴露给模型;
  • tool name 和 description 如何呈现;
  • 参数 schema 如何组织;
  • action granularity;
  • context compression;
  • tool result 的详细程度;
  • reasoning default;
  • recovery hint;
  • direct、deferred 或其他 tool exposure policy。

这里最重要的一条边界是:

specialize the interface, not the execution authority.

假设未来 benchmark 确实证明 Grok 使用 read_file 明显优于通过 exec_command 自己组织文件读取。

正确的方向更可能是:

model-facing read_file

canonical filesystem operation

stock Codex execution environment

而不是:

GrokReadFileRuntime
GrokFileSystem
GrokToolRouter

前者改变的是模型 interface。

后者开始复制 harness semantics。

Capability 和 ergonomics 不是同一类事实

如果未来真的把 Model ergonomics 引入 model profile,还需要避免把 ergonomic preference 写成 capability。

例如:

supports_image = true

描述的是 capability。

它回答:

这条执行链是否支持 image?

而:

prefer_file_tools_over_shell = true

如果未来存在类似策略,它描述的是 ergonomic preference。

它回答:

根据当前 benchmark,这种 interface 是否更容易让模型稳定发挥?

两者的稳定性完全不同。

Capability 通常来自 API、模型或完整执行链的确定事实。

Ergonomic policy 则是一种经验性结论。随着模型版本、system prompt、tool implementation 或训练方法变化,它完全可能失效。

因此 Model ergonomics 应该满足几个条件:

  • 有 benchmark 或 trajectory evidence;
  • 可以单独替换;
  • 可以进行 regression;
  • 不成为 durable semantic contract;
  • 不因为一次观察就写入长期架构。

这也是为什么看到 Grok 使用 Python,并不足以成为增加 read_file 的理由。

行为异常只是调查起点。

不是设计结论。

Model ID 可能也不是最终的抽象

更进一步,Model ergonomics 最终也未必应该完全围绕 model ID 建模。

我们当然可以从:

grok-4.6
model-a
model-b

选择不同 profile。

但真正值得理解的是模型背后的行为维度,例如:

shell fluency
tool-schema adherence
parallel-call reliability
context-noise tolerance
self-recovery strength
action-granularity preference
planning reliability

这些维度目前还没有形成足够成熟的标准,因此现在就把它们设计成正式 schema 会过早抽象。

但它们指出了更重要的研究问题。

我们真正想知道的不是:

Grok 应该有哪些特殊代码?

而是:

Grok 在怎样的 interaction regime 下能够最稳定地完成任务?

同样的问题也适用于同一模型家族中的不同模型、不同 reasoning configuration,甚至模型升级前后的不同版本。

共享 API 并不意味着共享完全相同的 agent interaction optimum。

Harness 的质量至少有 Generality 和 Adaptability 两个维度

接受这个判断以后,“一个 harness 是否优秀”也需要更精确的定义。

第一个维度仍然是 Generality

有多少模型能够接入?多少 Provider 能够运行?多少环境能够被支持?

这是传统意义上的 portability。

但还应该有第二个维度:Adaptability

它问的是:

接入一个新模型以后,需要多少额外机制,才能让它接近自身的 agent capability frontier?

于是会出现两种完全不同的系统。

一个 harness 可以支持一百个模型,但所有模型都面对同一个 lowest-common-denominator interface。

另一个 harness 可能保持同一套 semantic kernel,却允许不同模型使用经过验证的 tool presentation、context policy 和 recovery policy。

只统计“支持多少模型”,无法区分这两种 harness 的质量。

甚至可以用一个并不严格、但很有启发性的概念来描述它:

Harness Efficiency(Model)
    =
Observed Agent Capability(Model, Harness)
    /
Potential Agent Capability(Model)

分母实际上无法直接观测,因此它不是一个可以直接计算的工程指标。

但它表达了一个重要目标:

一个好的 harness 不只是让模型“能运行”,而应该减少模型能力在 interface 和 execution loop 中的损失。

Benchmark 的对象应该是 Model × Harness

这也改变了 benchmark 应该如何设计。

假设我们观察到:

Model A + Harness X = 70
Model A + Harness Y = 48

Model B + Harness X = 52
Model B + Harness Y = 69

那么“Model A 和 Model B 谁更强”已经不是一个定义完整的问题。

至少应该改成:

在什么 harness、预算和 environment 下,哪一个 model-harness pairing 更有效?

近期的 Same Model, Different Harness 更直接地固定模型,改变 context management 和 stalled-work handling,再观察 coding-agent 结果变化。这个工作仍是较新的预印本,因此具体结果不宜单独视为成熟共识,但研究设计本身很好地说明了 harness effect 应该怎样被隔离。9

Self-Harness 则从另一个方向出发:通过 execution traces 发现 model-specific failure patterns,再提出较小的 harness modification,并进行 regression validation。10

这些工作共同指向一个方法论:

Model ergonomics 应该通过受控实验研究,而不是通过“这个调用看起来不够优雅”来决定。

回到 Grok:应该怎样验证 Model ergonomics

因此,对于 Grok 在 Codex 中频繁通过 Python 组织文件操作这件事,我不会从“怎样阻止它写 Python”开始。

Python 不是 failure。

应该首先定义真正重要的观测量,例如:

  • task success;
  • patch correctness;
  • token usage;
  • tool-call count;
  • latency;
  • invalid-action rate;
  • recovery rate;
  • 不必要的 shell complexity;
  • approval 和 sandbox surface。

然后比较受控的 harness configuration,例如:

A. current Codex tool surface

B. current surface
   + improved tool guidance

C. current surface
   + stock apply_patch

D. current surface
   + read_file

E. current surface
   + read_file / list_dir / grep_files

如果实验结果是:

A  61%
B  62%
C  69%
D  69%
E  72%

那么 ergonomic specialization 有明确价值。

如果结果只是:

A  61%
E  62%

而维护成本和 tool surface 明显扩大,那么 Python invocation 从 80% 降低到 10% 本身并没有足够工程价值。

工具调用变得“更漂亮”,不等于 agent 变得更强。

为什么 apply_patch 是一个更合适的早期实验

在当前 Grok × Codex 的具体实现里,我会优先研究 apply_patch,而不是立即增加完整的 read_file / list_dir / grep_files 工具组。

原因首先是架构成本。

Codex 已经拥有 stock ApplyPatchHandler,只是当前 Grok catalog 没有启用对应的 apply_patch_tool_type

因此,验证 Grok 是否可以通过现有 reversible tool projection 正确使用 stock apply_patch,是一个比增加全新工具集合更窄的实验。

其次,structured tool 还有一个 Model ergonomics 之外的价值:它保留 semantic intent。

当模型调用:

apply_patch

时,harness 知道模型正在修改文件。

当模型调用:

exec_command("python3 ...")

修改文件时,所有语义都隐藏进 arbitrary code execution。

前一种形式更容易支持 sandbox、approval、tracing、telemetry、replay 和 failure classification。

所以 structured tool 的价值不能只通过“模型是否更喜欢调用它”衡量。

它还可能提高整个 harness 对 agent action 的可理解程度。

如果最终需要文件工具,也不应该复制另一套 runtime

假设 benchmark 最终证明 Grok 确实明显受益于 read_filelist_dirgrep_files

这仍然不意味着应该把 GrokBuild 的整个工具运行时移植进 Codex。

Codex 已经允许 extension tools 进入同一个 ToolRegistry 和 ToolRouter。11

因此,更合理的结构应该是:

model-facing compatibility tool

Codex extension adapter

stock filesystem / sandbox context

stock ToolRouter

模型获得自己更容易使用的 action vocabulary,而系统继续保持:

one history
one router
one sandbox
one execution authority

这正是 generalized semantic harness 与 specialized Model ergonomics 可以同时成立的关键。

语义通用,交互可特化

最终,我认为 generalized harness 和 specialized harness 之间真正有价值的边界,可以压缩成一句话:

Semantic 上尽可能 generalized,ergonomic 上允许经过测量的 specialization。

对应的系统结构是:

Generalized Semantic Harness
        +
Thin Provider Compatibility Layer
        +
Measured Model Ergonomic Profiles

第一层阻止系统随着模型数量增加而不断分裂。

第二层处理不同 backend 真实存在的协议差异。

第三层承认一个越来越明显的事实:不同模型并不是完全相同的“API 消费者”。

它们可能有不同的工具选择习惯、context tolerance、action granularity、recovery pattern 和 execution bias。

一个成熟的 harness 不应该假装这些差异不存在。

但它也不应该因为这些差异,为每一个模型重新实现一套 agent runtime。

真正困难、也真正体现 harness engineering 水平的地方,是保持统一 semantics、安全边界和 execution authority,同时允许 interface 根据模型的实际行为进行有限而可验证的调整。

过去,我们首先关心的是:

Can the model run?

后来变成:

Can the model use tools?

再后来是:

Can the model finish long-horizon tasks reliably?

Model ergonomics 再向前推进了一步:

Does this harness allow this model
to use its capabilities efficiently and reliably?

这可能会成为评价 agent harness 的一个基础维度。

模型决定 agent 能力的潜在边界,而 harness 决定这些能力能够以什么方式、以多大比例变成可靠的现实行为。

真正需要优化的,从来都不只是模型。

而是整个 model-harness system。

Footnotes

  1. John Yang et al., SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering, 2024.

  2. Yilun Yao et al., Harness-Bench: Measuring Harness Effects across Models in Realistic Agent Workflows, 2026.

  3. 本文 Grok × Codex 案例基于 Harness-X-Harness/codexrelease/rust-v0.151.0 分支。其中 Grok Provider 负责 request projection、Responses dialect 和 flat-function projection 等 Provider-specific adaptation。

  4. grok_catalog.rs 中当前 Grok 4.6 catalog 配置 shell_type: UnifiedExecapply_patch_tool_type: Nonetool_mode: None

  5. spec_plan.rs 中,Unified Exec 注册 ExecCommandHandlerWriteStdinHandlerApplyPatchHandler 只有在 model_info.apply_patch_tool_type.is_some() 时注册。

  6. xAI GrokBuild 的 implementations/codex 模块包含 apply_patchgrep_fileslist_dirread_file,源码将其描述为从 Codex port 并修改的 Codex-specific tool implementations。

  7. GrokBuild 的 ToolConfig 支持 name_overrideparams_name_overridesdescription_override,将内部工具身份与 client-facing presentation 分开。

  8. Codex Third-Party Provider North Star 将目标定义为保留 stock Codex harness,只把经过验证的 backend API differences 放在 Provider projection 边界。

  9. Sydney Lewis, Same Model, Different Harness: Different Coding-Agent Results, 2026. 该工作在本文写作时仍属于较新的预印本,因此这里主要引用其研究问题和实验设计,而不把单篇结果视为最终定论。

  10. Self-Harness: Harnesses That Improve Themselves, 2026.

  11. 当前 Codex spec_plan.rs 会把 core tools、MCP tools、extension tools 和 dynamic tools 汇入同一个 ToolRegistry,再构造统一的 ToolRouter。这为增加 model-facing compatibility tools 而不复制执行 runtime 提供了现成边界。