Harness Engineering 笔记(一):从官方定义到核心类比——理解 Agent 的"控制层"

0 阅读8分钟

Harness Engineering 的正式出处

2026 年 2 月,HashiCorp 联合创始人 Mitchell Hashimoto 首次使用了 "Harness Engineering" 这个术语,描述为 Agent 构建"防止重复犯错机制"的工程实践。几天后,OpenAI 发表了重磅文章《Harness engineering: leveraging Codex in an agent-first world》,分享了他们用 Codex Agent 从零搭建整个应用的经验。Martin Fowler 随后发表分析,对 OpenAI 的实践做了系统性归纳。

Harness Engineering 是设计和实现约束、护栏、反馈循环和生命周期工具的工程实践,其使用在 LLM 上可以使 AI Agent 持续产生正确、可审计、可维护的输出。

举个例子,假如 LLM 是一匹骏马的话,那么 Harness(马具)就是缰绳、马鞍和跑道围栏。没有 Harness,骏马在空旷草原上跑得很快很好看,但完全没法干活。

Harness 有支架、驾驭的意思,可以给 LLM 套上一个系统,使其能够变得听话、持续稳定的输出正确的结果。

官方三大支柱

Martin Fowler 将 OpenAI 的 Harness 归纳为三个核心领域:

支柱一:Context Engineering(上下文工程)

持续增强的代码库知识库 + 动态上下文(遥测数据、浏览器状态等)接入。

核心思想:从 Agent 的视角看,任何它在上下文中无法访问的东西都不存在。 Slack 里的讨论、人脑中的知识,对 Agent 来说都是不可见的。所以必须把所有 Agent 需要知道的东西编码进代码仓库——架构决策、设计文档、质量标准、执行计划,全部版本化、可发现。

OpenAI 的实践中,一个约 100 行的 AGENTS.md 作为"地图"注入上下文,指向更深层的文档。他们发现一个巨大的 AGENTS.md 反而会失效——上下文是稀缺资源,塞太多 Agent 反而抓不住重点。

支柱二:Architectural Constraints(架构约束)

由自定义 Linter 和结构测试强制执行的确定性规则。

OpenAI 静态强制了结构化日志、命名规范、文件大小限制、依赖方向(Types → Config → Repo → Service → Runtime → UI,不可逆向)。关键细节是——Linter 报错时,错误信息被设计为直接注入 Agent 上下文,再将错误信息传给 LLM,形成自动修复的反馈循环。

光在文档里写规则,Agent 仍然可能违反;在系统层面强制执行,则从根本上防止违规。

支柱三:Entropy Management(熵管理 / "垃圾回收")

Agent 定期运行,清理文档不一致、违反架构约束的内容,对抗系统衰退。

OpenAI 团队过去每周五花一天时间手动清理 Agent 生成的低质量代码("AI slop"),后来自动化了:Agent 扫描偏差、提交小的重构 PR、大部分自动合并。本质上就是代码质量的垃圾回收——人类品味捕获一次,持续自动执行

层次关系

Harness Engineering(最外层——整个 Agent 系统的设计)
  ├── Context Engineering(上下文工程——管理所有喂给 LLM 的信息)
  │     ├── Prompt Engineering(提示工程——优化指令文本)
  │     └── + 工具定义、RAG、消息历史、MCP 数据、仓库知识库...
  ├── Architectural Constraints(架构约束——确定性的强制执行)
  ├── Entropy Management(熵管理——持续的质量维护)
  └── Workflow Control(工作流控制——Agent 的运行时管理)

用 mtrajan 的话说:Context Engineering 问的是"Agent 应该看到什么";Harness Engineering 问的是"系统应该防止什么、测量什么、纠正什么"。

本系列的聚焦范围

了解了完整定义后,说明一下本系列的范围。本系列会聚焦在 Harness Engineering 中 Context Engineering + Workflow Control 的部分——即主要讲怎么从零搭建 Agent 的运行时控制框架,主要可以区分为下面的几部分:

  • Harness 的本质
  • Agent 运行时的核心机制:循环控制(Loop)、输出路由(Router)、上下文管理(Memory)
  • 工具的调用和错误时的回复
  • Agent 运行的可观测性和可调试性
  • 多 Agent 编排,搭建一个可用的 Agent

Architectural Constraints 和 Entropy Management 属于"Agent 在生产环境中持续可靠运行"的工程治理维度,系列中会提及但不深入实现。


重新开始:为什么需要 Harness?

背景交代清楚了,回到最基本的问题。

如果你让 LLM 完成"帮我调研竞品并生成报告",光靠一次 chat completion 调用搞不定。你需要让它先搜索、判断够不够、不够再搜、整理、写报告、检查格式……这里面有大量的循环、判断、错误处理、状态管理

而 LLM 是无状态的——调一次 API 返回一个结果就结束了。它不会自己调用自己,不会记住上一轮说了什么。驱动这个多步循环的,就是 Harness。

