☰
AI写代码工作流:从需求到可运行代码的三段式生成法
2026/9/29 17:57:34 网站建设 项目流程

1. 先搞清楚“AI写代码”到底在写什么

很多人对“AI写代码”这件事的理解还停留在“让AI帮我补全一个函数”的阶段,觉得它就是个高级一点的自动补全工具。但如果你真的把AI当成主力开发手段,就会发现它的能力边界远不止于此——它能写业务逻辑、能重构模块、能生成测试用例、能读懂遗留代码并给出修改建议。问题在于,大多数人用AI写代码的方式太随意了:打开对话框,敲一句“帮我写个XXX功能”,然后复制粘贴,跑不通再回来问。这种方式偶尔能碰对,但根本谈不上“工作流”。

我说的“工作流”,是指一套可重复、可验证、可迭代的协作流程。它不是某个具体工具的使用技巧,而是你与AI之间形成的一种稳定的分工模式。就像一条流水线,每个环节有明确的输入和输出,有质量检查点,有回退机制。我目前手头项目的代码,大概有七成以上是AI参与完成的,靠的就是三个核心工作流。这三个工作流分别解决不同粒度的问题:一个管“从零到一”的功能开发,一个管“从一到N”的批量修改和重构,还有一个管“从N到稳定”的质量保障。

先说说为什么需要工作流。你直接让AI写代码,最大的问题不是它写得不好,而是你无法稳定地复现“它写得好”的那个状态。同样的提示词,今天写出来的代码能跑,明天可能就少了一个边界条件。这不是AI的问题,是你没有给它足够的上下文和约束。工作流的核心价值就在于:把“碰运气”变成“可预期”。你按照固定的流程走,每一步都有明确的检查标准,AI的输出质量就会稳定在一个可接受的水平线上。

还有一个常见的误区:很多人觉得AI写代码就是“我说需求,它出代码”。实际上,真正高效的协作模式是你负责定义问题和验收标准,AI负责探索实现路径。你得先把问题拆解到AI能理解的粒度,然后让它在一个受控的环境里试错。这就像带一个很聪明但完全没有项目背景的新人——你得告诉它代码规范、目录结构、依赖关系、异常处理习惯,它才能写出你能直接用的东西。

下面我会把这三个工作流拆开讲,每个工作流都会说清楚:它解决什么问题、具体怎么操作、我踩过哪些坑、以及怎么判断它适不适合你当前的场景。

2. 工作流一:从需求到可运行代码的“三段式生成法”

2.1 为什么不能一步到位让AI写完整功能

我见过太多人这样用AI:打开对话框,输入“帮我写一个用户登录功能,用Python”,然后期待AI直接吐出一个能跑的系统。结果AI给了一个Flask的示例,但你的项目用的是FastAPI,数据库是PostgreSQL而不是SQLite,认证方式是JWT而不是Session。你拿着这段代码,改了半天,最后发现还不如自己从头写。

这个问题的本质是:AI没有你的项目上下文。它不知道你的技术栈、代码规范、目录结构、已有的工具函数。你给的信息越少,它就越倾向于生成“教科书式”的通用代码,而通用代码在你的项目里往往需要大量改造才能用。

所以我的做法是:把一个功能拆成三段来生成。第一段是接口定义,第二段是核心逻辑,第三段是集成适配。每一段都有明确的输入和输出,AI只需要关注当前这一段的任务,不需要一次性考虑所有细节。

2.2 第一段:让AI先写接口和类型定义

不管用什么语言,我都会先让AI生成接口定义。以Python为例,我会给它这样的提示:

# 项目背景 # 这是一个FastAPI项目,使用SQLAlchemy ORM,PostgreSQL数据库 # 现有目录结构: # app/ # models/ # 数据库模型 # schemas/ # Pydantic模型 # services/ # 业务逻辑 # routers/ # 路由 # utils/ # 工具函数 # 任务:定义一个用户注册功能的接口 # 要求: # 1. 在schemas/下创建user.py,定义UserCreate、UserResponse # 2. 在services/下创建user_service.py,定义register_user函数签名 # 3. 在routers/下创建user.py,定义POST /register路由 # 只写接口和类型定义,不要写具体实现

这一步的关键是只让AI写“壳”。接口定义、类型注解、函数签名、路由声明——这些是AI最擅长且最不容易出错的部分。你拿到这些定义之后,可以快速检查:参数对不对、返回类型合不合理、路由路径是否符合项目规范。如果这里有问题,改起来成本极低。

