让AI改一行代码diff里却多了几处你没提的改动——用AI编程的人都遇到过。我整理了5种最常见的暗改模式每种附真实代码和防范方法。从一个简单的bug说起最近改一个状态更新的bug三行代码的事。让AI改完习惯性看了一眼diff——改动不止三行。翻了翻最近的commit记录这种事不是第一次了。AI改代码有个毛病它不只改你让它改的地方还会顺手动一些它觉得应该优化的代码。有些改动无伤大雅但有些能直接让项目炸掉。下面是我总结的5种最常见的AI暗改模式每种都在社区里反复出现过。暗改一删掉没人用的文件——其实是框架自动加载的这是最危险的一种。AI在重构的时候会扫描代码引用关系。如果一个文件没有被任何地方显式import它就认为是死代码直接删掉。问题是前端框架有大量约定式文件不需要手动import。# AI觉得这些文件没人引用删了src/ ├── middleware.ts ← Next.js自动加载不需要import ├── app/error.tsx ← Next.js错误边界约定文件名 ├── plugins/analytics.ts ← Nuxt自动加载plugins目录 └── composables/useAuth.ts ← Nuxt自动导入composables目录// middleware.ts — 没有任何文件import它但Next.js自动执行import{NextResponse}fromnext/server;importtype{NextRequest}fromnext/server;exportfunctionmiddleware(request: NextRequest){const tokenrequest.cookies.get(token);if(!token){returnNextResponse.redirect(new URL(/login, request.url));}returnNextResponse.next();}AI看到没有任何引用判定为死代码。删掉之后——所有页面的登录校验没了未登录用户可以直接访问所有路由。上线之前跑测试大概率还能过因为单测通常mock了auth逻辑。同类情况还有Vite的import.meta.glob自动注册的路由/组件Vue的全局插件注册app.use(plugin)所在文件被删require.context动态加载的模块Webpack项目常见Tailwind CSS的content配置引用的工具class文件防范看到AI删文件先想一下这个文件是不是框架约定的。middleware、error、layout、loading、plugins/目录、composables/目录——这些名字自带魔法删了就炸。暗改二把同步改成异步——优雅地炸了启动流程AI特别喜欢把同步代码改成异步的。在它的训练数据里异步好几乎是共识。// 改之前同步读取配置启动时必须阻塞等结果 const configfs.readFileSync(./config.json,utf-8);const parsedJSON.parse(config);initDatabase(parsed.db);initCache(parsed.cache);startServer();AI觉得readFileSync不优雅改成了// AI优化后异步读取 const configawait fs.promises.readFile(./config.json,utf-8);const parsedJSON.parse(config);initDatabase(parsed.db);initCache(parsed.cache);startServer();看起来没问题问题在于这段代码跑在一个没有顶层await支持的CommonJS模块里。或者更隐蔽的场景initDatabase内部依赖同步的初始化时序异步化之后其他模块在config还没读完时就开始初始化了。这种bug极其难排查——启动流程偶尔成功偶尔失败取决于异步操作的完成顺序。同类情况localStorage.getItem被改成异步的IndexedDB调用构造函数里的同步初始化被改成async构造函数不支持async同步的校验逻辑被改成异步导致校验还没完成就放行了防范AI把同步改异步时问自己一个问题这里用同步是不是有原因的启动流程、构造函数、校验逻辑——这三个地方的同步代码通常都是故意的。暗改三重构时弄丢了一个breakAI在做代码搬移或重构的时候偶尔会丢失控制流逻辑。最常见的是switch里的break和循环里的提前返回。// 改之前functionprocessItems(items){for(const item of items){if(item.typeinvalid){logError(item);break;// 遇到无效项就停止处理}transform(item);}}让AI重构这段代码比如拆成更小的函数// AI重构后functionprocessItems(items){for(const item of items){handleItem(item);}}functionhandleItem(item){if(item.typeinvalid){logError(item);return;// 这个return只退出handleItem不退出循环}transform(item);}break变成了return但语义完全不同。原来遇到无效项整个循环停止现在只是跳过这一项继续处理后面的。如果无效项后面的数据依赖前面的校验结果后续处理全是脏数据。同类情况continue在提取函数后变成return语义改变嵌套的break带label的被AI忽略直接删掉labelthrow在try-catch重构后被catch吃掉异常不再向上传播防范重构后的第一件事——diff里搜break、continue、return、throw。这四个关键词的任何变动都要逐个核对原始逻辑。暗改四给你两行代码套了三层抽象你让AI写一个判断空字符串的工具函数期望得到这个functionisEmpty(str: string): boolean{returnstr.trim().length0;}AI给你的interface StringValidator{validate(input: string): ValidationResult;}interface ValidationResult{isValid: boolean;reason?: string;metadata?: Recordstring, unknown;}class EmptyStringValidator implements StringValidator{privatereadonlytrimBeforeCheck: boolean;constructor(options?:{trimBeforeCheck?: boolean}){this.trimBeforeCheckoptions?.trimBeforeCheck ??true;}validate(input: string): ValidationResult{const processedthis.trimBeforeCheck ? input.trim():input;return{isValid: processed.length0, reason: processed.length0?String is empty or whitespace:undefined, metadata:{originalLength: input.length, processedLength: processed.length}};}}exportconst isEmpty(str: string): boolean{return!new EmptyStringValidator().validate(str).isValid;};两行逻辑变成了三十行。接口、类、配置项、元数据——全套。这种暗改不会让项目崩溃但它会让代码库快速膨胀。三个月后团队里没人敢碰这些AI写的专业架构因为看起来太正式了改了怕出问题。同类情况一个简单的fetch请求被包成了带重试、超时、拦截器的HTTP Client类一个环境变量读取被封装成了配置中心热更新类型校验一个数组过滤被改成了策略模式责任链防范如果你让AI写的功能用一句话就能描述清楚结果代码超过20行——大概率过度设计了。删掉让它重写prompt里加一句用最少的代码实现。暗改五把你手动改好的代码优化回去这是最让人崩溃的一种。你在AI生成的代码里发现了一个问题手动改好了。过了一会儿让AI继续改另一个地方它把你的修复给优化没了——因为它的上下文里记住了自己之前生成的版本认为那才是正确的。// AI第一次生成的 useEffect((){fetchData();},[]);// 你手动加了依赖项 useEffect((){fetchData();},[userId]);// ← 你手动加的 // 让AI改另一个bug它顺手改回来了 useEffect((){fetchData();},[]);// ← AI改回空数组了因为它觉得空数组是对的AI不理解你为什么改了它的代码。在它看来空依赖数组是标准写法你加的[userId]是多余的。这种情况在长对话中尤其频繁。对话越长AI越倾向于用自己早期生成的版本覆盖你的手动修改。防范手动改完AI的代码后开一个新对话再继续后面的任务或者在prompt里明确说不要修改useEffect的依赖数组那是我故意改的养成习惯每次AI改完代码完整看一遍diff不只看它改的地方看所有改动AI暗改防范速查表暗改类型危险等级排查方法预防措施删死代码致命diff里搜删除的class/文件有框架注解的class不是死代码同步改异步致命diff里搜async/await新增启动/构造/校验的同步是故意的丢失break/return高危diff里搜break/continue/throw重构后逐个核对控制流过度抽象低危一句话需求超20行代码prompt加最少代码实现覆盖手动修改致命看完整diff不只看改动点改完手动代码开新对话一条通用原则AI每次改完代码看完整diff不只看你让它改的那行。这不是AI的错说到底这些暗改不是AI故意搞破坏。它在做它认为正确的事——清理死代码、优化性能、统一风格。问题是它没有你项目的完整上下文不知道哪些不规范的代码是故意写成那样的。AI是一个能力很强但完全不懂你项目历史的新同事。你不会让一个刚入职的人直接push到main对AI也一样。你遇到过AI最离谱的暗改是什么评论区聊聊。