4569 字
23 分钟
如何用好 AI 写代码:从模型选择到长期维护

AI 写代码已经从“帮我补全一段函数”,发展成可以参与需求分析、方案设计、代码实现、测试和排障的工程协作者。但它并不会自动替代软件工程:模型越强,越需要清晰的边界、可靠的反馈和可持续维护的约束。

真正高效的 AI 编程,不是把代码尽可能多地交给模型,而是让模型在正确的上下文中解决正确的问题,并且让每一次修改都能被验证、被回滚、被理解。

一、先改变对 AI 编程的期待#

AI 最适合处理的是“有明确输入和输出、可以通过反馈判断对错”的工作。例如:根据现有接口补充一个页面、为服务增加测试、解释一段陌生代码、定位一个可复现的错误,或者把一组重复逻辑重构成统一实现。

它不擅长独自承担没有边界的目标,例如“把系统做得更好”“顺便优化一下架构”或“保证绝对没有问题”。这些目标缺少验收标准,模型很容易通过修改大量代码制造一种进展感,却没有真正解决业务问题。

因此,使用 AI 前应该先把任务改写成一个小型工程契约:

目标:为候选人列表增加按面试阶段筛选。
范围:只修改列表查询、筛选组件和相关测试。
约束:保留现有分页和权限逻辑,不改变数据库结构。
验收:各阶段筛选结果正确;清空筛选后恢复全部结果;测试通过。

目标、范围、约束和验收标准越清楚,模型的发挥空间越大,返工也越少。

比如,“帮我优化登录功能”就太宽泛。更好的说法是:“登录失败后增加每分钟最多 5 次的限制;连续失败时返回统一提示,不泄露账号是否存在;只修改认证服务和登录接口;为成功、密码错误、超出频率和锁定时间增加测试。”后一个任务不仅更容易实现,也更容易判断是否完成。

二、模型怎么选:不要只看排行榜#

模型选择首先应该服从任务,而不是服从品牌或版本号。可以把常见任务分成几类:

任务类型更重要的能力适合的模型特征
补全、改名、格式整理速度和成本响应快、价格低、指令遵循稳定
普通功能开发综合能力能理解仓库结构,代码质量和速度平衡
跨模块重构、疑难排障推理和长上下文能处理复杂依赖,愿意逐步验证
代码审查和安全检查稳定性和细节擅长找边界条件,输出依据清晰
需求拆解、架构设计推理、表达和权衡能说明假设、风险和替代方案

实际选择时,至少应关注以下指标:

  1. 任务完成率:一次完成并通过验收的比例,比单次回答看起来是否聪明更重要。
  2. 上下文能力:能否稳定理解项目约定、多个相关文件和历史决策。上下文窗口大不等于能有效使用所有内容,检索和摘要同样重要。
  3. 工具调用能力:如果模型要运行测试、搜索代码、操作浏览器或调用接口,工具参数的准确性和失败恢复能力非常关键。
  4. 输出稳定性:同一任务多次运行是否保持相近质量,是否经常修改无关文件。
  5. 延迟与成本:要计算完整任务成本,包括重试、人工审查、测试环境和失败后的修复时间。
  6. 隐私和部署条件:代码是否允许发送到第三方,是否需要私有化部署、区域限制、审计记录或企业数据隔离。

比较模型时,最好建立自己的小型评测集。选择十到二十个真实任务,记录输入上下文、模型版本、推理设置、工具权限、修改文件数、测试结果、人工修复时间和总成本。只有在相同条件下比较,结论才有意义。

一个实用的策略是“分层使用”:简单任务使用快速模型,复杂设计和高风险修改使用强推理模型,代码审查再使用独立的检查流程。模型路由应该是可配置的,不要把整个系统永久绑定在一个模型名称上。

例如,为一个按钮补充 loading 状态,可以使用速度快的模型;要排查“用户偶尔收到重复短信”,则需要能同时阅读队列任务、供应商客户端、重试逻辑和发送日志的强推理模型。前者比较单次响应速度,后者更应该比较能否定位幂等键缺失、重试时机错误等根因。

三、技术栈怎么选:优先选择可验证的栈#

AI 会放大技术栈的优点,也会放大技术栈的混乱。对 AI 编程来说,最重要的不是某个框架是否热门,而是项目是否容易被观察和验证。

一个适合与 AI 协作的技术栈,通常具备这些特点:

  • 官方文档、示例和社区资料充足,模型容易获得正确上下文;
  • 类型系统或明确的数据结构能够减少接口误解;
  • 有稳定的格式化、静态检查、单元测试和集成测试命令;
  • 本地环境容易启动,测试数据可以重复创建;
  • 依赖数量可控,升级和回滚路径清楚;
  • 日志、错误信息和数据库迁移状态可被直接查看。

