傻子可懂的 Harness Engineering 保姆级教程!零基础也能看懂,一个实战项目带你跑通全流程

你可能听过 Prompt Engineering、Context Engineering,现在又冒出来一个 Harness Engineering——这玩意到底是啥?跟前面俩啥关系?学了能干嘛?别急,这篇文章用最白的大白话,从零讲透,最后还带你跑一个实战项目。


一、用大白话讲清楚:Harness Engineering 到底是什么?

1.1 一个比喻你就懂了

想象你雇了一个超级聪明但没经验的实习生来帮你写代码。

  • Prompt Engineering = 你告诉他"帮我写个登录功能"——这是在说话方式上下功夫,让他听懂你的需求。
  • Context Engineering = 你把项目文档、代码规范、技术栈说明都放在他桌上——这是在信息环境上下功夫,让他有据可查。
  • Harness Engineering = 你给他配了电脑、装了开发环境、设了代码审查流程、加了自动化测试、规定他不能直接改生产库——这是在整个工作系统上下功夫,让他能干活、干好活、不闯祸。

一句话总结:Harness Engineering 就是给 AI Agent 搭一套"工作台",让它能可靠地完成任务,而不是到处闯祸。

1.2 正式定义

Harness Engineering 这个概念由 Mitchell Hashimoto(HashiCorp 联合创始人、Terraform 创作者)首次明确提出。他的核心观点是:

每当发现 Agent 犯了一个错误,就花时间设计一个解决方案,确保这类错误永远不再发生。

这里的"解决方案"不是改 Prompt,不是换个模型,而是在 Agent 的运行环境中加约束、加工具、加反馈、加护栏——这套包裹在模型外面的完整系统,就叫 Harness(缰绳/安全带)

1.3 为什么现在这么火?

OpenAI 的 Codex 团队用 3 个工程师、5 个月时间,写出了百万行级别的生产代码。他们能做到这件事的核心原因不是模型更强了,而是把 Harness 工程做到了极致——Agent 在一个高度约束、高度自动化的环境中工作,犯错率极低,产出极高。

2026 年初,多家科技公司披露 AI 项目延期,原因不是模型能力不够,而是 Harness 工程没到位——Agent 在不受约束的环境中频繁出错,人工兜底成本远超预期。

结论:模型决定上限,Harness 决定下限。


二、三者到底啥区别?一图讲透

2.1 层级关系

三者不是并列关系,而是一层套一层的包含关系:

┌─────────────────────────────────────────────┐
│           Harness Engineering                │
│  ┌───────────────────────────────────────┐  │
│  │        Context Engineering             │  │
│  │  ┌─────────────────────────────────┐  │  │
│  │  │      Prompt Engineering          │  │  │
│  │  └─────────────────────────────────┘  │  │
│  └───────────────────────────────────────┘  │
│                                             │
│  + 执行能力(工具、沙箱、命令)              │
│  + 任务编排(流程控制、多步协调)            │
│  + 反馈机制(验证、纠错、质量门禁)          │
│  + 架构护栏(约束、权限、安全边界)          │
└─────────────────────────────────────────────┘

2.2 对比表

维度 Prompt Engineering Context Engineering Harness Engineering
关注点 怎么跟 AI 说清楚需求 给 AI 提供什么信息 给 AI 搭什么工作系统
核心动作 调措辞、改指令 管上下文、控信息流 加约束、加工具、加护栏
解决的问题 AI 听不懂/理解偏 AI 信息不足/信息过载 AI 乱操作/不可靠/闯祸
类比 教你怎么跟实习生说话 给实习生准备参考资料 给实习生配完整工作台
生效范围 单次对话 单次会话 整个工程生命周期
代表实践 System Prompt、Few-shot CLAUDE.md、RAG AGENTS.md、工具白名单、CI 门禁

2.3 一个具体例子

