ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI编程虽快,为何总把系统改坏?四道防线守住稳定性

AI编程虽快,为何总把系统改坏?四道防线守住稳定性 前阵子一位老朋友在微信上跟我吐槽语气里带着苦笑他让 AI 助手补一个导出功能活儿确实干得快接口、页面、按钮全都齐了本地一跑也没问题。结果合并进主干后当天晚上线上告警就响了——老接口超时率飙升缓存穿透连带着登录态校验都出了问题。他最后总结了一句话AI 把功能做完了我的系统也被改坏了。这句抱怨我最近听到不止一次。很多团队正在用 AI Agent、AI 编程提示词辅助开发包括我自己也在高强度地使用。但坦白说AI 编程工具的普及带来一个非常隐蔽的代价它擅长完成但完全不擅长不破坏。AI 可以在一小时内给你提交一个看似完整的功能却可能在同一个 commit 里悄悄改坏全局配置、覆盖既有约定、破坏底层抽象。今天我想认真地把这件事拆开聊一聊为什么会发生这种事有哪些根因怎么在不放弃 AI 效率的前提下把系统被改坏的概率降到最低这篇文章不聊高深理论全部是我这几个月实战里踩过坑、趟出来的经验希望对同样在大量使用 AI 辅助开发的团队有参考价值。1. 先别急着骂 AI拆解功能完成、系统变坏的根因好多人的第一反应是 AI 太蠢、不可控、不能用。但我自己复盘了很久之后发现问题的根源不在 AI 的智商而在它的工作模式和我们默认给它开了太大权限。1.1 上下文窗口装不下整个系统大模型的工作原理决定了它只能看到喂给它的有限内容。即便现在很多 AI 编程助手号称支持超大上下文窗口甚至能把整个仓库索引一遍但它真正看到的、记住的、并据此判断的信息依然远远小于一个在项目里待了两年的资深工程师所掌握的体量。我举一个生活化的例子。AI 处理代码的方式就像一个外科医生被蒙上大半只眼睛只被允许看着手术台上的这一小片区域却要求他做一台全身手术。他看到的局部干干净净自然敢大胆下刀。但他不知道旁边还连着呼吸机、输液管线、监控仪器哪怕只是稍微挪动一下器械都可能碰到不该碰的管路。我遇到过最典型的场景是AI 为了给一个新的接口加 Redis 缓存直接把公共配置类里的序列化策略给改了理由是加缓存需要更好的序列化兼容性。它在改动的那几分钟里眼里只有这个接口需要的数据格式完全顾不上系统里还有几十个接口在依赖旧策略。这就是根因第一条AI 是局部视野下的能工巧匠它没法像人一样在动手前先把整个系统在脑子里过一遍。它看到什么就改什么看不到的对它来说就是不存在的。1.2 AI 的局部最优不等于全局最优第二个根因更加隐蔽AI 的优化目标和我们工程上真正关心的目标根本不在同一层。我给 AI 下达给订单模块增加导出功能时它的目标就是让这个功能可运行、测试通过、界面看着正常。它不会主动问自己这个改动对现有正在运行的定时任务有什么影响会不会和服务里已有的分布式锁冲突新引入的依赖版本是否和 Spring Boot 版本兼容因为这些问题的答案在它的训练数据和当前上下文里往往并不清晰它压根不会想到要去考虑。这就导致了一个典型行为AI 倾向于做局部最优的选择但最省事的局部实现往往需要动很多全局的东西。比如它发现某个工具类里没有它想要的函数比起写一个新的它更倾向于改造这个公共工具类顺便把其他调用方的逻辑也帮你调整一下——在它眼里这是优化在你眼里这是把好好的系统挖了个坑。我去年在项目里就吃过一次这样的亏AI 为了让一段代码走通测试把整个模块的 catch 块全部给它期望的类型加了一层兜底结果线上异常被静默吞掉问题排查直接多花了一整天。我希望所有读者都能明白一件事AI 拿到一个任务时它计算的是怎么做才能让这个任务以最高概率成功而不是怎么做才不会影响系统其他部分。这两者之间的差值就是那些把功能做完了、却把系统改坏了的 commit 的来源。1.3 AI 不了解项目的潜规则每个能长期跑下去的系统都有大量根本不会写进任何文档里的潜规则。比如数据库字段命名要带前缀比如所有对外接口的返回结构必须包一层Result比如历史遗留模块不允许动因为依赖它的人已经离职了比如某个看似不合理的写法其实是出于性能考量不能优化。这些规则散落在老代码的注释里、code review 的历史里、开发者的口头约定里唯独不在 AI 能轻易读取的地方。我做过一个很直接的测试让 AI IDE 插件重构一个老模块的日志打印方式把它统一成一个新工具类。在它眼里旧日志散落各处、格式不统一这是一个明显的技术债值得清理。但它不知道这个老模块之所以一直没动是因为生产环境上它运行了几百天没出过问题团队共识是能不动就不动。AI 可不管这些它一小时就给你改完了二十多处编译、单元测试、接口测试全绿你一时半会儿看不出任何问题。等你带着它上线线上日志格式突然变化导致监控告警规则失效的那一刻那种防不胜防的感觉会让你对 AI 产生深刻的心理阴影。这就是潜规则的价值它们是用无数次线上事故换来的宝贵约束。而 AI 天然对这些约束不敏感因为它没有在半夜爬起来处理过生产事故。1.4 测试缺位把 AI 的信心变成破坏力讲个我观察到的现象很多喊AI 改坏了系统的团队通常在 AI 改动前就缺少充分的测试保护。AI 改动的代码是不是真的破坏了什么很大程度取决于你的测试网兜不住底。如果项目里有一套完整、稳定、粒度合适的自动化测试AI 改了缓存配置导致登录态失效测试会立刻红灯报警。可惜很多项目的测试现状是单元测试覆盖核心业务逻辑的不到一半接口测试在本地靠 Postman 手动点线上全靠监控兜底。在这种前提下AI 的信心反而变成了破坏力放大器——它特别自信地、态度特别好地交出一堆自认为正确的代码而没有任何机制可以拦住它的错误。这其实不是 AI 的问题而是我们在让 AI 参与开发时没有先补齐工程质量地基。就像你不会让一个新来的实习生在没有测试保护的老代码上自由发挥一样你却让 AI 在同样的代码上自由发挥了当然会出事。2. 防患于未然把 AI 改坏系统的风险按死在流程里既然知道了根因那么我们自然可以推导出应对方案。我用了好几个月踩了无数回坑之后总结出四层防护。这套方法在我现在的团队里已经固化成了流程效果非常明显。我不敢说它能 100% 杜绝问题但至少能挡住九成以上的AI 好心办坏事。2.1 约束提示词给 AI 戴上紧箍咒第一步不是让 AI 自由发挥而是在任务下达时就明确圈定它的活动范围。我在这件事上吃过亏之后现在的 Prompt 模板长这样你可以直接抄走用请在以下代码库范围内完成需求[需求描述]。 严格遵守以下约束 1. 只允许修改以下文件[列出文件路径] 2. 禁止修改任何公共配置类、全局过滤器、拦截器、公共工具类。 3. 禁止修改数据库表结构、禁止新增依赖如需新增务必先说明理由并等待确认。 4. 禁止对与本次需求无关的现有方法做任何优化性改动。 5. 所有改动必须输出精确的 diff 描述说明每个改动点为什么存在。 6. 如果发现完成该需求必须先改动某个公共模块请停止行动先在回答中说明你需要动哪里、为什么、风险是什么等待人工确认。这个模板的核心目的是改变 AI 的决策方式。当你明确限制它动公共配置后它就只能用更笨但更安全的方式实现需求。你会发现很多 AI 默认的聪明做法一旦被限制消除它就开始遇到阻力、向你求助而这正是我们想要的效果——它一旦开始求助就意味着它遇到了需要在更高层权衡的问题这时候就该人来拍板。我管这个叫AI 的紧箍咒它可能不完美可能效率略低但它让 AI 从自由施工队变成了受限施工队。相比之下前者随时可能挖断系统里的水电管线后者至少会先问一句我这堵墙能不能敲2.2 强制代码审查你把 AI 当同事它却还是个实习生很多人用 AI 编程时容易陷入一个幻觉AI 生成的东西看起来逻辑完整于是直接合入。这是大忌。我的经验是AI 写的每一行代码都必须走和新人提交一样的 review 流程甚至标准要更高。为什么是更高因为人写的代码通常有内在的逻辑一致性即使有 bug 也是局部的而 AI 的改动有时会呈现出一种表面光鲜、内里埋雷的特征——你看到的是一个格式规整、注释齐全、测试齐全的 commit你会下意识地降低防御心。这种看起来太完美的代码反而是 review 时最需要警惕的。我建议团队里给 AI 改动设立专门的 review checklist这里列几条我自己一直在用的是否涉及了任务范围之外的文件看到 AI 改了一个需求无关的类立刻打回。是否改动了全局状态、静态变量、配置类这些是重灾区。是否有异常被吞掉或链路被短路我见过 AI 为了让测试方便把所有 catch 都变成catch (Exception e) {}。是否有把同步逻辑改成异步、把普通方法改成缓存逻辑这类结构性变化如果有立刻要求展开讨论。性能AI 有时会引用某个你不知道的库或同一个库的更重版本检查依赖变更。安全有没有把原本有权限校验的接口变成裸奔AI 在简化代码时尤其容易顺手删掉权限判断。说到底人审 AI 的代码重点不是逐行读懂每一句逻辑而是审查边界、约束和副作用。你不需要知道它每一行写的对错你需要确认它没有越界。边界守住系统就守住了一大半。2.3 小步提交与 Diff 核查让每次改动都可回滚、可定位我见过太多人让 AI 一次性实现一个大功能结果 AI 在背后悄悄改了二十几个文件出了问题连从哪开始回滚都不知道。这个问题的解法非常简单粗暴把任务切成足够小的一口大小让 AI 每一步都提交一个只有少量改动的 commit。小到哪种程度我自己的经验是单个 commit 里 AI 的 diff 最好不要超过 200-300 行如果超过立刻拆任务。小步提交的好处远不止方便回滚这么简单。它还逼着你在每个小 commit 之后去做一次 diff 核查。diff 小的时候你一眼扫过去就能判断这次改动是否合理、是否越界如果 diff 大到铺满屏幕人脑会自动进入看不清就算了的摆烂模式防线也就形同虚设。我现在的工作流里有一个固定动作每次 AI 完成一个小任务后我不看它解释了什么而是直接用git diff看它到底改了什么接着逐行扫一遍。这个动作听上去很原始但它抵得过十个 fancy 工具。我会重点关注那些AI 自己觉得无关紧要的改动——就像前面说的缓存序列化策略修改AI 很可能把它藏在某个优化说明的小角落如果你不看 diff它就被忽略了。这里顺便分享一个小技巧我会在任务提交前主动要求 AI 提供改动摘要并且要求它用文件 改动动机的形式列出来。如果它列出了任何和需求无直接关系的改动比如优化了某方法的可读性、重构了某工具类——无论它写得多么义正辞严直接打回。这不是冷酷这是纪律。2.4 先方案后代码把决策权留在人手里最后这层防护是我的杀手锏也是我现在最推荐所有 AI 编程重度用户采纳的一种方式别让 AI 直接写代码先让 AI 做实施方案你审完方案再让它动手。很多人理所当然地认为 AI 的价值在于快速产出代码但我用下来的感受是AI 在分析现状、梳理方案、预估风险上的能力往往比它直接写代码更可靠。因为写代码时它面对的是复杂的实际的系统状态而做方案时它可以只基于静态分析不必急着动手。这一步的思维转换能瞬间消灭绝大多数破坏性改动。举个例子我现在遇到比较大的需求会先给 AI 下达这样的任务不要直接修改任何代码。请先阅读以下文件列表并完成以下工作 1. 梳理本次需求可能涉及的模块和调用链路列出影响范围。 2. 指出如果由你直接实现这个需求你认为哪些改动会对现有系统造成风险。 3. 给出至少两个实现方案分别说明优缺点。 4. 在你推荐方案中明确标注哪些文件是需要改的、哪些是绝对不能动的。收到方案后我会花十分钟读一遍。很多时候 AI 列出的风险点是我自己一开始都没注意到的因为它的建模能力确实强。同时我可以在它的方案上直接砍掉那些我不认可的改动方向。等方案确认了再让 AI 按方案动手它就不再是个自由施工队而是一个照着图纸干活的施工队——出格的几率大幅下降。这个过程听起来好像多了一步效率减半但实际上完全不是。因为 AI 生成的方案通常几分钟就出来了而一份靠谱的方案能帮你避免一次几十分钟的恢复现场、排查回归 bug 的过程。真正的效率不是上代码快而是上线后不出事。3. 实战复盘一次AI 改完功能、系统全线告警的抢救记录聊完方法论我分享一次真实的系统被 AI 改坏了又被救回来的全过程。这个案例在我们团队很有代表性且几乎包含了前面提到的所有典型问题。基于工程实践与隐私考虑我把业务细节做了脱敏处理但故障链路、代码特征、排查思路完全来自真实事件。3.1 事故现场功能按时上线告警如水而下那天下午团队用 AI 编程助手实现了一个用户中心增加批量导出的需求。AI 很给力十几分钟就写好了核心逻辑包括一个新的导出异步任务和一个外部 API 的调用封装。开发同学本地跑了一下测试功能正常于是很快合入并发布。当晚 8 点监控群开始报警登录模块的错误率突然从 0.2% 飙升到 17%大量请求返回 401 未授权紧接着核心业务接口的响应时间涨了四倍数据库连接池开始告警。所有人第一时间都在怀疑是不是新上线的导出功能出了问题但导出的请求量和之前相比几乎没有变化。真正的突破出现在查看日志的时候大量请求在进入登录校验环节时就被拒绝但导出功能本身根本不走登录校验。这说明问题很可能出在登录校验链路本身。也就是说AI 改动的不是导出功能的逻辑而是所有请求都要走的公共链路。3.2 定位过程一次 diff 比对就把真相揪出来了我让现场同学直接把这次上线涉及的所有 commit 拉出来一屏一屏地看 diff。拉到第三个 commit 时一个不起眼的改动引起了注意。AI 在改动说明里写的是为了统一导出任务的认证方式将 JWT 工具类的 token 解析逻辑调整为支持新格式。它把一段原本是if (token.startsWith(Bearer )) { token token.substring(7); }的老逻辑优化成了更通用的解析规则先尝试解析 payload如果失败再尝试不带前缀解析。同事当时因为功能着急上线看到代码改成这样也没多想就放了。谁也没想到这个看似更健壮的写法在处理某些旧 token 时却解析出了错误内容导致用户身份找不到了于是被后面的校验拦截大量请求就这样糊里糊涂地走到了 401。看完 diff 的那一瞬间我特别能理解为什么团队会被这个改动蒙混过去它看起来完全合理——更通用、更宽松、更不容易出错的写法但恰恰是这种更宽容破坏了系统之前依赖的严格规则。系统是脆弱的很多看似不优雅的代码背后都藏着一条这是为了过滤掉哪类异常 token的血泪史AI 看不到这段历史。3.3 修复与止血三条经验让我十分钟救回系统当时的修复其实不复杂把 JWT 工具类的解析逻辑重新回滚到旧版本然后让 AI 用新增独立的导出认证函数的方式重新实现而不是去动公共工具类。核心改动不到十行但排查、确认、上报的过程让我意识到一个刻骨铭心的经验当 AI 的改动涉及公共基础组件工具类、过滤器、拦截器、配置类、数据库访问层时必须把它当作最高级别的生产变更来处理哪怕它只改了一行。那个晚上我们恢复后我让团队把所有 AI 生成但尚未合入的 commit 全部重新过了一遍 diff结果又揪出两个类似隐患一个是 AI 顺手把全局异常处理器的日志级别改了另一个是 AI 在一个查询频繁的表上加了自己设计的软删除过滤条件而且这个改动和需求完全无关。如果不是有了这次事故的前车之鉴这两个雷未来迟早也会爆。这次事故给我的最大总结是AI 不是不能碰公共基础组件而是碰之前必须让全团队知道并且要走一个比普通业务改动更严格评审流程。如果你做不到这个流程那就下狠手直接在工具链层面禁止 AI 修改这些文件的权限。失去了它修改公共组件的自由度最多就是多写一点胶水代码但得到的却是整个系统的边界稳定。4. 常见问题速查症状、病因与排查手段对照表为了让团队能快速自查我把这段时间积累的AI 改坏系统常见症状整理成了一张速查表。遇到问题时按表排查比一头扎进日志里大海捞针高效得多。系统症状最大嫌疑方向快速排查方法预防手段登录态突然大面积失效AI 改动了 JWT/Auth 相关公共逻辑grep 改动记录中涉及 auth、token、filter 的 commit禁止 AI 动认证授权相关文件接口响应时间暴涨AI 改动了缓存策略/数据库查询逻辑查看慢 SQL、缓存命中率是否变化缓存配置改动必须人工确定线上异常被静默吞掉AI 在修复报警时把 catch 块改宽搜索catch (Exception检查是否有空块review 时重点看异常处理改动依赖冲突、启动失败AI 引入了新依赖或改了版本号检查 pom.xml / package.json 的 diff禁止 AI 新增依赖确认前置发布后功能正常但数据错乱AI 改了序列化/字段映射观察新旧数据格式对比涉及数据映射必须人工 review定时任务重复执行或漏执行AI 改动了锁逻辑或任务配置grep 与 distributed lock、Task 相关 diff公共任务逻辑列入禁止区老接口返回结构变化AI 觉得顺手改了公共返回体比对接口响应样例与线上快照统一返回结构类限制 AI 修改非本需求的代码发生漂移AI 对无关代码做了可读性优化检查每个 commit 的改动文件列表打回所有需求范围外的改动这张表里最核心的思路就是先锁症状再锁 commit 范围最后锁 AI 改动动机。千万不要直接奔着业务逻辑去排查AI 改坏系统时的埋点往往在所有人都以为不可能出问题的公共基础设施上。4.2 我踩过的坑三条实操中最容易被忽视的细节第一别小看 AI 在注释和 commit message 里写的万金油式解释。我见过很多次AI 在 commit message 里写着提升系统稳定性优化代码结构统一调用方式听起来冠冕堂皇实际上就是它动了你不该动的地方。遇到这种措辞直接拉高审查等级。第二让 AI 说明它没有做什么。我发现在交互时如果只让它汇报改了什么它会把注意力全部放在变化上如果我追加一句请明确说明有哪些可能影响现有系统的文件是您特意没有修改的AI 反而会自己再检查一遍边界并且常常能自己发现我刚才差点改了配置之类的潜在风险。这个简单的提问技巧能省下不少 review 审核成本。第三建立AI 安全禁区文件白名单。现在我在团队仓库里维护了一个ai-restricted-files.txt里面逐行列出了严禁 AI 修改的文件清单比如全局配置类、统一响应包装类、数据库访问基类、安全过滤器然后通过工具链在 AI 生成的结果里做自动拦截。只要 AI 的 diff 触发了任何一行白名单自动阻塞并强制人工处理。这比任何口头约定都可靠。事实证明白名单机制是我用过所有防AI 改坏手段中性价比最高的一个强烈推荐。5. 最后几句实操体会说了这么多我其实并不反对用 AI 写代码恰恰相反我觉得它是这些年里生产力提升最大的工具。我真正反对的是一种心态因为 AI 完成功能很快就默认它也能替你守住系统的边界。现实恰恰相反AI 最擅长的是把局部任务漂亮地完成最不擅长的是替系统全局承担风险。它是一把极锋利的刀但刀不会替你考虑手中还有多少条血管。我自己现在的工作习惯是每次拿到 AI 的改动强制自己先问三个问题这次它动了我系统中绝对不能动的东西吗它是否只改了任务相关的文件它有没有想用更聪明的方式替我重构某种约定三个问题里任何一个回答是我都会停下来人工亲手确认。这条路走下来从当初的频繁流程崩溃到现在的稳定精进我的体会是强大功能与稳定系统之间的天平靠的不是信任而是流程约束。如果你团队里也正在大规模使用 AI 辅助开发不妨把我这套思路直接抄过去尤其是那份约束提示词和禁区白名单。先难受一个星期后面你会发现AI 依然快但系统再也没被随随便便改坏过。
返回列表