如果“代理能做什么”是技能,那么“它如何运作”就是 Harness。
>
🎯 本文涵盖内容
- OpenAI 的 Harness 工程实验 — 100 万行代码,0 行由人类编写
- Anthropic 定义的长期运行代理 Harness 结构
- 技能 (Skill) 与 Harness 的根本区别
- 为什么这两个概念容易混淆,以及如何区分它们
- 如何在实践中直接设计 Harness
📌 引入 — 为什么这种区分变得重要
从 2025 年底到 2026 年初,AI 代理世界出现了两篇重要文章。
一篇是 OpenAI 的“Harness Engineering”帖子,总结了其内部实验,即 Codex 代理在没有人为干预的情况下完成了大约 100 万行代码。另一篇是 Anthropic 的工程博客,介绍了使用 Claude Agent SDK 设计代理以在多个上下文窗口中保持一致工作的方法论。
这两篇文章都使用了“Harness”一词。然而,在实践中,这个概念经常与“Skill”混淆使用。
直接设计或操作代理的工程师必须准确理解这两个概念之间的区别。
🔍 什么是技能 (Skill)
技能是代理与外部世界交互的单位能力。简单来说,它是代理“能做什么”的列表。
| 分类 | 示例 |
| 基本工具 | bash 执行、文件读写、git 操作 |
| MCP 服务器 | Puppeteer(浏览器自动化)、Slack、Google Drive |
| 外部 API | 网页搜索、数据库查询、代码执行 |
| 子代理 | 委派给专注于特定角色的子代理 |
技能可以看作是代理的运行时或外围设备 — 它定义了模型如何与环境交互。
以人类类比,技能是个人的能力。能够用 Python 编程,能够用英语交流,能够分析数据 — 这些都是技能。
🔍 什么是 Harness
Harness 是围绕代理的整个执行环境。代理 Harness 包裹着 AI 模型,是一个管理其生命周期、上下文、工具访问、验证和安全性的基础设施层。如果模型生成文本,Harness 则决定模型看到什么、能做什么、何时停止以及出错时会发生什么。
Harness 是一组约束、工具、文档和反馈循环,旨在使代理保持高效和正确的方向。
再次以人类类比,如果技能是“个人能力”,那么 Harness 就像公司的入职系统、代码审查流程、KPI 和文档体系。即使是拥有卓越个人能力的员工,如果没有适当的工作环境,也无法持续产出高质量的结果。
🔍 两个概念的核心区别
| 区分 | 技能 (Skill) | Harness |
| 定义 | 代理的单个能力单元 | 包裹代理的执行环境 |
| 问题 | “能做什么?” | “如何运作?” |
| 组成部分 | 工具、MCP 服务器、API、函数 | 约束、反馈循环、上下文管理、文档结构 |
| 应用时机 | 代理行动时 | 代理存在的整个过程 |
| 设计主体 | 工具提供者(开发者) | 环境设计者(工程团队) |
| 比喻 | 员工的个人技能 | 公司的业务体系/流程 |

