深度学习 · 2026-07-14 · 细致版

Agent Harness Engineering
一个生产级 Agent 里,98% 不是 AI

「换个更聪明的模型」常常不如「把包裹模型的那层壳做好」。本版在概念之外,补齐了可参考的伪代码、逐层机制、主流框架对照与一次完整的「修 bug」走查。

0 · 30 秒速览

一句话:Agent Harness(外壳/运行环境),是包在大模型外面、负责「给它喂上下文、管它能用哪些工具、拦住危险动作、记录它每一步、出错帮它兜底」的一整套工程基础设施。模型只负责「想」,harness 负责把「想」变成可靠、可审计的「做」。

有个数字最能说明问题:MBZUAI 在 2026 年 5 月分析 Claude Code 源码后估算——一个生产级 Agent 里约 98.4% 是 harness 基础设施(权限、上下文管理、沙箱、工具路由、恢复),真正的「AI 决策逻辑」只占约 1.6%(来源)。也就是说,当大家都能调到差不多强的模型时,产品好不好用,几乎全押在这层壳上。

AI 决策 1.6% Harness 外壳基础设施 98.4%
图:MBZUAI 对 Claude Code 源码的分析估算——绝大部分「Agent」其实是外壳工程。图为占比示意,数据来源见正文。
🔑 一句话结论Agent 竞争的主战场,正从「谁的模型更强」转向「谁的 harness 更好」。业界观察也印证:各家前沿模型能力已大幅收敛,「模型外面的 harness 现在承担了大部分工作」(来源)。

📖 本版阅读建议:第 1–3 节是概念地基;第 4–7 节是逐层机制 + 伪代码(想动手实现看这里);第 8 节是Claude Code / Cursor / Copilot / Codex 真实对照;第 9 节用一次「修 bug」把所有层串起来走一遍

1 · 为什么需要「外壳」——先说痛点

光有一个聪明的模型,为什么造不出可靠的 Agent?因为把模型直接扔进真实环境里干活,会立刻撞上四堵墙:

墙一:模型是「无状态」的,任务是「长程」的
模型每次调用都像失忆——不记得上一步干了啥。但真实任务(修一个 bug、跑一个报表)要几十步、几小时。得有人替它维护「任务进行到哪了、之前做过什么」。
墙二:模型会「胡乱调工具」,而工具能造成真实破坏
模型输出一句「删掉这个数据库」,如果直接执行,后果不堪设想。必须有一层在中间做校验、拦截、审批。
墙三:出错是常态,但模型不会自动兜底
工具超时、参数写错、返回一堆报错——模型可能就卡住或原地打转(见近期「无限循环」研究)。得有重试、回退、失败归因的机制。
墙四:看不见 = 没法改
模型内部是黑箱,如果不记录它每一步在想什么、调了什么,线上出问题你连复盘都做不了。

业界一个扎心的数字:95% 的 AI 项目从未真正上线,瓶颈往往不是模型能力,而是「上下文交付」这类工程问题(来源)。harness 工程,就是来推倒这四堵墙的。

🧭 打个比方
模型像一位天才但健忘、还没有手脚的大脑。harness 就是给它配的整套「身体和工作台」:记事本(记住任务进度)、一副有安全锁的工具(能用但不会误伤)、一个随时录像的监控(出事能回放)、还有一个出错时拽它一把的安全绳。没有这套身体,再聪明的大脑也干不成活。

2 · Agent Harness 到底是什么

正式定义
一个 AI Harness 是围绕「基础模型软件 Agent」的运行时基座(runtime substrate),负责管理上下文、工具、项目记忆、任务状态、可观测性、失败归因、验证、权限与维护状态——从而把模型「潜在的编码能力」变成「可审计的软件工程行为」(arXiv 2605.13357)。

说人话:harness 不是 Agent 本身,而是包裹 Agent 的那一整套基础设施——它能用哪些工具、有哪些护栏、靠什么反馈自我纠正、人怎么监控它。(来源)