你要让 AI 帮你改一个用户认证模块的 Bug:

  • Prompt 层:“请修复 src/auth/login.ts 中的 token 过期验证逻辑,确保 refresh token 在 access token 过期后自动刷新。”
  • Context 层:在 CLAUDE.md 中写明项目使用 JWT + Redis 方案,token 过期时间配置在 config/auth.ts,相关测试在 tests/auth/ 目录。
  • Harness 层:规定 Agent 只能修改 auth/ 目录下的文件,改完必须跑 npm test,测试不通过就自动回滚,改动必须生成 PR 而不能直接 push 到 main 分支。

看到区别了吗?Prompt 是"说什么",Context 是"给什么信息",Harness 是"怎么管住它"。


三、五大核心模块拆解

一个完整的 Harness 系统由五个核心模块组成。下面逐个拆解,每个都配实际场景。

3.1 模块一:上下文架构(Context Architecture)

核心原则:Agent 应当恰好获得当前任务所需的上下文——不多不少。

给太少,Agent 不懂项目背景,瞎改一通;给太多,Agent 被信息淹没,抓不住重点。上下文架构就是解决"给什么、给多少、什么时候给"的问题。

分层策略:

层级 加载时机 内容示例 上下文占用
Tier 1:会话常驻 每次会话自动加载 AGENTS.md / CLAUDE.md、项目结构概览 最小
Tier 2:按需加载 特定任务被触发时 API 文档、数据库 Schema、设计文档 中等
Tier 3:临时注入 当前任务需要时 报错日志、Git Diff、特定文件内容 较大

实际场景:

你让 Agent 修一个支付接口的 Bug。Tier 1 的 CLAUDE.md 告诉它项目用 TypeScript + Express;Tier 2 在它打开支付模块时自动加载 Stripe API 文档和订单数据库 Schema;Tier 3 在它遇到报错时注入具体的错误日志。

关键操作: 在项目根目录创建 CLAUDE.md,写入项目核心信息:

# 项目概览
- 技术栈:TypeScript + Express + PostgreSQL
- 包管理:pnpm
- 测试框架:Vitest

# 代码规范
- 使用严格 TypeScript,禁止 any
- API 路由定义在 src/routes/
- 数据库操作只通过 src/repositories/ 层

# 常见约束
- 不要修改 migrations/ 目录下的已有迁移文件
- 环境变量通过 .env.local 管理,不要硬编码

3.2 模块二:执行能力(Execution Capability)

核心原则:Agent 不只是"说",还得能"做"——而且是在受控环境中做。

光有脑子不行,还得有手。执行能力就是给 Agent 装上"手":读写文件、运行命令、调用 API、操作数据库。但这些能力必须在受控范围内,不能让它想干啥干啥。

执行能力的三个层次:

层次 能力 示例
工具调用 Agent 可调用的预定义函数 读写文件、搜索代码、执行终端命令
沙箱环境 隔离的执行空间 本地沙箱、Docker 容器、远程虚拟机
权限控制 限制 Agent 能做什么 文件白名单、命令黑名单、网络隔离

实际场景:

Claude Code 的执行能力设计:Agent 可以读写项目文件、执行 shell 命令、调用 Git 操作,但所有操作都在用户本地的项目目录内进行,且危险操作(如 rm -rfDROP TABLE)会被拦截或要求确认。

关键操作: 在 CLAUDE.md 中声明工具权限:

# 工具权限
- 允许执行:git, npm, pnpm, vitest, eslint, tsc
- 禁止执行:rm -rf, DROP, TRUNCATE, 直接操作生产数据库
- 文件修改范围:仅限 src/ 和 tests/ 目录

3.3 模块三:任务编排(Task Orchestration)

核心原则:复杂任务不是一步完成的,需要拆解、调度、协调。

Agent 拿到一个大任务(比如"重构整个认证模块"),不能一上来就动手改代码。它需要先拆成小步骤,按顺序执行,每步验证后再进行下一步,遇到问题能回退或调整策略。

编排模式:

模式 说明 适用场景
线性编排 A → B → C → D,逐步执行 简单的修 Bug、加功能
条件编排 根据上一步结果决定下一步 需要判断的场景(测试通过才提交)
并行编排 多个子任务同时进行 互不依赖的修改(改前端 + 改后端)
递归编排 Agent 自己拆解子任务并编排 复杂的重构、多模块改动

