AI 辅助研发与生成结果验证:不能以"写过提示词"验收
前面的 AI 应用页讲的是把模型放进产品(RAG、Agent、评测);这一页讲的是把模型放进研发流程:用 AI 生成代码之后,怎样证明它是对的、怎样发现它的错、怎样修正,以及在给出上下文时怎样不泄露秘密。这两种能力在 JD 里经常被混为一谈,本页把它们分开。
本页是 U68(#105)的 C16 权威正文。先说清证据边界:2026-10-28 核查本机没有任何 LLM 凭据,真实模型的生成质量、"模型是否会犯这些错误"、提示词效果都受阻,本页不评测任何模型。本页验证的是生成之后的工具链——labs/ai-assisted-dev 的 20 个测试实跑:编译、测试、API 核实、敏感信息扫描、任务卡验收,以及"生成的错误代码确实错、修正版确实对"的可复现对照。文中所有"生成样本"都是人工构造的教学样本,不是任何真实模型的输出。
一句话主线:AI 负责"起草",工程师负责"证明";验收证据是测试、扫描与对照,不是提示词本身。
从任务到合入的六步
| 步骤 | 做什么 | 失败会怎样 | 本页证据 |
|---|---|---|---|
| 1 给上下文与约束 | 任务卡写清输入、边界、验收 | 生成物方向错误,返工 | tasks/ledger-refund-task.md 五条约束 |
| 2 任务拆解 | 把大任务拆成可独立验证的小步 | 一次生成太大,审查无从下手 | 任务卡按"窗口/金额/异常/幂等"拆断言 |
| 3 生成 | 模型起草代码 | 错误进入候选集 | 人工构造的生成样本(含 5 处错误) |
| 4 审查与验证 | 编译、测试、API 核实、敏感扫描 | 错误代码被当作正确代码合入 | 20 个测试实跑 |
| 5 修正与复验 | 按失败证据修正,重跑同一组测试 | 修一处坏一处 | FixedSnippets 与任务卡修正实现 |
| 6 合入与留档 | 记录审查发现、证据与限制 | 下次重犯,无法追溯 | 本页与证据 JSON |
这六步里,只有第 3 步依赖模型;其余五步都是工程能力——这正是 C16 要求"不能以写过提示词验收"的原因。
版本、工程与观察入口
JDK 21(Liberica 21.0.11+11)、Maven 3.9.9、macOS arm64;JUnit Jupiter 6.0.3(Boot 4.0.9 BOM)、Spring Boot 4.0.9(仅用 starter-test 提供 JUnit 平台)。无外部服务依赖,全部测试进程内执行。
公开入口在仓库根目录:
python3 labs/ai-assisted-dev/run.py入口执行 clean test、核对 3 份 Surefire 报告(合计 20 个测试)、校验 20 条 U68 观察行,把环境、依赖版本、凭据门状态(受阻)、生成样本声明、仓库敏感扫描结果与限制写入运行证据。凭据门受阻时退出 0——受阻是合法运行状态,不是失败。
上下文与约束:任务卡怎么写
一份可审查的任务卡至少包含四件事,本实验的任务卡逐条给出:
- 输入与输出:
canRefund(Order, LocalDate) -> boolean。 - 硬约束:金额只用
BigDecimal(两位、HALF_UP);7 个自然日窗口;null/负数抛IllegalArgumentException;已退款幂等返回 false;纯函数无 IO。 - 验收清单:把约束翻译成可执行的断言(边界日、异常消息、幂等)。
- 禁止项:不允许引入
Instant/时区换算,不允许外部依赖。
约束写得越可执行,第 4 步的审查越机械。写成"注意金额精度"这种形容词,审查就退化成主观判断。
任务拆解:为什么按断言拆
任务拆解不是按文件拆,而是按可独立验证的行为拆。任务卡的验收清单就是拆解结果:窗口边界一条、金额精度一条、异常一条、幂等一条。每条对应一个测试方法——生成物可以一次性交付,但验证必须逐条可定位。
反例:让模型"实现一个退款模块",生成几千行后无法定位错误;按断言拆之后,五处错误各有归属。
生成结果的审查与验证
常见生成错误与本地复现
本实验的"生成样本"(GeneratedSnippets)覆盖十类真实评审中最常见的错误,每一类都有对应的失败断言:
| 错误类别 | 生成版行为(实测) | 修正版行为(实测) | 证据行 |
|---|---|---|---|
| 金额用 double | 0.1+0.2 ≠ 0.3 | BigDecimal 精确比较 | U68 moneyPrecision=PASS |
| int 溢出 | 21_474_837×100 = -2147483596 | long 正确 + 溢出显式抛错 | U68 intOverflow=PASS |
| "一个月"=30 天 | 1-31 + 30 天 = 3-02 | YearMonth 得 2-28 | U68 monthEnd=PASS |
| null 静默失败 | null → NPE,空串 → 空串 | 显式 IllegalArgument | U68 nullContract=PASS |
| SQL 拼接 | 输入原样进入 SQL | 占位符 | U68 sqlInjection=PASS |
| 无界重试 | 永远失败的依赖 → 300ms 不返回 | 预算 3 次后抛错 | U68 retryBudget=PASS |
| 非原子计数 | 8 线程 × 1 万次 → 25184/80000 | AtomicInteger → 80000 | U68 counterRace=PASS |
| HashMap 并发 merge | 结果未定义 | ConcurrentHashMap 稳定 | U68 parallelCount=PASS |
| 浮点 == 判等 | 残差使条件失效 | 容差比较 | U68 floatAndIndex=PASS |
| 越界下标 | get(size()) 抛异常 | 空列表显式报错 | U68 floatAndIndex=PASS |
两类证据必须分开读:生成版的错误是被断言证明的(不是"可能有问题");修正版的正确也是被断言证明的。U68 counterRace=PASS generated=25184 fixed=80000 这类实测数字就是"发现错误"的直接证据——同一台机器、同一组线程,生成版丢了 68% 的更新。
API 与依赖核实
模型常声称"这个 API 存在/可以这样用"。核实分三层:
- 存在性:类/方法能否加载(
ApiCheckVerifier.methodMatches)。模型编造的方法名会被拒绝:U68 apiVerify=PASS invented=rejected。 - 弃用状态:
Thread#stop能编译但已废弃——"能编译 ≠ 应该用"(deprecated=flagged)。 - 依赖版本:入口的
dependency:tree记录实际解析版本(本实验 JUnit 6.0.3、Boot 4.0.9),与任务卡声称的依赖比对。
边界:API 核实不验证文档语义、线程安全或行为正确性——那要靠测试与官方文档。
敏感信息处理
AI 生成物与提示词里最容易夹带秘密:真实连接串、token、私钥、内网地址。本实验的扫描器(SensitiveScanner)用七条本地规则做机械检查:
- 能发现:私钥块、AWS access key、
sk-风格 token、GitHub token、密码赋值、内网 IP、带密码的 JDBC URL(U68 secretShapes=PASS、U68 privateKeyAndPassword=PASS)。 - 不能发现:base64、拆分拼接、图片内文字、被改写的 token 格式——实验用反例断言了这个盲区(
U68 dlpBoundary=PASS evasiveUndetected=true)。
所以敏感信息处理的完整链条是三层:不把秘密喂给模型(提示词卫生)→ 生成物入库前扫描(本实验)→ 提交门禁与轮换预案(发现泄露后的处置)。扫描器只是第二层里的一道最低防线。
- 报告必须脱敏:实验断言报告里不出现原值(
secretShapes的脱敏断言)。
任务卡闭环:从错误到修正
任务卡的生成样本(tasks/ledger-refund-generated.md)含五处错误:double 金额、Instant 参数、null 返回 false、已退款返回 true、doubleValue 比较。审查记录逐条列出"错误—违反的约束—修正",修正实现 RefundPolicy 用同一组验收断言证明满足约束:
- 边界:
U68 taskWindow=PASS day0=true day7=true day8=false future=false。 - 幂等:
U68 taskIdempotent=PASS refunded=false。 - 异常:
U68 taskIllegal=PASS nullOrder=true negative=true。 - 金额:
U68 taskAmount=PASS scale=2 exact=true。 - 生成错误会被抓住:
U68 taskGeneratedCaught=PASS doubleComparison=true refundedWrong=true。
这条闭环就是 C16 说的"能发现并修正生成错误"的最小可验收形态:错误可定位、修正可验证、断言可复跑。
人工确认与责任边界
AI 辅助研发的责任不是"模型背锅"也不是"人全背",而是按环节划分:
| 环节 | 谁负责 | 证据 |
|---|---|---|
| 上下文与约束是否完整 | 工程师 | 任务卡与验收清单 |
| 生成物是否可用 | 工程师(模型不可问责) | 编译、测试、扫描结果 |
| 合入决定 | 人(评审 + 门禁) | 审查记录与 CI |
| 泄露处置 | 安全流程 | 扫描报告、轮换记录 |
模型输出是候选,不是结论。把"AI 写的"当作免责理由,和把"AI 写的"当作质量证明,是同一种错误。
观测与度量
- 审查发现的错误数与类别(本实验 10 类)。
- 生成物一次通过率与返工轮次——只在有真实模型与凭据时可测,本票受阻。
- 敏感扫描命中数与误报率。
- 任务卡验收断言的覆盖率(几条约束 → 几条测试)。
这些是团队级指标,不应用于个人绩效排名(与架构治理与交付效能的交付指标纪律一致)。
本页证明边界与受阻
| 已验证(本地实跑) | 受阻(无凭据) | 明确不纳入 |
|---|---|---|
| 生成样本的 10 类错误被断言证明;修正版行为正确;API 存在性/弃用/依赖版本核实;敏感扫描 7 规则与盲区;任务卡五步闭环 | 真实模型生成质量、提示词效果、"模型是否会犯这些错"、一次通过率 | 模型训练/微调、提示词工程全集、具体 IDE 插件操作 |
本页证明"审查工具链能抓住这些错误";不能证明"某个模型会/不会犯这些错误"——后者需要真实模型与凭据,票面口径如实受阻。
实验读法
python3 labs/ai-assisted-dev/run.pyGeneratedReviewTest(10):十类生成错误的"生成版错、修正版对"对照 + API 核实。SensitiveScanTest(5):七条规则、脱敏、目录扫描、盲区反例。RefundPolicyTaskTest(5):任务卡验收断言与生成样本五处错误的对照。
闭卷验收
本页 26 道闭卷题收进了下方自测面板:先回忆,再展开参考答案与评分点,最后给三档自评。