所以「Harness Engineering(外壳工程)」这门手艺的本质,是工程师的角色从「自己写代码」变成「设计一套系统,去管住 Agent 怎么写代码 / 怎么干活」。它也被一些人称作 Agent 的「控制面(control plane)」。

📌 三个「工程」的粒度区别提示工程(prompt)是教模型「这次怎么想」;上下文工程(context)是决定「这次给它看什么」;而外壳工程(harness)是决定「它这一整趟能做什么、做错了怎么办」——粒度从一次调用,升到整个任务生命周期。

3 · 分层解剖:一个 harness 由哪些层组成

把定义里那串职责拆开,一个完整 harness 大致是这么几层「围着模型」叠起来的。记住这张分层图,后面每一节都在讲其中一层的内部机制:

④ 可观测性层:追踪 · 日志 · 指标 · 评测 · 成本(§7) ③ 执行环:计划 → 执行 → 验证 + 人类审批门(§4) ② 工具与权限层:schema 校验 · 权限分级 · 沙箱(§5) ① 上下文 / 记忆 / 压缩(§6) 模型
图:harness 的分层心智模型。模型在最内核,外面每一层各管一摊——越往外越偏「治理与监控」。括号是本文对应章节。
管什么典型内容本文
① 上下文 / 记忆模型每次「看到什么」、任务进行到哪上下文组装与裁剪、压缩(compaction)、项目记忆、任务状态§6
② 工具与权限它能调哪些工具、动作危不危险schema 校验、权限分级、沙箱隔离、MCP 接入§5
③ 执行环怎么把「想」变成有节奏的「做」计划-执行-验证循环、停止条件、人类审批门、子 Agent 委派§4
④ 可观测性看得见、出错查得到、花钱控得住tracing、日志、指标、评测、审计、成本控制§7

这也解释了为什么之前几期的主题(MCP、沙箱、上下文工程、多智能体、记忆、评测)其实都是 harness 的零件——而外壳工程,是把这些零件装成一台能上线的机器。

4 · Agent Loop 引擎:机制 + 伪代码

harness 的执行层,机械上「往往就是一个 while 循环——复杂度不在循环本身,而在这个循环所管理的一切」(来源)。先看这个循环长什么样:

调用模型 有工具调用? 校验→执行工具(§5) 结果回灌当「观察」,回到顶部 产出最终答复
图:最朴素的 agent 循环。真正的工程量在于循环里「校验/执行/压缩/停止判断」这些被循环管理的东西。

4.1 循环骨架(带预算与停止条件)

下面是一段提炼自公开实现的伪代码(概念示意,非可直接运行),把「预算、停止条件、结果回灌」这些关键点标出来:

# 概念伪代码:一个带边界的 agent 循环
def run_agent(task, tools, budget):
    ctx = build_context(task, tools)     # §6 组装初始上下文
    turns = 0
    while True:
        # ---- 停止条件:任何一条命中就退出(防无限循环)----
        if turns >= budget.max_turns:      return stop("超出最大步数")
        if budget.tokens_left <= 0:        return stop("超出 token 预算")

        # ---- 接近上下文上限则先压缩(§6)----
        if ctx.size() > CONTEXT_LIMIT * 0.9:
            ctx = compact(ctx)

        reply = model.call(ctx)          # 唯一一次「AI 决策」发生的地方
        turns += 1

        if not reply.tool_calls:            # 模型没再要工具 → 收工
            return done(reply.text)

        for call in reply.tool_calls:
            result = execute_tool(call)  # §5:校验+权限+沙箱执行
            ctx.append(observation=result)  # 结果回灌,拒绝/超时/报错也算

        if stuck_detected(ctx):           # 连续 3 次相同调用 → 判定卡死
            return escalate_to_human(ctx)