实际场景:

你要让 Agent 实现"用户注册功能"。线性编排如下:

1. 分析需求 → 2. 设计数据模型 → 3. 写数据库迁移 → 4. 实现 API 接口
→ 5. 写单元测试 → 6. 跑测试验证 → 7. 更新 API 文档 → 8. 提交 PR

每一步完成后,Agent 检查结果,确认无误再进入下一步。如果第 6 步测试失败,自动回到第 4 步修复代码。

关键操作: 在 CLAUDE.md 中定义任务流程:

# 任务流程
1. 任何代码修改前,先阅读相关现有代码
2. 修改后必须运行 pnpm test 确认测试通过
3. 新功能必须附带测试用例
4. 所有修改通过 PR 提交,不要直接 push 到 main

3.4 模块四:反馈机制(Feedback Mechanism)

核心原则:Agent 每做一步,都要有反馈告诉它做得对不对。

没有反馈,Agent 就是在黑暗中摸索。反馈机制就是给 Agent 装"眼睛":代码能不能编译、测试能不能通过、Lint 有没有报错、功能是否符合预期。

反馈类型:

类型 来源 示例
编译反馈 编译器/类型检查 TypeScript 报错、构建失败
测试反馈 自动化测试 单元测试失败、集成测试不通过
Lint 反馈 代码检查工具 ESLint 报错、格式不符合规范
运行反馈 实际运行结果 接口返回 500、页面白屏
人工反馈 人类审查 Code Review 意见、需求变更

实际场景:

Agent 修改了一段代码后,Harness 自动执行以下反馈链:

tsc 编译 → ESLint 检查 → Vitest 测试 → 手动 Review
    ↓           ↓            ↓            ↓
  通过 ✅     通过 ✅     失败 ❌      ——
                              ↓
                    Agent 自动修复 → 重新测试 → 通过 ✅ → 进入 Review

关键操作: 配置自动化的反馈流水线:

# 反馈流程
- 每次文件保存后自动运行 tsc --noEmit
- 每次代码修改后自动运行 pnpm test
- ESLint 错误视为阻断性错误,必须修复
- 测试覆盖率不得低于现有水平

3.5 模块五:架构护栏(Architecture Guardrails)

核心原则:有些事 Agent 永远不能做,有些边界永远不能越。

护栏是 Harness 的最后一道防线。不管 Agent 多聪明,有些红线不能碰:不能删生产数据、不能绕过安全检查、不能违反架构规范。护栏不是"建议",是"硬约束"。

护栏类型:

类型 说明 示例
文件护栏 限制可修改的文件范围 禁止修改 config/、migrations/
命令护栏 限制可执行的命令 禁止 rm -rf、sudo、curl 外部服务
架构护栏 限制代码架构选择 禁止引入新依赖、禁止跨层调用
安全护栏 限制敏感操作 禁止硬编码密钥、禁止提交 .env 文件
流程护栏 限制操作流程 必须通过 PR、必须通过 CI

实际场景:

Mitchell Hashimoto 在 Ghostty 项目中的 AGENTS.md 就是典型的架构护栏实践。这个文件里每一条规则都对应一次 Agent 犯过的错误——Agent 犯了新类型的错,就加一条新规则。这个文件会持续增长,形成一道越来越厚的防护墙。

关键操作: 在 CLAUDE.md 中设置护栏:

# 护栏规则
- 禁止修改 prisma/migrations/ 下的已有迁移文件
- 禁止在 src/ 之外创建新目录
- 禁止引入未在 package.json 中声明的新依赖
- 禁止在代码中出现硬编码的密钥、Token、密码
- 禁止直接操作 main 分支,所有改动走 PR
- 数据库查询必须通过 Repository 层,禁止在路由中直接写 SQL

四、实战项目:用 Harness 思维开发一个 Todo API

光说不练假把式。下面我们用一个真实的实战项目,带你走完 Harness 在方案设计 → 编码开发 → 测试验证 → 功能扩展四个阶段的全流程。

