Harness 工程实践:构建 AI Agent 的可靠开发工作流
# 前言:从写代码到"指挥"代码
2025 年初,Andrej Karpathy 提出了一个概念——Vibe Coding:程序员不再逐行编写代码,而是用自然语言描述意图,由 AI 生成代码。程序员的角色从"代码编写者"转变为"意图引导者 + 结果审查者"。
一年多过去了,这个趋势不仅没有消退,反而加速了。Cursor、Claude Code、GitHub Copilot、Windsurf 等 AI 编程工具快速迭代,大模型的代码生成能力越来越强。作为一名 Java 后端工程师,我在日常开发中逐渐感受到一个现实:
AI 写代码已经不是瓶颈了。瓶颈在于——怎么让 AI 写出符合你预期的代码,以及怎么验证它写得对不对。
这篇文章分享我在实际项目中摸索出的一套 AI Agent 开发工作流,核心围绕三个关键词:知识库、Spec、Harness。
# 几个关键概念
# 什么是 Harness
Harness 直译是"缰绳、挽具",在赛马中用来驾驭马匹。在 AI Agent 领域,Harness 指的是包裹在 AI 模型外围的整套控制基础设施,让模型从"只能聊天"变成"能真正做事且做得对"。
一个裸的大语言模型只能输出文本。但当你在它外围加上文件读写、Shell 执行、浏览器操作等工具,加上权限控制、上下文管理、任务调度、测试验证等机制——这些外围设施共同构成了一个 Harness。
一个越来越明显的趋势是:模型能力在快速趋同,真正拉开差距的是 Harness 的设计。 同样的底层模型,不同的 Harness 配置,产出质量和可靠性可能天差地别。
Harness 通常包含以下层次:
# 什么是 Spec
Spec 是 Specification(规范)的缩写。在 AI Agent 的工作流中,Spec 指的是一套可落地的精确规范,用来约束 AI 的行为。
先看一个反例:
实现一个用户登录功能。
这种描述对人来说足够理解,但对 AI 来说太模糊了。它不知道你要用 JWT 还是 Session,不知道登录失败要返回什么,不知道要不要做频率限制。
一个好的 Spec 应该包含:
- 拆成哪些接口,每个接口实现什么功能(1、2、3、4 列出来)
- 每个接口的入参和出参
- 需要注意的边界条件
- 使用哪些框架和技术
- 数据怎么存储
- 是否需要生成额外的文档或图例
核心原则:Spec 越精确,AI 执行越稳定。
# 为什么需要知识库
LLM 的上下文窗口是有限的,不可能每次都把整个项目塞进去。更重要的是,AI 对你的业务领域的理解不是天生就有的——它不知道你的用户有哪些字段、订单有哪些状态、支付流程涉及哪些服务。
知识库就是 AI Agent 的长期记忆,跨越单次会话持久存在。一个设计良好的知识库能让 AI 在每次新会话中快速获得项目的上下文,而不需要人反复解释。
一个关键做法:给索引不给内容。 在 Spec 中只引用知识库的索引路径,让 AI 按需加载,避免把大量领域知识直接塞进执行上下文造成污染。
# 我的 Harness 工程实践
下面进入正题,分享我在实际项目中搭建的 AI Agent 开发工作流。整体分为三个阶段:
双轮驱动
# 阶段一:构建知识库(环境准备)
在 AI 开始写代码之前,必须先让它理解项目全貌。我定义了一个 learn-project 的 Skill,在初始化工程时由人引导 AI 了解项目,生成结构化的知识库。
知识库分为三层:
📚 知识库
├── 🏗️ 项目结构 & 背景
│ └── 目录结构、技术栈、模块划分
│
├── 📏 编码规范
│ └── 命名规范、分层规范、异常处理
│
└── 📖 领域知识 Index
├── 用户 → /domain/user.md
├── 订单 → /domain/order.md
└── ...
└── 领域知识详情(每个概念包含):
├── 概念说明
├── 使用示例
└── 字段定义 & 查询方式
2
3
4
5
6
7
8
9
10
11
12
13
14
15
项目结构与背景说明项目的目录组织、技术选型、模块职责等宏观信息。
编码规范约束 AI 的代码风格,包括命名规范、分层规范、异常处理方式等。
领域知识是最核心的部分。它以 Index + 详情的形式组织:Index 列出所有领域概念及其存放路径,详情文档包含每个领域概念的字段定义、使用示例、业务规则。例如"用户"这个领域概念,知识库会记录用户有哪些字段、常用的查询方式、与其他实体的关联关系等。
这一步是前期投入,但复利效应非常明显——后续每个新需求都不需要重新解释项目背景。
# 阶段二:Spec & Harness 双轮驱动
如果说知识库解决了"AI 对项目的认知"问题,那么 Spec 和 Harness 解决的就是"AI 怎么执行"和"执行得对不对"的问题。
它们的关系是这样的:
Spec 告诉 AI "做什么、怎么做",Harness 验证 AI "做得对不对"。
# Spec:从模糊需求到精确规范
以一个实际需求为例,假设要实现"用户积分管理"功能。
模糊的写法:
实现用户积分的增减和查询。
精确的 Spec 写法:
接口1:查询用户积分
- 路径:GET /api/points/{userId}
- 入参:userId(Long)
- 出参:{ totalPoints: Integer, level: String, history: List<PointRecord> }
- 功能:返回用户的当前积分、等级和最近变动记录
- 边界:用户不存在时返回 404
接口2:增加积分
- 路径:POST /api/points/add
- 入参:{ userId: Long, points: Integer, reason: String }
- 出参:{ success: Boolean, currentPoints: Integer }
- 功能:为用户增加指定积分,更新等级
- 边界:points 必须 > 0,单次上限 10000
接口3:扣减积分
- 路径:POST /api/points/deduct
- 入参:{ userId: Long, points: Integer, reason: String }
- 出参:{ success: Boolean, currentPoints: Integer }
- 功能:扣减用户积分
- 边界:积分不足时返回失败,不允许负数
技术约束:
- 使用 MyBatis Plus 操作数据库
- 积分变动需要记录流水
- 参考知识库:/domain/user-points/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
可以看出,精确 Spec 的核心是穷举式地描述接口、功能点、边界条件,并且锚定知识库的索引路径,让 AI 按需查阅领域知识。
# Harness:自动化的质量守门员
Harness 负责验证 AI 产出的代码是否符合 Spec 的要求。它包含四个组成部分:
第一部分:测试数据集。 根据 Spec 中定义的场景,准备对应的测试数据,覆盖正常流程、边界条件和异常情况。比如积分增加的测试数据,需要包含正常增加、超出上限、负数等场景。
第二部分:执行环境。 明确测试怎么执行——是跑 SQL 验证数据库状态,还是调 API 验证返回值,还是运行单元测试。
第三部分:正确性评估。 这里分为两层:
- 硬断言:能用程序化方式校验的,必须硬断言。比如 API 返回的 status code 是否正确、数据库中的记录是否写入、字段值是否符合预期。
- AI 软判断:业务逻辑的合理性、边界场景是否充分等,由 AI 来评估。
第四部分:量化报告。 输出可量化的测试结果——用例通过几个、覆盖率如何、边界情况测试怎样。报告中对硬断言结果和 AI 评估结果分开呈现,确保硬断言部分的可信度。
# 工具推荐
Harness 的执行环境直接影响测试的可靠性和覆盖范围。这里推荐两个 MCP 工具来强化测试能力:
1. GenAI Toolbox(数据库测试)
Google 开源的 MCP 工具,支持 MySQL、PostgreSQL、Redis 等多种数据源。通过 MCP 协议让测试 Agent 直接执行 SQL 验证数据库状态,实现数据层面的硬断言。
详细配置方式可以参考我之前的文章:MCP 连接数据库
2. IntelliJ IDEA MCP(工程编译 & 接口验证)
从 2026.1 版本开始,IntelliJ IDEA 官方支持了 MCP 协议。这意味着测试 Agent 可以通过 MCP 触发 IDEA 的编译、启动应用、发送 HTTP 请求并验证返回结果——覆盖了从编译到接口调用的完整验证链路,比单纯跑单元测试更接近真实运行环境。
# 关键设计:测试 Agent 必须独立
这是整个 Harness 设计中最重要的一个原则:执行测试的 Agent 和编写代码的 Agent 不能是同一个。
为什么?因为大语言模型存在一种"自我一致性偏差"——它倾向于认为自己刚生成的输出是正确的。如果你让同一个 Agent 先写代码再测试自己的代码,它大概率会跳过真正的验证,直接编造一个"测试通过"的结果。
正确的做法是:仅携带必要的上下文(Spec 和被测代码),开启一个独立的子 Agent 来执行测试。这个测试 Agent 不知道代码是谁写的,也不关心结果好看不好看——它只负责客观地验证和汇报。
这本质上是用架构设计来解决模型的认知偏差问题,比在 prompt 里写"请认真测试"靠谱得多。
# 阶段三:持续迭代
知识库不可能一次性构建完美,初期必然会有遗漏。关键是要建立一个持续迭代的闭环:
- AI 在开发过程中遇到知识库未覆盖的情况时,将新发现的领域知识按规范持久化
- 人工发现 AI 犯错时,分析是否是知识库的缺失导致,如果是则补充
- 开发新领域业务时,同样将行为固化为可复用的知识资产
核心原则:一次会话的收获,不应该随会话结束而丢失。
每一条被沉淀下来的知识,都会在后续的需求中复用,减少重复沟通的成本。这是一个典型的复利效应——知识库越完善,AI 的执行效率越高,人工介入越少。
# 完整工作流
把前面三个阶段串起来,形成完整的开发工作流:
# 逐步说明
第一步:手动编写需求 MD。 这一步是纯手动的。实际业务往往很复杂,两三句话很难跟 AI 交代清楚,最好由自己来拆分。按照 Spec 规范,把需求拆成接口,列出每个接口的功能点。
第二步:与 Agent 讨论方案。 把需求 MD 给 Agent,让它参与讨论。Agent 会基于知识库提出方案建议,双方一起细化需求文档。关键点:只给知识库的索引路径,不要让 AI 把实现内容直接写到 MD 中。
第三步:Agent 构建执行计划。 让 Agent 基于 Spec 生成执行计划(Plan)和回归测试计划。执行计划描述代码层面的实现步骤,测试计划描述如何验证。
第四步:人工审计。 这是人的核心价值环节。重点审计两方面:
- 执行计划的边界考虑是否与自己的一致,大致思路是否正确
- 回归测试计划的场景设计是否覆盖了需求中的关键路径和边界
第五步:AI 并行执行。 审计通过后,放手让 AI 执行。Claude Code 等工具会自动根据任务拆分多个 Agent 并行开发,这是整个流程中耗时最短的环节。
第六步:等待测试报告。 独立的测试 Agent 执行验证,输出量化报告。根据报告决定是否通过,或者需要修正后重新测试。
# 时间分配的变化
很多人使用 AI 辅助编程时,依然沿用的是"AI 写代码 → 人 review 代码"的模式。这种模式下,人并没有真正解放,只是从"自己写代码"变成了"审查 AI 的代码",大量的时间仍然花在代码细节上。
Harness 工作流带来的核心转变是:从 review 代码,变为 review 方案。 不再纠结 AI 写的某一行代码对不对,而是确保 AI 的执行方向和验证标准是对的。
左侧是大多数 AI 编程用户的现状——将近一半的时间在 review AI 的代码,四分之一的时间在反复让 AI 修改。本质上只是把"自己写代码"换成了"看别人写的代码",并没有真正提升效率。
右侧是 Harness 模式——人的精力集中在方案设计、Plan 审计和知识沉淀上,代码编写和验证交给 AI + Harness 自动完成。从关注代码细节,升级为关注工程决策。
# 一些经验总结
在实践这套工作流的过程中,我总结了以下几点经验:
1. Spec 的精确度直接决定 AI 输出的稳定性。 模糊的描述换来的是不可预测的结果。把时间花在写好 Spec 上,比花在反复让 AI 重写代码上高效得多。
2. 知识库的投入是前期成本,但复利效应明显。 刚开始时可能会觉得构建知识库很慢,但当你发现后续每个需求都不需要自己主动点醒,一次跑通时,就会感受到,爽!!
3. 接受"不完美",持续迭代优于一步到位。 不要指望一次性构建完美的知识库或 Harness。先跑起来,在实战中不断补充和完善。
4. 人始终是决策者。 AI 可以帮你写代码、跑测试、生成报告,但方案的最终决策、边界的判断、业务逻辑的正确性——这些始终需要人来把控。AI 是工具,不是替代者。
本文基于我在 Java 后端项目中使用 Claude Code 等 AI 工具的实际经验总结。Harness 的概念和应用方式因人而异,欢迎交流探讨。