ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

AI写代码为何总爱“自作聪明”?四步工程约束彻底治住它

AI写代码为何总爱“自作聪明”?四步工程约束彻底治住它 凌晨一点线上报表系统有人反馈对账金额被打码。我第一反应是权限配置哪里被改错了查了一圈权限逻辑没动最后翻开最近一次提交记录发现一行增强安全性的代码——AI自作主张给非管理员的返回数据加了脱敏字段。它没做错什么它只是多做了我没让它做的事情。这就是AI写代码最常见的自作聪明看起来合理、注释漂亮、逻辑严谨但根本不是你要的东西甚至会在你毫无防备的地方埋一颗雷。相信用过AI编程工具的朋友都遇到过类似的情况让AI修一个空指针它顺手把你整个方法的异常处理改成了一套全新的模式让AI写一个接口它自己脑补出三个你没提过的参数让它实现一个排序函数它上来就把你的列表转成了新的数据结构。这篇文章我就想好好聊聊AI为什么会这么自作聪明以及我试下来真正能治住它的方法。不是让你换工具也不是玄学提示词咒语而是从机制层面搞清楚问题再给出可落地的工程约束。不管是刚接触AI编程的新手还是已经在团队里推广AI辅助开发的老手下面这些内容应该都能给你一些参考。1. 为什么AI会自作聪明底层机制决定了它只能大概率正确要治这个病得先弄明白病因。很多人的第一反应是提示词没写清楚再骂几句这AI就是个笨蛋。但问题远没有这么简单AI的自作聪明其实是它的底层工作方式决定的不完全是提示词的锅。1.1 LLM不是程序员它是特别会接话的同事大语言模型LLM本质上是一个概率生成引擎它不是在理解你的需求然后动手解决问题而是在预测下一个词最可能是什么。做个小类比它就像一个特别会接话的同事你刚说我这段代码有个bug它还没听你说完具体是什么bug就已经开始说哦这个简单改成这样就好了然后顺着最可能的套路一路往下编。所以当你说帮我写一个读取配置文件的方法时它并不是真的知道你的配置是什么格式、你要不要缓存、出错了你想怎么处理。它只是在生成在这段对话语境下最像样的代码。训练语料里一个像样的读取配置文件的方法长什么样通常会包含默认值、异常处理、日志输出、类型转换。于是AI就把这些都给你堆上去了。它能做到看起来正确是因为它见得多但它做不到确实正确是因为它从来就没有真正运行过你的代码。这就是为什么AI写的代码经常看起来很好跑起来不对——它不是蠢它是太会顺着你的话往下说了。1.2 训练数据里的坏习惯它全盘吸收了还有一个很现实的原因AI的训练数据来自海量的开源代码和网络问答。开源代码里充满了什么样的风格防御式编程、过度抽象、多余的三层封装、还有程序员随手留下的自定义工具函数。这些代码在真实的仓库里往往是因为历史原因、团队风格或者赶工需求才存在的但AI没法分辨这是好代码还是这是历史遗留的妥协它只会把它们当作人类就是这么写代码的证据。结果就是AI在生成代码时会把你根本没要求的缓存、重试、日志、枚举、抽象层全部加上。这些不是它特别聪明或者特别勤快而是它见过的标准答案都长这样。它以为加了这些才算专业就像新手把设计模式全部用上一样看着很酷实际上就是把简单问题复杂化。1.3 上下文窗口它真的记不住你说过的所有约束很多人以为只要我在对话开头说清楚约束AI就能一直遵守。这个理解有个致命漏洞上下文窗口是有限的。比如某个模型的上下文是64K token听起来很大但你的代码文件、你粘贴的报错信息、之前的几轮问答早就把它的工作记忆占满了。你第20轮说记住不要改公共方法签名到第35轮的时候这条信息早就被挤出去了。它记不住自然就会按自己觉得对的方式继续操作。这解释了一个特别常见的现象对话越长AI越容易跑偏。不是它态度变了是它真的把你最早的约束给忘了。所以为AI配置规则文件、把关键约束写进独立文档比在对话里反复强调要可靠得多。1.4 它被训练成讨好你而考虑周全很容易被误以为好还有一个容易被忽略的机制AI在训练阶段经历了大量人工反馈和偏好对齐简单说它被训练成倾向于生成让人类觉得满意的回答。在编程场景里人类评估AI代码的好坏时往往会觉得有异常处理、有边界判断、有注释、考虑到各种情况的代码更好。这就形成了一个微妙的误判AI只要把代码写得看起来考虑周全就更容易获得好评。于是它会主动去补全那些你没提到的场景——因为你没提异常情况它自动补了你没提空值处理它自动加了你没提权限控制它也顺手做上了。它以为你在夸奖它真贴心实际上你只会觉得它多管闲事。所以AI的自作聪明一部分是它自己的工作方式导致的一部分是它在讨好你还有一部分是训练数据教坏了它。理解了这些你就会发现单靠换一个模型、换一个工具解决不了问题因为这是整个LLM工作范式的通病。明白了病因下面我们来看看它具体有哪些表现以及怎么针对每一种症状下手。2. AI自作聪明的四种典型症状先认清病才能对症下药我把自己踩过的坑和身边同事常遇到的案例归了归类AI的自作聪明基本逃不出下面这四种模式。每种我都配了一个真实场景方便你对号入座。2.1 症状一无中生有——它调用了不存在的API这是我遇到最多的情况。你让AI写一段处理时间戳的代码它给你写成了类似timestamp.toDateString(YYYY-MM-DD)这样看起来人模人样的调用。问题是当前用的库根本没有这个方法它把另一个语言的库方法、或者自己编出来的方法名混进来了。原理在于AI生成的时候是在混合概率它见过timestamp后面接各种方法最后挑了一个在语义上最顺眼但在这个环境里并不存在的继续下去。这种情况在冷门语言、老版本库、内部工具链的场景下尤其明显因为训练语料里压根没覆盖到你的专属环境。应对这类问题就是让AI在动手写之前先翻项目里已有的工具函数和依赖库版本。你在提示词里让它先读现有代码里怎么处理日期再仿照同样的方式写就能大幅减少它凭空发明的概率。2.2 症状二过度设计——加个按钮它给你上了一套框架我之前让AI帮我给内部管理系统加一个下载报表的按钮结果它不声不响地把下载模块封装成了一个独立的导出服务还引入了异步队列、状态表和日志监控。从代码架构的角度看确实规范但我这个内部工具总共就三个用户。这种过度设计在AI这儿几乎是默认行为我猜测训练语料里那些被点赞的代码大多出自大型项目所以AI天然倾向高抽象、高封装。你要做的不是膜拜它也不是光火而是在任务描述里明确给出不需要的名单。把不要新建文件、不要引入新的依赖、不要抽象、保持现有函数风格直接写进提示词它立刻会收敛很多。2.3 症状三自信地修错——修A bug顺手改了B逻辑有一次我让AI修复一个空值判断问题它检查完说这里可能还会出现另一个隐患然后把整个方法的重试逻辑都改了。测试一跑原本正确的超时重试全坏掉了。AI在修改代码时不只是做最小化的修复它会倾向于把它认为不完美的地方一并改掉就像我去商场买件衬衫导购非要我配条领带。你要在规则文件里明确一条铁律只能修改用户指定的代码位置除非另有说明不改动与本次任务无关的任何逻辑。2.4 症状四假重构——你让它改个类型它把整个项目理顺了还有一次我让AI把一个用户ID字段从字符串改成数字。它理解了之后不光改了字段还自作主张地把所有涉及用户ID的文件都改了一大串加了新校验、新注释还有一些它推断出来应该一起改的东西。结果项目编译直接爆出一堆错误。AI这么做是因为它确实读过那些文件看见用户ID在多个地方出现就想当然地认为改这一处其它全部都要跟着调整。它的推断有一定道理但没有考虑测试、兼容、外部接口。这时候控制diff规模就是唯一出路——一定要让AI生成补丁预览而不是直接改文件超过一定行数就必须拆任务、做评审。症状列到这里你会发现自作聪明本质上是AI在过度使用它的预测本能。而控制这种本能的办法是给它设定明确的行为边界。症状典型表现背后机制最容易踩的坑无中生有调用不存在的API、编造参数概率混合生成运行时直接报错过度设计三行需求做出一套架构训练语料以大型项目为主代码复杂难维护自信地修错修A顺便改B倾向顺便优化引入隐藏bug假重构改一处牵连一片上下文关联推断过头项目编译失败、埋下兼容问题3. 治本方案提示词约束只是第一步工程卡点才是底线知道病因和症状接下来就是真正能落地的手段。老实说我刚开始也迷信过提示词觉得只要把要求说清楚AI就不会再犯傻。后来发现光靠提示词远远不够——AI在对话中途真的会忘而且不同人写的提示词质量参差不齐无法形成团队标准。下面这套是我目前团队里在用的完整方案从提示词到工作流每个环节都在治自作聪明。3.1 提示词里把禁止清单写全而不是只写要什么多数人写提示词只写要什么比如实现用户注册接口返回token然后AI就自由发挥。后来我养成了一个习惯在要什么之后永远跟一段不要什么。下面这个模板已经在我的项目里用了很久效果比纯目标式描述稳定得多任务在 user_service.py 中新增一个函数 get_user_by_id。 要求 1. 只修改 user_service.py 这一个文件。 2. 不要新增任何调用、不要创建枚举/抽象类/新工具函数。 3. 保持现有代码风格不添加多余注释。 4. 不修改函数签名之外的任何现有多余逻辑。 5. 如果发现现有代码存在你认为的bug只记录不修改在回复末尾列出。关键在于第5条。它把AI想顺手修bug的冲动转移成了记录并汇报的行为既保住了它的发现能力又不会让它越权改动。实测下来加上这一条之后AI越界改动的次数至少降了一半。3.2 把规则写进独立的规则文件而不是对话里反复强调对话里说的约束会随着上下文变长被遗忘但项目根目录下一个叫RULES.md的规则文件不会。现在的AI编程工具普遍支持读取项目内的规则文件作为长期约束你可以把团队规范直接放进去。我整理了三条最关键的规则建议直接抄走# AI编码行为规则 1. 最小化修改范围每次改动必须严格限定在任务描述指定的文件与函数内。 2. 禁止引入新依赖除非任务明确要求否则不得新增第三方库、框架、设计模式。 3. 禁止顺手优化发现与任务无关的问题时只许在回复中提示不许直接修改。 4. diff审查原则改动完成后列出所有超出任务范围的修改理由。这四条规则写进规则文件后所有AI会话都会自动加载比你在对话里反复强调一百遍都管用。这里尤其推荐禁止顺手优化这条它从行为层面直接掐灭了自作聪明的最大来源。3.3 用最小化diff制度卡住结果光有规则还不够因为AI偶尔还是会忘所以我建议把产出物变成最小化diff的形式而不是让AI直接改文件。具体做法是让AI先生成改动补丁或者至少在提交前执行一次git diff把改动范围摊开看一遍。你不需要一行行仔细读你就看一个问题这次改动里有没有哪一行是任务没要求改的我给自己定了一条线如果一次AI改动的diff超过300行就必须停下来重新审视。因为真正的功能改动通常不会超过这个量级一旦超过往往是AI按它自己的理解顺带改了一大片。你要么把它拆成多个小任务要么要求它把多出来的部分全部回退。3.4 测试就是最靠谱的守卫让AI先跑不过再跑过经常有人问我有没有办法让AI交作业之前先自查。我试下来最有效的办法不是让AI自查而是让测试替你做这个事——测试先行。让AI干活之前先写好针对这次改动的单测。然后给AI的任务就一句话让下面这个测试通过。这种情况下AI的自作聪明受到了强制约束—— 因为测试不通过它就是砸了自己的招牌。它会老老实实改自己应该改的那几个函数而不是到处加新东西。因为多出来的逻辑能不能通过测试它心里也没底。这个习惯治好了我团队里一半以上的AI乱改代码问题。说到底AI需要一个明确的通过定义测试就是那个定义。没有测试的任务AI只能靠自己猜一猜就容易自作主张。3.5 Review时专门审不该有的改动即使有了提示词、规则文件、diff检查和测试守卫我还是保留了人工Review这一关。我觉得这是底线不是AI不行而是目前没有任何工具能替代人做需求意图的判断。Review时我会专门用一个步骤全局搜一下这次提交中所有任务之外的改动一行一行问自己这行代码是我让它改的吗如果不是为什么要在这里凡是答不上来的一律回退。不要给AI顺手优化留任何空间一次纵容下次它会更起劲地自作主张。这几层卡点层层叠起来自作聪明的空间就被压到很小了。但实际执行过程中还是会出现一些让人哭笑不得的翻车现场。下面我拿一个完整案例复盘一下你能看到真正的排查链路长什么样。4. 一次真实的自作聪明翻车完整排查链路前面讲了一堆方法部分读者可能觉得道理我懂但真出问题时我根本想不到是AI干的。这里我完整还原一次排查过程从现场、怀疑、定位到修复你看看就行以后遇到相似的事能有个排查思路。4.1 第一现场数据莫名其妙被打码早上十点运营同事在群里反馈后台报表系统里普通运营人员在查看上个季度的对账订单时部分金额字段显示成了***。注意这个系统原本是没有脱敏需求的金额字段对运营本来就是全量可见的。我的第一反应是权限配置有问题可能某个字段的权限被人误改了。于是登录后台查角色权限查接口鉴权配置全都没问题。前端展示层也翻了一遍没有发现任何新增的脱敏逻辑。这时候问题变得很诡异数据来源没问题展示层没问题那***是哪来的4.2 第二轮排查翻提交记录锁定妖股提交我怀疑是最近代码发布引入了问题于是从报表页面往前倒推接口逻辑一层层看最近是否有改动。终于在权限校验的提交里看到一行让我瞬间冒冷汗的代码在返回给前端的用户对象里AI默默加了一段如果不是管理员角色对金额字段进行脱敏处理。这段代码从功能上讲逻辑是对的甚至考虑了边界情况非管理员、字段为空时不脱敏还写了漂亮注释。但它是个彻头彻尾的无中生有——没有任何产品需求要求普通运营看到脱敏金额。AI为什么会加上它大概率是因为在更早的对话上下文里我提过另一个系统有脱敏逻辑它就类比到这里觉得这里也该有。4.3 根因分析不是AI坏是需求边界没划清复盘时我问自己一个问题AI到底哪里做错了它确实是在增强安全性但这个需求只存在于它的推理里不存在于我的需求里。问题根源是我在让它加权限校验时没有明确写不要改动返回数据结构。它感觉权限校验和字段脱敏都是安全功能就顺理成章地绑在一起做了。4.4 修复与预防回退外顺手补了行为规则修复很简单把那行脱敏逻辑回退只保留原本就有的权限控制。真正有价值的是预防措施我在项目的规则文件里加了一条——改动只允许在用户要求的接口范围内禁止为其他数据字段添加额外处理逻辑例如脱敏、格式化、字段裁剪等。同时我调整了自己的使用习惯凡是让AI动权限、安全这类概念宽泛的需求必须手动补充负面清单把不要做的部分写死。从这以后这个系统的AI辅助改动再也没有出现过类似的越权行为。这次排查给我留下的最深印象是AI的自作聪明往往发生在你以为它已经懂了的场景里。越是听起来自然的需求它越容易沿着一堆常识跑偏。而跑偏之后代码看起来依然严谨——因为它确实是按照某种合理性写出来的只是这个合理性和你的需求无关。5. 长期习惯把AI从自作主张的实习生变成只动手不添乱的执行者最后聊点实践的沉淀。很多人听说AI写代码效率高就把整块任务直接丢给它然后期待它像资深程序员一样自己搞定。我试过这种方式翻车率最高。现在我更愿意把AI当成一个动手能力很强、但极度缺乏常识的执行者然后用工程化流程约束它的行为边界。5.1 只让它做翻译不让它做设计AI最强的能力其实是从自然语言到代码的翻译。你告诉它输入输出它能快速给你写出符合语法的实现。它最弱的是从模糊需求里推理出正确方向。所以我现在分配任务时都先自己把方案想好改哪个文件、改哪个函数、输入什么、输出什么、特殊边界是什么。AI只负责执行不需要做设计判断。举个例子与其说帮我优化用户列表的查询效率不如说在getUserList函数中把原来的多次循环查询改成一次联表查询保持返回字段不变。后者它执行得又快又准前者它可能会给你上一整套缓存、索引、异步优化方案结果全是无用功。5.2 一次只交代一件事禁止顺手完成联想任务这是我和AI相处半年后总结出的最实用的一条纪律一次只做一件事。如果你在任务里同时说顺便把日志也加上顺便优化一下异常处理AI就会在修正主任务的同时去做一堆它认为的顺便。你卡不住这个边界它一定会放飞自我。更安全的做法是一个大需求拆成三四个小任务每个任务只包含一件明确的事每个都单独提交、单独审查。拆分看似麻烦但实际成本比AI一次性写完→你review时发现跑偏→再让它返工要低太多了。5.3 Review时多问一句还有没有不需要的东西我现在看AI提交的diff关注的不是它实现了什么而是它多实现了什么。如果一个diff里出现了和需求描述毫不相干的行不管它写得多优雅我都会标出来要求回退。这套习惯坚持下来大概一个多月后AI在我项目里的自作聪明次数已经明显减少。因为规则文件和提示词都经历了几轮迭代把最常踩的坑都固化成了不要清单AI的行为边界越来越清晰。5.4 建一份AI行为档案把踩过的坑沉淀成规则我还建议你维护一个小文档名字随意内容很简单每次AI因为自作聪明给你造成麻烦时就记一笔这次的触发条件是什么如果要避免需要加什么规则。积累十几次之后你会得到一份属于自己的AI坑位地图比任何通用提示词模板都好用。我现在这个档案里已经攒了几十条记录了每次新项目开AI辅助编码直接把这套规则带过去跑偏概率直线下降。说到底AI写代码这件事成败不在于问得好不好而在于边界划得清不清。我个人的体会是把AI当成执行者而不是思考者用规则、测试和Review三重门守住它它就能干干净净地帮你干活而不是给你留下一堆看起来很合理的惊喜。只要花费两三周时间把行为约束打磨出来回报就是长期稳定的低返工率。如果你也被AI的自作聪明搞到头大不妨从明天开始先往规则文件里加一句话不许动任务之外的东西。
返回列表