我实测下来,这一步能让后续的代码生成准确率提升至少一倍。因为AI在写具体逻辑时,有了明确的类型约束和函数签名,它就不会跑偏。就像盖房子先搭钢筋骨架,骨架正了,后面填砖就不会歪。

2.3 第二段:分函数生成核心逻辑,每次只给一个函数

接口定义确认之后,我会逐个函数让AI实现。注意,是逐个,不是一次性把所有函数都写完。比如register_user这个函数,我会单独给它一个提示:

# 实现以下函数 # 文件:app/services/user_service.py # 依赖: # - from app.models.user import User # - from app.schemas.user import UserCreate # - from app.utils.security import hash_password # - from sqlalchemy.orm import Session async def register_user(db: Session, user_data: UserCreate) -> User: """ 注册新用户 - 检查邮箱是否已存在 - 密码加密后存储 - 返回创建的用户对象 - 如果邮箱已存在,抛出ValueError """ # 请实现这个函数

为什么一次只给一个函数?因为AI的注意力是有限的。你给它一个函数,它会认真处理边界条件、异常分支、类型转换。你给它十个函数,它就会开始“偷懒”,很多地方用pass或者TODO糊弄过去。而且单个函数生成之后,你可以立刻跑单元测试验证,有问题马上改,不会积累到最后一起爆发。

这里有个小技巧:在提示里把依赖的导入语句写清楚。AI有时候会猜错模块路径,你直接告诉它从哪导入,它就省去了猜测的过程。另外,函数的docstring要写清楚业务规则,比如“邮箱已存在时抛出ValueError”,这样AI就知道要加这个判断。

2.4 第三段:集成适配与手动缝合

所有函数生成完之后,最后一步是集成。这一步AI能帮的忙有限,主要靠你自己。你需要把生成的代码放到正确的文件里,检查导入关系,处理循环依赖,调整异常处理策略,确保和现有代码风格一致。

我一般会做这几件事:

  • 跑一遍静态检查:用mypy或者pyright检查类型,用ruff或者flake8检查风格。AI生成的代码经常会有未使用的导入、行长度超限、类型不匹配的问题,这些工具能帮你快速定位。
  • 补全缺失的异常处理:AI倾向于只处理“正常路径”,异常分支经常写得比较粗糙。你需要根据项目规范,补充日志记录、错误码返回、事务回滚等逻辑。
  • 写一个最小的集成测试:不需要覆盖所有边界,但至少要跑通主流程。比如注册功能,就测“正常注册成功”和“重复邮箱注册失败”两个用例。

这个三段式生成法听起来有点繁琐,但实际用起来很快。因为每一步AI的响应时间都很短,你检查的成本也很低。比起让AI一次性生成一大堆代码然后花几个小时调试,这种“小步快跑”的方式整体效率反而更高。

3. 工作流二:批量修改与重构的“模式提取+批量应用”

3.1 什么时候需要批量修改

项目开发到一定阶段,总会遇到这种情况:你需要把某个函数的所有调用方式改掉,或者给一批接口统一加上某个参数,或者把某个模块的错误处理从返回None改成抛异常。这种修改单个不复杂,但数量多了就非常烦人。手动改容易漏,而且改到后面会麻木,质量下降。

我以前的做法是写脚本用正则替换,但正则的局限性很大——它不理解代码结构,遇到嵌套调用、多行参数、变量名相似的情况就容易误伤。后来我发现,这种场景其实非常适合让AI来做,但前提是你要用对方法。

3.2 先让AI提取“修改模式”

直接让AI“把项目里所有调用old_function的地方改成new_function”效果很差,因为它不知道old_function在哪些文件里、调用方式有哪些变体。正确的做法是:先让AI帮你归纳出所有需要修改的模式。

我会先给AI几个典型的修改示例:

# 修改前 result = old_function(param1, param2) # 修改后 result = new_function(param1, param2, timeout=30)

然后让AI分析:“请找出项目中所有类似old_function的调用,列出它们的文件路径、行号、以及当前的调用形式。”AI会扫描你提供的代码片段或文件列表,给出一个模式清单。这个清单可能包括:

  • 直接调用:old_function(a, b)
  • 带关键字参数:old_function(a, b, verbose=True)
  • 嵌套调用:process(old_function(a, b))
  • 赋值后调用:func = old_function; func(a, b)