例如,TypeScript、Ruby、Go、Java 等语言都可以与 AI 高效协作,区别不在语言本身,而在团队是否把项目约定写下来、是否有自动化验证、是否能让模型快速定位真实错误。一个测试完善的旧项目,往往比一个没有约束的新项目更适合 AI 参与。

技术栈选择可以遵循三个问题:

  1. 这个栈能否让核心业务规则被清楚表达?
  2. 这个栈能否让错误尽早暴露,并提供足够线索?
  3. 团队能否在未来几年持续维护它,而不是只在 AI 生成代码时感到方便?

不要为了让 AI 生成代码更快,就引入团队不熟悉的新框架。短期生成速度无法抵消长期调试、招聘、升级和迁移成本。

举例来说,一个已有稳定 Rails 单体应用的团队,想增加一个后台报表。为了让 AI“使用最新技术”,直接引入新的前端框架和独立 API 服务,可能只让第一版页面更快出现,却同时增加了认证、部署、监控和数据一致性成本。如果现有 Rails 视图、查询对象和测试体系已经能满足需求,沿用它们通常是更适合维护的选择。

四、方案设计:让 AI 先思考,再动手#

复杂任务不要一上来就让模型修改代码。更稳妥的流程是先要求它阅读相关代码并输出方案,方案至少包含:

  • 当前实现和已有约定;
  • 需要修改的文件及其原因;
  • 数据流、状态变化和异常路径;
  • 兼容性、权限、安全和性能风险;
  • 测试策略和明确的验收条件;
  • 哪些问题仍然需要人来决定。

方案不是形式主义,它可以暴露模型是否理解了系统。例如,在增加“删除用户”功能时,方案应该说明软删除还是硬删除、关联数据如何处理、管理员权限在哪里判断、操作是否需要审计,以及删除后缓存和搜索索引如何更新。

对于跨模块需求,可以使用分层设计:

业务目标
领域规则与数据模型
服务接口与权限边界
页面、任务和外部集成
测试、日志、监控与回滚

每一层都应有清晰的输入、输出和失败行为。让 AI 逐层实现并逐层验证,通常比让它一次性生成完整功能更可靠。

以“增加订单导出”为例,方案至少应该先回答:导出哪些订单,谁有权限导出,查询结果是否受当前筛选条件影响,数据量大时是同步下载还是后台生成,生成失败如何提示,重复点击是否会创建多个任务,以及导出的手机号、地址等字段是否需要脱敏。等这些问题明确后,再让 AI 分别实现权限检查、查询、导出任务和下载接口,代码会更贴近真实需求。

五、上下文和提示词:给事实,不给噪音#

模型回答质量很大程度取决于上下文质量。把整个仓库无差别塞进上下文,通常不如提供少量但相关的文件。

好的上下文一般包括:

  • 项目结构和启动、测试命令;
  • 相关模块的实现和类型定义;
  • 数据库表结构、接口契约或产品规则;
  • 已知限制、历史兼容逻辑和不能修改的部分;
  • 一个成功案例和一个容易出错的边界案例。

提示词不需要写成复杂的“咒语”,但应该明确任务角色和工作方式。例如:

请先阅读相关文件,不要立即修改代码。
先输出:现状、拟修改文件、潜在风险、测试计划。
如果发现需求与现有权限或数据模型冲突,请暂停并指出冲突。
确认方案后再实现,并只修改必要文件。
完成后运行相关检查,报告实际结果,不要把未运行的检查写成已通过。

项目级说明文件也很重要。它应记录目录职责、代码风格、常用命令、测试约定、敏感文件、部署注意事项和“不要做什么”。这些内容比一段孤立的提示词更容易在长期协作中复用。

例如,不要只告诉 AI“修复这个接口”,而可以补充:“接口返回值必须使用项目已有的 ApiResponse 类型;数据库查询统一放在 repository 层;权限检查放在 controller 之前;先运行 pnpm test --filter user;不要修改生成文件。”这些项目规则比“请写出优雅代码”更有操作价值。

六、实现阶段:控制变更规模和副作用#

AI 生成代码时,应该把每次修改控制在一个容易审查的范围内。一个提交最好只对应一个主题,例如“增加筛选条件”“补充接口校验”或“修复时区转换”。不要把功能开发、全仓库格式化和依赖升级混在同一次修改里。

需要特别关注以下问题:

  • 模型是否修改了任务范围之外的文件;
  • 是否重复实现了项目已有的工具和组件;
  • 是否改变了公共接口、数据库结构或默认行为;
  • 是否把异常吞掉,或者用过宽的类型和默认值掩盖错误;
  • 是否只实现了成功路径,没有处理空数据、重复请求、超时和权限不足;
  • 是否生成了看似合理但与真实业务规则不符的演示数据。

对于数据库、支付、消息发送、文件删除和权限变更等有副作用的操作,应要求 AI 先提供 dry-run、迁移方案或回滚方案。真正执行前,确认目标环境、数据范围和幂等策略。

