首页 / 资讯中心 / 文章详情

AI编程助手越帮越乱?提案式编辑把决定权还给你

AI编程助手越帮越乱?提案式编辑把决定权还给你 ★ FEATURED ARTICLE
不知道你有没有经历过这种时刻装上某个 AI 编程助手头三天感觉自己是全世界最幸福的开发者代码哗哗往外冒需求一两句就能变成能跑的模块。两周后再打开仓库却发现自己面对一堆不认识的函数签名、重复了三遍的工具逻辑、还有若干被顺手优化到没人敢碰的核心模块。想回滚git 历史比你的发际线还乱提交信息写着refactor但你根本不知道它动了什么。这个现象不是我一个人的错觉翻翻各种技术社区的吐槽帖越帮越乱几乎成了 AI 编程助手的默认评价。今天这篇文章我想把这个问题拆开看它到底出在哪为什么不是换个模型、调几个参数就能解决的。然后我会聊聊我在调研中遇到的一个 93K Star 的解法——一个来自 TypeScript 圈、作者非常硬核的开源项目。它没有走帮你想、帮你写、帮你改的老路而是换了一套完全不同的思路AI 只做提案你做决定。这套机制怎么运作、为什么偏偏是 TypeScript 圈子的人做出了这个答案、我用它跑完一次真实重构之后的体验如何下面一项一项说清楚。1. AI 编程助手越帮越乱四种典型的翻车死法1.1 死法一上下文窗口耗尽后的逻辑漂移用过 AI 辅助编程的人基本都见过这个场景你跟助手描述一个需求它给出了第一版代码看起来不错。你让它改一个边界条件它改了但把另一个边界弄坏了。你继续让它修它又改了一个地方这次把之前的逻辑也带偏了。反复几轮之后代码变得看起来对但实际已经和你最初的意图差了十万八千里。原因在于大多数 AI 编程助手是把整段对话历史塞进上下文窗口。窗口有上限一旦超过系统就开始截断最早的内容。于是 AI 对项目的理解会逐渐漂移——它记住的是你最近几条指令里的局部信息而忘了最初的约束条件。这就像一个人带着一张不断缩水的任务清单干活干到后面只记得眼前这一件事忘了整体目标。更隐蔽的是很多助手在截断后不会告诉你我忘记上下文了而是继续自信地生成代码。它自己都不知道自己丢了信息你怎么指望它主动纠错这是生成式模型的结构性问题不是本地调一调提示词就能绕过去的。1.2 死法二幻觉 API 与看起来合理的伪代码第二个常见死法是 API 幻觉。AI 会生成一个不存在的函数、不存在的参数、不存在的包而且因为生成模型擅长编造合理的东西这些幻觉代码往往语法正确、风格统一光看根本看不出来问题。我印象最深的一次某个助手帮我封装了一个缓存工具用了一个它自己发明的第三方库还贴心地写好了安装命令。我照着装上编译直接报错——因为那个库压根不存在。这种错误比语法错误更恶心语法错误编译器会告诉你而幻觉错误要等到运行时、甚至等到特定条件下才会暴露。一个隐藏在核心链路上的幻觉函数可以让整个服务的稳定性变成笑话。1.3 死法三无差别重构与顺手优化比幻觉更普遍的是 AI 的热情过度。你让它修一个 bug它顺手把旁边的函数重命名了你让它加一个字段它自作主张把整个类重构了一遍。在它看来这是顺手优化在你的角度看这是未经授权的破坏性变更。关键问题在于AI 没有最小改动这个概念。它理解的是让代码变得更好而不是让代码在你的控制下变得更好。如果你不严格约束它它会倾向于重写而不是修改倾向于大改而不是小改。改完之后测试全绿还好要是测试覆盖率不高你根本不知道它偷偷动了什么。这种黑盒重构是团队协作里最危险的因为它破坏了代码评审最基本的前提——你知道变更范围。1.4 死法四错误叠加与负反馈螺旋最让我头疼的是第四种AI 在错误的基础上继续修复。代码出了问题它给出的补丁本身就有问题你跑了测试报错它基于这个报错再生成第二个补丁结果第二个补丁为了绕过第一个的错误引入了更绕的逻辑。几轮下来代码复杂度和不可读性同时爆炸。这背后的本质是生成式模型没有真正的执行反馈闭环。它不是在运行-观察-修正的循环里工作而是在推测-输出的循环里工作。它看不到测试失败的堆栈看不到 Lint 的输出更看不到运行时性能变化。没有这些信号它的自我修正实际上只是再猜一次而且猜的次数越多累积的偏差就越大。这就像蒙着眼睛开车打了方向盘但不知道车往哪边偏越修越歪。2. 93K Star 背后的核心思路把决定权从 AI 手里拿回来2.1 这个项目发生了什么从替你写到给你选在踩了一圈坑之后我开始关注一个来自 TypeScript 圈的开源项目——确切说是一个用 TypeScript 编写、在开源社区攒下 93K Star 的 AI 编程辅助工具。说实话我一开始看它的 README 没太当回事直到真正用起来才意识到它解决的恰恰是上面那四种死法共通的根源AI 拥有太多自主决策权。这个项目没有走Agent 自动改代码的路子而是把工作流拆成了两个阶段。第一阶段AI 读取你的代码、分析问题、生成一份详细的变更提案第二阶段它把提案展示给你由你逐项确认、修改或否决。只有你点头的提案才会真正落到文件系统里而且每个提案会先自动创建一个 git 分支应用失败或者你不满意一条命令就能干净利落回到原点。听起来很简单对吧但你仔细琢磨一下会发现这个设计刚好打在了所有越帮越乱案例的七寸上。AI 不再拥有写就写的能力它拥有的只是提议的能力最终执行权始终在开发者手里。上下文截断导致的逻辑漂移因为每次提案都是基于当前仓库实际状态重新生成的漂移累积不起来幻觉 API因为提案阶段会附带解释和影响范围分析你更容易发现它编了什么东西无差别重构因为提案按文件、按符号拆分改动范围一目了然错误叠加因为每个提案独立验证、独立回滚不会在错误地基上继续盖楼。2.2 为什么 TypeScript 是这个方案的关键拼图可能有人会问一个 AI 编程辅助工具用什么语言写真的很重要吗我的答案是在这个项目里TypeScript 不是实现语言那么简单它是整个方案成立的前提之一。第一类型系统本身就是约束。AI 生成的提案要经过 TypeScript 编译器的校验才能被标记为可应用类型错误直接被弹回。这意味着 AI 不能随便发明一个不存在的方法或者搞错参数类型——语法层面的幻觉在审核之前就被拦截了一大半。第二TypeScript 的生态里有非常成熟的 AST抽象语法树处理工具。这个项目对代码的修改不是基于字符串替换而是基于 AST 级别的结构化编辑它知道改这个函数和改这个函数里面的某一行的区别能精确追踪每个符号的引用位置。字符串替换做不了的安全重构在 AST 层面可以做。第三也是常被忽略的一点TypeScript 社区对工程质量的要求普遍很高。这个项目的作者是那个社区里出了名的硬核人物写代码极其较真对测试覆盖率、类型安全、文档完整性都有近乎苛刻的标准。你去看这个仓库的 issue 区会发现很多讨论不是加个功能而是这个边缘情况的类型定义不严谨。这种社区文化决定了它做出来的工具天然会把安全放在效率前面。这是那些快速迭代的 Python 脚本式 AI 工具很难复制的基因。2.3 一个比喻它更像代码评审而不是自动驾驶如果非要用一个词概括这个项目的设计哲学我会说它是副驾驶而不是自动驾驶。自动驾驶的逻辑是我替你开你负责坐好。副驾驶的逻辑是我帮你看路、提建议、提醒你哪里有风险但方向盘始终在你手里。副驾驶模式的直接好处是团队里的每个人对代码变更都有完整的知情权和控制权。你不理解某个改动可以不合并它你觉得某个重构方向不对可以直接打回。整个过程完全是在 git 的正常工作流里进行的不会出现AI 已经改了三个文件但你完全不知道的失控状态。对于一个人维护的小项目来说这个差别可能不明显但到了需要 code review 的团队场景自动驾驶式的 AI 助手几乎必然引发冲突而副驾驶模式能顺畅地嵌进现有的评审流程里。3. 机制拆解提案式编辑、原子操作与范围控制3.1 提案式编辑每个改动都先过审这个项目的核心数据结构是提案Proposal。一次 AI 交互不是直接产生代码 diff而是产生一个结构化提案对象它包含四个部分目标描述为什么改、变更范围涉及哪些文件、哪些符号、具体代码片段修改前后对照、风险提示哪些调用方可能受影响。我实际使用中最大的感受是这个结构强制 AI 先做阅读理解再动手。以前用别的助手我说帮我把这个函数改成异步它会直接甩一段新代码给我至于改了之后哪些地方需要加 await、哪些调用方的错误处理要变它一概不管。这个项目不会这样它在生成提案之前会先扫描整个仓库里所有引用这个函数的位置并且在提案里老老实实列出这个改动会影响以下 7 个文件其中 3 个需要同步修改错误处理逻辑。这些信息都是人看得懂的也是可以逐条质疑的。我不再需要去 diff 里扒拉 AI 到底改了哪儿提案本身就是一个自带说明书的 diff。3.2 原子操作与自动回滚像数据库事务一样管理代码变更提案式编辑如果没有配套的安全机制只会多一层麻烦而不是多一层保障。所以这个项目的第二个关键设计是原子性每个提案从应用到回滚都是一个完整的事务。具体做法是当你选择应用某个提案时工具会自动基于当前 HEAD 创建一个临时分支在临时分支上应用变更、跑测试、跑类型检查。如果全部通过它把分支合回来如果失败它直接丢弃临时分支你的工作区干净得跟什么都没发生过一样。整个过程你可以理解为数据库里的 begin / commit / rollback。这个设计解决了一个我前面提到的核心痛点错误叠加。以前 AI 改坏了你得自己 git revert然后祈祷 revert 本身不会引入冲突现在它把尝试和保留分开了尝试失败的成本趋近于零。我可以放心大胆地对 AI 的提案说你先试试反正不行就回滚。这种心理安全感看起来微不足道但实际使用中它大幅提升了我试用 AI 提案的频率——人只有在不担心后果的时候才愿意多做尝试。3.3 范围控制知道什么时候该不碰第三个关键机制是范围控制。这个项目允许你给 AI 划定明确的行动边界包括文件级、符号级和仓库级三个层次。文件级边界最好理解你可以指定只允许修改 src/core 目录下的文件AI 的提案如果越界工具会直接拦截。符号级边界更有意思你可以指定允许修改 utils/date.ts 里的 formatDate 函数但不允许碰同一个文件里的 parseDate。这种细粒度控制在官方文档里叫symbol-level fencing实际使用中我觉得它特别适合那种有一颗定时炸弹但有太多依赖的旧文件——你希望 AI 只拆特定区域不要顺手清理其他地方。仓库级边界则适用于 monorepo你可以让 AI 只在一个子包里工作不影响其他包。说实话这个范围控制机制我第一次用的时候没当回事觉得反正我自己会看 diff。但用久了才发现它真正的价值不是防止 AI 越界因为我本来就能在审核时发现而是防止 AI 自己不知道自己越界。AI 一旦越过边界去改了别的文件它在后续提案里就会基于这个错误的变更继续推理把越来越多的无关改动牵扯进来。范围控制相当于从源头掐断了这种越界-污染-再越界的连锁反应。3.4 上下文管理不让 AI记太多反而让它每次重新看前面说上下文窗口耗尽会导致逻辑漂移这个项目对这个问题没有采用加大窗口的解法而是采用了不依赖长上下文的解法。它的交互方式不是传统的一问一答长对话而是任务式的短会话。每当你把项目状态同步给工具它会重新分析当前的仓库快照而不是凭记忆回答。也就是说AI 每次给出的提案都是基于当前真实代码状态生成的而不是基于之前某轮对话里它自己的推测。这就切断了错误累积的链路——上一轮 AI 理解错的东西不会进入下一轮因为下一轮它重新睁开眼睛看代码了。代价是每轮多花一点分析时间但换来的是提案质量的稳定。我在一个 5 万行左右的项目里测过一轮分析大概 10 到 20 秒完全在接受范围内。而且这个设计跟人的工作习惯也很匹配你本来就不是连续 8 小时盯着 AI 聊天你是分段任务的——改完一个功能去喝杯水回来继续下一个。短会话恰好对应你的自然工作节奏。4. 实操记录用它跑完一次真实重构4.1 环境准备装好之后第一件事是配边界先交代一下我的测试环境一个维护中的中型业务系统后端 Node.js TypeScript大约 5 万行代码前端 React测试覆盖率还行但不完美。我选了这个项目的一个老模块做实验——那个模块的日期处理逻辑一直有 bug但改动风险高平时没人敢动。安装过程不复杂一条命令装全局 CLI然后在你自己的项目里初始化配置文件。配置的核心是两件事第一告诉工具哪些目录是可以碰的哪些是绝对禁止的第二配置测试命令和类型检查命令因为工具要用它们来验证提案。提示初始化配置时我强烈建议你把 node_modules、dist、build 这些目录直接拉进禁止名单。虽然工具一般不会主动动它们但多一层保险没坏处。我后来遇到过几次 AI 提案里意外包含 build 产物路径的情况幸亏提前堵住了。4.2 第一步让 AI 先读懂再开干重构任务是这样的把模块里散落的 7 处日期格式化逻辑统一收敛到一个新的工具函数里并且修掉其中两处时区偏移 bug。我把它拆成一个任务描述发给工具但是特意没有给怎么做的指令只给了目标是什么。结果它返回了一整套分析它先列出了这 7 处逻辑各自的位置、输入输出和现有测试覆盖情况然后给出了一个重构顺序建议——先改哪些后改哪些每步的影响范围是什么。这个先分析后动手的过程放在传统 AI 助手那里是完全没有的传统助手听到需求直接就开始改了。这一步给我的启发是AI 编程工具的价值不仅在于生成代码更在于生成对代码的理解。而只有当工具先充分理解代码、再把理解结果摊开给你看的时候你才有机会纠正它早期理解偏差。我那次就发现它对其中一处调用的输入类型理解错了——它以为那个函数接收的是 UTC 字符串实际接收的是本地时间的 ISO 字符串。因为它在提案里写清楚了假设我才来得及指出错误避免了后面一连串的返工。4.3 第二步逐个审提案该改的改该拒的拒分析完成之后工具一口气生成了 6 个提案按依赖顺序排好了。我一个个审过来提案 1新增统一的时间处理工具函数纯新增无破坏性直接应用。提案 2修改第一处调用点把逻辑切换到新函数。这里我发现它漏了一个时区参数手动在提案里加了然后应用。提案 3修改第二处调用点。这个其实和第一处调用逻辑几乎一样但它没有合并而是单独列了一个提案。好在审核成本也不高逐条看反而更清楚。提案 4修改第三处调用点。这里它没有按我的要求处理时区偏移我直接否决了并在备注里写了原因。工具没有任何情绪也不会觉得被拒绝了很受伤重新生成了更合理的版本。提案 5、6清理旧的废弃逻辑。它列出的清理范围比我想象的大我删掉了其中两个它想动的函数只保留了真正不再被引用的部分。整个审核过程大概花了 40 分钟。坦白说这不是一个很快的速度若我用传统助手自动改可能 10 分钟就改完了。但差别在于传统助手改完我不放心需要自己重新检查每一处这个项目改完我在审核阶段就已经把每一处改动都看过了后面的检查只是走个过场。总时间算下来反而是这个项目更省。4.4 第三步验证与回归一次标准化的验收流程所有提案应用完毕之后工具自动跑了一遍我配置好的检查流程TypeScript 类型检查、Lint、测试。第一轮跑下来有两个测试挂了挂的位置让它定位到第 4 个提案的时区处理逻辑上。我修复了提案里的错误重新应用再跑全绿。这里有一个体验上的细节特别值得说因为每个提案都是独立分支上应用的当测试失败时工具直接把失败定位到了具体提案而不是给我看一整坨 diff。它甚至能告诉我这个提案里有两个改动点第 2 个改动点引入了时区错误。这种精确到改动点的归因能力放在传统助手的使用场景里是不可想象的——以前遇到这种情况我只能面对一坨已经覆盖了三个文件的改动自己猜哪里错了。4.5 一次真实踩坑它也不是万能的说了这么多好处也得说说它不完美的地方。那次重构中我遇到过一个它处理不了的情况一个旧文件里有大量风格奇怪的代码工具的分析引擎对它的 AST 解析不完全导致它对其中某些符号的引用追踪遗漏。它生成的提案里把一个仍然被动态引用的工具函数标记成了无引用差点被清理掉。还好我审核的时候多看了一眼调用栈发现了问题。这也提醒我任何 AI 工具的全量分析都不能 100% 保证覆盖到动态调用、反射调用这些边角情况。在你决定应用一个删除 XX 函数的提案之前最好自己先全局搜索一下那个函数名的所有出现位置。工具能帮你拦截 90% 的问题剩下 10% 永远要靠你的判断力兜底。5. 横向对比同样的 AI为什么用出了两种效果5.1 一张表看清三种工作流的本质差别为了让自己更直观地理解这个项目和其他 AI 编程助手的差异我整理了一张对比表按工作流维度列出了三种典型方案的特征维度传统对话式助手自动 Agent 式助手提案式编辑工具改动前是否需要分析不需要简化版强制先产出分析报告谁拥有最终决定权AI你事后才发现AI你事后 Review你你事前逐项审批回滚成本依赖 git 手动处理依赖 git 手动处理每个提案独立安全回滚上下文连续性依赖长对话依赖长上下文每次基于仓库快照重建范围控制无弱文件级/符号级/仓库级错误归因难较难精确到提案内改动点上手门槛低低中等需要理解审核流程这个表不是要说前两种方案一无是处。事实上在探索性的快速原型阶段传统对话式助手依然非常高效——你想在半小时内搭一个验证 demo根本不需要提案审核这种流程。但当你面对的是要长期维护的生产代码提案式编辑的安全优势就会全面体现出来。5.2 为什么你的代码库越小越觉得这个项目慢还有一个现象值得聊为什么很多人在小项目上用这个项目觉得太慢了因为在 200 行代码的项目里你自己看一眼就能搞定的修改AI 还要先分析再提案再审核纯属脱裤子放屁。这个项目的适用场景有明确的边界当项目规模超过你的个人脑内缓存容量时它的价值才开始显现。什么是脑内缓存容量就是你能在不借助工具的情况下清楚地记得一个函数被哪些地方调用、改动它会影响什么。对大多数开发者来说这个容量大概是几千行代码。一旦超过这个量级你对改动影响的预判就会下降这时候 AI 的全仓库扫描能力就比你个人的记忆力可靠了。我现在的用法是分场景切换临时脚本、学习 Demo、一次性工具直接上传统助手怎么快怎么来生产仓库、多人协作模块、没有人敢乱碰的老代码就用提案式编辑。两种工具不是替代关系是不同场景下的不同工具。5.3 它的代价学习成本和过程感说句公道话提案式编辑是有代价的代价就是过程感变重了。传统助手是一问一答像微信聊天轻快随意这个项目是任务分析、提案列表、逐项审批像个正式的项目评审会。前者舒服后者安心但它们的时间成本不一样。还有一个隐性成本它需要你有一定的代码评审能力。如果连你自己都看不出提案里的逻辑问题那再好的提案机制也只是加了流程的 AI 幻觉。换句话说这个工具放大的是你已经具备的工程判断力而不是替代你的工程判断力。这个定位很诚实也很值得我们思考——它默认开发者是专业的人而不是一个只需要按确定按钮的操作员。6. 实测中的几个反直觉发现6.1 AI 写代码最怕的其实是不敢停用这个项目一段时间之后我观察到一个反直觉的现象在提案式工作流里AI 生成的代码质量反而比在自动模式下更高。一开始我以为这是错觉后来想明白了——因为它知道自己每个提案都会被审查所以它不敢乱写。它会更谨慎地分析调用关系、更仔细地检查改动影响、更倾向于生成带注释的解释性代码。换句话说审查机制本身改变了 AI 的行为模式。这有点像考试的时候知道有人会逐行看你的答案你下笔自然会更谨慎。自动 Agent 模式下 AI 肆无忌惮地写是因为反正没人逐行看——你说帮我改它改完你说测试挂了它再改。它没有动力在第一轮就做到最好因为所有错误都要靠你事后发现。提案式工作流把这个逻辑彻底倒过来了。6.2 先写分析、后写代码比一步到位更高效第二个反直觉发现是强迫 AI 先写分析报告并不会降低效率反而提升了整体产出速度。因为分析报告是廉价的一次分析如果方向错了改起来容易一段完整代码如果方向错了修改成本就高很多。这个项目把分析和实现分成两个阶段等于先把不确定性扼杀在成本最低的阶段。我自己的经验数据是让它先分析再动手第一版提案的可接受率大约在 70% 左右而直接让它动手的传统模式第一版代码的可接受率可能只有 30%。虽然前者多了一步分析时间但少了后续大量的发现问题-通知-修改-再验证循环。整体算下来前者的总耗时反而更短。这件事放在任何工程领域都是常识——先设计再施工永远比边施工边改设计省钱。6.3 大型仓库里的一个实战技巧按任务拆分会话最后一个反直觉发现涉及使用技巧。一开始我把这个项目当成传统助手用一个会话里塞了好几个无关的小任务结果发现它的分析质量明显下降——因为任务之间会互相干扰它对 A 任务做的改动会影响 B 任务的分析基线。后来我学会了一个技巧一个会话只谈一个任务任务之间用 git commit 隔开。这背后的逻辑也简单项目的上下文管理是基于仓库快照的如果你在同一次会话里改了两个无关区域它的下一次分析就要同时考虑两个区域的变更复杂的负担成倍增加。拆成独立会话后每个任务的分析基线都是干净的提案质量显著回升。这个技巧文档里没有写是我自己踩了几次坑之后总结出来的分享给大家。7. 一点个人体会工具再好也换不掉你的判断力用了这个项目一段时间我的总体评价是它没有让我写代码更快但让我写的代码更安全也让 AI 辅助编程这件事重新变得可控。以前用自动 Agent我总有一种在跟一个不太靠谱的实习生合作的焦虑感用提案式编辑我的感觉更像在跟一个读代码极快的资深同事做结对编程——它提议我把关两边都舒服。最后分享一个使用心得不管工具怎么进化AI 编程助手能替代的是从意图到代码的翻译过程替代不了从业务到意图的决策过程。工具能保证每个提案是安全的但只有你知道这个功能到底该不该做、这个重构方向对不对。我见过一些人把所有决策权都交出去最后代码库变成了一个看起来在演进、其实没人理解的黑盒那比越帮越乱更可怕——因为乱还能理清不理解的东西连理都无从下手。如果你现在也被越帮越乱困扰我的建议是别急着换更强的模型先换一种工作流。让你的 AI 从代驾变成副驾驶把方向盘牢牢握在自己手里。这个 93K Star 的项目给了我一个很好的示范也希望这篇记录能给你带来一点启发。
阅读完成 · 觉得有帮助?
咨询建站