拿到这个清单之后,你可以确认哪些模式需要处理,哪些可以忽略。这一步的价值在于:你把“找”和“改”分开了。找的时候专注找全,改的时候专注改对,不会混在一起导致遗漏。

3.3 用“批量提示”让AI逐文件处理

模式确认之后,我会把文件列表分批给AI,每批5到10个文件,让它逐个文件输出修改后的代码。提示大概长这样:

# 任务:批量修改函数调用 # 修改规则: # - old_function(...) -> new_function(..., timeout=30) # - 如果原调用已经有timeout参数,则保持不变 # - 保持原有缩进和换行风格 # 文件1:app/services/order_service.py # [粘贴文件内容] # 请输出修改后的完整文件内容

这里有几个关键点:

  • 每批文件不要太多:5到10个比较合适。太多了AI会开始“偷懒”,后面的文件可能只改一部分就草草结束。
  • 要求输出完整文件:不要让它只输出diff,因为diff的格式AI经常写错,而且你还要手动合并。直接输出完整文件,你复制粘贴覆盖就行。
  • 明确规则边界:比如“如果已经有timeout参数则保持不变”,这种边界条件一定要写清楚,否则AI可能会重复添加参数。

3.4 修改后的验证策略

批量修改最怕的是“改错了但没发现”。我的验证策略分三层:

第一层是语法检查。修改后的文件先跑一遍语法解析,确保没有括号不匹配、缩进错误这种低级问题。Python可以用python -m py_compile,JavaScript可以用node --check。

第二层是差异审查。我会用git diff查看每个文件的修改,重点看:有没有误改的地方、有没有漏改的地方、修改后的代码风格是否一致。这一步不能省,AI偶尔会在无关的地方“顺手”改点东西,你需要及时发现。

第三层是测试验证。如果项目有单元测试,跑一遍;如果没有,至少手动触发几个关键路径。批量修改最容易出问题的地方是边界条件,比如某个调用原本传了None,修改后变成了默认值,行为就变了。

我踩过的一个坑:有一次让AI批量给所有数据库查询加上分页参数,结果它把一个内部调用的查询也加上了分页,导致那个内部逻辑每次只返回第一页数据,引发了很隐蔽的bug。后来我在提示里明确写了“只修改routers/目录下的调用,services/目录下的内部调用不要动”,才避免了这个问题。所以批量修改的规则一定要写到最细,不要给AI留猜测的空间。

4. 工作流三:AI代码的质量兜底与回归防护

4.1 AI写的代码为什么容易“看起来对但实际错”

AI生成的代码有一个很迷惑人的特点:它读起来非常通顺,逻辑看起来也很合理,但跑起来就是不对。这是因为AI是在“预测下一个token”,它生成的是“最像正确代码的代码”,而不是“经过验证的正确代码”。常见的隐蔽问题包括:

  • 边界条件处理反了:比如应该是if len > 0写成了if len >= 0
  • 异常类型不对:抛了ValueError但调用方期望的是CustomError
  • 异步/同步混用:在async函数里调用了同步的阻塞操作
  • 资源泄漏:打开了文件或连接但没有在异常路径关闭
  • 并发问题:多个请求同时修改共享状态但没有加锁

这些问题静态检查工具往往查不出来,单元测试如果覆盖不够也测不出来。所以你需要一套专门的兜底机制。

4.2 让AI自己写“对抗性测试”

我的做法是:代码生成之后,让AI扮演“挑刺的人”,专门针对这段代码写测试用例。提示大概是这样的:

# 以下是一段AI生成的代码,请为它编写单元测试 # 要求: # 1. 覆盖正常路径 # 2. 覆盖边界条件:空输入、None、极大值、极小值 # 3. 覆盖异常路径:依赖服务失败、数据库超时、权限不足 # 4. 尝试找出代码中可能存在的bug,并写出能触发bug的测试 # [粘贴代码]

这个方法的妙处在于:AI在“找bug模式”下,会变得非常挑剔。它平时写代码时忽略的边界条件,在写测试时反而会主动考虑。我经常通过这种方式发现一些自己都没注意到的问题,比如某个函数在输入为空列表时会返回None而不是空列表,调用方如果直接遍历就会报错。