🔑 三类停止条件都要有成熟实现的终止是「分层」的:模型给出无工具调用的答复、超过最大步数、token 预算耗尽、护栏 tripwire 触发、用户打断、或安全拒绝——任一命中即停(来源)。少了预算上限,Agent 就可能停不下来、烧钱又卡死。

4.2 关键细节:每个结果都是「观察」,卡死要能识别

两个容易被新手漏掉、却决定 Agent 稳不稳的机制:

  • 结果回灌要「诚实」。拒绝、超时、参数错误、中止——这些「坏结果」也是观察,必须原样回灌给模型当反馈,而不是悄悄吞掉。Agent 的自我纠错能力,全靠这些诚实反馈(来源)。
  • 加一个「卡死检测」启发式。一个简单有效的做法:如果最近三次工具调用完全相同,就跳出循环、把当前状态交给用户(来源)。这直接对应近期「Agent 无限循环」的失败模式。

「计划-执行-验证(Plan–Execute–Verify)」是这个循环的一种有结构的版本:计划阶段好的 harness 会先做「仓库影响图」——动手前跑符号分析,搞清任务会碰到哪些文件(Red Hat 实践,来源);执行阶段模型只产出结构化调用交给 harness(§5);验证阶段用测试/规范检查结果,没过就再转一圈。

5 · 工具与权限层:整个 harness 的命门(含代码)

如果只能记住一条 harness 铁律,就是这条:

⚠️ 铁律永远不要让 LLM 直接调用工具。正确做法:模型只返回一个结构化的工具调用;由 harness 来校验 schema、检查权限、执行、再把结果注入回去。这样能防止「提示注入(prompt injection)」升级成「任意代码执行」(来源)。Anthropic 在架构上就把「权限执行」和「模型推理」分开:模型决定尝试什么,工具系统决定什么被允许(来源)。

5.1 一次工具调用要过的「预执行关卡」

harness 在真正执行工具前,会连问几个问题(pre-execution gates):这是已知工具吗?参数合法吗?这个动作需要用户批准吗?请求的路径在工作区内吗?(来源)。落成代码大致长这样:

# 概念伪代码:工具执行的校验层(模型永远碰不到真实副作用)
def execute_tool(call):
    # ① schema:是不是已知工具、参数结构对不对
    if call.name not in TOOL_REGISTRY:      return deny("未知工具")
    if not validate_schema(call.args, TOOL_REGISTRY[call.name].schema):
        return error("参数不合法")           # 回灌给模型,让它改

    # ② 边界:路径/资源是否越界
    if not path_inside_workspace(call.args):
        return deny("越出工作区")

    # ③ 权限:按风险等级决定放行 / 审批 / 拒绝
    risk = classify_risk(call)             # 见 5.2
    decision = permission_gate(risk, call) # allow | ask | deny
    if decision == "deny": return deny("策略禁止")
    if decision == "ask":  wait_for_human_approval(call)   # 高危动作停在这

    # ④ 沙箱执行 + 记录(§7)
    result = sandbox.run(call)
    audit_log.write(call, result)
    return result

5.2 按「风险」给动作分级

不是所有工具调用都一样危险。harness 要按风险走不同的权限路径(来源):

风险级别动作举例建议策略
读文件、查数据、起草(draft)可自动放行
写文件、改配置沙箱内执行 + 记录
对外通信、发邮件、调外部 API需策略校验 / 人类审批门
极高金融操作、删除、提权等破坏性/特权动作强制人工确认,绝不自动执行

可以用一份声明式配置来表达这套分级,让策略和代码分离:

# 概念示例:声明式权限策略(风险→路径)
policies:
  read_file:      { risk: low,     action: allow }
  write_file:     { risk: medium,  action: allow, sandbox: true }
  http_request:   { risk: high,    action: ask }        # 弹审批
  send_email:     { risk: high,    action: ask }
  delete_path:    { risk: critical,action: ask, require: human }
  run_migration:  { risk: critical,action: deny }        # 直接禁

5.3 人类审批门:动作被「冻结」而不是被执行

