摘要
这是《AI 辅助研发内部复盘》系列的第五篇,也是收官之作。在前四篇中,我们讨论了工具选型、老项目改造、约束管理(CLAUDE.md)以及上下文隔离(Git Worktree)。
很多读者反馈:“道理我都懂,但一到验证环节就懵。”确实,AI 生成代码的速度已经远超人类审查的速度。如果验证环节跟不上,AI 就是埋雷工具。
本篇将直面这个痛点,通过三个可直接复制的硬核代码案例,展示如何构建 AI 时代的自动化验证体系,并探讨产品与研发的协作新模式。

第一章:为什么“验证”是 AI 时代的最大瓶颈?
在传统开发中,工程师写一行代码,脑子里同步在想边界条件和逻辑漏洞。但在 AI 辅助开发(AI-Assisted Development, ADD)中,这个闭环被打破了:
速度差:AI 3 秒生成 300 行代码,人类肉眼 Review 需要 30 分钟。
幻觉盲区:AI 生成的代码往往“看起来完美”,编译能通过,但业务逻辑是错的(例如:把“余额增加”写成了“余额减少”)。
越界修改:AI 为了修复 A 模块的 Bug,擅自修改了底层公共库,导致 B、C 模块崩溃。
因此,我们提出核心观点:AI 时代的研发效能,取决于验证体系的吞吐量,而非代码生成的速度。
第二章:实战案例一——用 pytest 和 AI 构建“自证清白”的测试闭环

痛点:AI 写完了代码,但它真的理解业务了吗?传统的测试编写耗时费力,且测试代码本身也可能有 Bug。
解决方案:利用 AI 生成测试代码,但通过 Property-based Testing(基于属性的测试) 和 Golden Master Testing(金主测试) 来验证 AI 的输出。
2.1 场景设定
我们有一个计算订单折扣的函数,业务逻辑复杂(满减、折扣、VIP 叠加)。AI 重构了这个函数,我们需要验证其正确性。
2.2 代码案例:AI 生成测试 + 人工定义契约
Step 1:定义业务契约(人类负责)
人类不需要写具体测试用例,只需要定义“规则”。
# tests/contracts/test_discount_contract.py
"""
折扣计算的业务契约(不可动摇的真理)
1. 最终价格不能为负数。
2. VIP 折扣后的价格不得高于普通折扣。
3. 总价必须大于等于各项商品单价之和(防止计算溢出导致负值)。
4. 任何情况下,折扣金额不能超过商品总额。
"""
import pytest
from hypothesis import given, strategies as st
from decimal import Decimal
from src.discount import calculate_final_price
# 使用 Hypothesis 进行基于属性的测试
@given(
original_price=st.decimals(min_value="0.01", max_value="1000000", places=2),
vip_level=st.integers(min_value=0, max_value=5),
coupon_value=st.decimals(min_value="0", max_value="5000", places=2)
)
def test_discount_properties(original_price, vip_level, coupon_value):
"""
验证折扣计算的基本数学属性
"""
final_price = calculate_final_price(original_price, vip_level, coupon_value)
# 契约 1: 非负性
assert final_price >= Decimal("0.00"), "最终价格不能为负"
# 契约 2: 上限性
assert final_price <= original_price, "最终价格不能超过原价"
# 契约 3: 逻辑一致性(如果 VIP 等级高,价格应该更低或相等)
# 这里需要构造对比用例,简化示意
price_vip_0 = calculate_final_price(original_price, 0, coupon_value)
price_vip_5 = calculate_final_price(original_price, 5, coupon_value)
assert price_vip_5 <= price_vip_0, "高等级 VIP 价格不应高于低等级"
# 金主测试:防止回归
def test_regression_critical_cases():
"""
针对历史上出过 Bug 的特定场景进行回归测试
"""
# Case 1: 历史 Bug – 浮点数精度丢失导致的 0.01 元差异
assert calculate_final_price(Decimal("9.99"), 0, Decimal("5.00")) == Decimal("4.99")
# Case 2: 历史 Bug – VIP 叠加优惠券导致的负数
assert calculate_final_price(Decimal("100.00"), 5, Decimal("120.00")) == Decimal("0.00")
Step 2:让 AI 生成实现代码(AI 负责)
Prompt: "请根据 tests/contracts/test_discount_contract.py 中的测试用例和业务契约,实现 src/discount.py 中的 calculate_final_price 函数。确保通过所有测试。"
Step 3:CI/CD 自动化验证
在 .github/workflows/ci.yml 中加入 AI 代码验证步骤:
name: AI Code Validation
on: [pull_request]
jobs:
validate-ai-code:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v3
– name: Set up Python
uses: actions/setup-python@v4
with: { python-version: '3.10' }
– name: Install dependencies
run: pip install pytest hypothesis
– name: Run Contract Tests
run: pytest tests/contracts/ -v –tb=short
– name: Check for AI Hallucinations
run: |
# 检查是否有 AI 擅自修改了测试文件(安全红线)
if git diff HEAD~1 HEAD –name-only | grep "tests/contracts/"; then
echo "ERROR: AI attempted to modify test contracts! Reverting."
exit 1
fi
案例价值:人类只定义“规则”(Contract),AI 负责填充“实现”。CI 流水线确保 AI 不敢篡改规则。这就是“人类立法,AI 执法”。
第三章:实战案例二——产品侧的“可交互原型”如何约束 AI

痛点:产品给的 PRD 是文字,AI 理解有偏差。研发拿着错误的理解去写代码,最后返工。
解决方案:产品提供 HTML 交互原型 作为 AI 的唯一真相源(Single Source of Truth)。
3.1 传统模式的失败
PRD 描述:“用户点击删除按钮后,弹出确认框,点击确认后列表刷新,显示删除成功。”
AI 理解:可能生成了一个没有回调函数的假弹窗,或者删除了数据但忘了刷新列表。
3.2 代码案例:产品交付 HTML 原型 + AI 解析
Step 1:产品交付物(HTML 原型)
产品不再只给 Word 文档,而是给一个可运行的 HTML 文件。
<!– prototype/order_list.html –>
<!DOCTYPE html>
<html>
<head>
<title>订单列表原型</title>
<style> /* 省略样式 */ </style>
</head>
<body>
<table id="orderTable">
<thead><tr><th>订单号</th><th>金额</th><th>操作</th></tr></thead>
<tbody>
<tr data-id="1001">
<td>ORD1001</td>
<td>¥199.00</td>
<td>
<!– 关键交互:按钮和 JS 事件 –>
<button onclick="handleDelete(1001, this)">删除</button>
</td>
</tr>
</tbody>
</table>
<script>
// 产品的交互逻辑定义
async function handleDelete(orderId, btn) {
// 1. 弹出确认框
if (!confirm(`确定要删除订单 ${orderId} 吗?`)) {
return; // 用户取消
}
// 2. 调用 API (模拟)
const response = await fetch(`/api/orders/${orderId}`, { method: 'DELETE' });
// 3. 刷新列表 (关键逻辑)
if (response.ok) {
// 必须从 DOM 中移除该行
btn.closest('tr').remove();
alert('删除成功');
} else {
alert('删除失败');
}
}
</script>
</body>
</html>
Step 2:研发 Prompt(喂给 AI)
"请根据上述 HTML 原型 (prototype/order_list.html) 中的 JavaScript 交互逻辑,实现后端的 DELETE /api/orders/{id} 接口。注意:前端期望在成功后移除 DOM 节点,因此后端必须返回 200 OK 状态码,并确保数据真正从数据库中删除。"
Step 3:AI 生成的后端代码(验证点)
AI 生成的代码会自动包含事务处理和正确的 HTTP 状态码返回,因为它“看”到了前端的预期。
// AI Generated Code Snippet
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteOrder(@PathVariable Long id) {
// AI 理解了前端需要 200 OK
boolean deleted = orderService.deleteById(id);
if (deleted) {
// AI 理解了前端需要刷新列表,所以数据必须真的删除
return ResponseEntity.ok().build();
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
}
案例价值:HTML 原型消除了自然语言描述的二义性。AI 通过阅读 HTML/JS,精确理解了“点击->确认->删除->刷新”的完整链路。这比任何 PRD 都管用。
第四章:实战案例三——Git Hook 拦截“越界修改”

痛点:AI 为了修复 A 模块的 Bug,擅自修改了 CommonUtils.java 这种公共类,导致全局崩溃。
解决方案:利用 Git Hooks 在提交前强制检查 AI 的修改范围。
4.1 代码案例:Pre-commit Hook 限制修改范围
在项目根目录创建 .git/hooks/pre-commit 文件(需赋予执行权限):
#!/bin/bash
# .git/hooks/pre-commit
# 获取本次提交所有被修改的文件列表
CHANGED_FILES=$(git diff –cached –name-only –diff-filter=ACM)
# 定义“高危禁区”文件列表
# 这些文件是项目的基石,严禁 AI 随意修改
PROTECTED_FILES=(
"src/main/java/com/example/common/CommonUtils.java"
"src/main/java/com/example/config/DatabaseConfig.java"
"pom.xml"
".claude/CLAUDE.md"
)
echo "🔍 Checking for protected file modifications…"
for FILE in "${PROTECTED_FILES[@]}"; do
if echo "$CHANGED_FILES" | grep -q "^$FILE$"; then
echo "❌ ERROR: Attempted to modify protected file: $FILE"
echo "🛑 This file is critical to the system stability."
echo "💡 If you must change this, please update the pre-commit hook or seek Lead Engineer approval."
exit 1 # 终止提交
fi
done
# 检查是否引入了未声明的 Maven 依赖(AI 常犯的错)
if echo "$CHANGED_FILES" | grep -q "pom.xml"; then
echo "⚠️ Warning: pom.xml changed. Please verify dependency necessity."
fi
echo "✅ Pre-commit checks passed."
exit 0
4.2 配合 AI 的指令约束
在 CLAUDE.md 中必须加上这一条:
## 🚨 绝对禁令
– **严禁修改** `CommonUtils.java`, `DatabaseConfig.java`, `pom.xml`。
– 如需新增依赖,必须先提出请求,由人工修改 `pom.xml`。
– 违反上述规则将导致 Git Commit 失败。
案例价值:通过 Git Hook + CLAUDE.md 的双重保险,我们建立了一道物理防火墙。AI 再聪明,也无法绕过操作系统的文件权限和 Git 的钩子机制。这确保了核心代码的稳定性。
第五章:近两周行动项(落地清单)

基于以上案例,我们制定了以下可执行的行动项:
建立 Contract 测试目录:各项目组立即建立 tests/contracts/ 目录,将核心业务逻辑转化为不可变的测试契约。
产品侧转型:产品经理开始学习使用 Figma 或纯 HTML 输出交互原型,停止输出纯文字 PRD。
部署 Git Hooks:将 pre-commit 钩子脚本提交到代码库,要求全员安装。
量化指标试点:选取一个非核心模块,试点统计“AI 生成代码占比”和“AI 代码一次通过率”。
每周 AI 复盘会:分享本周 AI 犯的蠢事(Hallucinations),并更新 CLAUDE.md 和 Skills。
结语:从“工具使用”到“体系对抗”

AI 辅助研发不是装个插件那么简单。当代码生成变得廉价时,验证、约束和协作就成了昂贵的稀缺资源。
本系列的五篇文章,从工具选型到老项目改造,从约束管理到验证体系,构建了一套完整的防御工事。我们希望传达的理念是:
不要试图让 AI 变得完美,而是要建立一个即便 AI 犯错也能立即发现并纠正的工程体系。
未来已来,唯变不变。愿各位工程师都能成为驾驭 AI 的“架构师”,而非被 AI 取代的“打字员”。
免责声明:本文涉及的脚本与代码案例需在测试环境充分验证后方可应用于生产。Git Hook 机制可能因操作系统或 Git 版本差异需微调。AI 模型的输出具有随机性,自动化验证不能完全替代资深工程师的人工审查。
本文相关文章序列:
AI辅助研发深度复盘(1/5):老项目改造的核心逻辑与人机分工最优路径-CSDN博客
AI 辅助研发内部复盘(2/5):老项目改造的工程化实践-CSDN博客
AI 辅助研发内部复盘(3/5):上下文工程与认知解码-CSDN博客
AI 辅助研发内部复盘(4/5):约束、上下文与技能——把“人的判断”工程化
AI 辅助研发内部复盘(5/5):验证体系、产品协作与行动项(含硬核实战案例)


![[特殊字符]DeepSeek‑Harness(DSH)小白保姆教程-171主机测评](https://www.171host.com/wp-content/uploads/2026/08/20260816085112-6a817a009aabf-220x150.png)