4.3 建立“回归测试集”防止AI改坏旧功能

当你用AI频繁修改代码时,最大的风险是“改好了新功能,改坏了旧功能”。AI在修改时只关注你给它的任务,它不知道这个函数还被其他地方调用,也不知道某个看似无关的改动会影响下游逻辑。

我的解决方案是维护一个回归测试集。这个测试集不需要覆盖所有代码,但必须覆盖所有核心路径和曾经出过bug的地方。每次AI修改代码之后,先跑这个测试集,通过了再合并。

回归测试集的维护也有技巧:

  • 每个bug修复后,把触发bug的用例加进去。这样同样的bug不会出现第二次。
  • 核心业务逻辑的测试要写得“笨”一点。不要用mock,不要用复杂的fixture,就老老实实准备数据、调用函数、断言结果。这种“笨”测试最稳定,AI改代码时最不容易绕过。
  • 定期清理过时的测试。如果某个功能已经废弃了,对应的测试也要删掉,否则会干扰判断。

4.4 人工审查的“三看”原则

不管AI生成的代码通过了多少自动化检查,最终合并前我一定会人工看一遍。看的时候遵循“三看”原则:

一看数据流:数据从入口到出口经过了哪些转换?每一步的类型对不对?有没有可能为None?有没有可能越界?AI经常在数据流的中转环节出错,比如把字符串当数字用,或者把可选值当必选值处理。

二看异常路径:每个可能失败的操作,失败之后会发生什么?异常有没有被吞掉?资源有没有释放?状态有没有回滚?AI倾向于只写“成功路径”,异常处理经常是敷衍了事。

三看并发安全:如果这段代码会在多线程或异步环境下运行,有没有共享状态?有没有竞态条件?AI对并发问题的理解很浅,它生成的代码在单线程下没问题,一上并发就出各种奇怪的现象。

这三看不需要花太多时间,但能拦住大部分严重问题。我一般看一个函数不超过两分钟,重点看那些“感觉不太对”的地方。直觉往往是对的,你觉得这里可能有问题,大概率真的有问题。

5. 三个工作流怎么串起来用

5.1 一个完整功能的开发流程

假设我要开发一个“订单导出”功能,支持按时间范围筛选、导出CSV格式。我会这样走流程:

第一步:用工作流一生成接口和骨架。让AI定义导出请求的schema、导出服务的函数签名、路由的声明。确认接口没问题。

第二步:用工作流一逐个实现函数。先实现查询订单的逻辑,再实现CSV生成的逻辑,最后实现文件下载的响应。每个函数生成后立刻跑一下,确保基本逻辑通。

第三步:用工作流三写对抗性测试。让AI针对导出功能写测试,重点覆盖:空结果集、超大结果集、时间范围颠倒、特殊字符转义、并发导出。跑测试,修问题。

第四步:用工作流二做集成适配。把新功能接入现有的权限系统、日志系统、监控系统。这一步可能需要批量修改一些现有的中间件配置,用工作流二的方式处理。

第五步:回归测试+人工审查。跑回归测试集,确认没有影响旧功能。人工看一遍关键代码,重点看数据流和异常路径。

这套流程走下来,一个中等复杂度的功能大概半天到一天能完成,而且质量比较稳定。比起“让AI一次性生成然后花两天调试”,效率高很多。

5.2 什么情况下不要用AI写代码

虽然我是AI写代码的重度用户,但有些场景我绝对不会让AI碰:

  • 涉及资金安全的核心逻辑:比如支付扣款、退款计算、对账逻辑。这些代码一旦出错就是真金白银的损失,必须人工写、人工审、多重验证。
  • 涉及用户隐私的数据处理:比如数据脱敏、权限校验、加密解密。AI可能会生成“看起来安全但实际有漏洞”的代码,这种风险承担不起。
  • 性能极度敏感的代码:比如高频交易、实时渲染、大规模数据处理。AI生成的代码通常“能跑但不够快”,优化性能需要对人家的硬件和业务有深入理解。
  • 没有明确验收标准的探索性代码:如果你自己都不知道要写成什么样,AI更不知道。这种情况下先自己写个原型,理清思路,再让AI帮忙完善。

5.3 工具选型的一些实际体会

我用过的AI编程工具不少,从最早的代码补全插件到现在的对话式编程助手。说几个实际体会:

