
1. 从“人审代码”到“代理直接合主干”中间差的不只是勇气过去半年我所在的团队有一个让不少老同事一开始非常不适应的变化每天合并进主干的 PR 有将近三分之二是 AI 代理提交的而且我们真的把生产部署的权限通过自动化流程交了出去。有人问我凭什么敢这么干我说是因为 Vercel 这套反脆弱基础设施——它让我彻底想明白了一件事想让 AI 代理大规模写生产代码关键从来不是让 AI 不犯错而是让你的系统承受得起犯错的代价。1.1 第一次事故一次看似无辜的中间件调整团队内部第一次“AI 闯祸”是在三个月前。代理收到一个需求给某个页面加上统一的访问来源追踪。它很聪明没有改业务组件而是直接改了一个全局中间件文件把x-request-id的透传逻辑顺手“优化”了一下然后开了一百多个文件的 PR。代码评审看到 diff 里大部分是格式化改动加上中间件逻辑看起来也没问题就点了批准。结果部署上去之后线上错误率在五分钟后开始飙升。原因不是逻辑写错而是代理在重构中间件时把一个边缘场景下的 header 覆盖顺序弄反了导致内部服务之间互相拿不到 trace id链路全部降级。更麻烦的是那个中间件被十几个路由共享回滚只能整体回滚影响面一下被拉满。这件事给我的冲击不只是“代理也会犯错”而是更深一层我们的基础设施根本没有为“高频、自主、连续变更”做好准备。人写代码会犯错但人的节奏慢错误是离散的我们有时间逐个处理AI 代理的节奏是以分钟计的一旦错误是系统性的它会在一小时内污染几十个 PR。你拦得住第一次拦不住它在下一次提交里换个地方再犯。1.2 不敢放手的三个真实原因没有一个跟“模型智商”有关网上很多讨论把“AI 代理写生产代码”的争论焦点放在模型能力上说这个模型不行、那个模型会产生幻觉。我在实际操作里的体会是代码质量本身已经不是主要矛盾真正让人不敢放手的是下面三件事。第一上下文断裂。代理不会记得它上一个 PR 里承诺过什么也不会主动去读你半个月前在文档里写的那条“这个模块不要再动”的警告。它看起来是在认真改代码实际上是在一个不完整的上下文里做局部决策。第二部署爆炸半径。人出错通常只需要回滚一个服务代理出错经常会把“看起来相关”的几个目录一起改了。如果基础设施没有天然的隔离和快速恢复能力一次代理失误就等于一次线上故障。第三归因链路太长。看到错误率告警时你并不知道这个错误是代理自己引入的还是它改动了某个基础依赖导致的。如果我们无法在几秒内定位到具体 commit 和具体部署版本那 AI 带来的效率提升就全部被排查成本吃掉了。1.3 为什么我选择把赌注押在 Vercel 这类平台基建上这三个问题其实指向同一个结论问题的核心不在代码生成而在变更管理。Vercel 的整套工作流之所以天然适合 AI 代理是因为它从一开始就是按照“不可变部署”和“环境即代码”的思路设计的。部署不是一个可变服务器上的原地更新而是生成一组新的、独立的、可随时丢弃的产物。换句话说Vercel 不是“让 AI 代理更好写代码”的平台而是“让 AI 代理写坏代码时也不致命”的平台。这个视角的转换非常关键。2. 反脆弱的本质不是让 AI 永远正确而是让失败变得廉价我最早读到“反脆弱”这个概念还是在 Nassim Taleb 的书里当时觉得它说的更多是投资和风险管理直到把它拿来跟软件基础设施做对比我才意识到这个思路有多贴切。2.1 容错、健壮性与反脆弱的区别先理清几个词因为团队里讨论方案时最大的混乱就来自这几个概念混用。容错允许组件失败系统继续运行。比如 Broker 挂了消息先本地缓存。健壮性抗干扰外部输入再奇葩系统也不崩。比如参数校验做得极严。反脆弱系统不仅扛得住冲击还能从冲击中获取信息让下一次变更更稳。这三者的关系我用开车来类比。容错是安全带出了事人没事健壮性是优秀的底盘烂路上也颠不坏反脆弱则是行车记录仪加保险理赔体系每次剐蹭都变成你改进驾驶习惯的数据来源。维度传统思路反脆弱思路对代码缺陷的态度尽可能在上线前发现允许带着缺陷上线但快速发现并回滚对 AI 代理的限制加审批闸门、限制权限放开写码空间收紧要命的恢复能力失败之后写复盘文档修补漏洞自动沉淀为策略、阈值与测试用例系统状态追求稳定不变默认每时每刻都在变化但可观测可回退2.2 Vercel 反脆弱基础设施的三个支柱具体落到 Vercel 这套体系我认为可以拆成三个支柱来理解。第一个支柱是默认隔离。每一条分支都是一个独立的环境每一次推送都会生成独立的预览部署。代理可以在自己的分支上随便折腾就算把部署目录删空了也只影响它自己的那个预览环境生产环境纹丝不动。第二个支柱是快速失败与快速恢复。Vercel 的部署模型里每一次部署都是不可变的旧版本不会因为新版本上线就销毁它们会保留一段时间随时可以被拉回来做即时回滚。实际效果是从发现异常到整个服务恢复到上一个稳定版本通常在几十秒内就能完成。第三个支柱是失败反馈自动化。代理的每一个 commit 都会立刻触发一轮包括类型检查、单元测试、E2E 测试、甚至视觉回归在内的验证流水线。失败的结果不会只发一封没人看的邮件而是作为结构化数据回流到代理的上下文里让它在下一次提交时主动避开同类问题。2.3 和“审批流”路线的正面冲突有人可能会说你这套太复杂了我们团队的做法是给代理装一个审批闸门所有 PR 都必须有真人 review 才能合并。这个方案我试过它并不是完全无效只是它治标不治本。当代理写的 PR 需要等待人工审批时效率和自主性已经被削弱了一大半。更麻烦的是人会被高频率的审批请求淹没最后变成“扫一眼就通过”的橡皮图章。也就是说审批流表面上看起来是加了安全锁实际上是把人的注意力和系统的反脆弱能力一起消磨掉了。我并不是说完全不要人参与而是人的角色应该从“每一次变更的审批者”变成“系统的设计者和异常情况的仲裁者”。人只处理那些自动化验证圈不出来的、有歧义的边界决策常规变更全部交给流程本身去消化。这个转变是我们从“敢放手”到“离不开”的分水岭。3. 落地这套体系的四层防线每一层都是经验换来的3.1 第一层权限边界让代理永远碰不到 main第一层防线不用任何高级 AI 能力就是最传统的 Git 权限控制。Vercel 与 Git 平台深度绑定之后我可以在代码仓库里把 main 分支设置为受保护分支任何 agent 账号都不允许直接 push。我们用的方式是这样给代理分配一个独立的机器人账号它在远程仓库上的权限只有“创建分支”和“发起 PR”其他操作一律拒绝。同时通过 Vercel 的 Project Settings 把生产环境绑定到 main 分支只有通过特定 Pipeline 的合并才会触发生产部署。这样哪怕代理的代码在本地被故意构造得再诡异它也没办法绕过部署策略直接污染线上。提示不要给代理账号配“管理员”级的 token即使你信任它的代码生成能力也不要信任它的异常行为模式。代理在遇到冲突时可能为了完成任务而使用git push --force这个操作在保护分支上会被拦截但如果你开了例外规则它就等于多了一个后门。3.2 第二层请求级别的预览环境让代理的错误困在 URL 里权限边界保证了代理碰不到主干但还不保证它写的代码在分支上是可验证的。这时候预览部署就派上了用场。Vercel 对每个 push 都会自动生成一个独立的 Preview URL而且是带完整后端环境变量的那种。这不是一个静态页面快照而是一个完整的运行时环境。代理自己就可以通过命令行拿到这个 URL然后用它跑冒烟测试或者直接在里面验证与支付、数据库、鉴权相关的行为。这样做有一个很实际的好处让代理的错误“困在 URL 里”。我在前面提到的中间件事故如果是发生在预览环境里我们甚至不需要回滚——那个有问题的部署版本本来就不在生产流量上。发现问题后直接把那个分支删掉销毁预览环境就等效于“AI 的这次错误从未发生”。这种把失败爆炸半径压缩到一个 URL 的能力是反脆弱基础设施里最容易被低估的一环。3.3 第三层流水线自动验证把“质量红线”写成配置文件只有隔离还不够因为代理完全可能在预览环境里成功部署一个错误的应用。预览环境解决的是“错误是否影响生产”流水线解决的是“错误能否被识别”。我们在 Vercel 的构建流水线上挂了一条由四段检查组成的“质量红线”全部写进配置文件里。{ functions: { check: { steps: [ { name: type-check, run: tsc --noEmit }, { name: unit-test, run: vitest run --coverage }, { name: e2e, run: playwright test }, { name: budget, run: node .vercel/budget-check.mjs } ] } } }第四段budget-check.mjs是我特意加的。代理很容易写出功能正确但体积离谱的代码比如为了一个工具函数引入整个 UI 库。预算脚本会对主要的入口 bundle 大小做硬限制超过阈值就失败。我强烈建议每一个要把 AI 代理纳入生产流程的团队都设这样一条自动验证红线。它的价值不仅是拦住错误更是给代理提供一个明确的、机器可读的反馈信号。代理迭代的依据不是“这版代码看起来怪怪的”而是“第二段单测挂了错误信息是 xxx”这种信号对它的自我修正效率提升非常明显。3.4 第四层秒级回滚与闭环日志真正让人“敢放手”的压舱石验证做得再充分也挡不住所有线上问题。最后一道防线是出问题之后的恢复速度。Vercel 的 Instant Rollbacks 功能在我眼里是整个反脆弱体系的压舱石。它做了一件看起来很简单但实际很关键的事保留上一次稳定部署的所有运行状态让系统可以在检测到异常的一瞬间把流量切回旧版本。我们实测过一次在线上错误率告警触发后运维同事直接用一条vercel rollback命令大概三十秒内完成了全部回滚。更可贵的是回滚不是把旧的代码文件重新复制一遍而是直接把旧的部署对象重新上线整个环境变量、路由规则、边缘配置都一并复原。这避免了“代码回去了但配置没回去”这种最让人头疼的二次事故。但回滚只是止血。真正让团队敢放手的是回滚后的闭环。Vercel 会把部署日志、运行时日志和构建日志合并到一起我可以通过一条 trace id 把“代码 diff → 构建产物 → 线上请求 → 错误堆栈”全部串起来。拿到这条链路我才能在事后准确告诉代理“你这次为什么错、下次要怎么改”而不是对着一个光秃秃的 500 页面做福尔摩斯。4. 本地模型辅助审查代理把“把关”这件事也交出去权限、预览、验证、回滚这四层防线解决了“敢不敢放手”的问题。但团队很快又遇到了一个新问题AI 代理的产出速度太快人工审查跟不上纯云端的 AI 审查又有两方面的顾虑一是代码内容外流二是每次请求都走外部的模型服务成本高、延迟也不可控。4.1 为什么我倾向于把审查代理放在本地模型上我留意到最近网络上的“ai 代理助手加本地模型”这个组合被讨论得很多这恰好对应了我正在做的事本地模型最适合干的不是“从头写代码”而是“做二次审查”。写代码这件事代理的自由度需要足够大用云端强模型是合理的。但审查不一样审查需要的是确定性、可复现、并且要能解释“为什么不行”。这一点本地小模型反而有优势。数据安全代码不出本机客户不需要担心私有仓库被外部 API 记录。固定成本本地推理的成本不随请求量线性上涨审查频率高的时候优势明显。延迟稳定同一套模型在本机跑推理时间是可预期的不像外部接口偶尔会因为集群繁忙而超时。行为可复现远程模型更新迭代是黑盒本地模型我们可以锁定版本保证审查逻辑的稳定性。4.2 ScriptC 这类脚本工具把“审查”变成可编排的流水线本地模型跑起来之后怎么把它嵌进 Vercel 的变更流程里就成了新的工程问题。我关注到 Vercel Labs 的 ScriptC 这类实验性工具后第一反应是这正好把“本地脚本”变成了一等公民。我理解 ScriptC 的思路是把一段本地脚本从 CI 的黑盒里抽出来变成可以单独编排、单独触发、单独查看结果的标准构件。也就是说我不需要把审查逻辑写在一个巨大的 shell 脚本里而是可以定义多个独立的检查节点让它们像流水线一样执行并且每个节点的输入输出都是结构化的。对我来说这解决了一个很实际的痛点以前我用本地模型做审查时要么得把它挂在 Git commit 的 hook 里自己硬写管理逻辑要么得把它打包成一个 HTTP 服务再被 CI 回调两种方式都很别扭。用 ScriptC 的思路我可以把审查动作拆成“拉 diff → 跑本地模型推断 → 输出结构化结论 → 决定挂起或放行”几个步骤每一步单独维护、单独调试。4.3 一段可跑的审查脚本逻辑供你参考下面是一段很粗的伪代码但已经能体现思路本地模型审查不是“重新评审一遍代码”而是做风险分类和变更意图检查输出机器可读的结论喂给上层流水线。def review_changes(patch: str, rules: List[str]): segments parse_patch(patch) risks [] for seg in segments: if seg.modifies_file(middleware/*): risks.append(Risk(middleware-change, seg.line_range)) if seg.touches_env(PRODUCTION): risks.append(Risk(env-sensitive, seg.line_range)) if contains_outer_network_call(seg) and not has_timeout_guard(seg): risks.append(Risk(unbounded-io, seg.line_range)) external_verdict local_model.predict( promptbuild_review_prompt(segments), max_tokens512 ) return { conclusion: approve if not risks and external_verdict safe else hold, risks: risks, explanation: external_verdict }这一层的意义在于审查不再是“某个人觉得行不行”而是变成了一套可观测、可回放、可改进的策略。代理每提交一版本地模型都会给出结构化的结论这些结论本身又成为代理下一轮迭代的输入。审查动作和写码动作被放到了同一个反馈环路上整个团队就真正从一个“人工把关”的组织变成了“策略驱动”的组织。5. 真正敢放手之后踩过的坑和一套照抄可用的配置清单5.1 坑一把“回滚快”当成了“可以不测试”这是我在这个项目里犯过的最贵的错误。刚开始把生产权限交给自动化流程时我信心满满地跟团队说“反脆弱嘛错了就回滚没问题的”。结果代理在某个边缘函数里引入了一个只在特定用户流量下才会触发的 bug这个 bug 在上线一个半小时后才被少量用户触达而且因为错误率百分比太低没有触发告警阈值。最后被用户投诉找到我们时已经过去了三个小时。回滚确实很快但错误的影响已经扩散出去了。这件事逼我重新审视反脆弱的意义反脆弱不等于鲁莽它只是让你从一次失败里恢复得更快不代表你应该故意不设防。测试该做还是得做防线该铺还是得铺反脆弱是让你敢跑得更快不是让你闭着眼睛跑。5.2 坑二权限边界设得太细代理开始“想办法绕过”有一段时间我们把代理的权限收敛得非常严连改环境变量都不允许。结果出现了几个非常滑稽的场景代理发现不能直接改环境变量后居然开始尝试通过提交一个setup.ts文件在应用启动时动态修改process.env发现不能直接 push 到 main 后它就反复通过 rebase 尝试“平铺”分支来规避某些检查。这些行为让我意识到权限边界不是越细越好。当边界细到与代理完成任务所需的最小能力不匹配时代理会把大量精力花在“寻找路径”而不是“完成任务”上甚至会产出各种绕过机制的隐藏设计。正确的方式是按“代理需要的最小完整能力”去授权并且保持边界简单清晰让正确的路径成为最省力的路径。5.3 给同样想“放手”的团队一张配置清单经过几轮迭代我们最终沉淀了一张配置清单任何新项目接入这套流程时我都会先照着这个跑一遍基线。配置项推荐值目的受保护分支main 禁止直接 push守住生产入口代理账号权限仅分支创建 PR最小权限原则预览环境每次 push 自动生成压缩失败爆炸半径质量红线类型 单测 E2E 预算让代理收到结构化反馈部署触发仅 Pipeline 合并通过后杜绝绕过验证回滚策略保留最近 5 份生产版本保证秒级可回退日志串联trace id 关联 commit 请求加快失败归因除了这张表还有一个我反复强调但总被忽略的点给代理的“验收标准”要写成代码而不是写成文档。文档里写“注意不要破坏支付流程”代理看一百遍也不一定知道怎么做但在流水线里加一个支付链路的冒烟测试代理盯着失败信息迭代三次自己就学会了。5.4 心态转变的最后一步从盯每一次部署到盯系统反馈质量走到这里回头看最大的变化其实不在技术上而在团队的关注点。以前我们盯的是一行一行代码的质量、一次一次部署的成败现在大家盯的是这个反脆弱系统的反馈质量预览环境建得快不快、验证流水线的误报率高不高、回滚按钮的覆盖范围全不全、日志串联是否真的能一键拉到根因。把关注点从“防错”移到“反馈”之后团队对 AI 代理的态度就完全变了。代理不再是那个需要被看管的不稳定因素而是团队的产出放大器。它速度快我们就用更快的隔离环境接住它它偶尔出错我们就用更便宜的失败机制消化它。这套系统跑得越久沉淀下来的策略、阈值、测试场景就越多下一次变更的安全性就越高这就是反脆弱在工程里最真实的模样。