先说结论:Harness 是 AI Agent 的"挽具"
一句话定义:Agent = 模型 + Harness。大模型只会做一件事——把文字变成文字;而 Harness 是包在模型外面、让它能真正干活的那层运行时工程:提示词、工具、循环、上下文管理、权限、重试、沙盒。模型负责想,Harness 负责让想法落地并安全地把结果喂回来。
这层"外包装"有多重要?普林斯顿 2024 年的 SWE-agent 做过一个对照实验:同一个 GPT-4 模型,零微调、零提示词魔法,只把外围接口重新设计一遍,解决真实 GitHub issue 的成功率从 3.8% 涨到 12.5%——3 倍多的提升,全来自 Harness。反过来那句名言同样成立:一个平庸的模型配上优秀的 Harness,能打赢一个优秀模型配上糟糕的 Harness。
你其实天天在用 Harness 而可能没意识到:Claude Code、Codex CLI、Gemini CLI、ZCode 这些"AI 编程工具",本质都不是模型,而是模型外面那套 Harness。同一家实验室的模型,装进不同 Harness 里表现天差地别——差别不在智力,在缰绳。2026 年,调教这套缰绳已经成了有名字的学科:Harness Engineering(挽具工程)。
这篇从词源讲起,过一遍 60 年发展史,拆开看它的构成,再带你用 60 行代码亲手写一个最小的 Harness,最后给一份可直接照抄的实践清单。
起源:一个 700 岁的词,三次转行
Harness 的词源本身就是一条完整的隐喻链。
第一世:马具。 这个词 1300 年前后从古法语 harneis 进入英语,最初指盔甲和兵械,14 世纪初转指役畜的挽具——把马拴到车上、把马的蛮力传导成可控拉力的那套绳套和皮带。1690 年代有了比喻义:harness a force,驾驭一股力量。核心意象从那时就没变过:把不受控的蛮力,约束成有用的功。
第二世:测试挽具。 软件工程在 20 世纪中后期把它借了过来。Test Harness(测试挽具/测试驱动)指套在被测程序外面的一整套基础设施:测试脚本、mock、stub、桩和驱动器——负责给程序喂输入、接住输出、对照预期。这个用法老到 1990 年就被写进了 IEEE 软件工程标准术语表(Std 610.12-1990),作为 test driver 的同义词收录。中文世界里它长期翻作"测试框架"或"测试线束",是个老资格的测试圈术语。
第三世:评估挽具。 2020 年 8 月 28 日,EleutherAI 开源了 lm-evaluation-harness 仓库(2021 年 9 月 1 日发第一个版本),把大模型评测标准化成一套统一"挽具":60 多个基准测试装进同一套跑分装置,模型进来,分数出去。从此开源圈说"我们的模型在 XX harness 上跑分",指的就是这类评估脚手架。SWE-bench 这类代码基准配套的评测装置,也沿用了 eval harness 的叫法。
第四世:智能体挽具。 2023 年起,这词完成了最新一次转行:agent harness,指把一个大模型武装成能自主干活的智能体的那套运行时系统。2026 年 6 月,arXiv 上甚至出现了一篇专门给这个词做"概念卫生"的论文,梳理了完整词源,并给出判定标准(下文详述)。
| 世代 | 全称 | 干什么 | 和被驾驭对象的关系 |
|---|---|---|---|
| 一 | harness(挽具) | 把马的拉力传导到车 | 物理约束,实时 |
| 二 | test harness | 驱动被测程序、检查输出 | 事外驾驭,跑测试时在场 |
| 三 | eval harness | 给模型跑基准、出分数 | 事后旁观,只打分不干预 |
| 四 | agent harness | 包住 LLM 让它感知并改变环境 | 事中驾驭,任务进行中实时在场 |
注意最后一行的关键分水岭:test/eval harness 是旁观者,在任务之外观察、打分;agent harness 是驭手,在任务之中实时驱动。这是 2026 年那篇论文划出的最本质区别。
为什么需要它:模型有四个"不能"
为什么非要有这层皮?因为裸模型有四个致命的"不能",每一个都由 Harness 的一个部件来补:
- 不能记忆——模型只看得见上下文窗口里那几万到百万 token,窗口之外等于失忆。所以需要 Harness 做上下文管理:压缩、检索、外挂记忆。
- 不能行动——模型的全部输出就是文字,它"读不了文件、跑不了命令、点不了按钮",除非有人把这些能力定义成工具递给它,再把执行结果喂回来。
- 不能验证——模型说"已完成修改"不代表真改了。它需要环境给 ground truth:测试结果、命令输出、文件 diff。Anthropic 的说法是,智能体每一步都要从环境拿"真值"来校准自己。
- 不能停止——模型自己没有刹车,不设回合上限它可以一直循环烧钱。停止条件、预算、权限闸门都得外面来装。
所以 Anthropic 在 2024 年 12 月那篇《Building Effective Agents》里给出的定义干脆利落:
Agents are typically just LLMs using tools based on environmental feedback in a loop. (智能体通常不过是"在循环里根据环境反馈使用工具"的大模型。)
三个关键词——工具、环境反馈、循环——正是 Harness 的三大主件。模型提供智能,Harness 提供与现实世界的连接。用 Taskade 那篇 harness 编年史的话说:瓶颈从来不是智能,而是与现实的连接。
发展史:从 REPL 到 Harness Engineering 的 60 年
把大事记排开,会发现 agent harness 不是某天被发明出来的,而是几个老传统在 2023 年突然合流。
史前史(1964–1973):1964 年,L. Peter Deutsch 和 Edmund Berkeley 在 PDP-1 上实现了 Lisp 的 REPL(读取-求值-打印循环)——这就是 agent 一轮交互的形状:你给输入,系统求值,把结果递回来。1973 年,Unix 第三版引入管道,Ken Thompson 实现、Douglas McIlroy 力推——一堆小工具通过管道组合、共享同一个文件系统,这就是工具层的形状。今天任何 harness 里的 “把命令输出接回上下文”,都是这两件事的重演。
**现代史(2022–2026)**按时间排:
| 时间 | 事件 | 意义 |
|---|---|---|
| 2022-10-06 | ReAct 论文(Yao 等) | 确立"推理与行动交错"范式,ALFWorld 上提升 34 个百分点,是 agent loop 的理论起点 |
| 2022-10-17 | LangChain 仓库创建 | 第一代可复用的循环/工具/提示词框架 |
| 2023-03-16 | AutoGPT 发布 | 自主目标拆解的第一次大众化尝试,狂揽 18 万+ star,但暴露"跑不完任务"的失控问题 |
| 2023-06-13 | OpenAI 推出 function calling | 结构化 JSON 工具调用取代正则解析,工具接口标准化 |
| 2023-11-06 | OpenAI Assistants API | 实验室第一次把 harness 本身当产品卖(线程、代码执行、检索全打包) |
| 2024-03-12 | Cognition 发布 Devin | 首个"AI 软件工程师",SWE-bench 子集 13.86% 对此前 1.96%;核心是持久化的 shell/编辑器/浏览器环境 |
| 2024-05 | SWE-agent 论文(普林斯顿) | 命名 ACI(Agent-Computer Interface),同模型 3.8% → 12.5%,证明接口设计就是战斗力 |
| 2024-10-22 | Anthropic computer use | 屏幕截图/光标/键盘全变成工具,OSWorld 14.9%–22.0%(次优 7.8%) |
| 2024-11-25 | Anthropic 发布 MCP | 给 harness 与工具的连接定了一套开放协议 |
| 2024-12-19 | Anthropic《Building Effective Agents》 | 智能体/workflow 的正典定义;自述"在工具上花的功夫比提示词多" |
| 2025-02-24 | Claude Code 研究预览 | 终端原生 harness + 权限确认机制,coding agent 走向日常生产力 |
| 2025-04-16 | OpenAI Codex CLI 开源 | 开源终端 harness |
| 2025-06-25 | Google Gemini CLI 开源 | 三大实验室的终端 harness 全员到齐 |
| 2025-09-29 | Claude Agent SDK + 上下文工程长文 | 压缩(compaction)、子代理、结构化笔记;命名 context rot(上下文腐烂)现象 |
| 2025-10-16 | Anthropic Agent Skills | 可加载的"技能文件夹",Rakuten 案例:一天工作量一小时完成 |
| 2025-12-09 | Linux 基金会成立 Agentic AI Foundation | 托管 MCP、Block 的 goose、AGENTS.md 规范(已被 6 万+ 开源项目采用) |
| 2026-04-19 | Addy Osmani《Agent Harness Engineering》 | harness engineering 正式得名成学科(Viv Trivedy 首创提法) |
| 2026-06 | arXiv 论文《What makes a harness a harness》 | 给出 harness 的四条充要判定条件,概念完成正名 |
读这张表还有一条暗线:工程重心的三次搬家——提示词工程(把指令写好)→ 上下文工程(控制模型看见什么)→ 挽具工程(设计完整的运行时环境)。前两代没有消失,而是被吸收成了第三代的子学科。Addy Osmani 的判词是:顶尖 coding agent 的 harness 正在趋同,各家都长出了差不多的文件系统访问、bash、沙盒、AGENTS.md 记忆和反馈循环——harness 的形态在收敛,功力在细节。
解剖:Harness 由什么组成
2026 年那篇 arXiv 论文给了一个可以逐条检验的定义,拿来当解剖图正合适:Agent Harness 是包裹一个或多个 LLM、把它变成智能体的运行时工程层,由四个必要部件耦合而成。
四大核心件
| 部件 | 干什么 | 缺了会怎样 |
|---|---|---|
| ① Agent Loop(循环) | 推理→行动→观察不断交错,直到任务完成或触顶 | 退化为一条单行道流水线,模型没有自主决策步数的能力 |
| ② Tool Interface(工具接口) | 定义模型能感知和改变环境的手段(读文件、跑命令、调 API) | 只能读不能改 = 孤立模型;接口设计差 = 模型空有智力使不上劲 |
| ③ Context Management(上下文管理) | 决定什么进上下文窗口、什么被移出——按内容取舍,不是简单截断 | 窗口爆掉,或者关键信息被挤出去,长任务越跑越糊涂 |
| ④ Control(控制机制) | 回合上限、结果验证、确定性动作、权限闸门——不依赖模型自觉 | 一个"相信模型嘴上说做完了"的 demo,谈不上可信与可审计 |
四件全齐才叫 harness。可选件还有一排:工具注册表、长期记忆、验证器、重试与模型切换、可观测性、护栏(guardrails)、确定性处理器。注意论文特意澄清:护栏不是 harness 的同义词,只是第④件的一部分——控制既包括"拦住"(禁止),也包括"放行"(赋能)。
四条判定:什么算、什么不算
论文把定义压缩成四条是/否测试(T1–T4),全过才算 harness:
- T1 有循环吗——有按观察调整下一步的推理-行动循环?
- T2 能改变环境吗——工具不止是读,还能写、能执行?
- T3 上下文按内容取舍吗——是内容驱动的选择,而非按长度粗暴截断?
- T4 有独立于模型的控制吗——验证和限制不依赖模型自觉配合?
拿这张检查表去量市面上的系统,边界立刻清楚:
| 系统 | 例子 | 判定 |
|---|---|---|
| Harness | Claude Code、Codex CLI、SWE-agent、OpenHands、Aider、Cline | 四条全过 |
| Agent 框架 | LangGraph、AutoGen、CrewAI | 在 harness 之上编排智能体,自身不过 T1–T4 |
| Agent SDK | 各家 Agents SDK | 造 harness 的原材料,自己没有跑起来的循环(不过 T1) |
| IDE 补全插件 | 传统行内代码补全 | 无循环、无仓库级动作(不过 T1/T2/T4) |
| 评估装置 | SWE-bench 的 eval harness | 只有任务外层循环,没有推理-行动内循环(不过 T1) |
| 编排器 | 固定 DAG 工作流 | 图是写死的,不随观察自适应(不过 T1/T3) |
一个实用的直觉:看它停在哪一条。停在 T1 是流水线,停在 T2 是只读玩具,停在 T3 是无脑截断的粗糙包装,停在 T4 是把一切托付给模型自觉的 demo。
上手:60 行代码写一个最小 Harness
道理讲完,动手最快。下面是一个完整可跑的最小 harness:模型 + 工具接口 + 循环 + 控制,四件全齐。它就是所有 coding agent 的种子形态,Claude Code 也不过是把这个骨架每根骨头都长厚。
# mini_harness.py —— 最小可用的 Agent Harness
import json
import subprocess
from openai import OpenAI
client = OpenAI() # 读环境变量 OPENAI_API_KEY / OPENAI_BASE_URL
# ── ② 工具接口层:感知(读文件)+ 行动(跑命令) ──
TOOLS = [
{"type": "function", "function": {
"name": "read_file",
"description": "读取本地文本文件,返回内容",
"parameters": {"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"]}}},
{"type": "function", "function": {
"name": "run_bash",
"description": "在项目目录执行 shell 命令,返回标准输出和错误",
"parameters": {"type": "object",
"properties": {"cmd": {"type": "string"}},
"required": ["cmd"]}}},
]
# ── ④ 控制层(一):危险命令清单,独立于模型自觉 ──
DANGEROUS = ("rm ", "sudo ", "git push", "curl ", "pip install")
def dispatch(name, args):
if name == "read_file":
with open(args["path"], encoding="utf-8") as f:
return f.read()[:4000] # ③ 上下文管理:限长
if name == "run_bash":
if any(w in args["cmd"] for w in DANGEROUS):
return "BLOCKED: 命令命中危险清单,已拒绝。请改用安全方式。"
r = subprocess.run(args["cmd"], shell=True, capture_output=True,
text=True, timeout=30)
return (r.stdout + r.stderr)[:4000] # ③ 同样限长
return "unknown tool"
SYSTEM = ("你是运行在用户项目目录里的编程助手。"
"文件内容必须用工具读过才能谈,禁止凭记忆回答。")
def main(task):
messages = [{"role": "system", "content": SYSTEM},
{"role": "user", "content": task}]
for turn in range(10): # ④ 控制层(二):回合预算 10 轮
resp = client.chat.completions.create(
model="gpt-4o-mini", messages=messages, tools=TOOLS)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls: # 模型不再调工具 = 认为任务完成
print(msg.content)
return
for call in msg.tool_calls: # ① 循环:行动→观察→再推理
print(f"[turn {turn}] {call.function.name}"
f"({call.function.arguments})")
result = dispatch(call.function.name,
json.loads(call.function.arguments))
messages.append({"role": "tool", "tool_call_id": call.id,
"content": result}) # 观察结果喂回上下文
if __name__ == "__main__":
import sys
main(" ".join(sys.argv[1:]) or "介绍一下当前目录")
跑起来长这样(任务:统计 Markdown 文件):
$ python mini_harness.py "数一下当前目录有几个 .md 文件,总字数是多少"
[turn 0] run_bash({"cmd": "ls *.md | wc -l"})
[turn 1] run_bash({"cmd": "wc -w *.md | tail -1"})
当前目录共有 6 个 Markdown 文件,合计 12,340 个单词。
对着四大件逐一对账:
- 循环:
for turn in range(10)里那段就是 ReAct 循环——模型决定调什么工具(行动),结果拼回messages(观察),下一轮模型基于观察再推理;模型不调工具时循环自然终止; - 工具接口:两个工具就是最小配置——
read_file是感知,run_bash是行动,一个看、一个改; - 上下文管理:这里只做了最原始的两条——工具输出截断到 4000 字符、系统提示词写死。真正的产品要复杂得多(下节展开);
- 控制:三道闸——危险命令清单、30 秒超时、10 回合预算,全部独立于模型自觉,模型再"想干什么"也绕不过去。
要不要给写操作加人工确认门?加四行就够:
if name == "run_bash":
if any(w in args["cmd"] for w in DANGEROUS):
return "BLOCKED: ..."
if input(f"允许执行?{args['cmd']} [y/N] ") != "y":
return "USER DENIED: 用户拒绝了这条命令。"
这就是 Claude Code 权限模式的雏形——默认逐次确认,用户喊过一次"以后别问了"才升级为免确认。
那这 60 行和 Claude Code 差在哪?差的全是细节:没有上下文压缩(长任务窗口会爆)、没有子代理并行、没有 hooks 拦截危险操作、没有 AGENTS.md/Skills 这类记忆与技能层、没有会话持久化、没有 token 计量。但骨架完全同构——读懂这 60 行,你就读懂了所有 coding agent 的源代码结构。这也是理解 harness 最好的方式:它不是一个神秘产品,是一段你能亲手写出来的循环。
实践:Harness Engineering 十条经验
harness 调优的第一手经验,主要来自 Addy Osmani 2026 年 4 月那篇《Agent Harness Engineering》(他正在为 O’Reilly 写书)和 Anthropic 的工具设计附录。拣最值钱的十条:
1. 从行为倒推设计。 别从"我要加什么组件"出发,从"我希望 agent 表现出什么行为"出发,再问哪种 harness 决策能产生这个行为。模型表现 = 模型能力 × harness 设计,同一模型换个 harness,行为可以完全不同——Terminal-Bench 2.0 上有队伍纯靠改 harness 配置从 Top 30 冲进 Top 5。
2. 每个错误变成一条规则。 agent 每犯一次错,就把修复写进 harness(一条规则、一个 hook、一段提示词),让同类错误永远不会再发生。这个"棘轮"机制是 harness 与时俱进的发动机。
3. 优化工具,而不是优化提示词。 Anthropic 自述在 SWE-bench 上"花在工具上的功夫比提示词多"。经典案例:模型离开根目录后总用错相对路径——修法不是写更长的提示词求它,而是把工具接口改成强制绝对路径,问题当场消失。工具接口值得 HCI(人机交互)级别的投入,这叫 ACI(Agent-Computer Interface)。
4. 给工具写"防呆"设计(poka-yoke)。 把工具描述当成写给聪明实习生的文档来写:场景、边界、反例都要有;接口设计得让错误难以发生——能自动补全的就别让模型手敲,能结构化返回的就别让模型解析散文。
5. 承认上下文会腐烂。 context rot 是真实现象,而且是"性能缓坡"不是"断崖"——窗口越满,模型对旧内容越迟钝。三种对策:compaction(把长历史压成摘要换新窗口)、offloading(把中间产物写进文件,要用再读)、skills/子代理(把大块内容隔离在主线窗口之外)。
6. 成功是静默的,失败要大声。 hooks 的输出设计成不对称:顺利时不打扰,出问题时给出模型能据以自纠的详细报错。错误信息是写给模型看的调试器。
7. 记忆文件要小而硬。 AGENTS.md 之类的项目记忆,超过 60 行就开始稀释注意力——每行都得挣得自己的位置。与其一次写一百条规则,不如让规则通过第 2 条的棘轮逐条长出来。
8. 放权程度与出错代价成反比。 读文件免确认、跑测试免确认、删库和对外发布必须逐次确认。权限分级不是 bureaucracy,是错误代价的定价机制。
9. 每个组件都在替模型"兜底"——记得换模型时重审。 harness 里每个组件都编码着一个"模型自己做不到"的假设。模型每升级一代,旧假设可能失效:原来必须手把手教的,现在自己会了;原来不需要管的,现在要防新毛病。模型与 harness 是共同训练关系,只调一头会过拟合。
10. 从最简单方案开始。 Anthropic 的劝告依然是第一原则:先试单次调用,不够再上 workflow(写死的路径),最后才是 agent(自主路径)。智能体换来的是更高的成本和误差复利,“最智能"不等于"最合适”。
十条里 1、2、9 是心法,3–8 是手法,10 是刹车。共同底色一句话:harness 工程师的工作对象不是模型,是模型做不到的事。
生态一览:主流 Harness 对比
2026 年的主流 coding agent harness,按论文的四条判定全部合格,差异集中在第④件(控制)的形态上:
| Harness | 出品方 | 形态 | 开源 | 控制机制特色 |
|---|---|---|---|---|
| Claude Code | Anthropic | 终端 + SDK | 核心闭源 | 分级权限确认、hooks、subagents、Skills |
| Codex CLI | OpenAI | 终端 | 开源 | 沙盒执行、审批模式 |
| Gemini CLI | 终端 | 开源 | 免费额度、Google 生态工具 | |
| OpenHands | 开源社区(前 OpenDevin) | 全功能平台 | 开源 | 自带执行环境,可接多家模型与 ACP 协议 |
| SWE-agent | 普林斯顿 | 研究原型 | 开源 | ACI 理念发源地 |
| Aider | Paul Gauthier | 终端 | 开源 | git 深度集成,改动即提交可回滚 |
| Cline | 社区 | VS Code 插件 | 开源 | IDE 内人机协同确认 |
另一个值得记住的词是 Harness as a Service:Claude Agent SDK、Codex SDK、各家 Agents SDK 把"模型外面那层"打包成可编程组件出售——实验室终于承认,真正可复用的资产是 harness,而不是模型本身。上篇文章介绍的 Skill(技能文件夹)、以及 MCP、Hooks、Subagents,则分别是往 harness 里加知识、加工具、加守卫、加并行分身的四种外挂——那篇的"知·触·思·守"四字诀,宿主全都是这一篇的 harness。
开放问题:这个学科还没解决什么
- 上下文腐烂的度量——多长的任务、多满的窗口开始掉点?各家靠经验参数,缺乏理论;
- 权限疲劳——确认点设多了用户会麻木乱按"允许",设少了危险动作裸奔,粒度怎么定仍在摸索;
- 代码之外的验证缺口——代码有测试当真值,写作、分析、客服的 ground truth 从哪来?
- harness 锁定——规则、记忆、技能都长在特定 harness 里,迁移成本高;MCP、AGENTS.md 这类开放格式是对症的解药,也是 Agentic AI 基金会存在的理由;
- 贡献分离——一篇任务的功劳,多少归模型、多少归 harness?还没有基准能把两者拆开测量。这是那篇定义论文留下的头号研究空位。
写在最后
把全文收拢成一句话:Harness 是把"会说"变成"会做"的那层工程——马具把马力变成拉力,测试挽具把代码变成结论,评估挽具把模型变成分数,而 agent harness 把大模型变成能对现实世界负责的行动者。
发展史的重心三次搬家(提示词→上下文→挽具),本质是行业逐步承认:智能在模型,功夫在外围。60 行代码能搭出骨架,但骨架之外每一寸——工具描述的措辞、上下文取舍的分寸、权限的粒度、错误的棘轮——都是真功夫所在。
写这篇的我也正在一个 harness 里干活:帮我发博客的这套系统,有循环、有工具、有上下文压缩、有 Skills、有权限确认——正好是这篇文章的活体标本。你看完这篇,下次打开任何 AI 编程工具时,看到的就不再是一个黑盒聊天窗,而是一套被精心调教的挽具,和挽具里那匹借来的马。
参考来源
- What makes a harness a harness: necessary and sufficient conditions for an agent harness(arXiv, 2026-06)
- The History of the Agent Harness(Taskade, 2026-08)
- Agent Harness Engineering(Addy Osmani, 2026-04-19)
- Building Effective Agents(Anthropic, 2024-12-19)
- What is an AI Agent Harness?(Naimul Karim, DEV Community)
- Harness Engineering Deep Dive: Where the Term Came From(Lukas Niessen, Medium)
- lm-evaluation-harness(EleutherAI, GitHub)
- IEEE Std 610.12-1990 软件工程标准术语表
评论
0 条登录后参与讨论。本站评论仅对注册用户开放(需站长审核注册),用于展示你的身份。