Harness 工程
一个能跑的 Demo 和一个可靠的产品之间还有巨大的鸿沟:模型可能幻觉出不存在的工具、选错工具、或在遇到错误时无法自我恢复。把 LLM 当作核心组件(Model),围绕它构建的全部支撑代码统称 Harness——在上下文与工具之外,再加约束、验证、纠正三层。
到这里你已经理解了 agent 的核心工作原理——LLM 通过 ReAct 循环,在上下文的辅助下使用工具完成任务。前面的实验证明了这套基本机制是有效的,但同时也暴露了明显的脆弱点:模型可能产生幻觉(编造不存在的工具或参数)、选错工具、或在遇到错误时无法自我恢复。一个能跑的 Demo 和一个可靠的产品之间还有巨大的鸿沟,而这些脆弱点正是 Harness 工程要解决的问题。
前面几节建立了 Agent = LLM + 上下文 + 工具 的核心公式,它描述了 agent 的内部组成。从 Harness 工程的视角看,还需要一个工程实现层面的视角:把 LLM 当作一个核心组件(Model),围绕它构建的所有支撑代码统称为 Harness。两个视角并非替代关系,而是不同抽象层次上对同一系统的描述。之所以换用更通用的 “Model” 一词,是因为 Harness 工程的原则适用于任何具备推理和工具调用能力的模型。Harness 的核心就是原公式中的“上下文 + 工具”,再加上三层保障机制:约束(限定能做什么、不能做什么)、验证(检查做得对不对)和纠正(做错了怎么补救)。用方程展开生产形态下的完整组成:
Agent = LLM + [上下文 + 工具 + 约束 + 验证 + 纠正] = Model + Harness
最小可工作的 agent 只需要 LLM、上下文与工具就能跑起来;要让它在生产环境中长期可靠运转,还需要补全约束、验证、纠正这三层工程外壳。用一个例子理解 Harness 的价值:让 agent 帮用户退掉 3 天前的订单。没有 Harness 时,模型看不到退款政策(缺上下文),不知道该调哪个 API(缺工具),直接编造一个退款结果回复用户(缺验证),用户发现退款根本没发生(缺纠正)。有了 Harness 后:系统提示词写明了退款政策(上下文),agent 调用 query_order 和 process_refund 完成操作(工具),框架校验退款金额不超过订单金额(约束),校验数据库状态确认退款成功(验证),如果 API 超时则自动重试(纠正)。同一个模型,有无 Harness,结果天壤之别。回到马具的隐喻:没有 Harness 的模型就像脱缰的野马,能力惊人,但无法可靠地完成任务。
Harness 的五个功能
模型之外的全部基础设施都属于 Harness。它的核心是上下文与工具,围绕它们构建了三类工程化保障机制:
| 功能 | 一句话职责 | 与上下文/工具的关系 |
|---|---|---|
| 上下文(Context) | 为模型提供感知信息 | 核心能力 |
| 工具(Tools) | 为模型提供行动手段 | 核心能力 |
| 约束(Constrain) | 设定行为边界——能做什么、不能做什么 | 围绕上下文和工具构建的安全边界 |
| 验证(Verify) | 自动判断操作结果的对错 | 围绕工具执行结果构建的检查机制 |
| 纠正(Correct) | 发现问题时自动修正或回退 | 围绕工具调用失败构建的恢复机制 |
上下文与工具让 agent “能做事”——理解任务并采取行动;约束、验证与纠正让 agent “不做错事”。在 agent 产品的成熟度曲线上,两者的重要性是不对称的:早期的 agent 框架主要关注上下文与工具,而生产级系统的重心已经转向约束、验证与纠正。以 Claude Code 为例,它的 Harness 中绝大部分代码都是约束、验证与纠正,而非上下文与工具——工具本身只是一小部分,围绕这些工具构建的保障机制才是真正的核心。行业正在从“能做事”向“可靠地做事”转变,Harness 工程因此成为 agent 系统的核心竞争力。
从提示工程到 Loop 工程
回顾 AI 应用工程的发展,可以看到一条清晰的演进弧线,而且层层包含:
- 软件工程是基础——传统的系统设计、架构、测试和部署实践。
- 提示工程是第一波创新——通过优化输入给模型的自然语言指令来提升输出质量。
- 上下文工程是第二波——人们认识到单纯优化提示词还不够,需要系统性地管理模型能看到的所有信息(系统指令、工具定义、对话历史、外部知识)。
- Harness 工程是第三波——它将视野从“模型能看到什么”扩展到“模型在什么样的系统中运行”,涵盖约束、验证、反馈循环和错误恢复等模型之外的全部基础设施。
- Loop 工程又把视野从单次运行扩展到跨轮次的持续自主运转:谁来发现下一件该做的事、何时验证、何时才算真正完成。
这几个阶段不是替代关系,而是层层包含:提示工程 ⊂ 上下文工程 ⊂ Harness 工程 ⊂ Loop 工程。每一层都在前一层的基础上扩展了工程师的关注范围和影响力。当各家模型的能力越来越接近、不再是决定性的差异因素时,竞争优势就转移到了模型之外的工程实践。
构建有效 Agent 的核心原则
根据 Anthropic 的经验,成功的 agent 系统遵循三个核心原则。
- 保持简单。从最简单的方案开始,只在确实必要时才增加复杂度。直接的 API 调用优于复杂的框架,清晰的代码优于聪明的抽象——因为每多一层抽象都会成为以后调试时新的盲区。
- 保持透明。明确显示 agent 的规划步骤、执行日志和决策轨迹——这不只是为了调试方便,也是让用户建立信任的前提。黑箱里的错误一旦发生,外部观察者既无法定位也无法纠正。
- 设计好工具接口(ACI,Agent-Computer Interface)。ACI 强调从 agent 视角设计接口(让 agent 容易理解和使用),而非传统 API 从程序员视角设计接口。工具的命名和参数要直观,容易误用的地方要从设计上让错误无法发生——就像 SIM 卡的缺角让卡片只能从一个方向插进卡槽。这种“用设计消除错误”的思路,在制造业里有一个专门的术语,叫防呆(Poka-yoke)。设计不好的工具会让再强的模型也频繁出错——因为模型与工具之间唯一的沟通通道就是接口本身。
如何选择模型
模型是 agent 的智能基座,选对模型往往比优化提示词更有效。由于模型迭代极快,这里不推荐具体版本,而是提供一些选择的方向:
- 三大闭源厂商。 目前最常用的是 OpenAI(GPT/o 系列)、Anthropic(Claude 系列)和 Google(Gemini 系列)。它们各有侧重:Claude 在复杂推理、编程和工具调用方面突出,Gemini 拥有超长上下文窗口和强大的多模态能力,GPT/o 系列各方面能力均衡。选模型时不要只看排行榜,要在你自己的任务上做评估。
- 国内模型与开源。 部署在国内或成本敏感时,豆包(低延迟)、Kimi(agent 能力较强)、Qwen / DeepSeek(开源、可私有化、可微调)都是务实选择。不同模型在工具调用方面的能力差异很大,选型前务必在具体场景中测试。
- 绝大多数 agent 需要支持思考(Reasoning)的模型。 agent 需要多步思考、工具选择等复杂决策,不带思考能力的模型在这些任务上往往表现很差;只有极少数单步简单任务例外。
- 关注输出速度和多模态能力。 agent 往往需要多轮推理,每轮都要等模型输出完成才能执行下一步,输出速度直接决定端到端的响应延迟;如果需要理解图片、音频或视频,多模态就是硬性要求。
工程实践
Harness 的核心在 Zapvol 的运行时表现为三个互不共享职责的部件——它们按状态归属与信任边界划分,而不是按公式的结构划分,所以这三块与三大组件不重合:agent 循环不等于 LLM,消息记录不等于上下文。
| 运行时部件 | 持有持久状态 | 受信 | 对应代码 |
|---|---|---|---|
| Agent 循环 | 否 | 是 | runAgentLoop() |
| 沙箱 | 否,随运行销毁 | 否 | ISandbox 端口 + createSandbox() 工厂 |
| 消息记录 | 是,本次运行全部历史 | 是 | TaskRepository.getMessages() |
沙箱唯一不受信、消息记录唯一持久——这两点分别兑现了 Harness 的约束与纠正:约束——凭证不进入沙箱(沙箱不受信,凭证经 KeyEncryption 端口隔离);纠正——崩溃可恢复(循环不持有需持久化的状态,重启后重放消息记录即可回到原处)。这也回答了一个容易混的问题:循环跨轮累积上下文,但并不拥有它——消息记录才是上下文的唯一源,模型每一轮看见的都是从这份只追加历史投影而来。
沙箱经统一工厂 createSandbox() 按 SANDBOX_TYPE 分派,这是唯一的构造路径——换 provider 只需改一行 env、零代码改动,“给定 task id 重连它的沙箱”也收在这一处。目前真正落地的只有 NodeSandbox;Daytona / E2B 的 config 类型与 env 已经接好,但 adapter 仍是占位,工厂对它们会直接抛出明确错误,直到被移植。
相关阅读
- 编排模式:工作流与自主——Harness 中“上下文与工具”的组织方式。
- 护栏与安全性——“约束、验证、纠正”的核心落地手段。
- 上下文工程——Harness 五功能里最核心的“上下文”那一层。