项目背景: 用 Node.js + Express + SQLite 开发一个 Todo REST API,支持增删改查。

4.1 阶段一:方案设计——先搭 Harness,再写代码

很多人拿到需求就开写,结果 Agent 到处乱改、反复出错。正确做法是先把 Harness 搭好,再让 Agent 干活。

Step 1:创建项目骨架

mkdir todo-api && cd todo-api
npm init -y
npm install express better-sqlite3
npm install -D vitest eslint typescript @types/node @types/express

Step 2:搭建目录结构

todo-api/
├── src/
│   ├── index.ts          # 入口文件
│   ├── routes/
│   │   └── todos.ts      # 路由定义
│   ├── repositories/
│   │   └── todoRepo.ts   # 数据库操作层
│   ├── services/
│   │   └── todoService.ts # 业务逻辑层
│   └── types/
│       └── index.ts      # 类型定义
├── tests/
│   └── todos.test.ts     # 测试文件
├── CLAUDE.md             # ← Harness 核心配置
├── package.json
└── tsconfig.json

Step 3:编写 CLAUDE.md(这是最关键的一步)

# Todo API 项目

## 技术栈
- Runtime: Node.js + TypeScript
- Framework: Express
- Database: SQLite (better-sqlite3)
- Test: Vitest
- Lint: ESLint

## 项目结构
- src/routes/ — 路由定义,只处理 HTTP 请求/响应
- src/services/ — 业务逻辑,不直接操作数据库
- src/repositories/ — 数据库操作,不包含业务逻辑
- src/types/ — TypeScript 类型定义

## 代码规范
- 严格 TypeScript,禁止 any
- 三层架构:Route → Service → Repository,禁止跨层调用
- 每个 API 端点必须有对应的测试用例
- 错误处理统一使用自定义 AppError 类

## 护栏规则
- 禁止在 routes/ 中直接写 SQL
- 禁止在 services/ 中直接操作数据库
- 禁止修改 package.json 中的依赖(需人工确认)
- 数据库文件存放在 data/todo.db,禁止修改路径
- 所有 API 响应遵循 { success: boolean, data?: any, error?: string } 格式

## 开发流程
1. 先在 types/ 中定义类型
2. 在 repositories/ 中实现数据操作
3. 在 services/ 中实现业务逻辑
4. 在 routes/ 中实现 API 端点
5. 在 tests/ 中编写测试
6. 运行 pnpm test 确认通过

这一步的本质: 在 Agent 动手之前,就把上下文(项目结构、技术栈)、护栏(禁止跨层、禁止改依赖)、流程(开发顺序、测试要求)全部定义好。这就是 Harness 思维——先建轨道,再让火车跑

4.2 阶段二:编码开发——让 Agent 在轨道上跑

现在 Harness 搭好了,让 Agent 开始写代码。

给 Agent 的指令:

请根据 CLAUDE.md 中的项目规范,实现 Todo API 的完整功能:
1. 在 src/types/index.ts 中定义 Todo 类型
2. 在 src/repositories/todoRepo.ts 中实现 CRUD 数据操作
3. 在 src/services/todoService.ts 中实现业务逻辑
4. 在 src/routes/todos.ts 中定义 API 路由
5. 在 src/index.ts 中组装 Express 应用

Agent 在 Harness 约束下的工作过程:

读取 CLAUDE.md → 理解三层架构约束
    ↓
定义 Todo 类型(id, title, completed, createdAt)
    ↓
实现 Repository 层(CRUD 操作,直接操作 SQLite)
    ↓
实现 Service 层(调用 Repository,处理业务逻辑)
    ↓
实现 Route 层(调用 Service,处理 HTTP 请求响应)
    ↓
组装 Express 应用,注册路由

因为 CLAUDE.md 中明确规定了三层架构和禁止跨层调用,Agent 不会在 Route 里直接写 SQL,也不会在 Service 里直接操作数据库。护栏在默默生效。

Agent 生成的核心代码示例:

src/types/index.ts

export interface Todo {
  id: number;
  title: string;
  completed: boolean;
  createdAt: string;
}

