一声棒喝,本不立文字
偏要著録,已是二义

baseten

Harness 是一切:如何优化你的 Harness

Harnesses are everything. Here's how to optimize yours.

二〇二六年五月九日 · 英文原文

文章总结 AI coding harness 的使用方法,涉及 Roo Code、DeepAgent CLI、HumanLayer 等。内容包括精简 CLAUDE.md/AGENTS.md、用 progressive disclosure 管理 CLI、Skill 与 MCP tool context,采用 HumanLayer R.P.I. framework 分离 Research、Plan、Implement,并用 subagent 的 parallel fan-out 与 pipeline 保持主 context window 简洁。

工程师过去争论 IDE。现在我们争论 harness。

我一直在使用并参与开源 harness(Roo CodeDeepAgent CLIHumanLayer),这是我希望第一天就知道的事:你现在就可以做三件事,让你的 harness 输出与 slop 正交。但这三件事仍然都需要人的判断。

本指南介绍这些简单的操作面,它们区分了两类 harness:一类会放大你的产出,另一类会放大你的错误。内容包括:如何让 config 文件保持精简、足以推理;如何使用 R.P.I. framework 来组织 prompt,让模型像 staff engineer 一样处理问题;以及如何使用 subagent 保持主 context window 干净。

图 1:最大化 harness 使用体验的 3 个通用好模式最大化 harness 使用体验的 3 个通用好模式

读完之后,你会得到一组今天就能应用到现有 setup 的具体改动,也会更清楚地理解:真正体现工程判断力的地方,不只是模型本身,还有 harness。

如果说模型是智能的来源,那么 harness 就是让这种智能变得有用的东西。harness 的主要职责是作为脚手架:

  1. 通过 session 和 compression,在本质上 stateless 的 LLM 中管理 context

  2. 围绕模型,让 tool call、I/O processing、guardrail 等功能正常工作。

可以把 harness 理解成一个 while (have next message) do {tool} 循环。一个顺手的 harness 会从此以后放大你生成所有代码的速度和质量。

图 2:harness 的简化结构harness 的简化结构

让你的 .md 文件保持精简,并由人来写

今天 agent 的核心短板是“instruction budget”这个概念。转述 HumanLayer 的 Kyle 的说法,frontier thinking LLM 在进入“dumb zone”之前,只能遵循几百条 instruction;进入这个区域后,它会开始在冗余内容中漏掉相关 instruction。给出过多 instruction,实际上是在鼓励模型 hallucinate。

对于全局 system prompt——CLAUDE.mdAGENTS.md——人工编写优于 LLM 生成。ETH 的研究发现,LLM 生成的 system prompt 会降低性能,同时让 inference 成本增加约 20%。只描述最低限度的要求:这个项目是什么,最终用户是谁。每个 token 都应该有充分理由存在,因为它会在每个 session 中被全局注入。

人的直觉往往是把模型可能需要的一切都提前塞进去,并尽可能详细地规定 if-else 规则;但直接解析长 context 会消耗 context window 中宝贵的空间,迫使 reasoning window 缩小。

相反,应使用 progressive disclosure:只在需要时让 agent 拉取 context,并通过给各个 .md 文件起描述性名称,让它知道有哪些内容存在。下面看看它在三种常见 interface 中如何体现。

CLI

工程师其实早就在 CLI 中使用 progressive disclosure,只是没有这样命名。你运行 --help 查看可用的 subcommand,然后进入某个特定 subcommand 的 --help 查看它的 flag。agent 也可以这样做。

这对模型从未见过的 CLI 最重要——一个封装你们 API 的内部自定义工具没有任何训练数据。没有 progressive disclosure,你就需要把整份 reference 粘贴进 context。有了它,agent 会运行 mycli --help,找到相关 subcommand,然后运行 mycli deploy --help 获取具体 flag。模型会按需发现该工具的 command,就像你自己会做的那样,同时 context 仍然保持干净。

kubectlgh 这样的流行工具并不能很好地说明这一点,因为模型已经从训练数据中知道它们的 interface。真正的测试是公司外部没人用过的 CLI。这也让 CLI 成为 CLAUDE.mdAGENTS.md 最干净的用法之一。与其用行为规则膨胀这些文件,不如用几行文字记录如何调用模型没有训练过的 CLI。例如,uv 正在快速普及,但模型仍然会搞错它的 flag 和 subcommand。一句简短的话,比如“使用 uv 管理 Python package;在假定语法之前,先运行 uv --help 发现 subcommand”,就能给 agent 一个入口点,而不必把完整 reference 浪费在 context 中。

Skill

这是行业已经趋同的地方。Claude Code、Codex 和 OpenCode 都以相同方式为 skill 实现 progressive disclosure:启动时,只有每个 skill 的名称和描述被加载进 context。只有当 agent 判断某个 skill 与当前任务相关时,完整的 SKILL.md instruction 才会被读取。skill 可以指向 reference file 或 script,而这些内容也只会在需要时加载。写清楚、具体的描述,agent 就可以在不读取正文的情况下完成匹配。Codex 自己的文档明确称其为 progressive disclosure,并认为这是保持 context 干净的核心。对工程师而言,这具体意味着:在代码库中用清晰的命名约定,把特定 instruction(skill)维护在独立文件里,让 agent 可以根据请求检索它们。