高危动作命中 ask 时,一个优雅的实现是:当 Agent 走到写操作,harness 不执行,而是把这个待执行的调用序列化、发出一个审批请求、阻塞执行,并把 Agent 的状态「停泊」在这个写节点上,完整保留现场,直到收到批准信号才继续(来源)。好处是:人不在时任务不会失败,而是安全地暂停等待。

5.4 两类控制协同

预防性控制(preventive)在坏结果发生前就拦住;纠正性控制(corrective)在检测到违规后触发响应(来源)。工具箱本身则常通过 MCP 扩展——把 CI 状态、部署日志、运行指标接成 Agent 可用的实时数据源;MCP 月 SDK 下载已达约 9700 万次,几乎所有主流编码 Agent 都支持它(来源)。

6 · 上下文与记忆:压缩(compaction)机制

模型的上下文窗口是有限的,而长任务的历史会越堆越长。harness 必须在「快撑满时」把上下文压小,又不能压丢关键信息——这就是 compaction。

最少两种压缩策略
一个最小 harness 至少要有两招:裁剪(clipping)——把过长的文档片段和巨大的工具输出截短;转写归纳(summarization)——把整段会话历史变成一份更小、可再喂给模型的摘要(来源)。
# 概念伪代码:接近上限时触发压缩
def compact(ctx):
    # 1) 裁剪:超长工具输出/文档只留头尾
    for msg in ctx.tool_outputs:
        if len(msg) > CLIP_LIMIT:
            msg = msg[:800] + " …[截断]… " + msg[-400:]
    # 2) 归纳:把早期回合压成摘要,保留近期原文
    old, recent = ctx.split_at(keep_last=RECENT_N)
    summary = model.summarize(old, keep=["决定","改动","待办"])
    return Context(summary + recent)
⚠️ 压缩的两个反噬其一,工具的 schema 也占上下文,schema 太多会「逼着模型赶紧行动、来不及深思」;其二,如果归纳提示太激进,Agent 会忘掉工具 schema、项目约定或正在进行的工作(来源)。所以压缩要「保住待办、决定、约定」这些骨架。

工程上还有个实用挂钩:Claude Code 提供 PreCompact 钩子,在压缩前触发,让你先把重要状态快照下来,免得早期回合被摘要抹掉(来源)。这就是「记忆层」和「可观测层」联动的一个例子。

7 · 可观测性与失败恢复

「看不见就没法改」——可观测性是 harness 里最容易被省略、又最不该省的一层。

最低限度:先把日志打起来
记录 Agent 的动作、工具调用、token 用量。哪怕只是简单的文件日志,也能给你「诊断失败、迭代改进 harness」的数据(来源)。

成熟一点的做法,是一整套横跨所有环节的可观测层:tracing(追踪)、logging(日志)、metrics(指标)、evals(评测),配合 Opik、Langfuse、Braintrust 这类工具(来源)。这也和「Agent 评测需要 trace 埋点做前提」接上了——评测其实是可观测层之上的一个应用。

更进一步,可观测性能反过来驱动 harness 自我进化:arXiv 上已有「观测驱动的、自动演化 harness」的工作(Agentic Harness Engineering,arXiv 2604.25850)——用线上观测到的失败,自动改进外壳配置。

🔑 恢复的三板斧失败归因(是模型错、工具错、还是环境错)→ 分级重试(可重试的自动退避重试,不可重试的直接上报)→ 状态回滚(沙箱/事务让「做错了能撤回」)。有了这三样,偶发失败才不会变成任务崩溃。

8 · 真实框架对照:各家的 harness 长什么样

「模型趋同、harness 决定体验」在真实产品上体现得很明显。下面对照四家主流编码 Agent 的外壳能力(据 2026 年公开对比,来源1来源2):

