尧图精选

AI编程实战:从提示词到代码审查的真实项目工作流

🕒 发布时间:2026/9/26 18:15:45 📁 来源:尧图网络
这一年我把 AI 用到了真实编程里而且不是拿它写玩具 demo。所谓真实编程我的定义是有业务约束、有存量代码、要兼顾性能与可维护性、还要能熬过 code review 的那种编码。说直白点能在一个空目录里让 AI 生成 1000 行漂亮的代码那只是第一步真实场景里这三行代码要接进别人的模块、要处理异常输入、要在高并发下不崩、要在三个月后还有人看得懂。过去大半年我在公司核心项目和自己的开源项目里一直用这套 AI 编程工作流不是头脑风暴式的玩票而是真的让它参与日常交付。这篇文章把我沉淀下来的工具分工、提示词组织方式、调试验证方法以及踩过的各种坑一次性讲清楚。如果你是在职开发、独立开发者或者正在评估团队要不要引入 AI 编程的技术负责人这篇内容应该能给你一个足够真实的地面视角。1. 为什么我用 AI 做真实编程而不是停在玩具 demo1.1 真实编程和 demo 编程的差距很多人刚开始玩 AI 编程的时候感觉特别爽一句话下去一个 Python 爬虫、一个 React 页面、一个排序算法就出来了。跑一下完美。然后信心满满地把同一套方法搬进公司项目结果发现生成的代码要么引入了一堆没用的依赖要么没考虑现有系统的约束要么压根编译不过。问题出在哪出在 demo 编程和真实编程根本是两回事。我习惯用一个类比来解释demo 编程就像拍一道菜的短视频你可以只挑光线最好的一块肉拍特写不在乎冰箱库存、不在乎重复出餐、不在乎高峰期排队。真实编程是开一家餐厅你考虑的是食材能不能稳定供应、出餐时间能不能控住、后厨流程有没有卫生隐患。AI 在短视频拍摄里可以轻松出彩但扔进餐厅后厨它要先理解你的菜单、你的设备、你的食材渠道然后才谈得上炒菜。具体到代码层面demo 编程不需要考虑存量代码风格、公共接口兼容性、运行环境差异、数据边界、错误恢复、测试覆盖更不需要考虑代码评审人的感受。真实编程每一项都是硬约束。AI 如果不了解这些约束生成得越快你返工越多。这也是很多团队尝试 AI 编程之后又退回老路的原因不是 AI 不行是他们把 AI 用在了错误的问题层级。1.2 AI 在真实代码库里的靠谱区间和不靠谱区间我自己的实测结论是AI 在真实编程中的能力边界非常清晰关键看你把它放在哪个环节。靠谱的区间主要集中在结构性、模板性、可验证性很强的任务上。比如把接口定义转换成实现骨架把一段 Python 逻辑翻译成 Rust 或 Go 的等价代码为已有函数补齐单元测试的边界输入把一长串配置信息整理成结构体把重复的 CRUD 代码按既有模式铺出来。这些任务的共同点是规则明确、上下文可以完整描述、结果可以通过编译器和测试用例快速验证。AI 干这些活非常稳能省掉特别多手指上的重复劳动。不靠谱的区间是那些需要领域判断和隐性知识的任务。比如一个交易系统里订单状态机和金额计算逻辑AI 没有你的业务领域模型它只能根据训练语料里“一般电商系统长这样”的想象来补全。一旦你无脑接受轻则埋下逻辑隐患重则上线之后被真实数据教训。我的原则很简单AI 适合加速从规格到代码的转写过程但它不明白规格为什么是这么写的。业务规则背后的取舍、政策限制、历史包袱只有你清楚。所以涉及这种判断的地方我一定会亲手处理或者至少要严格审查 AI 产出的逻辑。1.3 谁适合这套打法谁别急着用先说适合的人。第一类是能清晰拆解需求的开发者你心里清楚一个功能要拆成多少个可验证的小步骤能把这种结构喂给 AI第二类是能读懂 AI 输出并愿意修改的人你把编译器和测试跑通只是起点还得自己确认代码质量和扩展性第三类是团队有 code review 和 CI 机制的人AI 提交的代码会被自动测试和人工评审拦一道安全性高很多。不适合的人我得直说完全零基础的新手。AI 编程生成的代码经常存在“看起来完全正常但实际有微妙错误”的问题一个没有编程经验的人根本没有能力识别这种差异。你让 AI 写一个登录功能它可能写出了能运行的代码但没做参数化查询你完全看不出来上线之后被拖库就晚了。零基础阶段还是应该先把语言基础、数据结构和调试能力打扎实等你具备基本辨别力再让 AI 当加速器而不是把 AI 当成自动驾驶。2. 搭建 AI 编程工作流工具选型和定位2.1 我平时在用的主力工具组合很多人以为 AI 编程工具选得越强越好我一开始也这么干结果三套工具同时开着上下文互相干扰反而让我更混乱。后来我把工具按任务类型做了分工稳定跑了大半年。第一类是编辑器里的代码补全型助手它适合在写代码过程中提供即时建议补全样板代码、提示常见写法、帮忙改局部命名。这种东西我从不让它做全局重构它看到的信息有限做全局判断容易自作聪明但在局部补全上体验很好。第二类是聊天型编程 AI它才是主力。适合用来做跨文件的方案讨论、代码生成、逻辑解释、测试设计。这类工具能承载很长的上下文你可以把模块说明、数据模型、现有代码片段一起贴过去它给出的回答质量会明显更高。我几乎每天都会在里面完成几个真实任务。第三类是本地私有化部署的开源模型主要处理敏感代码和离线环境。公司内部一些核心仓库我肯定不会把代码贴到外部服务上这时候本地模型虽然能力弱一些但胜在数据可控、没有外发风险。我对它的定位不是主力生产工具而是约束环境下的安全垫。第四类是能扫仓库的 CLI 编程代理适合做中型重构。给它一个任务它能自己读代码结构、定位相关文件、多轮修改。这类工具对仓库质量的敏感度极高如果项目本身就一团乱麻它也会跟着乱所以只在结构清晰的仓库里使用。2.2 各工具的分工定位我整理了一张表基本是我现在每天都在执行的分工方案工具类型适合场景不适合场景我的使用习惯编辑器补全写样板代码、局部重构、注释生成跨文件改动、架构调整常驻打开但只看建议不盲从聊天型编程 AI复杂需求生成、逻辑解释、测试设计一次性把所有大需求全部输出主力按任务粒度开新对话本地私有化模型敏感代码处理、离线开发、规范检查高阶抽象推理、复杂代码生成只用于安全边界内的任务CLI 仓库代理中型重构、跨文件一致改动高度依赖领域判断的业务模块先在分支上跑逐文件审 diff这张表背后的核心逻辑是上下文控制。真实项目的代码量远远超过任何模型的上下文窗口你不可能把整个项目喂给它。工具选择的本质不是看谁最聪明而是看谁能用最少的上下文覆盖最合适的任务。编辑器补全适合“局部”聊天型适合“把背景讲清楚”本地模型适合“不能外发的片段”CLI 代理适合“让模型自己按需去读文件”。把任务分配给合适的工具比追求单一工具的极致能力实在得多。2.3 让项目本身更适合 AI 参与这一点我很少在别人的分享里看到但它是整套流程能不能长期运转的关键。你不是把任何代码库扔给 AI 都能得到好结果项目本身也需要做一些“AI 友好化”改造。首先是保持模块职责清晰。AI 在语义识别上是靠名字和注释猜意图的如果你的模块叫utils里面什么都有函数名是do_stuff它生成的配套代码大概率也是乱的。反过来模块命名准确、函数职责单一、目录结构规整AI 能更准确地对齐开发者的意图。其次是重视接口契约文档。项目里的 README、接口定义、数据模型文档不光是给人看的更是给 AI 检索的锚点。AI 在生成代码时会优先参考你贴进去的契约如果契约缺失它只能按自己的臆测来补错误率自然高。第三是写代码注释时多写“为什么”少写“是什么”。AI 和人都一样理解“这段代码是在校验文件后缀”很容易但知道“这里不校验是因为系统里有一类网关还会继续加工 .part 文件”之后它才不会在重构时把这个细节当成垃圾清理掉。这种注释成本很低但对 AI 产出的准确率影响很大。3. 把需求“切开”给 AI 写编程提示词的实操方法3.1 一个能直接抄的提示词模板网上流传的提示词技巧很多什么角色扮演、什么加一段话术我试了一圈发现真实编程里最有效的提示词其实就是一个结构化的小需求文档。我给自己定了一套模板基本每次都用它组织输入。模板结构大概是这样的背景这个模块是干什么的上游谁调用下游依赖谁。 目标给定什么样的输入应该产生什么样的输出。 输入/输出示例一个具体的小例子越具体越好。 边界与失败场景超时怎么办、空数据怎么办、非法参数怎么办。 非目标这次明确不做什么不要顺带加功能。 输出格式要完整代码、代码片段还是只给思路和方案。我拿一个简单的例子说明。如果我想让 AI 写一个请求转发函数我不会说“帮我写个 HTTP 转发”而是按模板写背景我要实现一个内部网关的请求中继函数上游服务通过它转发 POST 请求到下游 API。 目标收到 HTTP 请求后读取完整 body转发到指定目标返回下游的响应状态码和 body。 输入/输出示例上游发送一个 JSON body下游返回 200 和 {ok:true}我们原样返回。 边界与失败场景下游超时按 5 秒报错下游返回非 200 时也要原样返回而不是抛异常body 超过 1MB 直接拒绝。 非目标不要考虑鉴权不要加缓存不要改请求头。 输出格式先给函数签名再给完整实现最后列一下所有错误分支。这样一段话下去AI 给出的代码通常非常规整因为它拿到了足够多的约束。很多人抱怨 AI 生成的代码还得大改八成是提示词里根本没写清楚边界和失败场景AI 只能靠猜出来的东西当然和你想要的不一样。3.2 一次只让它解决一个可验证的问题我踩过最大的坑是让 AI 一口气把一个完整功能全写出来。曾经让它一次性实现一个用户导出功能包括权限校验、数据查询、格式转换、文件生成、异步通知结果生成的代码乍一看很完整实际上五个环节里有三个都有隐蔽问题权限判断没走统一拦截器、大数据量查询跑出了慢 SQL、错误处理直接用print了事。那次返工让我记住了一个原则AI 编程必须按可验证的粒度切分任务。我现在把一个大需求拆成多个 Prompt 的做法是这样的。拿导出功能举例第一轮只让它设计数据结构和接口定义因为接口定错了后面全白干。第二轮让它实现查询逻辑但要求附上 SQL 索引分析和边界条件。第三轮才做格式转换和文件生成。每一轮输出都要求能独立验证要么编译通过要么有单元测试要么能手动跑通一个最小用例。这种节奏看起来慢实际上返工率大幅下降。背后道理也不复杂。大任务拆得越细每一轮交给 AI 的上下文越完整它的正确率就越高同时你验证每一小步的成本远低于验证一个巨型产出。真实编程里最贵的不是让 AI 多跑几次而是你花几个小时 review 一件基于错误前提生成的作品。3.3 三个必须写进提示词的“负面清单”我摸索出一个很有意思的规律对 AI 编程来说告诉它“不要做什么”往往比“要做什么”更能提高准确率。原因也很直白大模型在生成时倾向于把自己见过的常见模式搬过来如果你不拦截它就会自由发挥到你不认识的程度。第一个负面项是依赖约束。我会明确要求“只能使用标准库如果确实需要第三方库先列出来再等确认”。AI 特别容易虚构出一些听起来合理但实际不存在的包名和接口有了这个约束至少它不会悄悄写入一个你没有审查过的依赖。严格管控依赖是给 AI 装上边界不然它会自己往项目里拉一堆东西。第二个负面项是兼容性约束。我会写“不要改动这个模块对外的函数签名和返回结构”因为 AI 生成新代码时经常顺手把旧接口改了它觉得那样更“优雅”但这对你现有的调用方是一场灾难。先把接口冻结让它在给定边界里做文章稳定感会强很多。第三个负面项是过度工程约束。我会写“不要引入缓存、异步化、消息队列除非明确要求”。AI 天然喜欢把系统设计得复杂因为训练数据里的“优秀代码”大多来自大型系统。但一个几百行的小服务根本不需要分布式锁AI 却能给你造出来。用负面清单把复杂度预期钉死能省掉大量不必要的代码。4. 真实案例用 AI 把一个 Python 小服务改写成 Rust4.1 一个真实项目的基本情况说这么多理论不如看一个我真实操作过的案例。这个项目原身是一个跑在单机上的 Python HTTP 小服务主要职责是接收内部脚本上传的文件把它暂存后转发到后端对象存储并把处理结果返回给调用方。代码量不大但暴露了一个典型问题内存占用高、每次请求要起线程、在高并发下经常触顶。这个服务换成 Rust 重写是当时团队确认过的方向因为它的逻辑够简单、边界够清晰、重写风险可控非常适合用来验证 AI 真实编程的能力。我选择用 AI 辅助迁写而不是手写正统流程。技术栈定的是 tokio 异步运行时加 hyper 处理 HTTP这两个是 Rust 生态里最常用的组合。整体思路是保持接口完全不变内部实现全部替换。因为上游调用方很多不能因为重写让它们跟着改代码这是一条硬约束。4.2 分四步走完的改造过程第一步是设计和建模。我没有让 AI 直接写代码而是让它先输出一个 handler 的接口和数据模型。当时给它贴上了现有 Python 服务的请求样例、响应样例、超时要求、失败码定义然后问它如果用 Rust 表达这套交互结构体和错误类型应该怎么设计。它给出了一套初步方案我改掉了其中几个字段命名之后就定稿了。第二步是做核心链路。我拿着设计好的数据模型让 AI 实现请求接收、文件流读取、转发到对象存储、返回结果这一段主流程。生成出来的代码骨架大致是下面这种感觉use tokio::time::timeout; use tokio::net::TcpStream; #[derive(Debug)] enum RelayError { Io(std::io::Error), Timeout, InvalidUpstream, } async fn relay_once(target: String, body: Vecu8) - ResultVecu8, RelayError { // 这段原本由 AI 补齐我只保留核心链路没有直接应用到生产。 Ok(upstream_body) }这层骨架很快成型但我也注意到它生成的错误处理比较粗糙部分分支直接返回了通用的InvalidUpstream根本没有细分原因。我把它拉出来重新设计成Timeout、UpstreamRejected、BodyTooLarge三个具体错误让调用方可以根据错误类型做不同处理。这一步人工修正非常关键AI 擅长搭骨架但错误语义这种决定系统可观测性的东西还是得由人把关。第三步是补测试。我让 AI 针对转发逻辑生成一组模拟上游的测试用例故意让它覆盖几种边界情况上游超时、上游返回 500、body 为空、body 超过上限、并发请求同时进来。AI 生成的测试很多但肯定不能直接用我会逐个检查断言是不是真的反映了业务预期。测试的作用不是为了让 AI 开心而是给重写加一道安全网。第四步是对照和压测。我在分支上保留旧 Python 服务把新 Rust 服务挂到测试环境同一批请求分别打到两个服务上逐条对比响应结果。这种新旧对照是重写类项目不可跳过的一步AI 生成的代码常有一些微妙的语义差异只有真实数据才能暴露出来。实测下来内存占用从旧版的 300MB 量级降到了 30MB 不到请求响应时间也稳定了不少。整体效果在预期内但真正让我放心的还是那套对照测试。4.3 对 AI 生成代码的核查清单重写完成后我把整个过程中反复使用的检查项整理成了一份清单现在每次让 AI 生成较大产出时都会照着过一遍错误分支是不是真的实现而不是打一行日志就结束有没有虚构不存在的第三方库或者内部方法对外接口是否保持兼容函数签名有没有被悄悄改动资源有没有正确释放连接、文件句柄、临时目录是不是管理干净并发访问下有没有共享状态被多个线程同时修改生成的代码里有没有大段死代码或者用不上的结构体。这份清单不需要每次全量执行但对代码质量要求较高的模块我会一条条过。真实编程里AI 生成代码之后最重要的事情不是惊叹它多快而是用怀疑的态度检查它就像你在 review 一个新同事的代码一样。5. 用 AI 做调试、测试和代码审查的实操5.1 把报错丢回去让它缩小排查范围调试是编程里最费脑子的环节AI 在这上面也能帮上大忙但前提是你得学会怎么描述问题。很多人直接把一堆报错日志复制过去丢一句“帮我看看”得到的结果往往是泛泛而谈。我的做法是给 AI 一个足够小的定位范围。举个例子如果我在 Rust 项目里遇到一个文件解析的段错误我不会贴整个项目代码。我会这样说“这里有一个约 500 行的二进制解析模块崩溃点在第 41 行这行是通过一个 map 结构取字段。崩溃发生在数据里出现长度为零的片段时。请给我三个可能的原因每个原因附带一个排查步骤不要直接给修改代码。”这样做的好处很明显三段候选原因正好给了你排查的方向比盲翻代码高效得多而且让它先别改代码避免了 AI 自作主张重构掉你本来没出问题的部分。这个原则我一直在用让 AI 先做定位再做修复。5.2 让 AI 生成边界测试用例的套路写测试是 AI 编程里回报率最高的环节之一。我自己写测试的时候容易陷入“沿正常路径写几个用例就过关”的思维惯性AI 反而能带来一些撞边界的思路。但它生成的测试也容易出问题最常见的毛病是断言写得特别宽松看起来测了实际上啥也没验证。我让 AI 生成测试用例时的提示词一般是这样的“请为这个函数生成一组边界用例覆盖空输入、最大长度、非法编码、重复调用、并发调用这五类场景每个用例必须给出具体输入和预期输出断言要写明确不能让模棱两可的通过。”然后我拿到测试之后会重点关注断言强度一个测试如果不是“输入 X 一定得到输出 Y”那它就没有测试价值。还有一点AI 生成的测试只是参考不能直接当成验收标准。测试用例背后的预期值往往来自业务逻辑而这个逻辑是你要把关的。如果 AI 生成的测试断言和产品需求不一致那这个测试是维护了一套错误行为反而有害。我通常会把 AI 生成的测试和需求文档逐条核对一遍确认它的“预期”是不是真实的“预期”。5.3 用 AI 做初步 code review 的三个检查点AI 做代码审查比 AI 写代码更稳因为它不需要从头生成整个逻辑只需要在给定范围内寻找问题。我在日常流程里会把 AI 当一道预审关卡写完代码先让它审一轮改完再提交给人审。这里有三个固定的检查点。第一个是错误处理完备性。我会明确要求它检查所有分支的异常处理。AI 很擅长发现某个调用之后缺少错误传播或者某个错误被吞掉之后可能留下隐患。第二个是资源生命周期。文件有没有关闭、连接有没有释放、临时对象有没有及时 drop这类问题在 AI 输出里尤其常见因为它生成代码时容易漏掉收尾操作。第三个是并发一致性问题。共享状态有没有加锁、锁的范围是否过大、会不会死锁这些是审查里很值钱的议题。但我这里要强调一个边界AI 的 review 结果本质上是基于统计模式的意见它看不透你团队的业务意图。它可以说“这里可能有并发风险”但它不知道你其实用了一个外部的串行队列来规避这个风险。所以 AI 的 review 意见只能作为第一层防护最终决定权永远在参与业务上下文的人手中。6. 踩坑与排查技巧实录6.1 常见的翻车现场我把这大半年里最典型的翻车现场整理成一张表基本涵盖了 AI 编程最容易踩的雷问题现象发生原因解决方式引用了不存在的包或过时接口模型训练的语料中包含了一些旧版本或虚构的 API要求 AI 先列依赖清单所有第三方库必须在官方文档或仓库里确认存在对外接口被悄悄改了AI 觉得新代码比旧接口更优雅提示词冻结公共 API代码 review 时对比接口 diff错误分支只打日志没处理缺失对失败场景的定义用负面清单和错误类型强制要求每一个失败分支返回明确错误生成了一堆没用的代码模型追求完备输出导致工具函数冗余要求只输出指定结构其他多余的一律不要并发场景下共享数据错乱AI 没意识到这个函数会被多个线程同时调用把并发约束写进提示词审查时检查共享状态访问在新项目上跑得飞起接进老项目就崩存量代码有大量隐性约定把关键存量代码、接口文档一并贴给 AI不要让它只依赖自己的泛化感受这些坑每一个我都实打实遇到过。印象最深的是有一次 AI 生成了一个处理文件上传的模块本地测试通过放上测试环境之后稳定运行结果过了一周收到一个奇奇怪怪的内存上涨告警。查到最后发现是它生成的一个Vecu8缓冲没有及时释放在循环处理大文件时不断累积。这种问题如果没有洞察会浪费你非常多的排查时间。6.2 怎么避免被 AI 带偏AI 编程最让人头疼的不是它说“不知道”而是它非常自信地输出一个看似合理的错误结果。我吃过几次亏之后形成了一套防止被带偏的实操习惯。第一凡是关键决策我会强制它给我多个方案而不是一个答案。比如我在让它设计一个异步任务队列时我会说“请给我三种消息传递方案列出每种方案的适用场景和代价”。这样我能在备选方案中做选择而不是被动接受一个可能有隐藏偏好的方案。第二凡是它输出的数值型结论我都会反过来追问一句“这个结论的依据是什么”。如果它给不出清晰的推导路径那这个结论大概率是编的直接丢掉。第三我会特意在提示词里要求它标出自己不确定的地方让它明说“这部分需要人工确认”。这样能逼出它那层模糊的自我怀疑而不是把不确定当作理所当然。还有一个很实用的小技巧每次拿到 AI 生成的代码我都会要求它同时给出一个你自己写的简短测试用例。如果它连一个测试都写不清楚那这段代码的正确性就打问号。测试在这里不仅是验证手段更是给 AI 自己设的一道自检关卡严格约束它的证明义务。6.3 团队代码和公司代码的安全边界真实编程绕不开数据安全问题。公司核心代码、业务数据、密钥配置这些信息一旦被扔进外部 AI 服务就是不可控的。我的原则是凡是代码里包含内部系统名、客户数据样例、密钥或凭证一律不直接贴给外部工具。可以先做脱敏处理把变量名、表名、路径替换成抽象的xxx再用外部工具讨论逻辑结构。团队内部如果确实需要让 AI 大量接触代码我会建议优先考虑私有化部署的模型或者严格的代码审查流程。不要让 AI 直接拥有推送主分支的权限不管它生成的 diff 看起来多漂亮都应当先在分支上跑完测试、人工看过之后再合入。这条规则听起来很基础但很多团队在追求效率的过程中会忍不住跳过真出了问题代价极大。7. 一点个人体会有一阵子我试过把更大的决策也交给 AI给它一个完整需求让它自己拆任务、自己写代码、自己提交。结果并不理想它在给自己拆任务的时候容易东拉西扯产出的复杂度远远超出实际需要。后来我还是退回了自己控制需求、AI 负责执行的模式稳定性和交付质量反而高了一截。这件事给我的体会是AI 编程真正的价值不是替代我们的判断而是把我们在“写完代码”到“验证代码”这段过程中的体力劳动压缩掉。过去写测试、搭骨架、翻文档、处理机械性重构动不动就要半天的时间现在大大缩短。我们真正应该珍惜的是脑子里对方案的理解、对业务的理解、对系统整体的判断。把这些判断守住让 AI 去做它擅长的高速转录这是我认为目前最合理的 AI 真实编程姿势。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →