前言:我的角色变了
过去一年,我的日常工作发生了一个微妙但根本性的变化:
以前,我 80% 的时间在写代码,20% 在想架构。现在反过来了------我 80% 的时间在设计规则、约束和反馈机制,剩下 20% 在审查 Agent 的产出。
我不再是一个「写代码的人」,而是一个「驾驭 AI 写代码的人」。
这种转变有了一个正式的名字:Harness Engineering(驾驭工程)。Harness 直译是「马具」,就是套在马身上、让骑手能控制方向和速度的那套装备。用在 AI 语境下,它指的是包裹在模型外面的那整套控制系统------规则、约束、Skills、工具链、反馈循环。
一组数据让我确信这件事的价值:同一个模型,只改 Harness,编程基准成功率从 42% 跳到了 78%。 模型没换、提示词没换,性能翻了将近一倍。换句话说,Harness 带来的提升,相当于换了一代模型。
这篇文章不讲概念(概念已经有太多人讲了),我想聚焦一个实操问题:Harness 到底怎么开发?从哪里入手?日常怎么迭代?
一、先看全景:驾驭系统的架构
在讲具体怎么做之前,先建立一个整体认知。下面这张图是 Harness 的完整架构------它就像 Agent 的操作系统,夹在底层模型和上层应用之间:
scss
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────────────┐ │
│ │ AGENT (应用层) │ │
│ │ 执行具体任务的 AI │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ AGENT HARNESS (驾驭层 / 操作系统) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌──────────────────────┐ │ │
│ │ │ Prompt │ │ Tool │ │ Filesystem │ │ │
│ │ │ Presets │ │ Handling │ │ Access │ │ │
│ │ │ 提示词预设 │ │ 工具调度 │ │ 文件系统访问 │ │ │
│ │ └─────────────┘ └─────────────┘ └──────────────────────┘ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌──────────────────────┐ │ │
│ │ │ Lifecycle │ │ Planning │ │ Sub-Agent │ │ │
│ │ │ Hooks │ │ 规划引擎 │ │ Management │ │ │
│ │ │ 生命周期钩子 │ │ │ │ 子Agent管理 │ │ │
│ │ └─────────────┘ └─────────────┘ └──────────────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────┐ ┌──────────────────────────┐ │
│ │ MODEL (CPU) │ │ CONTEXT WINDOW (RAM) │ │
│ │ 模型 = 原始算力 │ │ 上下文窗口 = 工作记忆 │ │
│ └──────────────────────┘ └──────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
关键认知:模型是 CPU,算力再强,没有操作系统也跑不起来。 过去两年我们一直在升级 CPU,但操作系统还停留在 DOS 时代。
驾驭层的六个模块,就是我们要「开发」的对象:
| 模块 | 做什么 | 类比 |
|---|---|---|
| Prompt Presets(提示词预设) | 定义 Agent 的角色、行为边界、输出格式 | 员工的岗位说明书 |
| Tool Handling(工具调度) | 控制 Agent 能用哪些工具、怎么用 | 员工的权限和工具箱 |
| Filesystem Access(文件系统访问) | 决定 Agent 能看到哪些文件和上下文 | 员工的资料柜访问权 |
| Planning(规划引擎) | 拆解复杂任务为可执行步骤 | 项目经理的排期表 |
| Sub-Agent Management(子 Agent 管理) | 协调多个 Agent 协作、隔离、合并 | 团队分组与汇报关系 |
| Lifecycle Hooks(生命周期钩子) | 在 Agent 执行前/中/后插入检查和干预 | 质量检查站 |
二、工程师角色的根本转变
在深入具体开发方法之前,先明确一件事:你的交付物变了。
swift
┌──────────────────────────────────────────────────────────────────┐
│ 工程师角色的转变 │
│ │
│ ┌──────────────────────┐ ┌──────────────────────────┐ │
│ │ 传统工程师 │ │ 驾驭工程师 │ │
│ │ │ │ │ │
│ │ 输入:需求文档 │ │ 输入:Agent 的错误模式 │ │
│ │ 过程:写代码 │ ──▶ │ 过程:写规则 / 约束 / │ │
│ │ 产出:功能代码 │ │ 反馈循环 │ │
│ │ 度量:代码行数/ │ │ 产出:AGENTS.md / │ │
│ │ 功能完成度 │ │ linter规则 / │ │
│ │ │ │ CI流水线 / │ │
│ │ │ │ 工具配置 │ │
│ │ │ │ 度量:Agent 产出合格率 / │ │
│ │ │ │ PR 一次通过率 │ │
│ └──────────────────────┘ └──────────────────────────┘ │
│ │
│ 以前写的是 implementation(实现) │
│ 现在写的是 specification(规约) │
└──────────────────────────────────────────────────────────────────┘
这不是说你不需要懂代码了。恰恰相反,你得比以前更懂------因为你要写出机器能理解和遵守的规则,这比写一段能跑的代码难得多。
三、开发驾驭系统:六个模块逐个击破
模块一:Prompt Presets(提示词预设)
这是驾驭系统的「身份层」------告诉 Agent 它是谁、该怎么做、不能做什么。
不是写一条 prompt,而是开发一套预设体系:
scss
┌──────────────────────────────────────────────────────────────┐
│ Prompt Presets 的分层架构 │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Layer 1:全局预设 (AGENTS.md) │ │
│ │ 适用于所有任务,定义通用行为准则 │ │
│ │ ≈ 公司级别的员工手册 │ │
│ └────────────────────┬───────────────────────────────┘ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Layer 2:模块预设 (/docs/agents/*.md) │ │
│ │ 针对不同模块的专属规则 │ │
│ │ ≈ 各部门的操作规范 │ │
│ └────────────────────┬───────────────────────────────┘ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Layer 3:任务预设 (动态注入) │ │
│ │ 根据当前任务类型自动拼接的上下文 │ │
│ │ ≈ 针对具体工单的特殊说明 │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ 💡 关键原则:每层只写「目录」,不写「百科全书」 │
│ 全局预设控制在 60 行以内,详细内容通过引用链接 │
└──────────────────────────────────────────────────────────────┘
实操示例:三层预设体系
markdown
# ===== Layer 1: /AGENTS.md(全局预设,~50行)=====
## 你是谁
你是本项目的 AI 开发工程师,负责根据任务描述生成代码并提交 PR。
## 核心架构(必须遵守)
- 分层架构:Types → Config → Repo → Service → Runtime → UI
- 每层只能依赖其下层,严禁反向依赖
- 架构细节见 /docs/agents/architecture.md
## 通用行为规范
- 写代码前先读 /docs/agents/ 目录下对应模块的规则文件
- 所有新增代码必须附带测试,覆盖率不低于 80%
- 禁止留下 TODO / FIXME / HACK 注释
- 禁止使用 any 类型
- 修改文件前先运行该文件的已有测试确认当前状态
## 犯错记录(持续追加)
- ❌ 不要把 API 路由定义在组件文件里 → ✅ 统一放 /src/api/
- ❌ 不要用 moment.js → ✅ 用 dayjs
- ❌ 不要在循环里发请求 → ✅ 用 Promise.all 批量处理
markdown
# ===== Layer 2: /docs/agents/frontend.md(前端模块预设)=====
## 组件开发规范
- 使用函数组件 + Hooks,禁止 class component
- 样式方案:Tailwind CSS,禁止内联 style 对象
- 状态管理:
- 组件局部状态 → useState / useReducer
- 跨组件共享 → Zustand store(定义在 /src/stores/)
- 服务端数据 → TanStack Query(定义在 /src/queries/)
## 文件组织
src/
├── components/ # 通用组件,PascalCase
│ └── Button/
│ ├── Button.tsx
│ ├── Button.test.tsx
│ └── index.ts
├── features/ # 按业务域组织的功能模块
│ └── UserProfile/
│ ├── components/
│ ├── hooks/
│ ├── queries/
│ └── stores/
└── ...
## 常见陷阱
- 路由懒加载必须用 React.lazy + Suspense
- useEffect 清理函数不能省略(Agent 经常忘)
- 表单校验统一用 zod schema,不要手写 if-else
markdown
# ===== Layer 3: 任务预设(动态注入,根据任务类型拼接)=====
# 当任务类型 = "新增API接口" 时,自动注入:
## 本次任务上下文
- 你正在开发的接口归属于 UserService 模块
- 相关数据模型定义在 /src/types/user.ts
- 现有的接口示例参考 /src/api/auth.ts
- 数据库 schema 见 /prisma/schema.prisma 的 User 模型
## 本次任务检查清单
- [ ] 定义请求/响应类型(在 /src/types/ 下)
- [ ] 实现路由处理函数(在 /src/api/ 下)
- [ ] 添加输入校验(使用 zod)
- [ ] 编写集成测试
- [ ] 更新 API 文档(/docs/api.md)
这三层预设的开发节奏:Layer 1 建项目时写一次、持续追加犯错记录;Layer 2 每个模块启动时写一次、稳定后很少改;Layer 3 可以用脚本根据任务类型自动拼装。
模块二:Tool Handling(工具调度)
这是驾驭系统的「权限层」------决定 Agent 能用什么工具,以及在什么条件下用。
核心原则:少即是多。 Vercel 把工具从 15 个砍到 2 个,准确率从 80% 升到了 100%。
scss
┌──────────────────────────────────────────────────────────────────┐
│ 工具调度策略:按任务类型分配工具子集 │
│ │
│ ┌──────────────────┐ │
│ │ 全量工具池 │ │
│ │ (如 Stripe 的 │ │
│ │ 500 个 MCP 工具)│ │
│ └────────┬─────────┘ │
│ │ │
│ ┌──────────────┼──────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ 前端 UI 任务 │ │ 后端 API 任务 │ │ 数据库迁移任务 │ │
│ │ │ │ │ │ │ │
│ │ ✅ 文件读写 │ │ ✅ 文件读写 │ │ ✅ 文件读写 │ │
│ │ ✅ 浏览器截图 │ │ ✅ 终端执行 │ │ ✅ 终端执行 │ │
│ │ ❌ 数据库访问 │ │ ✅ 数据库查询 │ │ ✅ 数据库完整权限 │ │
│ │ ❌ 终端执行 │ │ ❌ 浏览器截图 │ │ ❌ 浏览器截图 │ │
│ │ ❌ 部署操作 │ │ ❌ 部署操作 │ │ ❌ 部署操作 │ │
│ │ │ │ │ │ │ │
│ │ 2 个工具 │ │ 3 个工具 │ │ 3 个工具 │ │
│ └───────────────┘ └──────────────┘ └──────────────────┘ │
│ │
│ 💡 给实习生 15 把螺丝刀他会手忙脚乱;给一把十字一把一字, │
│ 他反而知道该怎么干了。Agent 也一样。 │
└──────────────────────────────────────────────────────────────────┘
实操示例:MCP 工具配置文件
jsonc
// .agent/tool-profiles.json
{
"profiles": {
"frontend": {
"description": "前端 UI 开发任务",
"tools": ["file_read", "file_write", "browser_screenshot"],
"restrictions": {
"file_write": {
"allowed_paths": ["src/components/**", "src/features/**", "src/styles/**"],
"blocked_paths": ["src/core/**", "prisma/**", "server/**"]
}
}
},
"backend": {
"description": "后端 API 开发任务",
"tools": ["file_read", "file_write", "terminal_exec", "db_query"],
"restrictions": {
"terminal_exec": {
"allowed_commands": ["npm test", "npm run lint", "npx prisma generate"],
"blocked_commands": ["rm -rf", "npm publish", "docker push"]
},
"db_query": {
"mode": "read_only" // 只能查,不能改
}
}
},
"migration": {
"description": "数据库迁移任务",
"tools": ["file_read", "file_write", "terminal_exec", "db_full_access"],
"requires_approval": true // 需要人工确认才能执行
}
}
}
开发节奏:先给所有任务只配 2 个基础工具(文件读写),然后根据实际需要逐个添加。每次加工具都问自己:不加这个,Agent 是真的做不到、还是只是做起来麻烦一点?如果是后者,别加。
模块三:Lifecycle Hooks(生命周期钩子)
这是驾驭系统的「质检层」------在 Agent 执行的关键节点插入自动检查。
scss
┌─────────────────────────────────────────────────────────────────┐
│ Agent 执行的生命周期钩子 │
│ │
│ ┌─────────┐ pre_start ┌──────────┐ pre_write ┌────────┐ │
│ │ 任务分配 │─────────────▶│ 读取上下文 │────────────▶│ 生成代码│ │
│ └─────────┘ 钩子 └──────────┘ 钩子 └───┬────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────┐ │
│ │ ✅ 检查 AGENTS.md │ │ ✅ 校验目标文件 │ │ ✅ 运行 linter│ │
│ │ 是否已加载 │ │ 是否在允许范围内 │ │ ✅ 运行测试 │ │
│ │ ✅ 注入任务级预设 │ │ ✅ 检查上下文 token│ │ ✅ 架构合规 │ │
│ │ ✅ 加载相关历史 │ │ 是否超预算 │ │ 检查 │ │
│ └──────────────────┘ └──────────────────┘ └──────┬───────┘ │
│ │ │
│ ┌───────────────────┘ │
│ ▼ │
│ ┌─────────────────────┐ │
│ ┌───────────│ post_test 钩子 │────────────┐ │
│ │ 全部通过 │ │ 有失败 │ │
│ ▼ └─────────────────────┘ ▼ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ 提交 PR │ │ 自动修复 │ │
│ │ 进入审查流程 │ │ (最多 2 轮) │ │
│ └─────────────┘ └──────┬───────┘ │
│ │ │
│ ┌──────────┴───────┐ │
│ │ 仍然失败? │ │
│ │ 转交人类 + 记录 │ │
│ │ 失败原因到 │ │
│ │ Harness 改进日志 │ │
│ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
实操示例:用 Git Hooks + 脚本实现生命周期钩子
bash
#!/bin/bash
# .agent/hooks/pre-commit.sh --- Agent 提交代码前自动执行
echo "🔍 [Harness Hook] 开始提交前检查..."
# 1. 架构合规检查:是否有跨层依赖
echo " 检查架构分层..."
npx eslint --rule 'no-restricted-imports: error' --quiet .
if [ $? -ne 0 ]; then
echo " ❌ 架构违规:存在跨层依赖。请检查 /docs/agents/architecture.md"
exit 1
fi
# 2. 禁止提交包含 TODO/FIXME 的代码
echo " 检查遗留标记..."
if grep -rn "TODO\|FIXME\|HACK\|XXX" --include="*.ts" --include="*.tsx" src/; then
echo " ❌ 发现未完成标记。Agent 不得留下 TODO,请完成所有实现。"
exit 1
fi
# 3. 类型安全检查
echo " 检查类型安全..."
npx tsc --noEmit
if [ $? -ne 0 ]; then
echo " ❌ 类型检查失败。请修复类型错误后再提交。"
exit 1
fi
# 4. 测试覆盖率检查
echo " 运行测试..."
npx vitest run --coverage --silent
COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo " ❌ 测试覆盖率 ${COVERAGE}% < 80%。请补充测试。"
exit 1
fi
echo "✅ [Harness Hook] 所有检查通过,允许提交。"
关键设计:linter 的报错信息里嵌入修复指引。 不要只说"错了",要告诉 Agent 怎么改、去哪里查。这等于把老员工的经验写进了编译器。
模块四:Planning(规划引擎)
这是驾驭系统的「大脑层」------把一个模糊的需求拆解成 Agent 能执行的确定性步骤。
scss
┌──────────────────────────────────────────────────────────────────┐
│ 规划引擎:确定性节点 与 Agentic 节点的混合编排 │
│ (借鉴 Stripe 的 Blueprint 模式) │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 输入:用户需求 │ │
│ │ "给用户资料页添加头像上传功能" │ │
│ └──────────────────────┬───────────────────────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Step 1 [确定性] 拉取相关上下文 │ │
│ │ • 读取 /src/features/UserProfile/ 目录结构 │ │
│ │ • 读取 /src/types/user.ts 类型定义 │ │
│ │ • 读取 /docs/agents/frontend.md 规则 │ │
│ └──────────────────────┬───────────────────────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Step 2 [Agentic] 生成执行计划 │ │
│ │ LLM 分析需求 + 上下文,产出结构化的子任务列表 │ │
│ └──────────────────────┬───────────────────────────────────┘ │
│ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────────────────┐ │
│ │ Step 3a │ │ Step 3b │ │ Step 3c │ │
│ │ [Agentic] │ │ [Agentic] │ │ [Agentic] │ │
│ │ 新增类型 │ │ 实现上传 │ │ 编写 UI 组件 │ │
│ │ 定义 │ │ API 接口 │ │ │ │
│ └─────┬──────┘ └─────┬──────┘ └────────────┬───────────┘ │
│ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Step 4 [确定性] 运行全量测试 + linter │ │
│ └──────────────────────┬───────────────────────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Step 5 [Agentic] 审查测试结果,自动修复失败项 │ │
│ └──────────────────────┬───────────────────────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Step 6 [确定性] 浏览器截图 → 提交 PR │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ⚙️ = 确定性节点(脚本执行,不调用 LLM,零幻觉风险) │
│ 🧠 = Agentic 节点(LLM 判断,需要约束和验证) │
│ │
│ 传送带是确定性的,手艺活是 Agentic 的 │
│ 你不会让工人自己决定传送带往哪走 │
└──────────────────────────────────────────────────────────────────┘
实操示例:任务计划模板(存储在仓库中,Agent 执行前自动加载)
yaml
# .agent/plans/add-feature.yaml
name: "新增功能"
steps:
- id: gather_context
type: deterministic # 确定性步骤
actions:
- read_file: "AGENTS.md"
- read_directory: "{{target_module}}/"
- read_file: "docs/agents/{{domain}}.md"
- id: generate_plan
type: agentic # LLM 判断步骤
prompt: |
基于以下上下文,为需求「{{task_description}}」制定实施计划。
输出格式为 JSON,包含需要修改/新增的文件列表和每个文件的变更摘要。
output_schema: "schemas/plan-output.json" # 强制结构化输出
- id: implement
type: agentic
parallel: true # 子任务可并行
max_retries: 2 # 最多重试 2 次
sub_tasks: "{{from: generate_plan.output.files}}"
- id: validate
type: deterministic
actions:
- run: "npm run lint"
- run: "npm run test"
- run: "npm run type-check"
- browser_screenshot: "{{if: has_ui_changes}}"
- id: review_and_fix
type: agentic
condition: "{{validate.has_failures}}"
max_iterations: 2 # CI 最多跑两轮
fallback: "escalate_to_human"
- id: submit
type: deterministic
actions:
- git_commit: "{{generate_plan.output.commit_message}}"
- create_pr: true
模块五:Sub-Agent Management(子 Agent 管理)
当任务变复杂,一个 Agent 扛不住时,你需要拆分和协调:
vbnet
┌──────────────────────────────────────────────────────────────────┐
│ 递归 Planner-Worker 模型(借鉴 Cursor 最终方案) │
│ │
│ ┌──────────────────┐ │
│ │ Root Planner │ │
│ │ 拥有全局视野 │ │
│ │ 不写代码 │ │
│ └────────┬─────────┘ │
│ │ │
│ ┌──────────────┼──────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Sub-Planner │ │ Sub-Planner │ │ Sub-Planner │ │
│ │ 前端模块 │ │ 后端模块 │ │ 测试模块 │ │
│ │ 自己的上下文 │ │ 自己的上下文 │ │ 自己的上下文 │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ ┌───┴───┐ ┌───┴───┐ ┌───┴───┐ │
│ ▼ ▼ ▼ ▼ ▼ ▼ │
│ ┌─────┐┌─────┐ ┌─────┐┌─────┐ ┌─────┐┌─────┐ │
│ │Work-││Work-│ │Work-││Work-│ │Work-││Work-│ │
│ │er A ││er B │ │er C ││er D │ │er E ││er F │ │
│ │ ││ │ │ ││ │ │ ││ │ │
│ │在仓库││在仓库│ │在仓库││在仓库│ │在仓库││在仓库│ │
│ │副本上││副本上│ │副本上││副本上│ │副本上││副本上│ │
│ │独立 ││独立 │ │独立 ││独立 │ │独立 ││独立 │ │
│ │操作 ││操作 │ │操作 ││操作 │ │操作 ││操作 │ │
│ └─────┘└─────┘ └─────┘└─────┘ └─────┘└─────┘ │
│ │
│ 关键设计: │
│ • 每个 Worker 在仓库的独立副本上工作(git worktree) │
│ • 互相不干扰,不会出现锁竞争 │
│ • Sub-Planner 有自己的上下文窗口,防止噪声累积 │
│ • 不同子任务可以用不同的模型(重活用强模型,轻活用快模型) │
└──────────────────────────────────────────────────────────────────┘
Cursor 团队走过的弯路值得引以为戒:单 Agent 扛不住大任务 → 多 Agent 共享状态会打架 → 僵化的角色分工太死板 → 最终收敛到递归 Planner-Worker 模式。还有个教训:差的初始指令会在数百个 Agent 间被放大。一条模糊的指令乘以几百个并发 Agent,后果可想而知。
模块六:Filesystem Access(文件系统访问)
这是驾驭系统的「信息层」------决定 Agent 能看到什么、看不到什么。
bash
┌──────────────────────────────────────────────────────────────┐
│ Agent 的信息视野控制 │
│ │
│ ┌──────────── 仓库全部文件 ────────────────────────────┐ │
│ │ │ │
│ │ ┌─────── Agent 可见区域(白名单)──────────────┐ │ │
│ │ │ │ │ │
│ │ │ AGENTS.md ← 每次启动必读 │ │ │
│ │ │ /docs/agents/*.md ← 模块规则 │ │ │
│ │ │ /src/types/ ← 类型定义 │ │ │
│ │ │ /src/features/目标模块/ ← 当前任务相关 │ │ │
│ │ │ /tests/目标模块/ ← 对应测试 │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────── Agent 不可见区域(黑名单)────────────┐ │ │
│ │ │ │ │ │
│ │ │ .env / .env.local ← 敏感凭证 │ │ │
│ │ │ /infrastructure/ ← 基础设施配置 │ │ │
│ │ │ /scripts/deploy/ ← 部署脚本 │ │ │
│ │ │ /src/core/ ← 核心模块(需审批) │ │ │
│ │ │ node_modules/ ← 无需关注 │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ 💡 原则:Agent 看到的越多 ≠ 做得越好 │
│ 精准的视野 > 全量的信息 │
│ 就像给新员工只开放他负责的模块的代码权限 │
└──────────────────────────────────────────────────────────────┘
实操示例:.agentignore 文件(类似 .gitignore,控制 Agent 视野)
bash
# .agentignore --- 控制 Agent 不能看到的文件
# 敏感信息
.env
.env.*
**/secrets/
**/credentials/
# 基础设施(Agent 不应触碰)
infrastructure/
terraform/
scripts/deploy/
docker-compose.prod.yml
# 核心模块(需要人工审批才能修改)
src/core/
src/auth/
# 无关噪声
node_modules/
dist/
coverage/
.git/
开发节奏:初始配置时花 10 分钟写一个
.agentignore,之后每次发现 Agent 去动了不该动的文件,就加一行。成本极低但收益巨大。
四、完整的驾驭系统开发流程
前面讲了六个模块怎么分别开发,现在把它们串起来,看看一个驾驭系统从零到一的完整建设流程:
yaml
┌──────────────────────────────────────────────────────────────────┐
│ 驾驭系统的开发生命周期(从 Day 1 到持续运营) │
│ │
│ Phase 1: 地基(Day 1-3) │
│ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ① 创建 AGENTS.md(~30 行,写核心规则和架构约定) │ │
│ │ ② 创建 .agentignore(控制可见范围) │ │
│ │ ③ 配置基础 linter 规则(类型检查 + 命名规范) │ │
│ │ ④ 配置基础工具集(只给文件读写 + 终端执行 2 个) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Phase 2: 试运行(Week 1-2) │
│ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ⑤ 从简单任务开始跑 Agent(如:补测试、改样式、加字段) │ │
│ │ ⑥ 每次 Agent 犯错 → 诊断原因 → 决定修哪个模块: │ │
│ │ • 规则不够? → 加 AGENTS.md │ │
│ │ • 看了不该看的? → 改 .agentignore │ │
│ │ • 用错工具? → 调整工具配置 │ │
│ │ • 架构违规? → 加 linter 规则 │ │
│ │ ⑦ 补充 Layer 2 模块级预设(前端规则、后端规则等) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Phase 3: 扩能(Week 3-4) │
│ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ⑧ 接入反馈循环(Agent 自己跑测试 + 浏览器截图验证) │ │
│ │ ⑨ 建立生命周期钩子(pre-commit 检查、CI 限速两轮) │ │
│ │ ⑩ 开始把中等复杂度任务交给 Agent │ │
│ │ ⑪ 引入 Sub-Agent(如果任务需要并行拆分) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Phase 4: 持续运营(长期) │
│ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ⑫ 每周运行「垃圾回收 Agent」扫描技术债和文档漂移 │ │
│ │ ⑬ 月度 Harness 瘦身:砍掉已被模型学会的冗余规则 │ │
│ │ ⑭ 记录 Agent 失败轨迹,反哺为团队知识库 │ │
│ │ ⑮ 逐步提升 Agent 自主权限(从审查合并到自动合并) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
五、核心飞轮:驾驭系统的持续进化机制
驾驭系统不是一次性搭完就完事的,它的灵魂在于持续改进的飞轮:
┌──────────────────────────────────────────────────────────────────┐
│ 驾驭改进飞轮 │
│ │
│ ┌─────────────┐ │
│ ┌──────▶│ Agent 执行 │──────┐ │
│ │ │ 任务 │ │ │
│ │ └─────────────┘ │ │
│ │ ▼ │
│ ┌────────────────┐ ┌─────────────────┐ │
│ │ Harness 更新 │ │ 产出代码/PR │ │
│ │ │ │ │ │
│ │ • 加一条规则 │ └────────┬────────┘ │
│ │ • 改 linter │ │ │
│ │ • 调整工具集 │ ▼ │
│ │ • 优化计划模板 │ ┌─────────────────┐ │
│ └───────┬────────┘ │ CI / 测试 / 审查 │ │
│ ▲ └────────┬────────┘ │
│ │ │ │
│ │ ┌────────┴────────┐ │
│ │ ▼ ▼ │
│ │ ┌──────────────┐ ┌──────────────┐ │
│ │ │ ✅ 通过 │ │ ❌ 失败 │ │
│ │ │ 合并 PR │ │ │ │
│ │ └──────────────┘ └──────┬───────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────┐ │
│ │ │ 人类诊断 │ │
│ │ │ 根本原因 │ │
│ └────────────────────────────│ │ │
│ │ 缺规则? │ │
│ 这个飞轮越转越快 ──▶ │ 缺工具? │ │
│ Agent 产出质量持续上升 │ 缺文档? │ │
│ │ 缺约束? │ │
│ └──────────────┘ │
│ │
│ 💡 Mitchell Hashimoto 的核心操作: │
│ 每当 Agent 犯了一个错,就花时间工程化一个解决方案, │
│ 让它再也不会犯同样的错。 │
└──────────────────────────────────────────────────────────────────┘
实操示例:错误诊断 → Harness 更新的完整记录
markdown
# .agent/changelog.md --- 驾驭系统变更日志
## 2026-03-20
**问题**:Agent 在 UserProfile 组件中直接调用了 fetch,没有走统一的 API 层
**根因**:AGENTS.md 里虽然写了"API 请求统一走封装函数",但没告诉 Agent 封装函数在哪
**修复**:
- 在 AGENTS.md 的 `常见陷阱` 区加了一条:
`API 请求统一使用 /src/lib/api-client.ts 中的 apiClient 实例,禁止直接使用 fetch`
- 在 linter 中加了规则:禁止在 /src/features/ 和 /src/components/ 下 import fetch
**效果**:该类错误未再出现 ✅
## 2026-03-18
**问题**:Agent 创建新文件时,把组件、hooks、类型全写在一个文件里
**根因**:没有给出明确的文件组织示例
**修复**:
- 在 /docs/agents/frontend.md 中添加了标准的目录结构示例
- 加了一条 linter 规则:单文件超过 200 行时报 warning 并建议拆分
**效果**:后续 PR 的文件组织明显改善 ✅
## 2026-03-15
**问题**:Agent 给数据库迁移 Agent 用了浏览器截图工具(完全没必要)
**根因**:所有任务类型共享同一个工具集
**修复**:
- 实现了工具配置的 profile 分离(见 .agent/tool-profiles.json)
- 前端任务和后端任务使用不同的工具子集
**效果**:工具调用的命中率从 ~70% 提升到 ~95% ✅
这个 changelog 本身就是最有价值的资产之一。 它记录了你的驾驭系统为什么长成现在这个样子------每一条规则的背后都对应着一次真实的失败。新加入的工程师读完这个文件,就能理解整个驾驭系统的设计逻辑。
六、一个完整的项目示例:从零搭建驾驭系统
假设你要从零开始一个 Next.js 全栈项目,全程由 Agent 开发。下面是驾驭系统的完整文件结构:
csharp
my-project/
│
├── AGENTS.md # 全局预设(50行以内)
├── .agentignore # Agent 视野控制
│
├── .agent/ # 驾驭系统专用目录
│ ├── tool-profiles.json # 工具调度配置
│ ├── plans/ # 任务计划模板
│ │ ├── add-feature.yaml
│ │ ├── fix-bug.yaml
│ │ └── refactor.yaml
│ ├── hooks/ # 生命周期钩子
│ │ ├── pre-start.sh # Agent 启动前检查
│ │ ├── pre-commit.sh # 提交前校验
│ │ └── post-failure.sh # 失败时自动收集诊断信息
│ ├── changelog.md # 驾驭系统变更日志
│ └── metrics/ # Agent 产出质量追踪
│ └── weekly-report.md
│
├── docs/
│ └── agents/ # 模块级预设(Layer 2)
│ ├── architecture.md # 分层架构规则
│ ├── frontend.md # 前端开发规范
│ ├── backend.md # 后端开发规范
│ ├── database.md # 数据库操作规范
│ └── testing.md # 测试编写规范
│
├── .eslintrc.js # linter 中嵌入架构约束
├── .github/
│ └── workflows/
│ └── agent-ci.yml # 专门针对 Agent PR 的 CI 流水线
│
├── src/ # 业务代码(Agent 的工作区域)
│ ├── types/
│ ├── config/
│ ├── lib/
│ ├── features/
│ ├── components/
│ └── app/
│
└── tests/ # 测试代码
专门针对 Agent PR 的 CI 流水线示例:
yaml
# .github/workflows/agent-ci.yml
name: Agent PR Validation
on:
pull_request:
labels: [agent-generated] # 只对 Agent 生成的 PR 触发
jobs:
validate:
runs-on: ubuntu-latest
steps:
# 第一关:基础检查(确定性,零 LLM 消耗)
- name: Type Check
run: npx tsc --noEmit
- name: Lint Check
run: npx eslint . --max-warnings 0
- name: Architecture Check
run: node scripts/check-layer-deps.js # 自定义的分层依赖检查
- name: No Forbidden Patterns
run: |
# 检查禁止模式:TODO、console.log、any 类型
! grep -rn "TODO\|FIXME\|console\.log\|: any" \
--include="*.ts" --include="*.tsx" src/
# 第二关:测试
- name: Unit Tests
run: npx vitest run --coverage
- name: Coverage Gate
run: |
COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "❌ 覆盖率 ${COVERAGE}% 不达标"
exit 1
fi
# 第三关:视觉验证(如果有 UI 变更)
- name: Visual Regression
if: contains(github.event.pull_request.changed_files, 'src/components') ||
contains(github.event.pull_request.changed_files, 'src/features')
run: npx playwright test --project=visual
# 结果标记
- name: Label Result
if: failure()
run: gh pr edit ${{ github.event.number }} --add-label "harness-review-needed"
# 失败了不是去改 Agent 的代码,而是去审查 Harness 哪里出了问题
七、心智模型的转变:从「代码审查」到「规则审查」
这是整篇文章最重要的一个思维转变:
arduino
┌──────────────────────────────────────────────────────────────────┐
│ │
│ 传统模式 驾驭工程模式 │
│ │
│ 需求 ──▶ 写代码 ──▶ 审代码 需求 ──┐ │
│ ▲ ▼ │
│ │ 写 Harness 规则 │
│ 手动修改 │ │
│ ▲ ▼ │
│ │ Agent 生成代码 │
│ 发现 bug │ │
│ ▼ │
│ CI 自动检查 │
│ │ │
│ ┌────────┴────────┐ │
│ ▼ ▼ │
│ ✅ 通过 ❌ 失败 │
│ 自动合并 │ │
│ ▼ │
│ 不改 Agent │
│ 的代码 │
│ │ │
│ ▼ │
│ 改 Harness │
│ (加规则/ │
│ 改约束/ │
│ 调工具) │
│ │
│ 如果一个 PR 需要大量修改才能合并, │
│ 问的不是"Agent 哪里写错了", │
│ 而是"Harness 哪里设计得不好,导致 Agent 会犯这个错" │
│ │
│ 代码审查 ──▶ 规则审查 │
│ Code Review ──▶ Prompt Review │
│ │
└──────────────────────────────────────────────────────────────────┘
Peter Steinberger 的实践最能说明这种转变:他不逐行审查 Agent 生成的代码,而是把精力放在审查生成代码的那个 prompt 和规则上。一个人同时运行 5-10 个 Agent,单月产出 6600+ commit。
一个有趣的发现:喜欢算法谜题的工程师反而很难适应这种模式,产品导向的工程师适应得更快。 因为驾驭工程本质上不是在解技术难题,而是在设计系统和管理流程。
八、驾驭系统的度量体系
你怎么知道你的驾驭系统是在变好还是变差?需要追踪几个核心指标:
scss
┌──────────────────────────────────────────────────────────────┐
│ 驾驭系统健康度仪表盘 │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 核心指标 │ │
│ │ │ │
│ │ PR 一次通过率 │ │
│ │ ████████████████████░░░░░ 78% ──▶ 目标 > 85% │ │
│ │ (Agent 提交的 PR 无需修改直接合并的比例) │ │
│ │ │ │
│ │ CI 首次通过率 │ │
│ │ ██████████████████████░░░ 85% ──▶ 目标 > 90% │ │
│ │ (Agent 代码首次跑 CI 就通过的比例) │ │
│ │ │ │
│ │ 平均修复轮次 │ │
│ │ ████████░░░░░░░░░░░░░░░░ 1.3 轮 ──▶ 目标 < 1.5 │ │
│ │ (Agent 自动修复平均需要几轮) │ │
│ │ │ │
│ │ 人工干预率 │ │
│ │ ████░░░░░░░░░░░░░░░░░░░░ 15% ──▶ 目标 < 10% │ │
│ │ (需要人类接手修改的 PR 比例) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 预警指标 │ │
│ │ │ │
│ │ • AGENTS.md 超过 100 行 → 该拆分/瘦身了 │ │
│ │ • 同类错误连续出现 3 次 → 该加硬约束了 │ │
│ │ • Agent 工具调用失败率 > 20% → 该精简工具了 │ │
│ │ • 单次任务 token 消耗持续上升 → 上下文可能膨胀了 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 每周回顾清单 │ │
│ │ │ │
│ │ □ 本周 Agent 最常犯的 3 类错误是什么?已加规则吗? │ │
│ │ □ 有哪些规则已经不需要了?(模型已经学会了) │ │
│ │ □ 工具集有没有冗余?Agent 实际只用了哪几个? │ │
│ │ □ 文档有没有过时的?架构有没有漂移? │ │
│ │ □ 运行垃圾回收 Agent 扫一遍 │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
九、护栏悖论:该投入多重?
最后聊一个很多人关心的问题:驾驭系统该做多重?
OpenAI 的 Noam Brown 说过:Harness 就像一根拐杖,终将被超越。他建议别花六个月搭建一个可能六个月后就被淘汰的东西。
这个观点有道理,但我认为他混淆了两样东西:具体的脚手架 会被淘汰,但约束和反馈循环的需求不会消失。
css
┌──────────────────────────────────────────────────────────────┐
│ 护栏悖论 │
│ │
│ 🚲 时速 30km 自行车道 可以没护栏 │
│ 🚗 时速 120km 高速公路 护栏是标配 │
│ 🚄 时速 300km 磁悬浮列车 整条轨道都是封闭的 │
│ │
│ 模型越强 = 速度越快 = 约束系统越重要 │
│ │
│ 从马车到汽车:马鞭消失了,但方向盘和刹车不会消失。 │
│ 从 GPT-4 到 GPT-6:某些规则会过时, │
│ 但架构约束、反馈循环、熵管理只会换形态,不会消失。 │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 正确的投入策略: │ │
│ │ │ │
│ │ ✅ 轻量化 --- 从 AGENTS.md + 几条 linter 规则开始 │ │
│ │ ✅ 模块化 --- 每个组件可独立替换,不牵一发动全身 │ │
│ │ ✅ 可删除 --- 随时准备拆掉重来,不做过度工程 │ │
│ │ ✅ 迭代式 --- 每次只修一个问题,不追求一步到位 │ │
│ │ │ │
│ │ ❌ 不要花 2 个月搭一个「完美的驾驭框架」 │ │
│ │ ❌ 不要在 AGENTS.md 里写 500 行规则 │ │
│ │ ❌ 不要把所有模块的规则耦合在一起 │ │
│ │ │ │
│ │ 三个词:Start Simple. Build to Delete. │ │
│ │ │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
十、总结:一张图看明白整件事
arduino
┌──────────────────────────────────────────────────────────────────┐
│ │
│ 从"写代码"到"写规则"的完整路线图 │
│ │
│ ┌─────────┐ ┌──────────┐ ┌───────────┐ │
│ │ 你的需求 │────▶│ 驾驭系统 │────▶│ Agent 执行 │ │
│ └─────────┘ │ │ └─────┬─────┘ │
│ │ 6 个模块: │ │ │
│ │ 预设 │ ▼ │
│ │ 工具 │ ┌───────────┐ │
│ │ 文件访问 │ │ 产出代码 │ │
│ │ 规划 │ └─────┬─────┘ │
│ │ 子Agent │ │ │
│ │ 生命周期 │ ▼ │
│ └─────┬────┘ ┌───────────┐ │
│ ▲ │ CI + 钩子 │ │
│ │ │ 自动检查 │ │
│ │ └──┬─────┬──┘ │
│ │ │ │ │
│ │ ✅通过 ❌失败 │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ 合并PR 诊断原因 │
│ │ │ │
│ └───────────────────┘ │
│ 改进驾驭系统,而非改 Agent 的代码 │
│ │
│ ───────────────────────────────────────────────────────────── │
│ │
│ 今天就开始: │
│ 1. 创建 AGENTS.md ← 10 分钟 │
│ 2. 创建 .agentignore ← 5 分钟 │
│ 3. 跑一个简单任务 ← 30 分钟 │
│ 4. Agent 犯错了?加一条规则 ← 2 分钟 │
│ 5. 重复第 3-4 步 ← 这就是驾驭工程 │
│ │
│ 写代码正在变得像打字一样廉价。 │
│ 设计让 Agent 持续、稳定、高质量工作的系统, │
│ 正在变成最值钱的技能。 │
│ │
│ 未来最稀缺的,不是训练模型的人,而是驾驭模型的人。 │
│ │
└──────────────────────────────────────────────────────────────────┘