维度Claude CodeCursorGitHub CopilotCodex
形态CLI / 终端AI 原生 IDEIDE 插件 + 云CLI / 云异步
配置载体规则文件 + Hooks + Skills + SubagentsRules、MCP、Hooks、Skills、Plugins、SubagentsIssues/PR/CI 原生集成.codex/agents 配置
工具协议MCPMCP(还读 .claude/.codex 配置)MCPMCP
权限机制PreToolUse 钩子 + 权限模式(见下)规则 + 钩子企业级策略控制沙箱 + 审批
擅长复杂推理、多文件协同改最深的 IDE 内 AI 体验最低迁移成本、企业管控成熟无人值守长任务、开 PR

值得注意:Cursor 会去读 .cursor.claude/agents.codex/agents 多套配置,而同一个 MCP 服务器(如 Firecrawl)用一套配置就能在 Claude Code、Codex、Cursor、Copilot、Gemini CLI、OpenCode、Devin 之间通用(来源)——这正是 harness 层标准化带来的红利。

8.1 以 Claude Code 为例:权限模式 + PreToolUse 钩子

Claude Code 把第 5 节讲的「权限层」做成了可配置的具体机制,很适合拿来理解「权限如何落地」:

权限模式(permission modes)
决定工具请求怎么处理:plan 模式屏蔽一切写操作(只让它读和规划);acceptEdits 自动放行文件编辑但 Bash 等仍需授权;bypassPermissions 放行到达它的请求;dontAsk 拒绝一切未预先批准的动作(来源)。这正是「按风险分级」的产品化。
PreToolUse 钩子
在每次工具调用之前运行,能看到完整命令串(含管道、子 shell);脚本可返回 allow / ask / deny,deny 时工具永不执行——而且 deny 即使在 bypassPermissions 模式下也照样生效(来源)。评估顺序是「钩子先跑,再查 deny 规则」。
SDK 层对应
在 Agent SDK 里,这对应 authorize_tool_call(执行前可放行/拦截)与 process_tool_result(执行后可改写结果)两个挂钩点(来源)。
# 示意:一个 PreToolUse 钩子,拦住危险 Bash
# 输入:工具名 + 完整命令串;输出:allow/ask/deny
if tool == "Bash" and matches(cmd, ["rm -rf", "curl | sh", ".env"]):
    return {"decision": "deny", "reason": "命中危险模式"}
if tool == "Bash" and writes_outside_repo(cmd):
    return {"decision": "ask"}     # 交人确认
return {"decision": "allow"}

8.2 另一种范式:OpenAI SDK 的三级护栏

OpenAI 的 Agents SDK 把护栏分三层跑:输入护栏(在第一个 Agent 上运行)、输出护栏(在最终输出上运行)、工具护栏(在每一次工具调用上运行)。护栏在动作执行前校验,于是「会删数据、花钱、碰受保护资源」的调用可以被拦截、改写或升级(来源)。不同框架名字不同,但「在执行前设卡」的思想完全一致。

9 · 完整案例走查:Agent 修一个 bug,harness 每步做了什么

把前面所有层串起来。任务:「修复用户反馈的登录超时 bug」。看 harness 在背后逐步做了什么(方括号标注对应章节):