对话式工具适合“从零到一”和“批量修改”。你可以把上下文、约束、示例都贴给它,它能在一个较长的对话里保持一致性。缺点是响应慢,不适合高频的补全场景。

IDE内置的补全工具适合“从一到N”的细节填充。你写个函数名,它帮你补全参数和简单逻辑。优点是快,不打断思路。缺点是它不理解全局,生成的代码经常需要手动调整。

本地模型和云端模型各有取舍。本地模型响应快、数据不出本地,但能力上限低,复杂逻辑容易出错。云端模型能力强,但需要考虑数据安全和网络延迟。我的做法是:敏感项目用本地模型做补全,非敏感项目用云端模型做生成。

不要迷信“最强模型”。模型的能力差异主要体现在复杂推理和长上下文理解上。对于日常的CRUD代码、简单的重构、格式转换,中等模型完全够用,而且响应更快、成本更低。把最强模型留给真正需要它的场景,比如架构设计、复杂算法、疑难bug排查。

6. 踩过的坑和总结出来的经验

6.1 提示词里必须写清楚的几件事

踩了无数次坑之后,我总结出一个“最小提示模板”,不管让AI做什么,这几项必须写清楚:

  • 技术栈和版本:Python 3.11 + FastAPI 0.100 + SQLAlchemy 2.0,不要只说“Python”。
  • 代码规范:行长度限制、命名风格、导入顺序、注释语言。AI默认的风格和你的项目风格往往不一致。
  • 错误处理策略:是抛异常还是返回错误码?异常类型是什么?要不要记日志?
  • 依赖关系:这个模块可以导入哪些模块?不可以导入哪些模块?避免循环依赖。
  • 验收标准:什么情况下算“写对了”?给一两个具体的输入输出示例。

这几项写清楚,AI的输出质量会有一个质的提升。我试过同样的任务,写清楚约束和没写约束,生成代码的可用率差了三倍以上。

6.2 AI特别容易犯的几个错误

  • 过度设计:你让它写个简单的配置读取,它给你搞出一个支持多环境、多格式、热加载的配置系统。解决办法是在提示里明确写“保持简单,不要引入额外的抽象层”。
  • 忽略已有工具函数:项目里已经有utils/date.py里的format_date函数,AI还是会自己写一个datetime.strftime。解决办法是在提示里列出可用的工具函数。
  • 异常处理过于宽泛:动不动就except Exception,把真正的bug也吞掉了。解决办法是明确要求“只捕获特定的异常类型”。
  • 测试用例只覆盖正常路径:AI写的测试往往只测“输入正确返回正确”,不测边界和异常。解决办法是明确要求“必须包含至少三个异常路径的测试”。

6.3 怎么判断AI生成的代码能不能用

我的判断标准很简单:如果这段代码出了问题,我能不能在五分钟内定位到原因?如果能,就可以用;如果不能,就重写或者让AI重写。

这个标准背后的逻辑是:AI生成的代码往往“可读性不错但可调试性差”。它可能把逻辑拆得很碎,调用链很长,出了问题你要跳好几个文件才能找到根源。这种代码维护成本很高,不如自己重写一个更直接的版本。

另外,如果一段AI生成的代码我看了三遍还没完全理解它的逻辑,我也会选择重写。因为不理解就意味着无法维护,无法修改,无法保证正确性。AI可以帮你写代码,但不能帮你理解代码——理解永远是你自己的事。

6.4 关于“AI写代码”这件事的长期看法

我用AI写代码两年多,最大的感受是:AI改变的不是“写代码”这件事本身,而是“写代码”之前的思考方式。以前我拿到需求就直接开始敲键盘,现在我会先想:这个问题能不能拆成AI能理解的粒度?验收标准是什么?哪些部分必须自己写?哪些部分可以交给AI?

这种思考方式的转变,反而让我对代码质量有了更强的掌控感。因为AI负责的是“实现”,我负责的是“定义”和“验收”。定义得越清楚,验收得越严格,最终代码的质量就越高。

所以如果你问我“AI写代码靠不靠谱”,我的回答是:靠谱的不是AI,是你的工作流。工作流对了,AI就是放大器;工作流不对,AI就是制造bug的机器。这三个工作流是我目前找到的平衡点,不一定适合所有人,但至少提供了一个可参考的框架。你可以根据自己的项目特点调整细节,但核心思路——拆解、约束、验证——应该是通用的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询