公司动态

构建工程师级 AI 编程工作流:让生成代码全链路可控

📅 2026/9/2 6:55:08
构建工程师级 AI 编程工作流:让生成代码全链路可控
如果你最近也在用 AI 写代码大概率已经体会到一种“薛定谔的代码”状态粘贴需求时信心满满运行起来一脸茫然。AI 能生成看起来非常专业的函数、组件和脚本但一旦放进真实项目就会出现类型不匹配、依赖版本冲突、业务逻辑漏判、甚至把不存在的 API 当成理所当然。很多人把这些问题归结为“提示词写得不够好”于是去找各种“魔法咒语”但真正的解法并不是让 AI 更听话而是把 AI 放进一套工程师级的工作流里让生成、审查、测试、集成全链路可控。这篇文章不是一份“AI 提示词大全”也不是某个工具的性能测评。我要讲的是 Matt Pocock 在 AI 编程实践中反复强调的一条主线别把 AI 当成代码生成器而是把它当成一个能力极强但需要工程约束的协作对象。如果你正在用 ChatGPT、Claude、Cursor 或 Copilot 写业务代码并且遇到“能用但不敢改”的困境这篇文章就是为你准备的。读完你会得到一套可落地的 AI 开发工作流包括需求拆解、上下文构建、代码审查、测试验证和回滚策略并附上完整的代码示例和排查清单。1. 为什么“让 AI 写代码”会翻车先看一个常见场景。开发者小张接到一个功能把订单列表按照状态分组并统计每组金额。他打开 ChatGPT输入“写一个按状态分组的函数”AI 马上给出一段 Promise.all 加 reduce 的代码。小张复制到项目里TypeScript 报错他不知道是类型问题还是逻辑问题又复制报错信息给 AI。来回三轮代码终于能跑了但他完全不敢改因为不理解这段代码的边界条件。问题出在哪里不是 AI 太笨而是工作流有问题。小张把 AI 当成“一次性生成器”既没有告诉它项目现有的类型定义、模块路径、代码风格也没有让它先解释设计思路更没有在他接管代码之后做严格审查。这就好比你把一个没看过图纸的施工队扔进工地却要求他们直接盖出一栋符合消防标准的楼。翻车原因可以归结为三类。第一类是上下文缺失。AI 并不知道你的项目里有没有框架、用什么状态管理库、错误处理约定是什么。它生成的是“通用代码”不是“适合你项目的代码”。通用代码本身没错但放进具体项目就像 M 码的衣服穿在 L 码的人身上。第二类是验证闭环缺失。很多开发者把“AI 生成的代码能编译通过”当成“功能正确”。可编译通过只说明类型层面没大问题不代表业务分支都覆盖了。没有测试用例、没有代码审查、没有边界条件讨论AI 的幻觉就会悄悄混进生产环境。第三类是代码所有权意识缺失。一段代码进入仓库之后维护责任在团队不在 AI。如果开发者自己不理解代码未来出了 bugAI 不会替你值班。Matt 的观点很直接AI 编程的核心不是让 AI 写更多代码而是让你在单位时间内写出更可控的代码。你要对代码的每一行负责。这就引出一个关键判断AI 编程的门槛不是“会不会写提示词”而是“有没有一套工程纪律”。2. AI 编程工作流的核心把生成变成协作传统的 AI 写代码流程是单向的需求输入 - 代码输出 - 复制粘贴。工程师级流程是环形的需求拆解 - 上下文构建 - 方案讨论 - 代码生成 - 代码审查 - 测试验证 - 集成部署 - 复盘反馈。AI 在每个环节都参与但每个环节的最终判断权都在人。这听起来像是流程多了好几步好像会降低效率。但实际体验是反过来的。如果 AI 生成了 100 行代码其中 30 行有问题你在集成测试阶段发现和在一周后的生产事故中发现成本完全不同。前置的审查和测试投入本质上是给后面的开发环节买保险。这里有一个容易混淆的概念需要先澄清AI 编程里的“上下文”不是指你给 AI 贴一大段文档而是指“让 AI 理解当前任务的约束条件”。约束条件包括项目结构、类型定义、已有的工具函数、编码规范、依赖版本、甚至团队习惯。AI 知道的约束条件越多生成的代码越贴近项目实际。换句话说AI 写代码的水平约等于你给它提供的上下文质量。这不是玄学而是大模型的工作机制决定的生成概率取决于输入序列输入里的有效信息越多输出落在正确区间的概率就越大。所以工程师级 AI 工作流的第一步不是“让 AI 写代码”而是“让 AI 理解任务”。这就是为什么很多资深开发者会花一半时间写规则文件、整理资料、设计提示结构。3. 完整开发工作流全景下面这张流程图描述了本文推荐的工程师级 AI 开发工作流。它适用于大多数中大型功能开发也可以裁剪成轻量版本用于日常小任务。3.1 需求拆解先不要把完整需求一次性丢给 AI。正确做法是先把需求拆成若干小任务。例如“实现订单分组统计”可以拆成定义订单数据结构和状态枚举实现按状态分组的纯函数实现金额统计编写单元测试处理空数组和未知状态。每个小任务都是 AI 可以独立完成的单元也是你可以单独审查和验证的单元。这个阶段人的主要工作是写清楚“验收标准”。3.2 上下文构建为每个任务准备相关上下文项目根目录结构相关类型定义文件路径你期望的代码风格需要遵守的约束例如不要修改已有函数签名依赖版本信息。在现代 AI 编程工具中上下文构建通常有两种方式一种是通过规则文件如.cursorrules或CLAUDE.md让模型自动读取项目规范另一种是在对话中明确粘贴目标文件内容。两条路可以结合使用。3.3 方案讨论让 AI 先输出设计方案而不是直接写代码。你可以要求它先列出“输入、输出、边界条件、设计选型、潜在风险”。这一步看起来慢实际能减少返工。如果 AI 的方案本身不对你可以在它动手前叫停。3.4 代码生成确认方案后让 AI 按照方案生成实现代码。这一步的关键是要求 AI 分文件输出并标注每个文件应该放在项目中的哪个路径。大模型在生成跨文件改动时容易遗漏关联修改明确文件路径能减少这种问题。3.5 代码审查AI 写完后你必须审查。审查顺序依次是类型定义是否正确、边界条件是否处理、副作用是否可控、依赖是否合理、命名是否符合项目风格。不要只读 diff要在大脑里把数据流跑一遍。3.6 测试验证AI 生成的代码必须配套测试。如果你没有写测试的精力至少让 AI 生成核心函数的测试用例然后你自己补充边界条件。跑完测试还不够还要跑类型检查、Lint、构建。3.7 集成与部署工具链允许的情况下让 AI 参与 commit message 的撰写和 PR 描述生成。但在合并之前必须保证所有检查通过并且在自己本地运行过关键场景。部署环节仍然由人操作AI 只负责辅助生成部署脚本或检查清单。3.8 复盘反馈功能上线后把这次任务中 AI 写得很差的部分记录下来反馈到规则文件里。比如“AI 总是忽略 undefined 判断”或“AI 不喜欢用项目已有的 logger”。持续把经验沉淀成规则是 AI 编程工作流提升的关键这也是系统和一次性对话之间的本质差异。4. 环境准备与工具选型工程师级 AI 工作流并不依赖特定工具但合适的工具能显著提升效率。目前市面上主流的 AI 编程工具分三类各有侧重。4.1 对话型工具包括 ChatGPT、Claude 等通用对话产品。它们适合需求分析、方案讨论、代码片段验证、知识问答。优点是模型能力更新及时缺点是项目上下文注入成本高。如果你主要用这类工具建议把项目规范和关键类型定义维护成文档每次对话时直接粘贴。4.2 IDE 插件型工具包括 GitHub Copilot、Cursor 内置的 Agent 模式等。它们直接读取你当前打开的文件和项目目录上下文构建成本更低适合在写代码时做补全、生成小函数、改 bug。缺点是在大型跨文件重构时容易“只见树木不见森林”需要你主动补充全貌信息。4.3 命令行 Agent 工具包括 Claude Code 和类似工具。它们可以在终端里执行命令、读取文件、运行测试对完整项目有更强的操作能力。优点是适合处理“需要跑命令才知道结果”的任务如修测试、分析报错、批量重构。风险是它拥有执行权限操作前必须明确限制它不能动哪些目录、不能执行哪些命令。从实践角度我建议团队或个人开发者以“IDE 插件 命令行 Agent”的组合为主对话型工具作为思路讨论和方案设计的补充。无论选哪一款版本都应以官方最新发布为准本文重点讨论的是工作流方法不绑定某个具体工具的版本号。安装和初始化时有四个环节值得做建立项目规则文件例如.cursorrules或AGENTS.md描述项目技术栈、代码规范、禁止事项把项目编译、测试、Lint 命令记录到规则文件中让 AI 知道怎么验证自己写的代码在 Git 分支上进行所有 AI 辅助开发确保可以随时回滚配置好格式化工具如 Prettier 和 ESLint让 AI 输出代码后自动统一风格。这个准备过程看起来繁琐但它决定了后续 AI 生成的代码是否“像团队成员写的”而不是“像散落在网上的博客碎片”。5. 上下文管理决定 AI 代码质量的关键很多人抱怨“AI 生成的代码不能用于生产”真实原因往往是上下文给得不够。同一个问题你用 20 个字描述和你用 200 个字描述AI 输出的代码差异是天壤之别。好的上下文至少包含五层信息。第一层是项目背景。告诉 AI 这是什么项目技术栈是什么核心业务是什么。不需要长篇大论两三句话就够。例如“这是一个基于 Next.js 14 的电商管理后台使用 TypeScript 和 zustand 做状态管理”。AI 对项目背景越清楚选型越贴合。第二层是现有代码约束。你希望 AI 使用项目里已有的工具函数、类型定义、组件库就要把这些文件的路径和相关代码片段提供给它。例如“项目中已有src/utils/format.ts里的formatCurrency金额显示请统一使用该函数”。这能避免 AI 自己重新发明一套格式化逻辑。第三层是任务目标。描述要具体到输入输出。不要写“优化这个函数”而要写“当前函数在输入为空数组时会返回NaN希望在输入为空时返回 0”。AI 对“做什么”的理解直接决定代码质量。第四层是边界与约束。明确告诉 AI 不要做什么。例如“不要修改数据库 schema”“不要新增第三方依赖”“不要改变函数签名只改内部实现”。这些显式的禁止项能有效减少 AI 的自由发挥。第五层是验证方式。告诉 AI 怎么验证它写的代码是否正确。比如“实现后运行npm test -- OrderService确保全部通过”。如果 AI 能力所及它可以自己运行命令并修正。用一个好的上下文模板包装任务比单纯堆砌“请写一个高质量函数”要有效得多。下面是一个可直接复用的任务描述模板项目背景{项目一句话描述、技术栈} 当前文件{文件路径关键代码片段} 任务目标{具体要做什么输入是什么输出是什么} 约束条件{不可修改的部分必须使用的工具函数禁止项} 验证方式{运行什么命令达到什么标准}这个模板看起来像写文档但它是在用工程思维管理 AI。你每多花一分钟写清楚上下文AI 就能帮你省下十分钟的返工。6. AI 辅助开发一个 TypeScript 功能完整示例为了把上面的工作流落到实际操作这里用一个真实小任务演示。假设项目是一个 Node.js TypeScript 服务需要实现一个订单聚合函数接收订单数组按订单状态分组并返回每个状态下的订单总数和金额合计。我先用传统方式把需求直接丢给 AI展示容易踩坑的地方再用工程师级工作流完整走一遍。6.1 传统方式的典型问题如果只输入“写一个函数按状态分组订单并统计金额”AI 很可能会输出类似这样的代码// src/services/orderAggregate.ts type OrderStatus pending | paid | shipped | cancelled; interface Order { id: string; status: OrderStatus; amount: number; } export function aggregateOrders(orders: Order[]) { return orders.reduce((acc, order) { if (!acc[order.status]) { acc[order.status] { count: 0, total: 0 }; } acc[order.status].count 1; acc[order.status].total order.amount; return acc; }, {} as RecordOrderStatus, { count: number; total: number }); }这段代码看起来没问题但真实项目里需求往往更复杂金额可能是字符串订单类型里还有createdAt状态未来会增加。直接用这个函数数据库返回的字符串金额会被算错amount类型只能是number一对接真实数据就崩。6.2 工程师级工作流的做法先拆解任务我只需要一个聚合函数输入是Order[]输出是按状态分组的统计结果。我明确要求 AI 先给方案再给实现。上下文构建如下项目背景Node.js TypeScript 服务使用严格模式。 现有类型src/types/order.ts 中已有 Order 类型状态枚举是字符串联合类型。 任务目标实现 aggregateOrders(orders): OrderAggregate输入订单数组 输出 RecordOrderStatus, { count: number; totalAmount: number }。 约束不能修改现有 Order 类型不能新增依赖金额字段为 number 如果订单数组为空返回所有状态都是 0 的完整结构而不是空对象。 验证方式运行 npm run test -- orderAggregate接着让 AI 输出设计要点而不是直接写代码。AI 给出的设计思路是先初始化所有状态的默认值避免累加时出现undefined再用 reduce 遍历数组累加 count 和 totalAmount。这个方案没问题我再让它进入实现阶段。AI 最终给出如下代码// src/types/order.ts export type OrderStatus pending | paid | shipped | cancelled; export interface Order { id: string; status: OrderStatus; amount: number; createdAt: string; }// src/services/orderAggregate.ts import { Order, OrderStatus } from ../types/order; export interface StatusAggregate { count: number; totalAmount: number; } export type OrderAggregate RecordOrderStatus, StatusAggregate; const DEFAULT_AGGREGATE: OrderAggregate { pending: { count: 0, totalAmount: 0 }, paid: { count: 0, totalAmount: 0 }, shipped: { count: 0, totalAmount: 0 }, cancelled: { count: 0, totalAmount: 0 }, }; export function aggregateOrders(orders: Order[]): OrderAggregate { return orders.reduceOrderAggregate((acc, order) { acc[order.status].count 1; acc[order.status].totalAmount order.amount; return acc; }, { ...DEFAULT_AGGREGATE }); }关键逻辑说明第 1 行到第 3 行从已有类型文件导入类型保证类型定义唯一第 10 行到第 15 行预先构造全状态默认结构避免累加过程中访问不存在的状态第 17 行到第 21 行使用reduceOrderAggregate明确泛型返回结构永远是完整的OrderAggregate第 20 行{ ...DEFAULT_AGGREGATE }做浅拷贝避免多次调用之间互相污染状态。这段代码相比普通生成的代码最大改进是考虑了空数组和状态完整性。这是上下文约束带来的结果不是 AI 突然变聪明了。6.3 配套测试用例让 AI 生成测试用例再人工补充边界条件。测试文件如下// tests/orderAggregate.test.ts import { describe, expect, it } from vitest; import { aggregateOrders } from ../src/services/orderAggregate; describe(aggregateOrders, () { it(should return zero aggregate for empty orders, () { const result aggregateOrders([]); expect(result).toEqual({ pending: { count: 0, totalAmount: 0 }, paid: { count: 0, totalAmount: 0 }, shipped: { count: 0, totalAmount: 0 }, cancelled: { count: 0, totalAmount: 0 }, }); }); it(should group orders by status and sum count and amount, () { const orders [ { id: 1, status: paid, amount: 100, createdAt: 2026-01-01 }, { id: 2, status: paid, amount: 50, createdAt: 2026-01-02 }, { id: 3, status: pending, amount: 30, createdAt: 2026-01-03 }, ]; const result aggregateOrders(orders); expect(result.paid).toEqual({ count: 2, totalAmount: 150 }); expect(result.pending).toEqual({ count: 1, totalAmount: 30 }); expect(result.shipped).toEqual({ count: 0, totalAmount: 0 }); }); });运行测试命令npm run test -- orderAggregate然后运行类型检查和构建npx tsc --noEmit npm run build到这里这个功能才算真正完成。整个过程里AI 承担了方案设计和代码生成但你在上下文、约束、边界设计上全程介入。这就是工程师级工作流和“复制粘贴”的本质区别。7. 代码审查AI 生成的代码必须过哪些关卡AI 代码即使测试通过也不能直接合并。测试只能证明你想到的场景是对的不能证明你没想过的场景不会出问题。因此代码审查仍然是必要环节。建议按下面七步逐项检查。第一步检查类型是否严格。看 AI 是否偷偷使用了any或类型断言。在 TypeScript 项目里AI 有时会用as绕开类型问题这在业务代码里是技术债。第二步检查边界条件。空数组、空对象、超大数字、非法枚举值这些场景是否都考虑了。AI 倾向于写“主路径”代码你需要主动检查“例外路径”。第三步检查副作用。函数内部是否修改了入参是否调用外部接口是否写了数据库如果 AI 在纯函数里塞入了副作用必须指出。第四步检查命名和结构。函数名是否准确表达行为参数是否单一职责AI 经常生成data、result、temp这类无意义命名需要重命名。第五步检查依赖是否合理。AI 是否有“重新发明轮子”的倾向或者引入一个重型库只为了一个工具函数。项目里已有相同功能时优先复用。第六步检查错误处理。AI 生成的代码往往忽略异常分支。例如网络请求没有处理超时JSON 解析没有处理非法输入。第七步检查性能隐患。虽然大多数业务代码不需要极致优化但明显的O(n^2)循环或未索引查询还是要避免。审查时可以直接把 review 意见返回给 AI让它修改后重新提交 diff。但注意AI 的修改要回归测试不能因为它解释了一句“已经修复”就信了。下面是一个 AI 代码审查清单可以用作 PR 模板。审查项检查内容通过标准类型安全是否存在 any、类型断言、隐式 any严格模式无告警边界条件空值、非法值、极端值是否处理测试覆盖副作用是否修改入参、是否引入外部调用纯函数无副作用命名规范是否使用语义化命名符合团队规范依赖控制是否引入新依赖无重复依赖、无重型库错误处理异常分支是否兜底关键路径有 try/catch性能是否存在明显性能问题主流程在可接受复杂度内8. 常见问题与排查思路AI 编程过程中遇到的问题很多不是模型能力问题而是使用方式问题。下面整理高频问题和排查思路。问题现象可能原因排查方式解决方案AI 生成的代码与项目风格不一致没有提供代码规范上下文查看规则文件是否生效在.cursorrules或AGENTS.md中补充代码风格约束生成代码无法编译类型报错多上下文缺少类型定义检查是否导入了真实类型文件提供明确类型文件路径要求 AI 先读文件再写代码测试通过但线上数据算错边界条件或真实数据格式与预期不符补打日志查看真实入参增加边界测试使用真实数据样本验证AI 总是重复造轮子上下文里没有项目已有工具函数搜索项目 utils 目录在上下文中列出已有工具函数清单AI 修改代码后引入新 bug修改后没有回归测试检查测试是否全部运行每次修改后跑完整测试套件不只跑单个用例AI 越权执行破坏性命令没有设置执行边界检查 Agent 工具配置在规则文件中明确禁止命令列表和受保护目录提示词写得很长但效果差上下文冗长关键信息不突出精简描述突出约束和验收标准使用任务模板按固定结构提供信息第 6 条值得展开。命令行 Agent 工具可以执行终端命令这是它的能力优势也是风险来源。在实际项目中建议在规则文件里写清楚禁止执行删除命令、禁止连接生产数据库、禁止修改node_modules或dist目录。生产环境的任何变更都必须通过人工确认和常规发布流程不能让 AI 直达线上。9. 最佳实践与工程建议工程师级 AI 工作流要在团队中落地不能靠某个人的自觉要形成一套项目级规则和协作习惯。下面按重要程度排序。9.1 把 AI 使用规范沉淀到仓库推荐在每个项目根目录维护一个AGENTS.md或.cursorrules文件内容包含项目技术栈、常用命令、代码风格、禁止事项。这样每次 AI 开始工作前都能自动读取规范连续性和一致性会好很多。一个最小规则文件示例如下# AGENTS.md ## 项目技术栈 - Node.js 20 / TypeScript 5 - Express 4 zod 做入参校验 - 数据库PostgreSQL通过 Prisma 访问 ## 常用命令 - 安装依赖npm install - 类型检查npx tsc --noEmit - 单元测试npm test - Lintnpm run lint ## 代码风格 - 函数命名使用 camelCase组件使用 PascalCase - 禁止 any禁止非必要类型断言 - 错误处理使用统一 AppError不直接 throw new Error - 货币金额统一以分为单位的 number 存储 ## 禁止事项 - 不要修改 migrations 目录下历史迁移文件 - 不要直接连接生产数据库 - 不要新增第三方依赖如果确有必要先说明理由再改 package.json这个文件的价值不在于模板本身而在于团队对“AI 应该遵守什么规则”达成了共识。随着项目演进规则也要持续更新。9.2 坚持小步提交AI 生成的代码动辄上百行如果一次性提交review 会非常痛苦。建议让 AI 按功能点拆成多个小 diff每次提交只解决一个明确问题。例如“先加 Order 类型定义”再“加聚合函数”再“加测试”。小步提交的好处是出问题时能精确定位回滚时不用连坐其他功能。9.3 不要在分支外运行 AI所有 AI 辅助开发都在独立分支上进行。你无法预知 AI 的改动会带来什么后果独立分支可以保证随时丢弃。代码合并前必须通过本地测试、类型检查、Lint、构建四道关卡。9.4 保护敏感信息对话型 AI 工具会把输入发送到外部服务因此不要向任何 AI 工具粘贴数据库连接串、API Key、客户手机号、密码等敏感信息。在代码中也不要让 AI 输出密钥。如果团队数据安全要求高可以部署私有化模型但这属于另一个话题本文不展开。9.5 维护一份“AI 踩坑记录”每次遇到 AI 反复出错的问题记录到项目文档里并沉淀为规则。例如“AI 总是喜欢在时间字段上使用any要求它使用dayjs类型”“AI 不理解金额单位是分需要再三强调”。随着踩坑记录增多AI 在你项目里的表现得会越来越好。9.6 保留人的判断力最重要的一条AI 是放大器不是决策器。如果开发者不懂编译原理、不了解框架运行机制、不清楚业务边界AI 帮不了你反而会放大错误。最好的使用方式是先用传统方式把一个功能学透再让 AI 帮你提速。AI 可以让资深工程师如虎添翼但很难让零基础的初学者直接写出生产级代码原因就在于缺乏判断力。10. 总结与后续学习方向通过对 AI 编程工作流的完整梳理可以看到真正的分水岭不是“用不用 AI”而是“怎么用 AI”。Matt Pocock 强调的工程师级工作流本质上是一种纪律需求拆解讲清楚、上下文给充分、方案先讨论、代码必审查、测试必覆盖、变更可回滚。这套纪律看起来比“让 AI 直接写”多花了一点时间但它避免了更昂贵的返工和线上事故。AI 生成的代码进入仓库后它就是你的代码你需要理解它、维护它、为它负责。如果你想继续深入下一步可以尝试三件事。第一把现有项目按本文方式补充一个AGENTS.md规则文件然后挑一个小功能走完整工作流体验“先方案后代码、先测试后合并”的节奏。第二选择一个命令行 Agent 工具用真实项目里的一个报错任务练手让它读取文件、运行测试、提交修复你负责审查它的每一步。第三把 AI 踩坑记录持续更新到项目规则里两个月后再回头看你的 AI 协作体验会有明显变化。AI 编程工具会继续迭代提示词技巧也会变但只要你有清晰的需求边界、代码所有权意识和验证反馈闭环无论未来工具怎么升级你都能把它用在正确的地方。