MCP tool

这是 harness 之间差异很大的地方。

Claude Code 内置 MCP tool search:session 开始时,它加载一个轻量级的 tool name 索引,然后按需搜索并拉取完整 schema——Anthropic 报告称这让 context 使用量减少了 85% 以上。Codex 和 OpenCode 会在 session 开始时把所有已配置的 MCP tool definition 加载进 context。OpenCode 的文档明确提醒用户限制启用的 server 数量,因为 context 很快就会被填满。

如果你的 harness 没有替你处理这件事,就自己管理:按项目选择性连接 MCP server,并编写具体且包含关键字的 tool description,让任何基于搜索的 discovery 真正可用。另一方面,也要确保断开无关或未使用的 MCP,以节省 context 和 inference token。

图 3:3 种流行 harness 之间的差异

使用 R.P.I. 在更高抽象层工作

有了精简的 config 文件和最小化的 toolset,下一步决定是如何组织 prompt。HumanLayer 的 R.P.I. framework 是一个有用的准则;与 harness 交互时,每个 prompt 都应该只做以下三件事之一:

  1. Research:如果代码库独特且复杂,把问题陈述交给 agent,让它探索结构,包括 prior art、function definition,以及文件之间如何相互关联。重要的是,这一步不要采取任何行动。

  2. Plan:agent 写出逐步执行计划。人应该主动 review 并验证生成计划的有效性,基于你对代码库的上下文和领域知识。在这一步外包思考或偷懒,之后会付出很高代价。

  3. Implement:在一个新的 context window 中执行已批准的计划,我们可以把它称为主窗口。这是你的 stack 底层。如果计划很长、让人有压力,我们建议使用 subagent 模式:每个 subagent 都在自己的 session 中运行,这样某个 subtask 的无关中间状态和迭代思考就不会污染主 context window。

操作 harness 会让它以优秀 staff engineer 处理问题的方式行事:把问题拆成子问题,先计划再实现,并让另一双眼睛审视计划。抽象层已经从逐行代码转移到 prompt,但底层纪律并没有改变。

使用 subagent 维护干净的 context

subagent 的核心 heuristic 很简单:当一份工作只需要摘要就足够供主 agent 使用时,就使用 subagent。如果你需要中间 context——如果你之后会想问“这和我之前看的内容如何关联”——就把它留在主窗口中。主 agent 只应该委派那些自己不需要推理其中间步骤的工作。例如,可以委派给 subagent 的任务是一系列 tool execution(如 retrieval),主 context window 不需要了解这些过程,只有最终结果重要。subagent 能保持主对话干净,同时让 subagent 处在“smart zone”中,不会被无关的早期消息干扰。

subagent 有两种效果不错的模式:parallel fan-out 和 pipeline。

图 4:harness subagent 的 2 种模式harness subagent 的 2 种模式

Parallel fan-out

这最适合 investigation 和 research。

当 alert 触发时,你的 agent 可以研究问题,生成三个关于 root cause 的候选理论,然后为每个理论启动一个 subagent 同时调查。每个 subagent 独立深入 logs、traces 和 metrics。主 agent 收到三个 summary 并综合得出结论,而自己的 context 中从来不需要放入数百行 log。

价值在于速度和 context 隔离:三次并行搜索比三次顺序搜索更快,噪声也被限制在各自范围内。gpt-oss-120b 发布时,我们之前在 Baseten 构建过一个初步版本(这里)。当你想同时获得多个模型的输出时,同样的模式也适用,例如启动一个 MiniMax M2.5 线程和一个 GLM-5 线程。

Pipeline

pipeline 在 fan-out 探索广度的地方强制深度。

把一个 feature 按顺序交给不同角色:评估用户体验的 UX designer、评估技术可行性的 architect、对假设进行压力测试的 devil's advocate。每个阶段接收上一阶段的输出并补充分析。主 agent 得到一个分层、多视角的评估,而不需要一次性在 context 中持有这三种视角。

这对 LLM 这类 non-deterministic system 尤其有益。在此基础上,你还可以使用 frontier model 作为 judge 来整合响应,并以更高置信度确保达到期望行为。

图 5:Claude Code vs. Codex CLI vs. OpenCode

要点:坚持投入

当某个 harness 在任务上失败时,人很容易想切换 harness。我们并不是说不要尝试各种 setup,从 Cursor、Claude Code、OpenCode、Codex 到 Deep Agent CLI;我们只是说,你需要投入时间,把其中一个真正塑造成适合你 workflow 的工具。不同 harness 有不同约束、context window 策略和 tool routing 逻辑;不断切换意味着你会丢失编码在 config 文件中的机构知识,并且每次都要从零开始积累 failure-case log。

所以我们的建议是,选择能覆盖团队大多数 use case 的 harness(后续文章会介绍如何选择 harness),并把每次失败都当作一个 data point:哪里坏了,发生在哪一步,在什么条件下发生。把这些加入你的 .md 文件,并相应调整 prompting 策略。最好的 harness,是经过你用人的工程能力自定义并持续迭代的 harness;它能处理那些在团队使用过程中被逐渐打磨平滑的 edge case。

译自 baseten · 录于 二〇二六年五月九日