export interface CreateTodoInput {
  title: string;
}

export interface UpdateTodoInput {
  title?: string;
  completed?: boolean;
}

src/repositories/todoRepo.ts

import Database from 'better-sqlite3';
import { Todo, CreateTodoInput, UpdateTodoInput } from '../types';

const db = new Database('data/todo.db');
db.exec('CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY, title TEXT NOT NULL, completed INTEGER DEFAULT 0, createdAt TEXT DEFAULT (datetime("now")))');

export const todoRepo = {
  findAll: (): Todo[] => db.prepare('SELECT * FROM todos').all().map(row => ({ ...row, completed: !!row.completed })),
  findById: (id: number): Todo | undefined => { const row = db.prepare('SELECT * FROM todos WHERE id = ?').get(id); return row ? { ...row, completed: !!row.completed } : undefined; },
  create: (input: CreateTodoInput): Todo => { const result = db.prepare('INSERT INTO todos (title) VALUES (?)').run(input.title); return todoRepo.findById(result.lastInsertRowid as number)!; },
  update: (id: number, input: UpdateTodoInput): Todo | undefined => { const sets = []; const values = []; if (input.title !== undefined) { sets.push('title = ?'); values.push(input.title); } if (input.completed !== undefined) { sets.push('completed = ?'); values.push(input.completed ? 1 : 0); } if (sets.length === 0) return todoRepo.findById(id); values.push(id); db.prepare(`UPDATE todos SET ${sets.join(', ')} WHERE id = ?`).run(...values); return todoRepo.findById(id); },
  delete: (id: number): boolean => db.prepare('DELETE FROM todos WHERE id = ?').run(id).changes > 0,
};

4.3 阶段三:测试验证——反馈机制自动生效

代码写完了,Harness 的反馈机制开始工作。

给 Agent 的指令:

请为 Todo API 编写完整的测试用例,覆盖所有 CRUD 操作和边界情况。

Agent 在 Harness 约束下的工作:

它知道测试框架是 Vitest(从 CLAUDE.md 读取),知道每个端点必须有测试(护栏要求),于是生成:

tests/todos.test.ts

import { describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest';
import { app } from '../src/index';

describe('Todo API', () => {
  beforeEach(async () => {
    // 每个测试前清空数据库
  });

  it('应该创建一个新 Todo', async () => {
    const res = await request(app).post('/api/todos').send({ title: '测试任务' });
    expect(res.body.success).toBe(true);
    expect(res.body.data.title).toBe('测试任务');
    expect(res.body.data.completed).toBe(false);
  });

  it('应该获取所有 Todo', async () => {
    await request(app).post('/api/todos').send({ title: '任务1' });
    await request(app).post('/api/todos').send({ title: '任务2' });
    const res = await request(app).get('/api/todos');
    expect(res.body.data).toHaveLength(2);
  });

  it('应该更新 Todo', async () => {
    const created = await request(app).post('/api/todos').send({ title: '待完成' });
    const res = await request(app).put(`/api/todos/${created.body.data.id}`).send({ completed: true });
    expect(res.body.data.completed).toBe(true);
  });

  it('应该删除 Todo', async () => {
    const created = await request(app).post('/api/todos').send({ title: '待删除' });
    const res = await request(app).delete(`/api/todos/${created.body.data.id}`);
    expect(res.body.success).toBe(true);
  });

  it('创建时缺少 title 应该返回错误', async () => {
    const res = await request(app).post('/api/todos').send({});
    expect(res.body.success).toBe(false);
  });
});

运行测试:

pnpm test

如果测试失败,Agent 会根据反馈自动修复代码,直到所有测试通过。这就是反馈闭环:写代码 → 跑测试 → 失败 → 修复 → 再测试 → 通过。

4.4 阶段四:功能扩展——Harness 持续演进

项目跑起来了,现在要加新功能:给 Todo 加上优先级和分类标签

错误做法: 直接让 Agent 开干,它可能乱改数据库、破坏现有接口。

正确做法: 先更新 Harness,再让 Agent 干活。

Step 1:更新 CLAUDE.md

在原有内容基础上追加:

## 新增功能:优先级与标签

### 数据库变更
- 新增 priority 字段(枚举:low / medium / high,默认 medium)
- 新增 tags 字段(JSON 字符串,存储标签数组)
- 必须创建新的迁移文件,禁止修改已有表结构

### API 变更
- GET /api/todos 支持 ?priority=high&tag=work 筛选参数
- 响应格式保持 { success, data, error } 不变

### 护栏
- 禁止删除已有字段
- 现有测试必须继续通过
- 新增字段必须有默认值,确保向后兼容

Step 2:让 Agent 在更新后的 Harness 下工作

请根据 CLAUDE.md 中新增的需求,为 Todo 添加优先级和标签功能。
注意遵守所有护栏规则,确保现有功能不受影响。

Agent 的工作流程:

读取更新后的 CLAUDE.md → 理解新需求和护栏
    ↓
更新 Todo 类型(新增 priority、tags 字段)
    ↓
创建数据库迁移(新增字段,设默认值,不改已有数据)
    ↓
更新 Repository 层(新增筛选查询)
    ↓
更新 Service 层(新增筛选逻辑)
    ↓
更新 Route 层(新增查询参数处理)
    ↓
运行全量测试 → 确认旧测试通过 + 新测试通过

关键点: 因为 Harness 中规定了"禁止修改已有表结构"和"现有测试必须继续通过",Agent 会选择新增字段而非修改字段,会确保向后兼容。护栏再次默默生效。


五、核心心法:Harness 的三条铁律

跑完实战项目,总结三条贯穿始终的铁律:

铁律一:约束优于指令

与其告诉 Agent “请小心不要跨层调用”,不如直接在 CLAUDE.md 中写"禁止跨层调用"并在代码审查中拦截。硬约束 > 软建议,能自动拦截的就不要靠 Agent 自觉。

铁律二:每次犯错加一条规则

Mitchell Hashimoto 的做法:Agent 每犯一个新类型的错误,就在 AGENTS.md 中加一条规则。这个文件会越来越长,但 Agent 犯错的概率会越来越低。Harness 是活的,不是一次性的。

铁律三:先搭轨道再让火车跑

不要一上来就让 Agent 写代码。先把项目结构、代码规范、护栏规则、开发流程在 CLAUDE.md 中定义好,再让 Agent 开始工作。前期多花 30 分钟搭 Harness,后期省 3 小时修 Bug。


六、不同工具的 Harness 实践对照

工具 Harness 配置文件 核心能力 适合场景
Claude Code CLAUDE.md 上下文管理 + 工具调用 + 沙箱执行 全栈开发、项目级编码
Cursor .cursorrules 上下文管理 + 编辑器集成 前端开发、快速迭代
Codex AGENTS.md 任务编排 + CI 集成 + PR 管理 大规模代码生成、团队协作
Windsurf .windsurfrules 上下文管理 + 多文件编辑 全栈开发

不管用什么工具,Harness 的核心思想不变: 约束行为、提供上下文、建立反馈、设置护栏。


七、从今天开始:你的 Harness 行动清单

  1. 今天: 在你当前项目根目录创建一个 CLAUDE.md,写上项目技术栈、目录结构、代码规范
  2. 本周: 每次发现 Agent 犯错,就在 CLAUDE.md 中加一条规则,持续积累
  3. 本月: 为项目配置自动化测试和 Lint,让反馈机制自动运转
  4. 长期: 把 CLAUDE.md 当成项目的"活文档",随项目演进持续更新

记住:Harness 不是一次性搭建的,而是在一次次犯错中长出来的。 每一条规则背后,都是一次真实的踩坑。这就是 Mitchell Hashimoto 说的——“每当 Agent 犯错,就花时间设计一个解决方案,确保这类错误永远不再发生。”


一句话带走: Prompt Engineering 教你怎么说,Context Engineering 教你给什么信息,Harness Engineering 教你怎么管住 AI 让它可靠干活。三者一层套一层,Harness 是最外层也是最重要的一层——因为模型决定上限,Harness 决定下限。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