最近读到一篇文章,把 Agent 工程的演化路线整理了出来:
ReAct(2023初)→ Plan & Execute(2023末)→ Multi-Agent(2024)→ Context Engineering(2025)→ Harness Engineering(2025+)
配了一句话让我想了挺久:「名词换了五六轮,核心问题从未改变------在不确定性上构建确定性。」
Harness Engineering 讲的是:不要靠提示词说服 AI 表现好,要靠工程框架约束 AI 的行为边界。这个思路本来是给「做 AI 产品」的工程师看的,但我越想越觉得,同样的道理完全可以用在日常开发上------用 AI 辅助做 Android 需求的时候,我们有没有在给 AI「套框架」?
大多数人没有。所以才会翻车。
一、一次典型翻车复盘
说一个真实场景。一个中等规模的 Android 需求,需要三天完成,中间换了两次对话窗口。
第一天:用 AI 拆解需求,理解清楚了,技术方案也定了。
第二天:换了个窗口,重新把需求说了一遍,AI 给出的方案和昨天的有出入,改动范围变大了。花了半小时对齐,才找回前一天的节奏。
第三天:又换了个窗口,这次忘了告诉 AI 项目里有个公共组件是不能动的。AI 很自然地改了那个组件,改完才发现影响了另一个模块,回滚花了一个多小时。
翻车清单:
• 需求被重新理解,偏了
• 第一天定好的技术决策丢了
• 同样的背景交代了两遍
• AI 不知道哪里是禁区,踩了
这些问题看起来是「AI 不够聪明」,实际上是「我没有给 AI 一个可以稳定工作的框架」。换句话说,AI 每次进场都是裸着进的,没有任何上下文承接,它只能靠当次对话里你告诉它的东西工作。
Harness Engineering 的核心洞察在这里就能用上:凡是你希望 AI「一定」做到的事,就不要靠提示词,要靠结构。
二、第一层:关键节点,强制产出文档
Harness Engineering 里有一个原则:工具描述是人机协议,不是注释。意思是工具的边界、使用时机、返回格式,都要显式写清楚,不能靠 AI 自己猜。
对应到开发流程里:每个关键节点的产出,就是下一个窗口的入口协议。
我建议在做需求的过程中,强制在四个节点生成文档,存到项目 .ai/ 目录里,和代码一起 commit:
节点一:需求理解文档
在需求拆解结束后生成,让 AI 输出:
• 需求拆解:把一句话需求拆成具体的功能点
• 边界确认:哪些在范围内,哪些明确不做
• 疑问列表:AI 不确定的地方列出来,让你当场确认
这一步的价值不只是备忘,更重要的是:让你在进入实现之前,就发现 AI 对需求的理解和你的理解有没有偏差。
节点二:技术方案文档
方案确定后生成:
• 涉及文件列表(精确到文件路径)
• 改动范围描述
• 关键决策及理由(为什么选这个方案,备选方案是什么,为什么没选)
「关键决策及理由」这一条很多人会跳过,但它恰恰是换窗口之后最难重建的信息。AI 下次进来,看到这条,就知道「这个方案是故意这样设计的,不是因为没想到其他方式」。
节点三:实现上下文文档
每次中断开发前更新,格式固定:
markdown
# 当前进度
> 正在做:HomeViewModel 的状态管理重构
## 已完成
- [x] DataRepository 接口定义完成
- [x] 本地缓存逻辑迁移完成
## 待完成
- [ ] HomeViewModel 注入新 Repository
- [ ] UI 层 collect StateFlow 改造
- [ ] 单测补充
## 已知问题 / 注意事项
- UserSessionManager 是全局单例,不能在 ViewModel 里持有强引用
- 网络请求统一走 NetworkModule,不要直接 new
格式不重要,重要的是下次打开新窗口的时候,把这个文件贴进去,AI 能在 3 句话内恢复现场,不用你重新交代。
节点四:收尾文档
需求完成后生成,写给下一个需求用:
• 改了什么(精确到模块)
• 没改什么(哪些地方绕开了,为什么)
• 遗留问题(临时方案、技术债、已知 bug)
• 下次继续的入口(如果还有后续工作)
三、第二层:重复操作,沉淀成 Skill
Harness Engineering 里有一条原则:给模型最小化、最精确的能力集。工具越少越聚焦,AI 的执行越可靠。
对应到开发流程里:把高频重复的操作从每次临时描述,变成可复用的标准 Skill。
做了一段时间 AI 辅助开发之后,你会发现有些 prompt 你反复在写:
• 「帮我 review 这段代码,关注空指针、线程安全、内存泄漏」
• 「按照项目的 ViewModel 规范帮我生成骨架,用 StateFlow,错误状态用 sealed class」
• 「帮我分析这个 ANR 日志,找出主线程被谁 block 了」
每次临时写,每次措辞不一样,AI 的输出质量也不稳定。把这些提炼成 Skill 文件,存到 .ai/skills/ 目录下:
bash
.ai/
skills/
android-code-review.md # Android 代码 review 标准
viewmodel-generator.md # ViewModel 骨架生成规范
anr-analyzer.md # ANR 日志分析流程
unit-test-template.md # 单测生成模板
context/
current-task.md # 当前任务上下文(节点三)
tech-decision.md # 本次技术决策(节点二)
PROJECT_MEMORY.md # 项目长期记忆(见下一节)
Skill 文件的内容不复杂,就是一个结构化的 prompt 模板,写清楚:触发时机、输入格式、期望输出、项目特有约束。
举个例子,android-code-review.md 的核心内容:
ruby
# Android Code Review Skill
## 触发方式
用户说"review 一下这段代码"或"帮我看看这个"时使用
## 必须检查的维度(按优先级)
🔴 严重:空指针/NPE 风险、内存泄漏、线程安全问题
🟡 一般:异常未处理、资源未关闭、魔法数字
🔵 建议:命名规范、方法长度、重复代码
## 项目特有约束
- 所有网络请求必须在 IO dispatcher 执行,不能在 Main
- Context 引用只能用 ApplicationContext,禁止持有 Activity
- 错误状态统一用 sealed class Result
## 输出格式
每个问题:严重程度 | 文件:行号 | 问题描述 | 修复建议(附代码)
积累路径很自然:第一次临时写 prompt,觉得好用,提炼成 Skill 文件,下次直接 @skills/android-code-review.md 引入。时间长了,你的 Skill 库就是你这个团队的 AI 使用规范。
四、第三层:全局认知,固化成长期 Memory
Harness Engineering 里另一条原则:让模型的初始状态可重现,而不是随机的。每次对话开始时注入的内容要是固定结构的,不能随窗口漂移。
对应到开发流程里:把项目的全局认知固化成一份 Memory 文件,让每次 AI 进场的「世界观」一致。
在项目根目录建 PROJECT_MEMORY.md,持续维护以下内容:
架构决策
markdown
## 架构决策
- 使用 MVI 而非 MVVM:因为状态变更来源复杂(网络+本地+用户操作),
单向数据流更容易追踪,不是因为追潮流
- 网络层用自研 HttpEngine 而非 OkHttp:历史原因,已有大量业务依赖,
不要引入 OkHttp,哪怕只是试验
- 图片库用 Glide 不用 Coil:团队熟悉度,且 Glide 在我们的 GIF 场景
表现更稳定
禁区清单
markdown
## 禁区(不要动,动了会出问题)
- UserSessionManager:全局单例,状态管理极其复杂,任何改动需要专项评审
- BaseActivity/BaseFragment:所有页面的基类,改一行影响全局
- NetworkInterceptorChain:鉴权逻辑在里面,不能随意增删拦截器
历史踩坑
markdown
## 历史踩坑
- MessageListAdapter 的 DiffUtil:曾经因为 areContentsTheSame
实现有 bug 导致消息列表闪烁,2025-Q3 修复,见 commit a1b2c3d
- 横竖屏切换时 ViewModel 数据丢失:根因是某个 ViewModel 没走
SavedStateHandle,2025-Q4 全量排查过一次
- 大图预览内存溢出:超过 4MB 的图片要用 BitmapRegionDecoder
分块加载,不能直接 decodeStream
当前技术债
markdown
## 已知技术债(临时方案,不要学,不要扩散)
- HomeFragment 里有一段硬编码的配置,计划 Q2 迁移到远端配置
- ProfileRepository 的缓存策略是手写的,后续统一换 Room
- 推送通知的渠道 ID 是 hardcode 字符串,应该用常量管理
这份文件的价值不只是给 AI 看的。新人入职、交接需求、写技术方案------贴进去,上下文立刻到位。
📌 维护这份文件的关键不是「写得全」,是「写得及时」。每次做完一个需求,花五分钟更新一下踩坑记录和技术债清单,长期下来价值极大。
五、高风险操作前,停下来确认
Harness Engineering 里的「危险操作拦截」:涉及外部写入、数据删除、发送消息的操作,不能靠提示词约束,要在代码层做硬拦截。
对应到开发流程里:涉及架构变动、公共组件修改、不熟悉模块的时候,主动停下来,不要让 AI 直接执行。
这条看起来像废话,但它是大多数翻车的真正原因。AI 给你一个改动方案,你觉得看起来挺对,直接让它改了。改完发现影响了你没想到的地方。
建议在 PROJECT_MEMORY.md 里维护一个「变更前需要人工评估」的清单,在开始新需求时让 AI 先读一遍:凡是这次改动涉及清单里的任何一项,先给我分析影响范围,不要直接动代码。
六、三层结构串起来
文档、Skill、Memory,三层分工很清楚:
三层的关系:
• 文档是当次任务的上下文,解决「换窗口后恢复现场」的问题
• Skill 是可复用的能力,解决「高频操作标准化」的问题
• Memory 是长期的项目认知,解决「AI 每次进场世界观一致」的问题
类比一个说法:文档是工作日志,Skill 是工具箱,Memory 是老员工的经验手册。
七、最后
Harness Engineering 的核心洞察是:大多数 Agent 出问题,不是模型的问题,是脚手架的问题。
用 AI 辅助开发也一样:大多数「AI 没帮上忙」,不是模型不够聪明,是我们没有给它一个可以稳定工作的框架。每次裸着进,每次从头开始,输出质量当然不稳定。
这套三层结构------文档 + Skill + Memory------搭起来之后,AI 换窗口不再是负担,你积累的越多,AI 对你的项目越「懂」,新需求的启动成本也越低。
工具在变,模型在迭代,但这个问题始终不变:怎么在 AI 的不确定性上,构建你工作流程的确定性。
下一篇打算聊多步任务的 checkpoint 设计------当一个需求跨越多天、涉及多个模块的时候,怎么设计断点,让任务可以从中途恢复而不是推倒重来。