🔍 OpenAI 的 Harness 工程
在 OpenAI 为期 5 个月的内部实验中,工程师们没有直接编写代码。他们设计的是一个能够实现可靠代码生成的环境,这个环境被命名为 Harness。
OpenAI Harness 的组成部分如下:
1. AGENTS.md — 作为目录的知识地图
不使用单个庞大的文档,而是将大约 100 行的简短 AGENTS.md 注入到上下文中,并将其用作目录。实际的知识库位于结构化的 docs/ 目录中,设计文档、执行计划和架构图作为单一信息源进行管理。
2. 强制分层架构
通过自定义 linter 和结构测试强制执行 Types → Config → Repo → Service → Runtime → UI 顺序的严格依赖层。代理不能违反这些模块边界。
3. 漂移检测代理
一个后台代理会定期扫描过时的文档并打开清理 PR — 这是一个由代理为代理编写文档的结构。
🔍 Anthropic 的 Harness — 解决长期运行代理问题
Anthropic 面临的核心挑战是代理如何在多个上下文窗口中保持一致的进度。每个新会话开始时,都没有之前发生过什么的记忆。这就像轮班工程师在没有交接的情况下工作。
Anthropic 的解决方案是将角色分为两个代理:
初始化代理 (Initializer Agent)
在初始会话中运行,设置 init.sh 脚本、claude-progress.txt 进度日志和初始 git 提交。
关键在于以 JSON 格式编写功能列表 (Feature List)。
{
"category": "functional",
"description": "New chat button creates a fresh conversation",
"steps": [
"Navigate to main interface",
"Click the 'New Chat' button",
"Verify a new conversation is created"
],
"passes": false
}
选择 JSON 是因为代理不当修改或覆盖 JSON 文件的可能性低于 Markdown 文件。
编码代理 (Coding Agent)
在之后的所有会话中,它被要求一次只处理一个功能。会话结束时,通过 git 提交和更新进度文件来清理环境,以便下一个代理能够快速掌握上下文。
🔍 代理失败模式和 Harness 解决方案
代理的主要失败模式有两种。第一,试图一次实现太多功能,导致在上下文中间终止,下一个会话只继承了部分完成的代码。第二,一些功能完成后,就宣布其余功能也已完成。
阻止这些失败正是 Harness 的作用。
| 失败模式 | 初始化代理应对 | 编码代理应对 |
| 过早宣布完成 | 创建 JSON 功能列表文件 | 会话开始时检查功能列表 |
| 未文档化的进度 | 设置初始 git + 进度笔记 | 会话开始/结束时更新 |
| 未经测试即完成 | 设置浏览器自动化工具 | 手动验证所有功能后标记为通过 |
| 浪费时间探索应用执行方法 | 编写 init.sh 脚本 | 会话开始时执行 init.sh |
—
💻 亲自构建 Harness 结构
以下是参考 Anthropic 博客的最小 Harness 结构示例。
project/
├── AGENTS.md # 代理目录 (100行以下)
├── docs/
│ ├── architecture.md # 系统架构
│ ├── decisions/ # 设计决策历史
│ └── api-contracts/ # 接口契约
├── init.sh # 开发服务器启动脚本
├── feature_list.json # 功能列表 (passes: false → true)
└── claude-progress.txt # 会话间交接文件
feature_list.json 功能项更新示例:
import json
def mark_feature_done(feature_id: str):
with open("feature_list.json", "r+") as f:
data = json.load(f)
for feature in data["features"]:
if feature["id"] == feature_id:
feature["passes"] = True
feature["completed_at"] = "2026-04-14"
f.seek(0)
json.dump(data, f, indent=2)
f.truncate()
claude-progress.txt 编写模式:
## Session 2026-04-14
### Completed
- [FEAT-012] 로그인 폼 유효성 검사 구현
- [FEAT-013] JWT 토큰 발급 로직 추가
### Current State
- 개발 서버 정상 동작 중 (port 3000)
- 기본 인증 플로우 동작 확인 완료
### Next Priority
- [FEAT-014] 리프레시 토큰 처리 로직 (미시작)
⚠️ 注意事项 — 常见的设计错误
认为技能越多 Harness 越强的误解
当 Vercel 将工具数量减少 80% 时,性能反而提高了。生产 Harness 会根据任务阶段动态限制可用工具。技能过载会使代理感到困惑。
单一庞大指令文件的陷阱
单一庞大的手册会成为过时规则的坟墓。代理无法区分哪些仍然有效,人类停止维护,该文件悄然成为有害的障碍。
上下文过载
当上下文利用率超过约 40% 时,性能会下降。用工具、冗长的文档和累积的历史填充代理,反而会降低性能。
✅ 总结
| 项目 | 技能 | Harness |
| 核心问题 | 能做什么? | 如何运作? |
| 主要构成 | 工具、MCP、API | 文档结构、约束、反馈循环、上下文管理 |
| 设计对象 | 代理的能力 | 代理的环境 |
| 失败时症状 | 无法执行特定任务 | 结果不一致、漂移、循环 |
代理时代的工程领域正在从编写代码转向环境设计。最有效的工程师不是最快的编码员,而是最优秀的环境设计师,他们理解如何构建存储库,以便代理能够在其中进行推理。
技能赋予代理翅膀,而 Harness 则是确保这些翅膀朝着正确方向飞行的空中交通管制系统。

发表回复