① 组装上下文 §6
harness 不把「修个登录 bug」这句模糊话直接丢给模型,而是拼装结构化上下文:相关文件、报错日志、代码约定、验收标准(测试要通过)。这就是「结构化上下文优于自由文本工单」。
② 计划 + 仓库影响图 §4
模型先规划;harness 跑符号分析生成「仓库影响图」,预判这次会碰到 auth/session.py 等文件,把盲改变成有地图地改。
③ 模型请求「读文件」 §5
模型返回结构化调用 read_file(auth/session.py)。harness 过关卡:已知工具 ✓、参数合法 ✓、路径在工作区内 ✓、风险=低 → 自动放行,沙箱读取,结果回灌。
④ 模型请求「改文件」 §5
调用 write_file,风险=中 → 在沙箱内执行、记录 audit log。若配了 plan 模式,这一步会被屏蔽,只让它先给出方案。
⑤ 验证:跑测试 §4
harness 执行测试工具。假设测试没过——报错原样回灌当「观察」,模型据此再改。循环进入第二轮。
⑥ 卡死检测 & 预算 §4
假设模型连着三次提交几乎相同的错误改动 → 卡死检测触发,或步数逼近预算上限 → harness 跳出循环,把现场交给人,而不是无限烧钱。
⑦ 高危动作命中审批门 §5
模型想 run_migration 改数据库结构 → 风险=极高 → 动作被「冻结」、状态停泊、弹出人类审批。人点「批准」后才继续。
⑧ 全程可观测 §7
上面每一步的工具调用、参数、结果、token、耗时都进了 trace。任务若翻车,你能回放整条轨迹定位是哪一步、哪类错误——也是评测与改进 harness 的原料。
🔑 看出来了吗整个过程里,模型只在「③④⑤⑦」这些点上做了几次「决策」;而「拼上下文、影响图、校验、沙箱、回灌、卡死检测、预算、审批门、trace」全是 harness 在干活——这就是那个 98.4% 的具体模样。

10 · 常见坑

  • 把模型直接接到工具上。省掉中间校验层 = 给提示注入开了一条直达「任意执行」的高速路。
  • 所有动作一个权限档。读文件和删库用同一套放行逻辑,迟早出事;必须按风险分级。
  • 只堆模型,不做外壳。指望换个更强模型解决一切,却忽略那 98.4% 的基础设施——上不了生产的根因通常在这。
  • 零可观测性。不打日志、不做 trace,线上一出问题就是黑箱,连复盘都做不了。
  • 循环无边界。不设步数/成本上限、不做卡死检测,Agent 可能陷入无限循环,烧钱又卡死。
  • 压缩太狠。归纳提示过激,Agent 会忘掉工具 schema、项目约定和在办工作——压缩要保住骨架。

11 · 落地六步

  • 先隔离执行环境。给 Agent 一个沙箱,别让它直接碰生产系统。
  • 把工具调用收进「校验层」。模型只产出结构化调用,harness 负责校验 schema、查权限、再执行(§5 的代码即模板)。
  • 给动作分风险等级。用声明式策略把低风险自动放行、高/极高风险加人类审批门。
  • 搭有边界的循环。设步数与 token 上限、加卡死检测,每步结果都回灌当反馈(§4)。
  • 打日志、接 trace。至少记录动作、工具调用、token;有余力上 Langfuse/Opik/Braintrust。
  • 用观测数据迭代外壳。拿线上失败去改进上下文组装、权限策略和工具集——这才是 harness 工程的日常。
换个说法:一句话记住这六步
关笼子(沙箱)→ 再装安检(工具校验)→ 分危险等级(权限)→ 给循环上刹车(预算+卡死检测)→ 装监控(trace)→ 照录像改进(用观测迭代)。

12 · 继续深入的资源

Around the Loop: Building a Coding Agent Harness in Python(Edd Mann)
从零搭循环、压缩、停止条件的实操长文,本文很多代码思路出处。链接
Configure permissions — Claude Code / Agent SDK Docs
权限模式、PreToolUse、authorize_tool_call 的一手官方文档。链接
Claude Code Hooks 完全指南
30+ 钩子事件、PreCompact、决定返回值(allow/ask/deny)。链接
Best AI Coding Agents 2026(Firecrawl)
Claude Code / Cursor / Copilot / Codex 的 harness、成本、准确率横评。链接
AI Agent Best Practices: Production-Ready Harness(2026)
本文很多铁律的出处(98.4% 数字、工具校验、风险分级、三级护栏)。链接
awesome-harness-engineering(社区精选清单)
工具、模式、评测、记忆、MCP、权限、可观测性、编排一站式索引。链接
arXiv 2605.13357 · 2602.14690 · 2604.25850
harness 的学术定义、编码 Agent 外壳研究、观测驱动的自动演化。