大语言模型本身是一个无状态函数:文本进、文本出。它无法打开文件、跑测试、记住昨天,或在看到错误后再尝试一次。一切让模型感觉像智能体(agent)的东西——读你的仓库、编辑文件、跑命令、从错误恢复——都活在包裹模型的软件里。那个软件是harness(运行外壳),把它做好是它自己的学科:harness 工程。随着前沿模型在原始能力上收敛,harness 越来越是编码工具胜负所在。本篇是 AI 编码智能体如何工作 的姊妹篇——那篇解释智能体;这篇关于工程化运行它的脚手架。

⚡ 速览要点
  • 模型是引擎;harness 是车。模型推理;harness 给它感官(上下文)、手(工具)、一个循环、记忆、护栏,和检查自己工作的方式。
  • 上下文组装是杠杆最高的活——决定什么进入有限上下文窗口比稍大的模型更决定输出质量。"上下文工程"已超越提示工程。
  • 智能体循环是心脏——构建提示 → 调模型 → 跑它的工具调用 → 把结果喂回 → 重复直到完成或预算耗尽。
  • 工具是你设计的 API——清晰 schema、好描述、合适粒度,和模型能从中恢复的错误消息。
  • 验证闭合循环——跑测试/linter/构建并把失败喂回,是把一次性生成器变成迭代纠正的智能体的东西。
  • harness 经验性调优——你需要 eval、轨迹分析和步数/成本预算,因为小的 harness 变化大幅摆动真实成功率。
  • 能力 ≈ 模型 × harness。较小模型上的好 harness 常胜过差 harness 上的好模型。
tldr

harness 是模型周围所有工程:智能体循环、上下文组装、工具定义、记忆/压实、权限和沙箱,以及环境锚定的验证。模型供应推理;harness 供应让那个推理可行动且可靠的一切。因为模型在商品化,harness 质量——尤其它多好地组装上下文和验证工作——现在是 AI 编码工具间的主要差异。

什么是 Harness?

在任何 AI 编码工具的两部分间划一条硬线有帮助。模型是一个前沿 LLM(Claude、GPT、Gemini):它接收一块文本并产生一块文本,无记忆、无行动能力。harness 是它周围使它有用的程序——它组装输入、解释输出、执行模型请求的任何动作,并循环。Claude Code、Cursor、Devin、OpenHands 和 Aider 全是同一小撮模型上的 harness;它们的差异几乎全是 harness 差异。

模型做harness 做
推理与语言组装被推理的上下文
决定调哪个工具定义工具并实际执行它们
产生文本/diff应用编辑、跑命令、解析输出
无状态持有记忆、历史和循环
无"安全"概念强制权限、沙箱、护栏

实际后果:大部分工程努力——和产品大部分质量——在 harness,而非你调的模型。

智能体循环

核心上,harness 是一个循环。模型被调用,若它要求用一个工具,harness 跑那个工具、把结果追加到对话,并再次调模型——重复直到模型产生最终答案或 harness 撞上预算。这一个循环就是把一次性文本预测器转成探索、行动和迭代的东西。

the agent loop — the heart of a harness
state = [system_prompt, tools, user_goal]
steps = 0
while not done and steps < budget:
    reply = model(state)              # 唯一一次对 LLM 的调用
    if reply.tool_calls:
        for call in reply.tool_calls:
            result = execute(call)     # harness 行动: 读文件、跑命令、grep…
            state.append(result)      # 观测回到上下文
    else:
        done = True                  # 模型给了最终答案
    state = compact(state)           # 保持在上下文窗口内
    steps += 1

注意多少是 harness 的责任:选预算、安全执行工具、决定什么算"完成",和压实状态。模型只见到 state 并发出下一步——循环及其中一切都是工程。

上下文组装:杠杆最高的活

模型只能推理它上下文窗口里的东西,而那是有限的。harness 最重要的单一工作是决定每轮什么进那个窗口——系统提示、工具定义、从仓库拉的正确文件、先前工具结果,和对话历史。把正确代码摆到模型面前,平庸模型也发光;搞错,最好的模型也幻觉。这就是为什么领域重心从提示工程移到上下文工程

budgeting a finite context window
上下文窗口(比如 200K tokens)
├─ 系统提示 + 工具定义 ............  ~5K    固定开销
├─ 检索的文件 / RAG ...............  ~40K   ◀ 高杠杆切片
├─ 对话 + 工具结果 ................  每轮增长
└─ 为输出保留的余量 ...............  ~8K
        填满时 → 总结 / 丢弃 / 压实较旧的轮次
提示工程上下文工程
把指令措辞好选择模型看到什么信息
一个提示,大体静态每轮动态——检索、修剪、排序
"我怎么问?""它面前需要什么才能回答?"

具体地,harness 做检索(找相关文件/符号,按索引或让模型按需 grep)、排序(把最相关的放前面),和修剪(丢弃或总结不再要紧的)。当一个智能体"忽略"一个明显的文件,几乎总是上下文组装 bug,而非推理失败。

工具设计

工具是智能体的手,harness 定义它们——它们的名字、schema、描述和行为(见工具使用、函数调用与 MCP)。好的工具设计是真正的 API 设计,带个转折:消费者是模型,所以描述是接口的一部分——它是模型决定何时及如何调用工具的方式。

a tool definition the model can use well
{
  "name": "run_tests",
  "description": "Run the project's test suite and return pass/fail"
                 " plus failing-test output. Use after editing code to"
                 " verify changes.",
  "input_schema": {
    "type": "object",
    "properties": { "path": {"type": "string", "description": "dir to test"} }
  }
}