跟现在的汽车驾驶做类比:

  • 驾驶员大脑 = LLM:负责决策
  • 方向盘/油门 = 工具调用接口:把决策变成动作,进行工具调用
  • 传感器 = 输入/输出处理:外部信号转化为大脑能理解的信息
  • 仪表盘 = 日志与追踪:随时知道状态
  • 安全气囊/ABS = 护栏与容错:出问题时自动保护

对应到官方定义:传感器和方向盘属于 Context Engineering;交通规则和道路围栏属于 Architectural Constraints;定期保养维护属于 Entropy Management。

大脑再聪明,没有这套控制系统,它可能连路都上不了。

简单的 Harness 示例

通过一个循环反复的让询问大模型、进行工具调用,以至于能够在有限的步骤内输出正确的结果。

class SimpleHarness:
    def run(self, user_query):
        messages = [
            {"role": "system", "content": self._build_system_prompt()}, // 系统提示词
            {"role": "user", "content": user_query} // 用户输入
        ]
        for step in range(self.max_steps):  # Workflow Control
            response = self.llm.chat(messages)    # Context Engineering
            parsed = self._parse_response(response)
            if parsed["type"] == "final_answer":
                return parsed["content"]
            elif parsed["type"] == "tool_call": // 工具调用
                tool_result = self._execute_tool(parsed["tool"], parsed["args"])
                messages.append({"role": "assistant", "content": response}) // 本轮模型输出结果
                messages.append({"role": "tool", "content": tool_result}) // 工具输出结果
        return "达到最大步数。"  # Architectural Constraint

for 循环是 Workflow Control,messages 列表是 Context Engineering,max_steps 是 Architectural Constraint。官方三支柱在这几行代码里都有体现。

  1. message中的 Role 体系一般可以分为下面这几种:
  • system:即系统提示词,一般是这个 Agent 的身份、规则和能力的边界,对应 Context Engineering 中的 "AGENT.md + 系统指令"。
  • user: 用户的输入,模型会被训练为回应 user 的请求,一个 Agent 就是为了处理用户的输入并且做出正确的行为。
  • assistant:对应模型在每轮对话的输出,Harness 会将其放回消息列表,这样模型才会“记住”他之前说了啥,做了啥。
  • tool:工具执行的结果,Harness 需要将工具执行的结果回传给模型,模型根据此再继续进行推理。

消息的 role(system / user / assistant / tool)是模型训练出来的能力,各个厂商的大模型现在基本会识别这几种角色的消息并区别对待。

  1. 上下文的管理策略

上面提到的 message 列表每次循环都在膨胀,而模型的上下文是有限的,越多的上下文可能会导致模型输出更加不确定的结果,因此需要在必要的时候对上下文进行管理,一般下面几种策略进行组合使用:

  • 截断/摘要:调用工具输出的结果过大的时候先进行压缩,例如读取一个技术方案,可以先使用一个小的模型对方案进行摘要总结、保留最核心的部分。
  • 滑动窗口:只保留最近 N 轮循环的上下文。
  • 按需注入:维护外部记忆,每次只注入当前步骤需要的

Claude Code 的上下文管理有四层组成:源头控制 -> 工具结果清理 -> 自动 Compaction -> Subagent 分流。

OpenAI 在 Harness Engineering 文章中也强调了同样的理念——上下文是稀缺资源,塞太多反而让 Agent 抓不住重点。

  1. 工具的调用几种形态
  • 本地函数的调用:进程内,速度最快,也最能由我们自己代码控制。
  • HTTP API调用:远端服务的调用,一般要处理复杂的认证问题。
  • MCP 协议调用:标准化的工具协议,即插即拔,提供了统一的发现和调用方式,具体服务由 MCP server 提供。

LLM 其实并不关心工具是哪种类型的,一般来说我们会告诉大模型有哪些工具可以用,模型推断出来要使用哪个工具,然后让 Harness 去负责路由调用,Harness 调用之后再将结果传个模型继续分析。

  1. 小结
  • Harness 是"确定性的壳"包裹"不确定性的核": LLM 的输出不确定,Harness 用确定性代码约束它。这呼应了官方的 Architectural Constraints——不是建议 Agent "请遵守规范",而是让它不可能违反。

  • Harness 拥有状态,LLM 没有: LLM 是无状态的,通过 Harness 维护消息列表、Trace、执行步数,帮助模型拥有记忆。这对应 Context Engineering 的核心——管理 Agent 能看到什么。

  • Harness 定义了 Agent 的"能力边界": 能调哪些工具、最多循环几次、错误怎么处理,都是 Harness 决定的。OpenAI 也说:模型质量在快速趋同,但 Harness 是每个团队必须自己搭建的资产,这才是长期竞争力的来源。

总结

  1. Harness Engineering 由 OpenAI 和 Mitchell Hashimoto 在 2026 年正式提出,包含 Context Engineering、Architectural Constraints、Entropy Management 三大支柱
  2. Harness 存在的根本原因是 LLM 无法驱动多步循环:LLM 是无记忆的!
  3. 本系列聚焦运行时实现层——接下来四篇分别讲核心架构、容错、可观测性、多 Agent 编排

下一篇深入 Agent 运行时的核心机制。