比如让 AI “清理三个月前的临时文件”时,不能直接生成 DELETE 或批量删除脚本。应该先让它输出待删除文件数量、时间范围、文件来源和 SQL 查询结果,再把执行动作改成可重复运行的 dry-run 模式;确认结果后,使用带备份或回收站机制的删除方式,并记录批次号,避免任务重试时重复处理。

七、验证:代码能运行不等于功能完成#

验证应该形成由近及远的反馈环:

  1. 格式化和静态检查,尽快发现语法、类型和风格问题;
  2. 单元测试,验证局部规则和边界条件;
  3. 集成测试,验证数据库、队列、外部接口和权限;
  4. 浏览器或真实接口验证,确认用户实际看到的行为;
  5. 差异审查,确认没有无关修改、敏感信息或破坏性变更。

测试不应该只问“有没有报错”,还要检查结果是否符合业务定义。比如“平均处理时长”是否排除了未完成记录,“发送成功”是否代表供应商接受还是用户最终收到,“用户可见”是否同时经过了权限过滤。这些定义需要写进测试和文档,而不是留给模型猜测。

让 AI 参与验证时,可以要求它输出一份简短证据清单:运行了哪些命令、命令是否成功、失败信息是什么、哪些部分没有验证、还需要人工检查什么。尤其不要把“代码看起来正确”当成测试通过。

例如,一个“发送邀请邮件”的功能,至少要分别验证:邮箱为空时是否被拒绝;重复点击是否只产生一封邮件;邮件模板变量缺失时是否阻止发送;供应商超时后是否按策略重试;接口返回成功究竟代表“已加入发送队列”还是“供应商已接受”。只测试 HTTP 接口返回 200,无法证明整条投递链路正确。

八、安全与隐私:把 AI 当作不受信任的协作者#

AI 编程工具可能接触源代码、配置、日志、用户数据和生产环境。使用前应明确数据边界:哪些内容可以发送,哪些必须脱敏,哪些文件完全禁止读取。

至少应落实这些保护措施:

  • 密钥、令牌、客户隐私和生产数据不进入提示词或提交记录;
  • 工具权限遵循最小权限原则,读权限和写权限分开;
  • 高风险操作需要人工确认,尤其是删除、付款、发布和权限提升;
  • 外部内容和仓库文本都可能包含提示注入,不应直接当作高优先级指令;
  • 依赖、生成代码和 SQL 需要经过常规安全检查;
  • 保留操作日志,能够追踪模型提出了什么、执行了什么、谁批准了什么。

安全并不是阻止 AI 工作,而是让错误和越权行为的影响被限制在可控范围内。

九、后续维护:最容易被忽略的部分#

AI 生成的代码同样需要人维护。上线后应观察错误率、性能、成本、重试次数和用户反馈,并把真实故障整理成回归测试。模型、依赖、提示词和工具接口发生变化时,也应重新运行关键评测集。

长期维护可以建立一份“AI 协作资产”:

  • 经过验证的任务模板和提示词;
  • 常见故障及其复现步骤;
  • 领域术语、数据规则和架构决策记录;
  • 真实任务组成的回归评测集;
  • 可重复运行的开发、测试和演示环境;
  • 模型路由、成本上限和降级策略。

不要把关键知识只留在某一次聊天记录里。聊天记录是过程,代码注释、测试、文档和架构决策才是项目的长期记忆。

一个常见的维护闭环是:线上发现“时区转换导致日报少算一天”,先让 AI 根据日志和代码还原复现条件,再修复实现;随后把这个日期边界加入回归测试,并在项目文档中写明统一使用的时区规则。这样下一次更换模型、重构报表或新增类似功能时,系统就能自动提醒团队,而不是再次依赖聊天记录中的上下文。

十、适合团队落地的一套工作流#

一套简单而完整的 AI 编程流程可以是:

明确需求与验收标准
→ 阅读仓库约定和相关代码
→ 让 AI 输出方案与风险
→ 人确认边界和取舍
→ 小步实现
→ 自动检查与真实场景验证
→ 人工审查差异和副作用
→ 合并、观察、沉淀回归案例

团队还可以约定三条底线:没有验收标准不开始大规模修改;没有测试或人工证据不宣布完成;没有明确回滚路径不执行高风险变更。

结语#

用好 AI 写代码,核心能力不是写出更长的提示词,也不是追逐每一次模型更新,而是把软件工程做得更清楚:需求可描述,方案可讨论,代码可审查,结果可验证,错误可恢复,知识可传承。

模型负责扩大个人和团队的执行能力,工程方法负责决定这种能力会带来生产力,还是带来更多难以维护的复杂度。选择合适的模型只是起点,建立完整闭环,才是 AI 编程真正的竞争力。

如何用好 AI 写代码:从模型选择到长期维护
https://www.uuz.io/posts/how-to-use-ai-for-coding/
作者
Yooyi
发布于
2026-09-07
许可协议
CC BY-NC-SA 4.0