审查 AI 代码:从真实约束到边界故障
文章提供审查 AI 代码与架构草案的检查清单、反馈表达和两个示例,覆盖辅助编程面试与日常评审。重点检查模型缺失的业务约束,以及空输入、边界、并发和失败场景。
AI 深度解读
AI 写出的代码越来越像成品,但格式整齐、测试通过、架构图完整,都不能证明方案适合你的项目。作者的核心主张是:工程师的价值正在更多地落到审查和判断上,既要找出错误,也要能解释为什么错、该怎么改。
这篇给了两套检查清单,以及限流器和内部投票应用两个例子。对日常使用 AI 编程的前端、全栈开发者,最有用的是一套接受建议前的检查顺序:先确认需求,再检查边界、并发和失败路径,最后追问复杂度是否有依据。
代码看起来写完了,还要检查什么
作者认为,AI 容易生成看起来合理的答案,却未必掌握真实流量、预算、团队规模和已有系统。它可能解决了一个相近但更容易的问题,也可能用同样笃定的语气调用不存在的库函数。
因此,审查的第一步不是看代码是否优雅,而是重新读需求,再对照实现。随后检查输入为 0、1、最大值、空列表、null、重复值时的行为。这些例子看着普通,却能暴露边界偏移和遗漏分支。
接下来要沿着正常流程之外的路径走一遍:网络超时怎么办,文件不存在怎么办,数据库拒绝写入后,错误有没有被吞掉?涉及共享状态时,还要增加一个问题:两个请求同时执行,会不会都读到旧值,再分别写回?
API 和安全也不能靠观感判断。陌生方法及参数要查文档,例如原文提到的 retryWithBackoff,应先确认当前客户端是否提供。字符串拼接 SQL、未转义的用户输入、硬编码密钥、缺失权限检查,也都需要逐项核对。
AI 写的测试通过,只能证明这些测试通过,不能证明它覆盖了你担心的错误。
作者要求同时审查断言:它验证的是需求,还是恰好复述了实现?如果把疑似缺陷放回去,测试会不会失败?最后还应能逐行向同事解释代码,否则审查尚未完成。
限流器为什么最容易暴露「差一点正确」
原文用令牌桶(token bucket)说明这类问题。它允许请求消耗令牌,并按经过的时间补充令牌;桶容量决定最多能积攒多少令牌,从而限制突发请求。
作者描述了三个缺陷。
首先是容量约束。长时间空闲后,按时间计算出的补充量可能让令牌数超过桶容量。如果超额令牌参与放行判断,就会允许超过预期的突发请求,因此补充后需要限制上限。
其次是并发。读取令牌数、减去一个、写回结果,是一组读改写操作。两个请求可能同时看到最后一个令牌,然后都获准通过。作者建议使用锁,或者共享存储提供的原子操作。
最后是单位。经过时间用毫秒表示,补充速率却按秒计算,一行代码里就可能藏着 1,000 倍的误差。
对 Node 服务,这个例子的启发是:看到状态更新,不能只检查减法是否正确,还要确认状态由谁共享、更新能否被其他请求穿插,以及时间单位是否一致。不过原文没有给出完整代码,无法核对这些缺陷出现在哪一行,也不能把它当作可复现的实验报告。
架构里每多一个组件,都要回答它解决什么
架构审查的起点,是把每个组件对应到具体需求。说不清用途的组件,仍然需要部署、监控和维护。
作者建议先做一个 2 分钟的粗略估算:有多少请求、多少写入、多少数据,再判断是否需要分片、缓存或队列。还要区分一致性要求:点赞和信息流可以接受短暂陈旧,支付和库存则需要更严格地讨论更新与读取规则。
平均流量也不够。名人发帖、限时抢购、链接突然走红,都可能把压力集中到少数数据上。同时要检查负载均衡器、主数据库、单个队列 broker、单一区域是否构成单点故障。
内部投票应用的例子很直观:AI 提议拆分用户、投票活动和选票微服务,接入 Kafka、Redis,再放一个 NoSQL 存储。但需求只有几百名用户、每天几千票,平均写入远低于每秒 1 次。作者认为,一个服务加一个关系型数据库就足够,使用 (poll, user) 唯一约束防止重复投票,也更直接。
原文还用每秒约 50 次写入说明,加入 Kafka 前应先检查数字;每秒几百次写入,也不能单凭吞吐量就证明五个服务和流处理平台的必要性。这些数字是讨论入口,不能当作所有数据库的性能承诺。
提出异议时,作者推荐按「风险、原因、替代方案」表达。例如,缓存可能让价格陈旧长达一小时,就应说明结账读取的风险,并提出结账查数据库、商品页使用缓存的方案。这样讨论才有可执行的下一步。
我的判断
我认可作者把审查放到接受建议之前,尤其是要求用需求和数量级解释架构。它能让讨论从「这个技术很常见」,回到「我们为什么需要它」。
但原文没有给出代码、压测结果或方案对照数据。两个例子属于教学演示,关于面试表现和团队信任的说法也主要是经验判断,不能据此认定遵循清单就能提高多少通过率。
简单架构同样有前提。已有 Kafka 平台的团队,与需要从零维护 Kafka 的小团队,新增组件的成本不同。每天几千票也无法说明峰值多高;是否集中在几秒内提交,还要补充需求。
此外,锁必须与状态的共享范围匹配。多个 Node 实例共享同一份令牌数据时,单个进程内的锁无法独立解决跨实例竞争。这是将原文建议落地时,需要继续追问的实现条件。
清单适合提醒你去哪里找证据,最终判断仍要落到代码、约束和验证结果上。
能拿来做什么
- 接受 AI 生成的函数前,按需求、边界、失败路径检查一遍;至少针对最担心的缺陷,确认现有测试能否把它检出。
- 审查 Node 限流或计数逻辑时,明确状态存放位置、并发更新方式和时间单位,再决定采用锁还是共享存储的原子操作。
- 让 AI 设计内部工具后,补上用户量、每日写入量和峰值假设,要求它逐个解释 Kafka、Redis、微服务对应的需求,以及以后增加组件的触发条件。
- 在代码评审或 AI 辅助面试中,用「这里有什么风险、为什么会发生、建议怎么改」组织反馈,让对方能够验证你的判断。