让 AI 写一段代码,现在已经不是难事;难的是让这段代码在你不盯着它的时候也能不闯祸。我最近在一个内部工具里让 AI 生成一个批量处理 CSV 的方法,第一版看起来非常干净:类型标注、异常捕获、日志都有。可真正放到数据集上一跑,发现空行、编码、重复主键、超大字段四个问题全没处理。那一刻我想明白了一件事:AI 生成代码的核心风险不是“写不出来”,而是“假正确”——它看起来是对的,边界条件却一碰就碎。
所以真正值得讨论的问题,不是怎么让 AI 写更多代码,而是怎么用一套约束体系,把 AI 生成代码的自由度装进可控的边界里。这套体系放在工程语境下,可以叫“线束工程”。它包含两个关键角色:确定性工具负责做硬校验,智能体审查负责做语义校验,再把人工评审作为最后一道兜底。谁先把这套约束体系建起来,谁才能真正把 AI 生成代码从“玩具”推进到“生产可用”。
1. AI 生成代码的真正风险,不是“写得少”而是“假正确”
先说一个可能反直觉的判断:AI 生成代码对你项目最大的威胁,不是它写得少,而是它写得“太像回事”。
不少团队引入 AI 编程助手之后,第一感受是效率提升明显。一个函数、一个接口、一组 CRUD,过去要写半小时,现在几秒就出来了。但问题往往也藏在这里:AI 生成的代码往往在结构上正确,在边界上不安全,在语义上可能偏离需求。这跟传统的人工编码不一样——人写错往往错得明显,比如漏了空指针判断、循环边界差一;而 AI 写错,常常是“该有的都有,但都不够到位”。
1.1 一个典型的“假正确”例子
我曾经给一个数据清洗工具做过一次实验,让 AI 生成一个从 CSV 导入并去重的函数。第一次生成的代码长这样:用 pandas 读取文件, drop_duplicates,然后返回 DataFrame。单看这一段,没毛病。
但拿真实数据一测,问题就出来了:
- 没有处理文件不存在、权限不足的情况;
- 没有处理 CSV 中空行和全空字段;
- 没有明确去重字段,默认去重逻辑可能把本来合法但部分字段相同的记录删掉;
- 没有处理超大文件时的内存问题;
- 没有处理编码不一致导致的乱码。
所有这些,GitHub Copilot 或者 GPT 这类工具不会主动帮你判断。它们只是根据上下文补全了“最大概率的下一步”。只有当你在提示词里、在约束清单里、在审查流程里把这些边界条件都定义清楚,生成结果才会收敛。
1.2 生成自由度和可控性的矛盾
我们可以把大模型生成代码理解成一个高维概率分布:给它一个起点,它会沿着最可能的路径继续走。问题是,“最可能”不等于“最正确”,更不等于“最符合你的业务约束”。
这跟硬件工程里的场景很像。一个复杂电路里有很多根导线,如果不做线束规划,导线就会乱跑、互相干扰、故障难排查。工程师的做法是设计线束:规定每根线的走向、编号、固定位置、屏蔽要求、连接器定义。这样系统才能从“能通电”变成“可维护、可诊断、可扩展”。
AI 生成代码也一样。如果只给大模型一句话要求,它生成的代码就是一堆“散线”:看起来功能实现了,但没有统一约束、没有明确边界、没有可验证的标准。线束工程要做的,就是把“散线”变成“线束”:
- 定义输入输出边界;
- 定义错误处理策略;
- 定义日志和可观测性要求;
- 定义性能和质量门槛;
- 用确定性工具把这些约束变成可自动检查的规则;
- 用智能体审查补上语义层的检查。
一句话:线束工程不是限制 AI 发挥,而是让 AI 在一个明确边界内发挥。边界越清楚,生成结果越稳定,返工越少。
2. 线束工程:把约束从提示词变成可执行的边界
很多人在用 AI 生成代码的时候,以为“约束”就是提示词里多写几个“请考虑异常情况”。但真正的约束,应该是可执行、可验证、可审计的边界。
提示词约束当然有用,但它本质上是一种软约束。大模型可能看到你的要求,也可能漏掉;可能这次遵守,下次不遵守。所以要真正约束 AI 生成代码,必须把约束分成两层:生成前的显式约束,和生成后的确定性校验。
2.1 不要只写提示词,要写“约束清单”
我比较推荐的做法是:在让 AI 写代码之前,先准备一份约束清单。这份清单不是作文,而是类似验收标准的东西。
一个比较通用的约束清单结构可以是这样:
| 约束类型 | 示例 | 为什么重要 |
|---|---|---|
| 功能边界 | “只处理 UTF-8 编码的 CSV 文件,其他编码报错提示” | 避免 AI 自由发挥编码处理逻辑 |
| 输入校验 | “文件不存在、权限不足、列为空时,返回明确错误码” | 让异常路径可预期 |
| 输出格式 | “返回结构化结果,包含成功条数、失败条数、错误明细” | 方便下游对接,而不是一个裸的 DataFrame |
| 资源边界 | “单次处理最大 200MB,超过则分块或拒绝” | 防止把内存打爆 |
| 可测试性 | “主逻辑拆成纯函数,文件读取和业务处理分离” | 让单测能覆盖核心逻辑 |
| 日志规范 | “每个主要步骤输出一条带耗时和状态的结构化日志” | 让线上问题可追踪 |
把这份清单贴在提示词前面,再让 AI 生成代码,效果会比单纯说“请写得健壮一点”好很多。原因很简单:大模型在生成时会更频繁地“看到”这些约束,虽然它仍然可能遗漏,但至少你有了一组可以逐条对照的需求基线。
2.2 确定性工具的约束是硬约束
提示词约束只是第一步,真正的“线束”来自确定性工具。
所谓确定性工具,指的是编译、类型检查、Lint、静态分析、单元测试、契约测试这类输出结果是确定性的工具。你运行一万次,结果都是一样的。它们不会“这次通过、下次不通过”,也不会因为上下文不同而给出模棱两可的结论。
在审查 AI 生成代码时,确定性工具最大的价值就是提供硬校验。AI 生成代码可以“说得天花乱坠”,但编译器不会骗人,单测不会骗人,契约测试不会骗人。如果有一个边界条件没处理好,测试就会红;如果有一个接口签名不对,类型系统就会报错。
所以我的原则是:AI 生成的每一段生产代码,都必须先过确定性工具链,再谈人工评审。顺序不能反过来。
注意:这里不是要用确定性工具替代人工评审,而是用确定性工具把低级的、规则性的问题先过滤掉,让人工评审把精力集中在语义和架构上。
3. 用确定性工具给 AI 生成的代码做“体检”
有了约束清单之后,下一步是建立一套确定性工具检查流水线。很多人以为“我让 AI 跑一下单元测试不就行了”,但实际落地时,检查深度和顺序都有讲究。
3.1 检查顺序不要跳
我见过不少团队直接把 AI 生成的代码丢进 CI,跑挂了再修。这种方式不是不行,但效率很低。更推荐的做法是分层次检查,每层只做一件事:
- 编译/类型检查:先确认代码能解析、类型是通的。这一步成本最低,也最容易自动化。
- 静态检查:Lint 规则、安全扫描、复杂度检查。重点看有没有明显的反模式、危险函数、未处理异常。
- 单元测试:针对生成代码的函数,验证正常输入、边界输入、非法输入三类用例。而不是只跑“主流程不报错”。
- 契约/集成测试:如果代码要对接数据库、外部 API 或消息队列,要验证接口签名、超时行为、错误码是否符合约定。
这四层不是并列关系,而是漏斗关系:越往下成本越高、越接近真实行为。如果编译都过不了,不要急着跑集成测试;如果静态检查还有严重问题,也不要急着写一堆单测。
3.2 单测不是“跑通”就完,还要看断言质量
用 AI 生成代码时,AI 也会生成测试。这个测试往往存在一个陷阱:它测试的是“AI 理解的预期”,而不是“业务真实需要的预期”。
举个例子,AI 生成的去重函数,测试用例可能是“输入有两行相同数据,输出一行”。但如果业务约束是“根据 user_id 去重,email 可以重复”,那么 AI 生成的测试反而会强化错误的默认行为。
所以用确定性工具审查 AI 生成代码时,要特别注意测试断言是否和约束清单一致:
- 断言是不是只检查了成功路径?
- 有没有覆盖约束清单里的异常项?
- 断言是通过具体值判断,还是只检查了“没有报错”?
- 测试数据是否太“干净”,缺少脏数据、重复数据、边界数据?
如果这些没确认,跑再多次通过也没有意义。
3.3 排查链路:确定性工具检查失败时,按这个顺序看
实际使用中,总会遇到检查不过的问题。我的排查顺序通常是:
- 先看现象:是编译错误、测试失败,还是静态检查告警?这决定了从哪一层开始。
- 再看输入:AI 生成代码的输入数据、参数类型、测试 fixture 是否符合约束清单?很多问题出在“给 AI 的需求本身就含糊”。
- 再看环境:依赖版本、Python 版本、系统差异、环境变量是否一致?AI 生成的代码经常隐式依赖某些库,要在 requirements 里锁定。
- 再看参数:函数签名、配置项、超时、批处理大小是否和约束清单一致?有时不是代码错,是参数定得不对。
- 最后看工具边界:这个确定性检查是不是覆盖了该检查的点?如果目前检查没覆盖语义层,就需要智能体审查或人工介入。
这个链路不一定每次都能一次定位,但至少能避免“看到失败就急着改代码”。因为很多时候,问题不在 AI 生成的代码本身,而在于输入、环境或约束定义。
4. 智能体审查:第二道“语义线束”
确定性工具能查规则,但查不了语义。编译器不知道你的业务需求是“去重后保留最新一条”,也不知道“这个函数的命名是不是误导了调用者”。这种语义层的偏差,需要另一层审查:智能体审查。
智能体审查不是简单地把代码丢给一个聊天窗口,说“你帮我看看这段代码有没有问题”。那样得到的回复往往大而空,比如“建议增加错误处理”“建议补充注释”。真正有效的智能体审查,是把审查当成一个结构化任务来跑。
4.1 一个可落地的智能体审查流程
我建议的流程是四步:
- 准备输入包:把需求描述、约束清单、AI 生成的代码、确定性工具检查结果,打包成一个结构化的审查上下文。
- 定义审查问题:不要问“这段代码好吗”,而是给出一组具体问题。比如:
- 这段代码是否满足约束清单中的每一项?
- 哪些边界条件没有被处理?
- 是否存在和需求语义不一致的假设?
- 异常路径是否清晰,调用者能否预判?
- 让智能体逐条输出:要求它按“问题编号 + 结论 + 证据位置 + 修改建议”的格式输出,而不是给一段泛泛的总结。
- 人工抽样复核:智能体的结论不能直接进仓库。至少要人工抽查关键结论,尤其是它说“通过”的项。
这个流程的核心是:把智能体当成一个“读过需求、会看代码、但也会犯错”的初级评审者,而不是一个权威裁判。
4.2 智能体审查的真正价值:把“隐性假设”显性化
智能体审查最有用的一点,是能帮忙发现 AI 生成代码里的“隐性假设”。
举个例子,需求是“把用户列表按创建时间排序后导出”。AI 生成的代码可能默认创建时间字段没有空值,默认排序是稳定的,默认导出格式是 CSV。这些假设,如果人肉 review,往往要看到细节才会注意;但智能体如果被明确要求“逐条检查需求描述中的每个词是否在代码里有对应实现”,它更容易发现“排序”和“导出格式”都没有被显式定义。
不过也要清醒:智能体本身也是大模型,它也会产生幻觉。它可能为了满足你的格式要求,输出一段看似合理但实际错误的结论。所以在智能体审查之后,必须保留人工评审作为最终闸门。
千万不能把“智能体说没问题”当作“代码没问题”。智能体审查是一道增强线束,不是替代安全带。
5. 一套可复用的“线束工程”落地框架
综合前面的思路,可以沉淀成一个四层约束框架。这四层不是可选项,而是层层递进、缺一不可。
| 层级 | 主要工具 | 输入 | 输出 | 关键检查点 |
|---|---|---|---|---|
| 第一层:需求约束层 | 约束清单、需求模板 | 业务需求 | 可验收的约束列表 | 功能边界、输入输出、异常策略、日志要求 |
| 第二层:确定性校验层 | 编译、Lint、单测、契约测试 | 约束清单 + AI 生成代码 | 测试报告、覆盖率、告警列表 | 规则是否满足,边界是否覆盖 |
| 第三层:智能体审查层 | 结构化审查 Agent | 约束清单 + 代码 + 测试报告 | 按问题编号的审查结论 | 语义是否一致,隐性假设是否显性化 |
| 第四层:人工复核层 | 代码评审人 | 前三层输出 | 合并决策 | 架构合理性、可维护性、长期风险 |
落地的时候,不要一上来就全量铺开。我比较建议的路径是:
- 先选一个业务边界清晰的模块,比如“CSV 导入导出”“用户信息校验”;
- 为它写一份约束清单;
- 用 AI 生成一个版本,跑一遍确定性工具;
- 再用智能体审查一遍;
- 人工评审拍板;
- 跑通之后,再把同样的流程复制到其他模块。
这个顺序的核心逻辑:先用一个低风险场景把管线跑通,再逐步扩大范围。如果一上来就让 AI 生成上百个文件、丢给 CI、然后指望四层约束自动兜底,大概率会被各种“假正确”问题淹没。
这套框架也有它的适用边界:
- 适合:边界清晰、可测试性强、规则明确的代码生成场景。
- 适合:接口层、数据转换层、工具函数层。
- 不太适合:架构设计、跨模块重构、需要大量隐性业务知识的早期探索。
- 需要谨慎:生成代码涉及复杂状态机、分布式一致性、安全敏感逻辑时,四层约束只能作为辅助,必须有人全程深入评审。
6. 落地中最容易翻车的五个地方
最后说说我在实践里见到的五个高频坑。每一个都曾经让某个团队以为“线束工程没用”,其实问题出在使用方式。
6.1 约束清单写得太“虚”
“请写出健壮的代码”“请考虑异常情况”——这类约束等于没约束。线束工程的第一步是写可验证的验收标准,不是写作文。约束清单里的每一项都要能在代码里找到对应实现,或者能在测试里看到断言。
6.2 只在最后阶段才接确定性工具
有些团队是 AI 生成完代码,人肉改几轮,最后才丢进 CI。这样其实已经错过了确定性工具最有价值的时机。更好的做法是:生成之后立刻跑编译和静态检查,让工具在第一步就把低级问题拦掉。
6.3 智能体审查输入太少或太多
输入太少,智能体只能瞎猜;输入太多,它会淹没在细节里,反而漏掉关键问题。比较好的做法是:给它约束清单、代码、测试报告这三样,再让它在约束清单的框架内逐项审查。不要贴十几个上下文文件进去。
6.4 把智能体的审查结论当成评审记录
智能体输出的内容可能是幻觉或猜测,不能直接作为代码评审记录。它更像是“候选问题清单”,需要人工确认后再转成真正的评审意见。
6.5 完全不设置失败重试和人工升级路径
AI 生成代码即使有约束,也可能一直修不好同一个问题。这时候不要无限循环重试,而是设定一个阈值:修两三轮还不过,就转到人工处理,或者换一个实现思路。这不是 AI 能力不足,而是当前约束和问题不匹配,需要人介入调整约束定义。
如果你在实际使用中遇到了问题,可以参考这套排查链路:
- 现象是什么?编译失败、测试失败、审查不通过、还是运行时行为异常。
- 输入有没有问题?约束清单、需求描述、测试数据是否清晰。
- 环境对不对?依赖版本、平台、配置是否一致。
- 参数设置是否合理?批量大小、超时、模型温度、审查轮次。
- 最后确认工具边界:当前这层约束是否覆盖了当前问题。
线束工程不会让 AI 生成代码这件事变得简单。它只是把“AI 写代码”从一场不可控的生成,变成了可控的流水线:先定义边界,再确定性校验,再语义审查,最后人工拍板。这个过程本质上是在给 AI 的能力装配安全边界,也是在给工程团队建立一条“可审计、可回退、可改进”的反馈闭环。
AI 生成代码的能力会越来越强,但工程上真正稀缺的,从来不是生成速度,而是对生成结果的约束能力。线束工程的意义也在这里:它不追求让 AI 少写代码,而是让每一段进入仓库的代码,都在明确的边界里完成它的职责。