使工具好用的原则:合适粒度(几个可组合工具胜过几十个超特定的)、清晰描述(模型只知道你告诉它的)、安全默认(破坏性工具应需显式确认),且关键地——可恢复错误:失败的工具应返回模型能读并行动的消息("文件未找到:你是指 X 吗?"),而非不透明的堆栈跟踪。错误文本是循环反馈的一部分。

记忆与状态

模型无状态,所以 harness 拥有记忆。有两层。短期记忆是对话/上下文窗口本身——目标、动作和观测的运行记录。长期记忆住在窗口外:一个 scratchpad 或笔记文件、一个 harness 每会话注入的项目指令文件,或一个智能体能查询的外部存储。难问题是短期层填满:一个长任务累积工具结果直到威胁窗口。harness 用压实(compaction)处理这个——总结或丢弃较旧轮次而保留目标和关键事实——使智能体能在比任何单个上下文窗口更长的任务上持续工作。

护栏、权限与安全

模型无"危险"概念。harness 是安全被强制的地方,因为 harness 是实际执行动作的东西。这层包括风险操作前的权限提示、命令的 allowlist/denylist、沙箱(sandboxing)(在受限环境跑工具调用,使智能体碰不到它不该碰的),和拦截动作以应用策略的 hook。一个工程良好的 harness 安全失败:当一个动作不可逆或对外时,它暂停确认而非信任模型的判断。这也是你阻止恶意文件的提示注入变成破坏性命令的地方。

关键点

安全不能住在模型——模型只发出一个行动请求。harness 决定是否兑现它。这就是为什么权限、沙箱和确认门是 harness 特性,以及为什么"模型不会那样做"从不是安全论证。

验证与自我纠正

最把真智能体与花哨自动补全分开的特性是验证:harness 跑代码、测试、linter 或构建,并把结果喂回循环。这把智能体锚定在环境而非它自己(可能错的)代码正确的信念。一个失败的测试成为模型推理并修复的观测——闭合一个模型独自无法闭合的循环。

verification turns one-shot output into iteration
模型编辑代码
      │
      ▼
harness 跑测试  ──▶ 失败?  ──是──▶ 把错误喂回 ──▶ 模型修复 ──┐
      │                                                       │
      └────────────────────────◀──────────────────────── 循环 ┘
                              否
      ▼
   完成 — 由环境验证,而非模型的一面之词

这个循环的质量取决于 harness 选择:跑什么、如何简洁地呈现失败(一个 5,000 行测试日志必须被修剪到要紧的部分),和何时停。带好验证的 harness 能让较弱模型磨到正确答案;没有它,即便强模型也自信地发布坏代码。

错误处理与恢复

智能体以一次性调用不会的方式失败,harness 必须预期它们:一个工具抛错、模型为一个工具调用发出畸形 JSON、一个命令挂起,或智能体卡在重复同一失败动作。健壮的 harness 加重试(带错误喂回使模型能调整)、工具执行的超时循环检测(注意同一动作重复并跳出),和硬步数/成本预算使困惑的智能体不能烧无限 token。设计这些恢复路径是生产 harness 难的很大一部分原因。

评估与迭代

你无法仅凭直觉改进 harness,因为小变化——调过的工具描述、不同的压实策略、重排上下文——大幅摆动真实成功率。严肃的 harness 工作是经验性的:对基准任务跑一个 eval harness(如 SWE-bench 式的"修这个真实 bug"套件)、测量成功率、延迟和成本,并检查轨迹(trajectory)(完整步骤序列)以看运行在哪出错。然后改一件事并重测。harness 是一个你对照数据调优的系统,而非你写一次的提示。

子智能体与编排

随任务增长,单个智能体的上下文变杂乱。一个常见 harness 模式是子智能体(sub-agent):主智能体把一个限定范围的活(搜索代码库、评审一个 diff)委托给一个有自己干净上下文的全新智能体,它只返回一个结论。这让主上下文聚焦、支持并行工作,并约束任何一个上下文窗口必须持有多少。编排——决定如何拆分工作、并行跑智能体、组合结果——是大任务越来越重要的 harness 能力。

为什么 harness 与模型一样重要

harness 工程的论点:有效能力 ≈ 模型 × harness。同一模型,放进更好的 harness,正确完成更多任务——因为 harness 控制模型看到什么(上下文)、它能做什么(工具)、它是否抓住自己的错误(验证),和它是否保持安全和在预算内(护栏)。随前沿模型收敛,这些因素而非原始模型 IQ 越来越决定哪个编码工具真正完成活。这就是为什么"上下文组装胜过更大模型"是反复的教训,以及为什么 harness 工程已成为它自己的学科。

总结

LLM 是一个聪明但盲、失忆、被绑手的推理者。harness 给它眼睛(上下文)、手(工具)、记忆、反射(验证和恢复)和良知(护栏)——并把它们接进一个循环。把那个脚手架做好,一个普通模型成为有能力的智能体;做差,世界上最好的模型也乱抓。harness 越来越就是产品。

🎯 面试速答

什么是"harness"?使 LLM 成为智能体的、模型周围的软件:循环、上下文组装、工具执行、记忆、护栏和验证。Claude Code 和 Cursor 是同一些模型上的 harness。
为什么上下文工程胜过提示工程?窗口有限;把正确代码摆到模型面前比措辞或稍大模型更决定输出质量。
什么把一次性生成变成智能体?循环加环境锚定的验证——跑测试/构建并把失败喂回,使模型迭代到一个正确、已检查的答案。
安全住在哪?在 harness,不在模型——模型只请求动作;权限、沙箱和确认门决定是否执行它们。
模型 vs harness——哪个更重要?两者;能力 ≈ 模型 × harness。随模型收敛,harness 质量是主要差异。

← 上一篇
工具使用、函数调用与 MCP