快搜阅读器
69.16M · 2026-03-18
Harness Engineering 是设计和实现约束、护栏、反馈循环和生命周期工具的工程实践,其使用在 LLM 上可以使 AI Agent 持续产生正确、可审计、可维护的输出。
举个例子,假如 LLM 是一匹骏马的话,那么 Harness(马具)就是缰绳、马鞍和跑道围栏。没有 Harness,骏马在空旷草原上跑得很快很好看,但完全没法干活。
Martin Fowler 将 OpenAI 的 Harness 归纳为三个核心领域:
持续增强的代码库知识库 + 动态上下文(遥测数据、浏览器状态等)接入。
核心思想:从 Agent 的视角看,任何它在上下文中无法访问的东西都不存在。 Slack 里的讨论、人脑中的知识,对 Agent 来说都是不可见的。所以必须把所有 Agent 需要知道的东西编码进代码仓库——架构决策、设计文档、质量标准、执行计划,全部版本化、可发现。
OpenAI 的实践中,一个约 100 行的 AGENTS.md 作为"地图"注入上下文,指向更深层的文档。他们发现一个巨大的 AGENTS.md 反而会失效——上下文是稀缺资源,塞太多 Agent 反而抓不住重点。
由自定义 Linter 和结构测试强制执行的确定性规则。
OpenAI 静态强制了结构化日志、命名规范、文件大小限制、依赖方向(Types → Config → Repo → Service → Runtime → UI,不可逆向)。关键细节是——Linter 报错时,错误信息被设计为直接注入 Agent 上下文,再将错误信息传给 LLM,形成自动修复的反馈循环。
光在文档里写规则,Agent 仍然可能违反;在系统层面强制执行,则从根本上防止违规。
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 的运行时控制框架,主要可以区分为下面的几部分:
Architectural Constraints 和 Entropy Management 属于"Agent 在生产环境中持续可靠运行"的工程治理维度,系列中会提及但不深入实现。
背景交代清楚了,回到最基本的问题。
如果你让 LLM 完成"帮我调研竞品并生成报告",光靠一次 chat completion 调用搞不定。你需要让它先搜索、判断够不够、不够再搜、整理、写报告、检查格式……这里面有大量的循环、判断、错误处理、状态管理。
而 LLM 是无状态的——调一次 API 返回一个结果就结束了。它不会自己调用自己,不会记住上一轮说了什么。驱动这个多步循环的,就是 Harness。
跟现在的汽车驾驶做类比:
对应到官方定义:传感器和方向盘属于 Context Engineering;交通规则和道路围栏属于 Architectural Constraints;定期保养维护属于 Entropy Management。
大脑再聪明,没有这套控制系统,它可能连路都上不了。
通过一个循环反复的让询问大模型、进行工具调用,以至于能够在有限的步骤内输出正确的结果。
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。官方三支柱在这几行代码里都有体现。
message中的 Role 体系一般可以分为下面这几种:消息的 role(system / user / assistant / tool)是模型训练出来的能力,各个厂商的大模型现在基本会识别这几种角色的消息并区别对待。
上面提到的 message 列表每次循环都在膨胀,而模型的上下文是有限的,越多的上下文可能会导致模型输出更加不确定的结果,因此需要在必要的时候对上下文进行管理,一般下面几种策略进行组合使用:
Claude Code 的上下文管理有四层组成:源头控制 -> 工具结果清理 -> 自动 Compaction -> Subagent 分流。
OpenAI 在 Harness Engineering 文章中也强调了同样的理念——上下文是稀缺资源,塞太多反而让 Agent 抓不住重点。
LLM 其实并不关心工具是哪种类型的,一般来说我们会告诉大模型有哪些工具可以用,模型推断出来要使用哪个工具,然后让 Harness 去负责路由调用,Harness 调用之后再将结果传个模型继续分析。
Harness 是"确定性的壳"包裹"不确定性的核": LLM 的输出不确定,Harness 用确定性代码约束它。这呼应了官方的 Architectural Constraints——不是建议 Agent "请遵守规范",而是让它不可能违反。
Harness 拥有状态,LLM 没有: LLM 是无状态的,通过 Harness 维护消息列表、Trace、执行步数,帮助模型拥有记忆。这对应 Context Engineering 的核心——管理 Agent 能看到什么。
Harness 定义了 Agent 的"能力边界": 能调哪些工具、最多循环几次、错误怎么处理,都是 Harness 决定的。OpenAI 也说:模型质量在快速趋同,但 Harness 是每个团队必须自己搭建的资产,这才是长期竞争力的来源。
下一篇深入 Agent 运行时的核心机制。