Model-Harness-Fit
核心论点:模型的后训练是针对特定 harness 进行的——工具名称、输入 schema、citation 标签、memory ritual、system prompt 结构——这些不是模型的通用能力,而是 baked into post-training 的字节级约定。把模型从它的 harness 里抽出来,性能会退化,因为模型的"本能"只在特定 harness 呈现特定世界时才触发。
"The harness is no longer a wrapper around the model. The harness is part of the model's effective parameters." — Nicolas Bustamante
实证:Terminal-Bench 2.0
| 配置 | 得分 | 差异 |
|---|---|---|
| Claude Opus 4.6 + ForgeCode | 79.8% | — |
| Claude Opus 4.6 + Capy | 75.3% | -4.5pp(同一模型,不同 harness) |
| Opus 4.6 + Meta-Harness (Stanford IRIS) | 76.4% | 第三方 harness 超越原生 |
- ForgeCode(第三方 harness)占据 top 6 中的 3 席,通过跨模型家族路由
- Cursor:仅改 harness,从 Top 30 跃升至 Top 5
- LangChain Vivek Trivedy:"Opus 4.6 in Claude Code scores far below Opus 4.6 in other harnesses"
结论:固定模型、切换 harness,pass rate 的变化幅度超过一代模型升级。Harness 在移动分数,比模型升级移动得更多。
三个 Harness,三种协议
这不是同一想法的三种实现,而是模型与运行时之间的三种不同契约:
| Harness | 协议 | 模型被训练来 |
|---|---|---|
| Codex | 类型化异步:Submission → Event stream。两层协议(agent + JSON RPC v2,10,721 行) | 发送 Submission,消费 Event |
| Claude Code | 直接类型化对话循环:每轮 Vec<AssistantEvent> |
在 assistant message 内发送 tool call |
| Copilot CLI | Supervisor:host 启动子进程,stdio 上 JSON RPC | 在 supervisor 内运行,发送 JSON RPC 事件 |
工具面:后训练最可见的地方
每个 harness 都有工具注册表。前六个工具名称相似(read/write/bash/grep/glob),之后全面分化:
Codex 独有
apply_patch(自定义 Lark 语法,JSON 变体)local_shell+exec_command_tool+write_stdin_tool(长生命周期进程)- 8 动词子 agent 面(spawn/send_message/wait/close/resume × v1/v2)
request_permissions_tool、goal_tool、tool_search/tool_suggest
Claude Code 独有
Edit(old_string/new_string)(非 Codex 的 apply_patch)Bash含最深沙盒面(run_in_background、dangerouslyDisableSandbox、namespaceRestrictions)Skill/ToolSearch(延迟加载原语)Agent(单工具子 agent 派发,非 8 动词)EnterPlanMode/ExitPlanMode、EnterWorktree/ExitWorktreeMonitor(与Bash run_in_background: true配对)
Copilot CLI 独有
apply_patch仅在 Codex 家族模型时包含read_bash/write_bash/stop_bash(三动词交互式 shell)task(子 agent,含深度和并发限制)store_memory(远程后端,非本地文件)
Cursor 团队:"OpenAI 的模型被训练用 patch-based 格式编辑文件,Anthropic 的模型被训练用 string replacement。任一模型都能用任一工具,但给它不熟悉的工具会消耗额外推理 token 并产生更多错误。"这是从数百万次 agent 轮次中以生产规模记录的具体可测量成本。
Skills 携带隐式工具契约
SKILL.md 的 YAML frontmatter 在各 harness 间看起来可互换,但 skill body 里命名的具体工具(Agent、TodoWrite、Skill、apply_patch)是 harness-specific 的契约。一个假设"你会在 system reminder 中看到所有 skills"的 skill body,在 harness 通过 embedding 排序只注入前三个时行为不同。
"我们都在用 SKILL.md"是误导。格式相同,底层契约不同。
Memory 层:最密集的碰撞面
| 维度 | Codex | Claude Code | Copilot CLI |
|---|---|---|---|
| Memory 写入 | Phase 1 JSON schema(841 行 prompt,严格验证) | Write/Edit 到 ~/.claude/projects/ |
store_memory 工具 → 远程后端 |
| Citation | <oai-mem-citation> → SQLite usage_count bump |
无 citation tag;verification grep 兼作信号 | 服务端追踪 |
| 检索 | Phase 2 consolidator 按 usage_count 排序 | 始终加载的索引 + <system-reminder> wrapper(含 age-in-days) |
服务端关键词搜索 |
跨 harness 后果:
- Codex 模型跑在 Claude Code 上 → 写入 Codex 格式的 memory,Claude Code 从不自动加载 → memory 在下次会话中不存在
- Claude 模型跑在 Codex 上 → 从不发送
<oai-mem-citation>→ decay 信号停止 → 数周内错误记忆被驱逐 - 任一模型跑在 Copilot CLI 上 → 本地文件本能无法迁移 →
store_memory是唯一路径
Mid-Chat Model Switching:最干净的失败演示
切换模型时三件事同时崩溃:
- Transcript out of distribution:先前模型的 tool call 对新建模来说是陌生词汇
- Prompt cache 全清:一次切换 = 全部 system prompt 和对话历史的原价重入
- 工具面变化:先前工具失效,新模型有不同的工具集
Cursor 的建议:用不同模型 spawn subagent,而非切换主对话。Subagent 从新鲜上下文窗口开始,无 transcript 偏差,无 cache 可破坏,从第一轮就是新模型的原生工具面。
GitHub Copilot CLI 的路由策略:诚实做法
- 每模型工具包含:
apply_patch仅对 Codex 家族模型暴露;Anthropic 模型获得它们训练时用的 Edit/Write 形态 - 每模型工具搜索:
ToolSearch仅对 Claude 模型暴露 - 互补模型 Critic agent:critic 使用与主 agent 不同的模型
"这不是'翻译成通用方言',而是'给每个模型提供正确的方言'。"
Identity File Convention
文件名已是线格式的一部分:
CLAUDE.md→ Claude Code 识别AGENTS.md→ Codex 识别SOUL.md→ 尚未被任何主要 harness 的默认 loader 识别;需要手动在 CLAUDE.md 中架桥
一个被训练来寻找
# auto memory下MEMORY.md的模型会搜寻这个精确标题。针对AGENTS.md训练的模型会寻找AGENTS.md而忽略CLAUDE.md。
实验室的共识
- Cursor(Stefan Heule, Jediah Katz):在一次聚焦冲刺中将意外 tool call 错误降低一个数量级。"Tool call 可靠性不是模型属性,是 harness 属性。"
- Anthropic(@rgb_prithvi):为 Sonnet 4.5 的"context anxiety"构建的上下文重置机制,在 Opus 4.6 上成为死重。"每个 harness 组件编码了关于模型不能独立做什么的假设。这些假设会过期。"
- LangChain(Vivek Trivedy):"Agent = Model + Harness。如果你不是模型,你就是 harness。"协同进化反馈循环:harness 原语 → agent 追踪 → 训练数据 → 下一代模型的本能。
实践含义
对平台构建者
选一个 harness,选一个模型,将它们作为一个配对发布。不要假装模型是可移植的,不要假装 harness 是中立的。
对模型实验室
Harness 是产品战略,不是基础设施。Anthropic 的 <system-reminder> 注入模型、类型化记忆分类法、每次 body 读取的验证——这些不是基础设施选择,而是模型被塑造的表面,是让模型变得不可替代的护城河。
对用户
切换成本比你想象的高(模型和 harness 在数月的训练中融合),也比供应商希望你相信的低(诚实的移植——复制工具面、citation 契约、system prompt 结构、memory ritual——可以弥补大部分差距)。成本等同于原始后训练的投入。
匹配对不是静态的
随着模型成熟,正确的 harness 会变化。Sonnet 4.5 需要上下文重置、sprint 分解、激进压缩;Opus 4.6 原生完成了这些工作。纪律:阅读追踪数据,识别哪些组件仍在发挥作用,淘汰那些已成为已解决问题补丁的组件。
"2026 年的前沿工作不是新的模型架构,而是新的 harness 原语。" — Ralph Loops、即时 harness 组装、自追踪 agent。
SOUL.md in Practice: SBTI Agent Packs
来源:Vox — 27 OpenClaw Agent Packs
SBTI(中国互联网病毒式传播的反-MBTI 测试)提供了 SOUL.md 的实战验证:27 种人格类型,每种都带有口头禅、本能反应和标志性动作。Vox 将每种类型打包为 OpenClaw agent pack(IDENTITY + SOUL + AGENTS + USER + README)。
同一模型,同一任务,不同 SOUL.md——结果在"本能反应"层面不同,而非措辞层面:
- CTRL(掌控者):"三件事。9 点的 sync 挪到 11 点。9 点你在写文章,中途打断你会暴躁。下一个会留半小时缓冲。晚上的 retro 跳过,今天没什么值得总结的。去吃饭。"
- MALO(吗喽/打工仔):"瞥了眼你明天的日历。三个会。我的看法:都没必要。但既然你坚持,我排好了。早上的别太拼,大家都在装。中午那个有免费饭,去就行。晚上的……能跳吗?我困了。"
"SOUL.md 不给 agent 加载知识,它加载的是响应模式。"
SBTI 的成功验证了 Identity File Convention 的核心观点:文件名(SOUL.md)是线格式的一部分,但更重要的是——人格的具体性(口头禅、本能反应、标志性动作)远比抽象维度(内向/外向/直觉/感知)更能塑造 agent 的可感知行为。所有 27 个 pack 可移植到 Claude Code、Codex、Hermes 或 ChatGPT——方法相同,只有文件名约定因 harness 而异。
Evidence across sources
| Source | Key claim |
|---|---|
| Model-Harness-Fit | 三个 harness 的逐层对比(工具面、memory、citation、system prompt、skills),Terminal-Bench 2.0 实证 |
| SBTI Agent Packs | SOUL.md 的实战验证:同一模型+不同 SOUL = 不同本能反应;人格具体性 > 抽象维度 |
| What is an Agent Harness? | "同样的模型仅通过改变 Harness 就可以从 top 30 以外提升到 top 5" |
| Agent Memory vs Context Substrate | 64 条 Claude Code 记忆放入 Codex 文件夹,bytes 落地但行为不同 |
| Cursor Research (2026-04-30) | "OpenAI 模型用 patch-based,Anthropic 模型用 string replacement" |
Prompts for witness
- 我们在 taste-harness 中写的 SKILL.md body 里的工具指令(
Agent、TodoWrite、Skill),如果将来想移植到 Codex,需要重写哪些部分? - Claude Code 的 memory ritual(
Write到~/.claude/projects/+<system-reminder>wrapper)和 Codex 的两阶段 pipeline —— taste-harness 应该偏好哪一个? - "删除大部分代码"的纪律:taste-harness 当前有哪些 scaffolding 可能在 Claude 模型升级后成为死重?
- SBTI 的 27 种人格中,哪一种最接近你希望 taste-harness agent 具备的"品味本能"?CTRL(高度自主决策)还是 THIN-K(信息纯度偏执)?