AI 写代码为什么会错?上下文、测试和反馈循环
写在前面AI 会写代码但不会替你负责现在用 AI 写代码已经很常见了。你描述一个需求它能生成组件你贴一段报错它能给修复建议你让它写测试它也能写得像模像样。于是很多人会产生一个期待既然它会写代码是不是可以直接交给它现实是可以让 AI 写但不能让它独自负责。AI 写代码会错而且错得很有迷惑性。它不是完全不会写而是经常写出“看起来合理、局部正确、放进项目就出问题”的代码。这篇文章不讨论 AI 会不会取代程序员。我们只讲一个更实用的问题AI 写代码为什么会错 怎么让它少错 错了以后怎么建立反馈循环错因一它没有完整上下文人类开发者写代码时脑子里不只有当前文件。你会知道项目用什么框架 状态管理怎么做 接口返回格式是什么 错误处理习惯是什么 哪些工具函数已经存在 哪些历史坑不能碰 团队代码风格是什么。AI 如果没看到这些就只能根据通用经验猜。比如你让它写一个登录接口它可能生成直接查数据库 自己拼 JWT 返回 user 对象 错误时抛 500。这段代码单独看好像能用但你的项目可能已经有统一认证中间件 统一响应 envelope 统一错误码 密码哈希工具 审计日志 限流策略 多租户权限。AI 没看到就不会自动遵守。所以很多 AI 代码错误本质不是“不会写”而是“上下文不够只能猜”。怎么补上下文不要只给一句需求。更好的输入是相关文件 现有接口示例 错误日志 测试用例 约束条件 不要改的边界 期望输出格式 项目已有模式。比如不要只说帮我加一个导出功能。可以说参考 UserExportService 的写法给订单列表加 CSV 导出。 保持现有 API envelope不改数据库结构。 权限走 requireAdmin中间件已经在 routes/admin.ts。 先补测试覆盖空结果、中文字段和无权限。这类 prompt 不只是“提示词更好”它是在把工程上下文交给模型。错因二它会补不存在的东西AI 很擅长根据模式生成代码。这个能力有用也危险。它可能会引用一个不存在的函数formatDateTime()可能会假设项目里有一个不存在的库import { createApiClient } from /lib/api也可能会写一个框架旧版本的 API。为什么因为在训练数据里这些写法很常见。模型看到你的需求后生成了“看起来像这个项目会有”的代码。但软件工程不是写作文。不存在就是不存在。这类问题最好的解决方式不是和模型辩论而是跑工具类型检查 lint 单元测试 构建 运行时 smoke test。让真实反馈告诉它哪里错了。错因三它喜欢局部最优AI 很容易修眼前错误。测试报Cannot read property id of undefined它可能加一行if (!user) return null;错误没了但业务逻辑可能错了。也许这里不应该返回 null而应该返回 401也许上游根本不应该传空 user也许这是权限绕过的信号。AI 常常解决“报错文字”而不是解决“系统问题”。人类开发者要追问这个错误为什么出现 输入边界是什么 正确行为是什么 有没有类似代码 这个修复会不会吞掉错误 测试有没有覆盖业务语义。AI 可以帮忙找方向但不能替你做工程判断。错因四测试缺失没有测试时AI 写代码就像蒙眼开车。它生成一段代码你看着还行但不知道边界条件对不对 老功能有没有坏 错误分支能不能跑 权限有没有绕过 输出格式有没有变 性能有没有明显退化。AI 最喜欢在没有测试的项目里“看起来很高产”。它能快速改很多文件但你没有反馈机制判断这些改动是否正确。所以 AI 编程越多越需要测试。这里不是为了完成某个覆盖率 KPI而是因为测试给 AI 提供了可执行反馈。一个好的循环是写测试 运行测试失败 让 AI 根据失败实现 再运行测试 失败就把错误反馈给 AI 通过后看 diff 补边界测试 再 review。错因五反馈循环太长AI 写代码的质量很依赖反馈速度。如果每次改完都要等半小时构建或者没人跑测试AI 就只能继续猜。反馈循环越短AI 越像一个能快速试错的助手。反馈循环越长AI 越像一个自信但不受约束的代码生成器。理想状态是小步修改 快速测试 立即反馈 只修一个问题 再进入下一步。不要一次让 AI “重构整个系统”。除非你有非常强的测试和 review否则这类任务很容易变成大面积不确定性。错因六它不理解你的隐性约定项目里有很多东西不会写在 README。比如这个字段历史上不能改名 这个接口虽然难看但外部客户在用 这个表不能加锁 这个模块不允许引入新依赖 这个错误码前端写死了 这个函数慢一点没关系但必须可回滚。这些隐性约定AI 不可能凭空知道。所以重要项目里要把隐性约定尽量显性化测试 注释 架构文档 编码规范 类型约束 CI 检查 代码审查清单。不是为了照顾 AI而是为了照顾整个团队。AI 只是把这些“工程卫生”问题放大了。怎么让 AI 更可靠地写代码我会按这个流程用 AI1. 先让它读不急着写先问请先阅读这些文件总结现有实现方式不要改代码。看它是否理解项目结构。理解错了后面写代码大概率也会错。2. 让它提出计划尤其是多文件修改先要计划需要改哪些文件 每个文件改什么 测试怎么补 风险在哪里 哪些地方不碰。计划不是形式主义它能提前暴露误解。3. 测试先行能写测试的任务先写测试。测试会把需求变成可执行约束。AI 后面实现时就有明确目标。4. 小步修改让 AI 一次只完成一块先补类型 再补服务逻辑 再接 API 再补 UI 最后整理错误处理。每一步都跑检查。5. 必须看 diff不要只看最终效果。一定要看它改了什么。重点看有没有无关重构 有没有删除重要逻辑 有没有硬编码 有没有吞掉错误 有没有新增依赖 有没有改变公开接口。6. 用工具验证不靠口头保证AI 说“已经修复”不算数。算数的是测试通过 类型检查通过 构建通过 关键路径手动验证 review 没发现高风险问题。AI 编程的正确心态不要把 AI 当成“自动程序员”。更准确地说它是一个很快、很博学、但没有项目责任感的协作者。它适合生成草稿 解释代码 补测试 查错误方向 写样板代码 整理重构计划 做初步 review。它不适合独自负责安全边界 架构决策 生产数据操作 复杂迁移 无测试的大重构 高风险业务逻辑。你可以让它开车但方向盘、刹车和验收标准要在你手里。按开发阶段看 AI 容易错在哪里AI 写代码不是每个阶段都一样危险。阶段AI 擅长什么容易错什么需求理解总结、拆分、提问忽略隐性约束方案设计给出候选方案过度设计或套模板写代码生成样板和局部逻辑引入不存在的 API写测试覆盖常见路径漏边界和业务语义修 bug根据报错定位方向只修表面现象重构提出整理思路改动范围过大Review找明显问题漏深层业务风险所以不要对 AI 一刀切。让它写样板代码通常很值。让它独自改核心架构风险就高。让它生成测试初稿可以测试是否真正覆盖需求还得人看。按代码类型分类不同代码AI 的可靠性也不同。1. 样板代码比如表单组件 DTO 路由注册 简单 CRUD 配置示例。AI 很擅长。只要项目模式清楚它能省很多时间。2. 胶水代码比如调用第三方 API 文件格式转换 脚本自动化 数据同步。AI 也比较适合但要注意版本和错误处理。它经常写出过期 SDK 用法。3. 业务核心代码比如计费 权限 订单状态机 审批流 风控规则。这类代码 AI 可以辅助但不能靠它猜。因为关键规则往往不在代码表面而在业务约定里。4. 并发和性能代码比如锁 缓存一致性 异步队列 批处理 数据库事务。AI 很容易给出看似合理但有隐藏问题的方案。必须通过压测、事务分析和代码 review。5. 安全相关代码比如认证 授权 加密 签名 输入校验 权限边界。这类代码要非常谨慎。AI 可以生成参考但最终必须按安全标准检查。按项目成熟度分类AI 在不同项目里的表现也不一样。新项目新项目没有太多历史包袱AI 发挥空间大。它适合搭目录结构 写初版组件 生成测试框架 创建 API 草稿 快速做 demo。风险是过度生成。它会把一个小项目写成大平台。成熟项目成熟项目有大量隐性约定。AI 如果没读上下文很容易破坏兼容性 绕开已有工具 重复造轮子 改掉历史逻辑 引入不符合团队规范的依赖。成熟项目里AI 最好先做阅读和局部修改不要一上来大重构。遗留项目遗留项目文档少、测试少、风格乱。AI 会更容易猜错因为它看到的模式本身就不稳定。这类项目更适合让 AI补注释 画调用关系 生成 characterization tests 整理风险点 小范围提取函数。不要让它直接“全面现代化”。验证也要分层不是所有改动都需要同样重的验证但至少要有梯度。验证层级适合改动语法检查小脚本、配置、简单函数类型检查TypeScript、Java、Go 等强类型项目单元测试纯函数、业务规则、工具函数集成测试API、数据库、队列、外部服务E2E 测试用户关键路径手动验收UI、交互、复杂业务安全 review权限、输入、数据、密钥AI 改代码后至少要跑和风险匹配的验证。比如改按钮文案可能不需要完整 E2E。改登录权限只跑格式化肯定不够。更好的 AI 编程任务写法把需求写给 AI 时可以按这个模板目标要实现什么 上下文相关文件和已有模式 边界哪些文件不要改 约束响应格式、权限、性能、安全要求 测试先补哪些测试 验收什么命令通过才算完成 风险哪些地方需要特别注意。比如目标给订单列表增加 CSV 导出。 上下文参考 UserExportService 和 admin routes。 边界不要改数据库结构不要改现有分页接口。 约束只允许 admin中文字段要正确编码。 测试空结果、无权限、含逗号字段、中文字段。 验收npm test 和 npm run build 通过。 风险不要把普通用户也暴露导出入口。这种任务描述比“帮我加导出”强很多。AI 代码 review 也要会用AI 不只适合写代码也适合做第一轮 review。可以让它检查是否有无关改动 是否重复造轮子 是否漏错误处理 是否有空值问题 是否违反现有模式 是否需要补测试 是否有明显安全风险。但 AI review 也不能代替人。它容易漏业务语义 历史兼容 组织约定 真实用户影响 性能瓶颈 安全边界里的细节。最好的方式是让 AI 做第一层机械检查人做最终判断。最终结论AI 写代码会错主要不是因为它“笨”而是因为软件工程本来就依赖上下文、约束和反馈。最常见的错因是上下文不完整 补了不存在的函数或库 只修表面错误 缺少测试 反馈循环太长 不了解项目隐性约定。让 AI 少错的办法也很明确给足上下文 先计划 测试先行 小步修改 跑工具验证 认真看 diff 保留人工 review。一句话AI 编程的关键不是让模型一次写对而是建立一个它写错了也能被快速发现、快速纠正的工程循环。