
我把自己写进了墙角一次 AI Coding 的失控与自救如果你最近几个月一直在用 AI 写代码大概率遇到过这样一种状态需求提给 AIAI 改完测试通过功能上线看起来一切正常。但一个月后你想加一个新功能AI 改了一处另两个看似无关的地方炸了你让 AI 修 bug它修好了 A却把 B 的逻辑悄悄改掉了代码里开始出现一堆你完全不认识、也没人 review 过的补丁式实现。这不是个例。我之前就经历过一次典型的AI coding 失控项目前期推进极快后期每改一个需求都要花掉比预估多好几倍的排查时间。代码量不少但项目越来越难推进最后我不得不花了两天时间做一次技术债清理把 AI 生成的混乱逻辑完全重写了一遍才走出来。这篇文章不打算讲AI 编程好强大之类的正确废话也不打算劝你放弃 AI。我想认真拆解一件事为什么用 AI 写代码容易把自己写进墙角以及当代码已经失控时怎么用工程化手段把自己捞出来。本文会从问题现象、底层原因、自救流程、预防机制四个层面展开适合正在用 AI 编程工具做真实项目、但已经隐约感到代码越来越难维护的开发者。如果你只是拿 AI 写着玩可能体会不深但如果你用它交付过真实需求下面这些坑你大概率踩过。1. AI Coding 的失控是怎么发生的先说清楚我理解的写进墙角是什么状态。它不是AI 生成的代码有 bug那很正常它指的是AI 生成的代码在局部看都对但整体上已经失去了可维护性。几个典型信号信号一改动一个需求要动三个模块。功能上需求很普通比如把列表页的筛选条件从单选改成多选但 AI 生成的代码把筛选逻辑散落在组件、状态管理、后端查询三个地方。你让 AI 改一个点它会顺手把另外两个也改了而它改完之后你根本不知道改了什么。信号二同一个业务规则代码里出现了多份实现。因为 AI 是在对话上下文里工作的每开一个新会话它就不记得之前的代码了。这时候你让 AI 实现一个金额格式化逻辑它可能写了一份新的和旧函数功能重复但命名不同。反复几次之后代码里全是功能重叠但细节不一致的同族函数。信号三AI 每次重构都像推倒重来。你让 AI优化一下结构它不是小步重构而是直接给你生成一个全新的版本。看起来更好了但和旧的实现没有任何衔接你需要在心里默默完成一次代码迁移。信号四项目已经没有人能完整讲清楚。这最致命。代码是你让 AI 写的AI 每次都是基于上下文生成的但上下文在变、需求在变、文件在变。三个月后你再让 AI 看这个项目它对你的代码完全不熟因为它没有持久化的记忆。这些信号叠加在一起项目就进入了我说的墙角状态不是跑不起来而是每走一步都撞墙。我当时的感受是——我明明在用最先进的生产力工具为什么把项目写成了最典型的祖传代码2. 不是 AI 不聪明而是你的工作方式出了问题先别急着卸载 Cursor 或者回到纯手写。失控的关键原因其实不在 AI 本身而在于我们怎么指挥 AI。2.1 AI 是逐词预测器不是项目架构师大模型LLM生成代码的本质是根据当前对话上下文预测最合理的下一段代码。它没有你整个项目的全局概念它的全局理解来自你喂给它的上下文窗口。一旦你的项目超过它的上下文限制或者你把关键设计决策散落在多个对话里它就只能局部正确整体盲人摸象。这很像是带了一个非常聪明、但没有记忆的实习生你告诉他这个函数怎么改他改得很好但他不记得上周定的命名规范、不记得那个工具函数放在 utils 还是 helpers、不记得数据库字段的枚举值已经换过一轮。他每次都是在当前这条指令的全局里做最优解而不是在你的整个项目的全局里做最优解。2.2 任务粒度过大是失控的起点很多人的使用方式是这样的帮我加一个用户积分系统、帮我做一个后台管理端。这种超大粒度需求扔给 AI它确实能跑出一个 demo但如果你是在真实项目里这个 demo 和你的存量代码怎么融合AI 会生成一套全新的命名、全新的数据访问方式、全新的错误处理模式。一次两次没关系十次之后项目内部就有十套风格各异的微架构在互相打架。2.3 缺少工程约束和持续验证传统开发里代码规范、架构设计评审、单元测试、代码 review 会逐步约束系统复杂度。但 AI Coding 的工作流里很多环节被压缩了。我们往往看 AI 改完跑一下没问题就觉得完成。但能跑和可维护之间差着十万八千里。我复盘自己那次失控最后归结为三个词无约束生成、无记忆协作、无架构治理。AI 负责产出但没有人负责给它划边界。3. 自救第一步先冻结“新增功能”做一次冷静审计发现代码失控之后我第一反应是“再让 AI 重构一下”。但很快意识到这是最大的误区让失控的 AI 去重构失控的代码等于让一个失忆的实习生去给一个混乱的项目写架构文档它只会按它理解的“最佳实践”再写一套新的。正确的第一步是冻结新增需求停止让 AI 大面积动代码先做一次人工审计。我当时的做法分四步第一步整理项目文件清单明确每个模块负责什么。不追求精读每行只求把所有文件过一遍知道“什么东西存在”。第二步找出重复实现。用一个简单的搜索脚本扫描函数命名和关键词比如一个电商项目里金额格式化可能出现formatPrice、formatAmount、priceFormat、formatMoney不同实现。把它们列出来。第三步标记危险区域。所谓危险区域是指那些改一处会引发其它地方跟着变的代码。这类代码往往是 AI 在多个上下文里生成的“拼接件”耦合度极高。第四步梳理出必须保留的核心路径和可以删除的冗余路径。这个阶段不要纠结完美设计先分清楚“哪些代码是项目真正在跑的”以及“哪些是 AI 顺手生成但永远没人调用的”。这一步执行完我对自己项目有了一个清晰的“地图”。这个地图不是架构图而是“代码真实分布状况图”。没有这张图后面所有重构都是盲人摸象。4. 自救第二步用“写代码之前先写文档”的方式重置上下文我知道很多人不爱写文档尤其是用 AI 写代码之后更不喜欢写文档。因为我只要把需求给 AI它就直接给代码了还要文档干什么但失控的核心问题恰恰是项目的关键上下文只存在于 AI 的上下文窗口里没有沉淀到项目的可复用资产里。文档就是人类和 AI 之间共享的“永久记忆”。我这里的文档不是 Word 类型的需求说明书而是一份面向开发者和 AI 的结构化项目约定。我当时建了一个docs/ai-context.md文件内容大概是这样# AI Coding 上下文约定 ## 项目简介 这是一个面向商家的订单管理后台核心业务是订单录入、库存扣减、对账导出。 ## 技术栈 - 前端Vue3 TypeScript Pinia - 后端Node.js Express PostgreSQL - 部署Docker Nginx ## 目录结构与职责 - src/api/所有后端接口调用统一封装 - src/components/通用 UI 组件 - src/views/页面级组件 - src/utils/纯工具函数禁止放业务逻辑 - src/store/Pinia 状态管理禁止直接请求接口 ## 关键约定 - 金额单位统一用“分”整数禁止用浮点数。 - 枚举值必须在 src/constants/ 集中定义。 - 错误处理统一抛出 BusinessError由全局拦截器提示。 - 所有新增接口调用必须走 src/api/ 封装禁止在组件里直接写 axios。 - 样式方案统一用 CSS Modules禁止在全局样式里堆叠组件专用样式。 ## 常见冲突点 - 之前有过“列表筛选”功能散落在三个模块的问题新代码必须把筛选状态统一收敛到 Pinia 的 filterStore。 - 库存在两个系统中各有扣减逻辑任何修改库存的代码都必须走库存服务禁止直接操作库存表。这个文件的作用不是给人看的“流程文档”而是给 AI 的“越权边界”。当你让 AI 改代码的时候它不再是“看着局部代码猜全局”而是先看到了你已经踩过坑的约定它知道哪些地方不能碰、哪些模式必须遵守。写完之后我每次给 AI 一个任务第一句话都会说“先读docs/ai-context.md”。这一步花的时间极少但效果是后面所有步骤的基石。5. 自救第三步从“一步到位”改成“小步执行 持续验证”有了上面的上下文文档接下来要做的是把代码逐块清理出来。这里最忌讳的是“让 AI 一次性把全项目重构完”因为一旦 AI 改到一半翻车你可能连“原来哪里是好的”都分不清了。我采用的方法是分批迁移每一批只处理一个清晰边界。以我当时清理过的“筛选条件”为例第一步让 AI 先梳理现状而不是直接改代码。我会给它这样的指令请阅读 src/views/order-list/index.vue 和 src/store/filter.ts梳理当前订单列表页的筛选功能是如何实现的状态存在哪里组件通信如何完成哪些地方直接依赖了列表数据请用列表形式输出现状梳理不要修改代码。这一步的关键是不要让它改。先让它把现状说清楚你来判断它是否真的看懂了。如果它输出的现状梳理和你认知的代码完全不符说明它没读懂你后续让它改就是灾难。第二步确认现状后给定一个非常具体的重构目标并且目标要带有验收标准。基于现状梳理把筛选状态收敛到 src/store/filter.ts列表页组件只读取 filterStore 的状态并调用 fetchList()。重构过程中不允许改动接口返回字段不允许改动 order-list 之外的页面行为。完成后运行 npm run test 验证现有用例并把改动文件清单列出来。第三步审查 AI 的改动。尤其重点看它是否偷改了“不该改”的文件。AI 经常做着做着就超出范围你让它改 A它觉得 B 也“顺带可以优化”于是把 B 也改了。这在代码 review 里是最危险的因为你很难发现那些“看起来更好但根本不是本次任务范围”的改动。这一步的核心原则是小步、明确、可验证。一次只让它动一个模块跑完测试再进入下一个模块。不要高估 AI 的“理解能力”也不要低估它“超范围发挥”的意愿。6. 自救第四步用“能力边界”约束 AI而不是靠“对话商量”很多人喜欢用“自然语言商量”的方式跟 AI 对话比如“我觉得这段代码不够优雅你帮我改进改进”。但一旦项目进入恢复期这种对话方式会进一步失控。因为“改进”在 AI 看来是一个开放式的重构许可。我后来总结出一个更安全的工作流叫“三层控制器”。第一层配置文件控制器。把可以被 AI 修改的范围明确在docs/ai-context.md里圈定。AI 只允许改它可见范围内的文件不在范围内的文件要么直接告诉它“不要碰”要么在工具层面用权限配置限制。如果你用的是 Cursor可以考虑在项目里加.cursor/rules或者利用 AI 工具的 ignore 配置把node_modules、dist、docs等目录排除在 AI 可编辑范围之外。不同工具的配置方式不同但思路一致在工程层面限制 AI 的操作面而不是靠对话提醒它“注意不要改错文件”。第二层任务描述控制器。给 AI 的任务必须包含“输入、输出、边界、验收标准”四个要素。一条合格的指令像这样任务在 src/utils/order.ts 中新增函数 calculateOrderAmount。 输入order 对象结构参考 src/types/order.ts。 输出返回订单总金额单位分格式为 number。 边界不修改 src/api/ 下任何代码不修改数据库查询逻辑。 验收执行 npm run test 后所有用例通过并新增一条针对满减计算的单测。第三层验证控制器。每次 AI 改完代码必须跑测试、跑 lint、跑类型检查而不是只看“能不能运行”。我当时给项目加了一条硬性规定任何 AI 提交的代码如果没有通过 CI 的全部检查就不能合入主干。这一步很重要因为它把“AI 生成了什么”和“项目接受了什么”之间加了一道工程闸门。7. 从自救到预防把 AI Coding 变成规范化的工程流程写完墙角再往回看其实值得做的不只是“救火”而是把整个过程沉淀成一套可复用的 AI Coding 工作方法。很多团队现在都在讨论 vibe coding、spec coding、AI coding agent 这些概念但我认为落到真正的项目实践里核心其实只有两条一条是控制上下文另一条是控制验证。控制上下文的意思是不要让 AI 每次都在“未知全局”里自由发挥。你要么给出准确的上下文文件要么做严格的任务拆分要么用工具的工作区/规则文件把它的视野固定住。你给 AI 看的上下文越稳定它生成的代码就越一致。控制验证的意思是AI 生成代码之后必须有独立的、可自动化的验证环节。单元测试、类型检查、lint、契约测试这些都算。没有验证的 AI Coding本质上是在裸奔——你永远不知道它生成的代码是不是“看起来对实际上一碰就碎”。在这个基础上接下来几个方向值得继续深入方向一spec coding。不是让 AI 看着需求直接写代码而是先让 AI 帮你生成一份可执行的技术规格数据结构定义、接口签名、状态流转、边界条件。你 review 这份规格确认无误后再让 AI 按规格实现代码。规格越明确AI 的代码就越稳定。方向二AI agent 协同。如果你开始使用多 agent 协作比如一个 agent 负责生成代码、另一个 agent 负责 code review那么更要注意“上下文隔离”。每个 agent 应该有自己的角色职责和上下文范围不要让一个 agent 又写代码又做架构评审那它很快会把两种职责混在一起。方向三团队协作里的 AI 规范。如果你的团队有多个人同时在用 AI 编程必须早早定下统一约定哪些目录 AI 可以动、哪些目录只能人工改、AI 的代码必须走什么 review 流程、上下文文档由谁维护。团队里一旦出现“每个人都在用 AI但每个人都在让 AI 按自己的习惯写代码”的状态项目会以极快的速度走向失控。8. 常见问题与排查思路我在自救过程中踩过不少坑这里整理成一张表格供遇到类似情况的读者快速对照排查。问题现象可能原因排查方式解决方案AI 改一处代码导致多个文件行为变化任务边界不清晰AI 自行扩大修改范围检查本次改动文件清单对比是否超出任务描述为任务增加“边界”字段明确禁止修改的文件review 时必须逐个确认改动文件AI 生成了功能重复的“同族函数”AI 没有项目级记忆只根据当前对话生成用关键词扫描搜索重复函数在docs/ai-context.md中维护“功能清单”注明已有实现和文件路径让 AI 先读文档再动手让 AI 重构后代码结构和原来完全不同任务粒度过大AI 相当于重写了一套实现对比重构前后的 diff观察是否“推倒重来”拆分为小步迁移每步只改一个模块要求 AI 先输出现状梳理确认看懂后再改AI 生成代码通过编译但运行后业务逻辑错误缺少测试覆盖AI 只追求“编译通过”为关键业务路径补写单测和集成测试把“通过测试”作为验收硬性条件必要时让 AI 先写测试再写实现新增需求接入时风格和现有代码不一致缺少统一代码规范约束检查新增代码的命名、模块划分是否符合项目约定在上下文文档中加入命名规范、目录职责、常见冲突点团队多人使用 AI代码风格迅速分裂没有统一的 AI Coding 协作规范查看最近的代码提交比较不同人的 AI 使用方式建立团队级 AI 协作规范统一上下文文档和 agent 使用方式AI 修改了不该动的基础模块AI 认为该模块“需要优化”用 git diff 查看是否有超出任务范围的改动在工具配置层面用 ignore 规则排除核心模块或约定核心文件禁止 AI 直接修改9. 最佳实践与工程建议经历过这次“写进墙角再写出来”的过程之后我给自己整理了一套 AI Coding 的使用原则现在分享出来希望在你们用 AI 交付真实项目时能够直接避开前面那些坑。第一把 AI 当成“需要明确工作边界的协作者”而不是“万能编码器”。你给它越模糊的任务它回馈给你的就是越不可控的代码。你给它的任务越明确它的产出就越贴近你的预期。第二永远维护一份项目上下文的“活文档”。它不需要多长但必须包含技术栈、目录职责、核心约定、已知冲突点。这份文档是你和 AI 之间的“共同记忆”也是团队成员之间对齐的“公共契约”。每次过完一个里程碑都记得更新它。第三AI 生成的代码必须经过“人工审查点”。我最推荐的做法是每次让 AI 完成任务后你先看它的 diff而不是直接信任它说的“已完成”。你不需要逐行读完但至少要确认它没有改动任务范围外的代码。这一个动作就能过滤掉大量隐性风险。第四用自动化验证兜底。单测、类型检查、lint、CI这些不是额外负担它们是 AI Coding 的“安全带”。没有安全带之前你可以靠专注和小心驾驶有了 AI 之后你面对的是一个会自己“变道”的驾驶助手没有安全带是不行的。第五每隔一段时间做一次“上下文压缩”。AI 的记忆只存在于对话里但对话会越来越长、越来越偏离主线。当你发现对话里的代码和当前项目已经对不上了那就果断新开一个对话然后把“上下文文档 当前要改的文件 具体任务”一起发送过去。这比在旧对话里让它“接着上次继续改”要可靠得多。10. 总结与后续学习方向回到标题这个问题用 AI 写代码把自己写进了墙角怎么才能写出来我这边的答案是你不能靠 AI 再写一遍走出来你要靠工程化的方式走出来。AI 生成代码的速度越快你越需要稳定的“上下文、边界、验证”三重约束。否则AI 帮你提升的那部分效率很快就会以“技术债利息”的形式还给项目。这次自救过程给我最大的启示不是“AI 还不够强”而是AI 越强开发者的架构能力、边界意识、验证意识就越重要。你不一定需要手写每一行代码但你得知道代码应该长成什么样你不一定每一步都手工操作但你必须掌握每一步的控制点。后续如果你对这个方向感兴趣可以沿着几条线继续深入一是研究 spec coding。核心思路是把“让 AI 直接写代码”变成“先让 AI 写规格、人类审查规格、AI 按规格实现代码”它能在源头大幅减少 AI coding 的随意性。二是研究 AI coding agent 的多角色协作。现在的 agent 已经可以扮演“写代码的”“做代码审查的”“写测试的”等多种角色但如何给不同 agent 划分上下文和权限还是一个非常值得实践的工程问题。三是研究团队的 AI 协作规范。相比于个人使用团队里会用得更乱也更需要提前定规则。哪个目录允许 AI 动、谁负责维护上下文文档、AI 代码合入主干的条件是什么这些规则越早定项目就越不容易失控。如果你现在也正处在“AI 写代码很爽、项目越来越难受”的状态我给的建议是先暂停新增需求花半天时间做一次代码审计写一份ai-context.md然后把最近一个模块按“现状梳理 — 局部重构 — 测试验证”的节奏重新过一遍。这个过程不轻松但它是你从“被 AI 带着走”变成“带着 AI 走”的转折点。