ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

当AI编程助手太会代劳:一个老工程师的卸载反思与判断力自救

当AI编程助手太会代劳:一个老工程师的卸载反思与判断力自救 上个星期二晚上我把电脑上所有 AI 编程插件都卸载了。不是卸载某一个是全部。说出来可能有点反直觉我并不是因为 AI 写不好代码才卸载它。恰恰相反它写得太像“人写的代码”太通顺、太完整、太正常了以至于我连续三周在代码审查中发现了同一类问题——那些代码没有语法错误没有明显 bug却正在往代码库里注入一批我不完全理解的、没有推导过程的复杂度。那一刻我意识到真正让我不安的不是我审查的速度变慢了而是我发现自己的判断力正在被一种“看起来靠谱”的输出一点点架空。一个写了 20 年程序的老工程师最终决定把 AI 请出自己的编码工作流不是它不够强而是因为它太会“替我做决定”了。这篇文章不打算劝任何人卸载或安装什么只想把一个使用了一年多 AI 编程助手、最终选择退回传统工作流的真实过程和判断标准写清楚。1. 卸载的导火索其实不是“AI写错”而是“AI写得太正常”1.1 连续三周我在 review 里发现了同一类问题过去一年里我的日常工作流基本上是这样的接到需求先让 AI 补全函数骨架再让它生成单元测试然后让它帮忙优化一段性能不太好的循环。坦白说在最开始的几个月这个流程让我产生了一种“我比以前快了很多”的错觉。尤其是写脚本、写工具类、写配置文件的时候AI 的表现确实像一个熟练的初级工程师。但问题也在这个过程中慢慢积累。我负责维护的一个支付对账模块三周内出现了两次线上问题。一次是时间边界处理错误一次是金额在极端小数位时出现了精度偏差。两次都不是那种肉眼可见的逻辑错误。代码格式规范变量命名清晰单元测试也覆盖了正常路径。但 AI 生成代码时选择了看起来最简洁、最常见的实现方式而不是这个业务场景里必须采用的那种带防御性判断的写法。这不是 AI 不懂业务而是它默认把“正常情况”当成了全部。它不知道这个字段在历史数据里曾经出现过空字符串不知道这个接口在凌晨两点会被一个老旧的批处理任务触发也不知道产品经理在两年前的会议上明确说过“这个场景宁可不处理也不能误判”。这些信息不在它的上下文里但代码审查者知道。于是 review 变成了一个非常消耗注意力的过程我看到一段 AI 生成的代码第一反应不是“它写对了没”而是“它为什么这么写”“它默认了哪些条件”“这些条件在这个模块里成立吗”。如果是我自己写的代码我至少知道哪些地方是试探性的、哪些地方是有意为之的。但对于 AI 生成的代码我失去了这个判断锚点。1.2 “没有错”和“是对的”之间隔着业务上下文和工程约束我后来想通了一个问题AI 编程工具最大的风险不是因为准确率不是 100%而是因为它的输出结果具有“看起来正常”的迷惑性。人类工程师写代码时通常会在不确定的地方留下痕迹。可能是命名更谨慎可能是多加了一个注释可能是用了更笨但更可验证的写法。这些痕迹是经验的副产品。而 AI 生成代码的风格是“平均值”——它会把网上的常见写法、常见命名、常见结构融合起来产出一段在任何代码库里看起来都不突兀的代码。这段代码没有编译错误通过了单测reviewer 也很难快速挑出毛病。但真正的风险恰恰藏在这里当代码看起来越正常审查者的警惕性就越低。而业务系统的绝大部分事故都发生在“看起来正常但默认条件不成立”的边界上。这不是 AI 工具的缺陷而是它的设计目标决定的。它被训练成“补全最可能的后续 token”而不是“在特定约束下推导出最正确的实现”。前者追求的是纹理上的相似后者追求的是语义上的正确。如果你把前者当成后者来用问题不在工具在使用方式。1.3 我的判断AI 不是把关老师只是一个“无限次尝试的实习生”如果把 AI 编程助手比喻成团队成员它更像一个精力旺盛、知识面很广、但缺乏业务记忆的实习生。它能快速给出草案能降低空白页焦虑能在你明确指令下完成大量重复劳动。但你不能让它独立对线上服务质量负责不能让它的输出直接越过审查进入主干更不能因为它“说得很有道理”就省略自己的判断。所以我卸载 AI 编程助手这件事本质上不是一次“取关”而是一次职责重定位失败后的“止损”。我希望它成为“草案生成器”但产品形态和使用惯性一直在推着它变成“决策者”。当我把“生成”和“决策”这两件事交给同一个工具时我的判断力就开始退场了。这里最关键的分界线是AI 负责生成候选方案人类负责判断哪个方案在业务约束下成立。一旦这条线模糊AI 的效率和它的风险就会一起放大。2. 拆开“AI体验很好”的包装里面有几笔隐性成本2.1 上下文塑造成本省下的敲键时间被提示词重构吃掉了AI 编程助手给人的第一印象是“我描述得越具体它输出得越准确”。于是你慢慢发现为了让一段函数生成得足够好你需要先描述模块背景、数据结构、边界条件、命名偏好、历史包袱甚至还要把相关的几个接口签名粘贴进去。这个过程本身就需要时间和思考。以前写一个工具函数我直接写也就十分钟。现在我要花三分钟整理上下文三十秒等它输出两分钟审查再花五分钟修改不符合需求的细节。表面上看我“没有从零写”但实际上我付出的认知成本并没有少多少。真正的差距体现在隔天维护时AI 五分钟生成的那个函数我只花了三分钟看但一周后我再看它时已经想不起来它为什么要处理某个 edge case。因为那是 AI 根据我当时的提示词补全的不是我自己推演出来的。知识没有经过我自己的推导过程就不会留在我的工作记忆里。短期效率是拿了长期可维护性是在打折的。2.2 代码审查成本越“干净”的代码越难快速判断对错一个容易被低估的事实是AI 生成代码的审查成本通常高于自己手写代码的审查成本。自己写代码时你脑子里有一套决策路径这里为什么用 Map那里为什么不用 Optional这段为什么先校验再查询。这些决策可能不够完美但你可以对每一个选择负责。审查自己的代码你是在检查已知的决策链有没有漏洞。审查 AI 生成的代码你面对的是一个没有上下文的成品。它把决策过程吞掉了只把结果留给你。你只能通过结果反推它当时“可能”基于什么假设。反推的次数一多审查就从“沿着逻辑走一遍”变成了“猜测对方的意图”成本高出一个量级。更麻烦的是AI 生成的代码往往风格统一、结构工整你很难通过“不对劲的表达”来快速定位风险点。一个写了 20 年代码的人通常会培养出一种对代码气味的敏感。但 AI 生成的代码把这种气味抹平了所有代码都像同一个认真但缺乏创见的工程师写的。这反而让 review 变得既费眼又费脑。2.3 知识留存成本代码库慢慢变成“AI 风格代码库”没人记得为什么刚开始卸载的念头并没有那么强。真正让我下定决心的是我在重构一个老模块时发现最近半年新增的代码里超过一半的逻辑我无法从提交信息或注释里理解“为什么这么做”。这不是注释缺失的问题。注释是有的但写的是“这里取前三个元素”而不是“为什么只取前三个”。AI 生成代码时倾向于解释“做了什么”而不是“为什么做这个选择”。因为它没有经历业务讨论它不理解这个选择背后的取舍。当团队里的每个人都习惯用 AI 生成代码后代码库会慢慢失去“历史记忆”。代码还在决策过程消失了。这对于一个需要长期维护的系统来说是比“多花两天排期”昂贵得多的成本。因为总有一天会有人需要修改这段逻辑而他的第一反应不是去读设计文档也不是去问原作者而是打开 AI 工具问“这段代码是干什么的”。AI 会给出一个语法层面的解释但业务层面的为什么永远留在了历史里。2.4 技能退化成本当工具替你思考20 年经验也会慢慢失效这一点听起来最像说教但它其实是所有成本里最实在的。手写代码的过程本身是一种思考训练。你在写循环时会顺带想数据规模你在写接口时会顺带想调用方的使用习惯你在写异常处理时会顺带想日志要打到什么级别。这些“顺带想”的东西构成了一个工程师的核心判断力。当 AI 把这些环节都包办之后这些“顺带想”就消失了。你不会因为 AI 生成了一个 O(n²) 的嵌套循环而感到疼痛因为你没有经历那个推导过程。你可能依然能写出架构清晰的设计文档依然能在会议上侃侃而谈但真正落到代码层面时你对边界、性能、异常、资源释放的敏感度正在以你察觉不到的速度下跌。20 年经验最值钱的部分不是记住了多少 API也不是手速快而是面对不确定问题时能快速判断“该往哪个方向试探”。如果这个能力被工具替代了那 20 年经验和 5 年经验的差距也就不存在了。这对我来说才是最不可接受的成本。3. 卸载之前我做过的所有“不卸载”尝试3.1 尝试一让 AI 只输出“草案”不输出最终实现我最早想到的妥协方案是允许 AI 生成代码但只把它当作第一版草稿。拿到草稿后自己重新写一遍或者在草稿基础上做大规模重构。这个方案在初期有效。因为“重新写一遍”的过程会强制我把 AI 生成的逻辑重新推演一遍把决策过程补回来。但也暴露了一个问题当你拿到一段看起来高度完整的代码时你很难忍住不去“直接用”。人类的大脑有路径依赖看到完成度 90% 的结果会本能地往“只差一点点”的方向想而不是“全部推倒重写”。结果就是草稿慢慢又变回了终稿。3.2 尝试二圈定 AI 的使用边界只允许“非核心代码”使用后来我给自己定了一套使用规则核心业务逻辑、性能敏感路径、状态机、资金相关模块全部手写AI 只能用于生成单测、写配置文件、写临时脚本、做批量替换、生成文档注释。这套规则执行了一个月确实减少了风险代码进入生产环境的机会。但它也带来了新的问题规则的维护成本很高。需求一变模块的重要程度一变我就需要不断判断“这段算不算核心”。判断本身就是一种消耗。而且AI 生成的那些“非核心代码”也并不是完全没有业务影响。一个测试里写错了预期值一个配置文件里弄错了超时时间照样会在某个午夜以奇怪的方式反噬。说到底把 AI 限制在“不重要的位置”只是缩小了出问题的半径并没有解决“AI 生成的东西是否需要完整理解才能使用”这个根本矛盾。3.3 尝试三把 AI 生成代码的审查强度提到最高我还试过最后一种方案保留 AI但要求自己每次 review AI 代码时必须逐行解释它为什么这么做。解释不出来就打回重写。这个方案坚持了不到两周。原因很简单如果我必须对每一行 AI 生成的代码做一次“重新论证”那我为什么不直接自己写自己写的成本是确定的AI 生成的成本是“生成时间 审查时间 反推时间 重写时间”。表面上 AI 快算总账反而更慢。这个体验让我明白一个道理AI 编程助手适合的场景不是“生成一段你不用看就直接合入的代码”而是“生成一段你本来就会写、但不想把时间花在打字上的代码”。如果你本身没有能力验证它的输出它带来的就不是效率而是新的技术债。3.4 为什么最终仍然卸载AI 改变的不是打字方式而是决策习惯卸载前的最后一个问题不是“AI 好不好用”而是“我能不能在使用 AI 的同时保持自己的判断力”。我试过很多方法最后发现至少在目前的工具形态和工作流设计下这个问题很难两全。因为 AI 编程助手设计的默认路径就是“输入需求 - 输出代码 - 人工确认”。问题出在“确认”这一步。一个连续一周都在用 AI 生成代码的人会本能地把“确认”理解为“看一眼有没有明显错误”而不是“从零开始验证这段逻辑是否应该存在”。这不是自律问题而是认知带宽问题。确认成本会被工具的流畅体验持续压低直到“信任”取代“验证”。到那时候卸载不卸载已经不重要了真正危险的是你已经失去对代码的判断力却不自知。所以我卸载了。不是因为它做错了什么而是因为我想在自己的工作流里重新恢复那个最简单的循环先思考再动手先判断再让工具提供辅助。4. 如果哪天我重新装上 AI它必须满足这 5 个条件卸载不是终点。我知道 AI 编程工具未来一定会继续演进我自己也可能在某个更成熟的阶段重新使用它。但再装回来之前我给自己列了一份清单。条件不算苛刻但每一条都对应着这次卸载过程中遇到的实际问题。4.1 条件一输出必须被标记为“待审查草稿”而不是正式代码现在的 AI 编程工具在交互上过早地把 AI 输出定义为“可用的代码”。我希望未来的工作流里AI 生成的每一段代码都默认带一个状态标识这是草案这是参考这是待验证而不是“可以合入”。这个标识不需要很复杂但必须形成默认心理暗示AI 给的东西不是答案只是一个候选。候选可以被采用也可以被丢弃关键是要经过人的推导和验证。4.2 条件二AI 必须能解释自己的推导过程而不是只给结果当 review 者把鼠标悬停在一段 AI 生成代码上时我希望看到的不只是“这句话做了什么”而是“为什么选择这个方案排除了哪些替代方案基于什么假设”。我知道这在技术上很难因为模型本身就是基于统计生成的它自己可能也“不知道”为什么。但作为使用者我需要这个机制来帮助自己理解。如果一个工具只给结果不给推导过程那它本质上是一个黑盒。黑盒用于辅助决策可以用于替代决策我拒绝。4.3 条件三我能精细控制 AI 的上下文输入范围现在的 AI 编程工具为了提升回答质量往往会自动把光标所在的文件、相关文件、甚至整个项目索引都纳入上下文。对新手来说这很方便对老手来说这非常危险。因为上下文越完整AI 的输出就越有“全局感”但同时也越难被人类判断。它可能引用了你根本没注意到的旧代码可能沿用了某个模块里早就想废弃的命名规范。我希望未来的工具允许我像一个严格的项目经理一样告诉 AI“你只需要看这两个文件其他上下文不要看不要猜。”精度优先全局感知其次。4.4 条件四它在不确定时必须主动说“我不确定”这一点我很少看到工具做得很好。大部分 AI 编程助手在不确定时倾向于给一个“合理的默认值”然后用非常笃定的语气输出。这不是模型的恶意而是训练目标使然它被训练成补全最自然的代码而不是表达不确定性。但工程实践最需要的恰恰是确定性。“我不确定这个 edge case 改怎么处理我建议你确认一下历史数据”这句话的价值远高于一段流畅但可能隐含错误假设的实现。如果 AI 不能在不确定时表现出不确定它就永远只能是一个“聪明的猜谜者”而不是一个“可靠的协作者”。4.5 条件五代码审查机制必须比 AI 生成速度更快进入流程最后一条是流程层面的。未来如果重新引入 AI 编程工具我一定不会让它直接嵌入到“写完就提交”的路径里。它必须被放在一个强制审查流程的前面。具体来说AI 生成的代码不能直接进入 IDE 的 diff 区域而是进入一个临时队列等人类工程师明确“接管”后才变成正式代码。这不仅仅是流程约束更是一种意图切换。它迫使开发者做一个承诺这段代码我从头到尾检查过了我理解它的每一行我为之负责。没有这种承诺AI 生成的代码就是无主代码。5. 给正在用 AI 编程同行的建议以及我现在的实践框架5.1 先把“判断力”放在工具前面而不是工具后面的让位卸载之后我并没有回到一个完全不用 AI 的远古工作流。我仍然会用 AI 来查资料、解释复杂正则、做文本批量处理、生成临时数据的 mock。只是这些场景都满足同一个条件无论它输出什么我都有能力快速判断对错并且不会对它产生依赖。真正重要的是顺序。以前我是“需求 - AI - 代码 - 我看一眼”现在我是“需求 - 我想清楚 - 我手写核心 - AI 帮我补边角料”。AI 的位置从“主驾驶”挪到了“副驾驶”从“产出者”挪到了“检查者”和“执行者”。这个顺序调整之后效率可能没有以前那样“看起来很爽”但每一段代码都重新长回了我自己的记忆里代码库的“为什么”也重新变得可追溯。5.2 一个可复用的“AI 使用自检链路”输出前、合入前、回顾时如果一定要给一个可复用的方法我会建议你在每个环节设置检查点输出前问自己如果不用 AI我知道这段代码该怎么写吗如果答案是“不知道”那先别让 AI 生成。先查资料先设计先理解问题。AI 只能放大你已经有的理解不能替代你没有的判断。合入前对 AI 的每一段生成代码做一次“为什么”测试。你能不看任何注释自己解释清楚这段代码为什么不是另一种写法吗如果不能说明你还没有真正读懂它就不要合入。回顾时每周检查一次代码库看有多少新代码是从 AI 生成来的这些代码是否正在改变团队的心智模型。如果代码库里出现了多段“说不清为什么”的实现就要警惕了。这不是 AI 的错是流程已经把判断权交给了不该交的位置。这个自检链路不复杂但它能把“AI 很好用”和“AI 对我的系统是好的”分开来看。这两件事完全是两码事。5.3 适用边界什么场景用 AI 是赚的什么场景是亏的基于这次体验我的判断是AI 编程助理在下面这几类场景下是真正赚的一次性脚本、数据处理、文件格式转换这类“用完就扔”的代码AI 的高效和低维护成本非常匹配。代码注释、测试桩、测试数据生成、配置模板这些是“需要做但不是核心价值”的重复劳动。对已有逻辑做解释、对陌生代码块做翻译式说明适合用 AI 做快速预研。而这几类场景目前我会谨慎使用甚至不用核心业务逻辑尤其是涉及资金、状态、权限、数据一致性的场景。高并发、性能敏感、有严格资源约束的代码。遗留系统改动。老系统里充满了文档没有记录的约束条件AI 很容易给出理论上正确、实际上会踩坑的答案。需要长期维护、多人协作的公共模块。代码风格统一固然好但业务记忆的统一比代码风格的统一重要得多。你可能会说这些“不能用 AI 的场景”几乎覆盖了一个正式项目的核心部分。那问题就来了如果 AI 只能用在边角料上它还能称得上“革命性的编程工具”吗我的看法是它仍然是革命性的只是革命的方向不是“替代编程”而是“把工程师生涯里那些低密度思考的部分压缩掉”。真正好的工程师不会因为 AI 会写代码就失业。反倒是那些把 AI 当成“独立思考替代品”的人会慢慢失去在这个行业里最稀缺的能力——判断力。5.4 20 年经验真正值钱的部分不是手速是判断力卸载 AI 这件事让我重新想清楚了一个很朴素的问题一个工程师的价值到底体现在哪里年轻的时候我以为是写代码的速度是对新框架的掌握是能熬夜上线。后来我才发现这些能力都会随着工具演进被快速抹平。你花一个月学会的框架可能三年后就没人用了你引以为傲的手写算法可能已经被标准库封装好了。真正能穿越周期的只有一种能力在信息不完整、约束条件复杂、后果不可逆的情况下做出尽量不后悔的决定。这个东西叫工程判断力。判断力从哪里来从你亲手写代码时踩过的坑里来从你 review 别人代码时吵过的架里来从你维护一个老系统时被迫读懂的“历史包袱”里来。这些东西没有捷径也不能外包给 AI。所以我卸载的其实不是 AI而是那段时间里“让 AI 替我做判断”的坏习惯。工具可以再装回来但习惯一旦定型再想找回那种对代码的掌控感就真的很难了。如果你也正在大量使用 AI 编程工具我唯一想说的是请把它当作一个很聪明但不会负责的实习生而不是一个可以放心交付核心模块的高级工程师。让它帮你填补重复劳动但不要让它替你做判断。因为一旦你开始依赖它做决定你所积累的 10 年、20 年经验就会从“核心竞争力”慢慢变成“收藏品”。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进