
最近开发者圈里有一句话被反复引用减少 AI slop 的办法不是换更强的模型也不是堆更多的提示词而是写更少的代码。TypeScript 社区里比较活跃的 Matt Pocock 一直强调这个观点Dex Horthy 也站出来呼应认为 AI 辅助编程真正的问题在于它制造了太多“看起来能用、实际上并不需要”的代码。这类代码被英文社区叫成 AI slop翻译过来就是 AI 垃圾、AI 平庸产出。它不是编译错误也不是明显崩溃而是在语法上正确、结构上模仿正常工程却充斥着多余分支、伪抽象、重复逻辑和缺乏上下文的设计。这篇文章不站在“抵制 AI 编码工具”的角度而是想拆一个更实际的问题为什么代码写得越多AI 反而添乱有哪些策略能让 AI 输出保持精简哪些边界问题必须由人来控制如果你正在用 GitHub Copilot、Cline、Cursor 这类工具或者团队已经在推行 AI 辅助编程这篇文章可以直接帮你建立一套更抗污染的工程习惯。1. 从“AI slop”这个热词说起垃圾内容长什么样先给一个偏实操的定义AI slop 是 AI 生成的高数量、低信息密度的输出。这个词最早在内容创作领域流行指用生成式 AI 批量制造“看起来有意义实际没信息增量”的文章、图片和视频。当它进入代码场景时表现往往是这样的# 打开一个项目经常能看到“大而全”却没人看懂的工具函数 rg -n def (parse|get|fetch|normalize|convert)_ src | head -20结果可能是几十个相似函数负责解析、转换、校验但真正被调用的只有其中几个。其他函数之所以存在只是因为 AI 在生成代码时“觉得未来可能会用到”于是顺手就把扩展点做出来了。从工程角度看AI slop 并不总是错误代码。它的危害比错误代码更隐蔽错误代码会在测试或运行时暴露出来而平庸代码会安静地编写出来形成技术债务。技术债务与代码量之间存在强相关代码量越大上下文越难理解训练 AI 的上下文窗口也难以覆盖。最终人类工程师不得不在更大的噪声中找信号而 AI 则带着同样的噪声进入提示词生成更多无意义的能力。这里需要明确的一点是“写更少的代码”不等于“少写功能”。它指的是在实现同样业务目标的前提下尽量减少表面复杂度、多余的路径分支和无根据的抽象。用数学语言表达就是降低代码“熵”。2. Matt Pocock 和 Dex Horthy 的共识代码量本身是一种成本很多开发者在接受 AI 编码工具后会不自觉地陷入一个误区只要 AI 能在几秒内生成几百行代码那么让 AI 做更多事就是优势。但 Matt Pocock 的表述颠覆了这种想法。他认为当你让 AI 产生更多代码时你是在为一堆将来需要阅读、维护、修改和审查的代码付出人力成本。行数是负债而不是资产。Dex Horthy 的回应更进一步减少 AI slop 的秘密武器就是限制代码总量。代码量越大AI 模型的推测空间越大出现“貌似合理但整体错误”的概率也就越高。你问 AI 一个高度孤立的、目标明确的小问题它往往能给出高质量答案你让它直接生成一整个 service 文件它会用一套平均值逻辑去填补你业务里各种不含典型位置的因素结果就是看似结构完整实则把你项目的非规则信息都埋进去了。这本质上是一个信息论问题。人类对复杂软件系统的认知带宽有限模型的能力边界也同样受限于上下文和训练分布。你可能在本地保存了关于用户、账号、权限、产品逻辑的多种隐性知识这些知识分散在代码注释、需求文档和同事记忆中而 AI 只看到了当前编辑的这一个文件。它越主动生成的代码越像从通用模板里复制出来的。问题并不在于模型不够聪明而在于你让它承担了本不该承担的“设计决策”。3. 减少 AI 代码的三个基本功想避免生产 AI slop最关键的动作不是“写一遍提示词”而是从更前面就介入控制。首先给 AI 的任务范围要写清楚边界。不要一上来就让 AI “实现完整的用户管理系统”“为未来扩展预留接口”这类描述。你应该明确当前需要解决什么不需要解决什么哪些行为不允许改变哪些层不允许触碰。你已经主观上完成一次范围筛选模型才不至于开足马力生成大量无关结构。其次接受 AI 生成代码之前要带着“删除思维”去审查它。AI 擅长做加法而你更需要做减法。要在一段新代码里找出哪些函数参数可能永远不会被使用哪些配置项在整个项目里没有被引用哪些冗余的 catch 分支只是为了让 AI 自己看起来更全面。删除这些代码不会让程序变弱反而会让真正重要的逻辑更容易凸显出来。第三建立一套轻量级的代码评审模板。不是所有项目都需要 AST 级别扫描但至少要有人花时间回答“这段代码的复杂度达到 80%是它本身复杂还是被 AI 写复杂了”如果本质只是查个数据库却生成了中间层、校验函数、缓存装饰器和日志封装这通常就是典型的 AI slop。下面这张表可以帮你快速判断一段代码是否满足“更少”的原则检测点说明函数参数数量参数越多潜在组合越多AI 生成错误分支的几率越高抽象层数量是否每个抽象层都对应真实变化点还是为了“以后有可能”重复代码比例同样逻辑是否被多次生成在不同文件里所有公共方法调用次数没有被调用的方法是未来的负担依赖数量AI 是否引入了本来不需要的包或模式条件分支深度分支多意味着状态空间大普通测试难以覆盖4. 代码越少为什么越能反向约束 AI 的推断AI 编程工具的底层逻辑是根据当前代码上下文推断后续 token 的概率分布。当一个文件里只有非常少的类型和函数模型的推断空间会被压缩它只能生成和你项目实际情况更加接近的代码。反过来如果文件里已经躺着几十个装饰器、泛型工具类型和用不到的常量配置模型就会认为项目“喜欢”这种风格从而生成更多类似代码使上下文进一步污染。这也是微服务、整洁架构和模块化思想在 AI 时代重新重要的原因。当你给每个模块划定清晰边界AI 在同一时刻看到的单元就锁定在一个很小的范围内。在这个范围内它只需要搞清楚一个明确的对外接口而不用自己去猜整个系统的隐式调用关系。举个实际例子。假设你正在写一个拉取账户信息的函数。如果文件里到处都是 Service、Repository、DTO、Factory 这些包装AI 会自动模仿生成同样冗长的结构。但其实一个直接、明确的实现可能更易于维护type AccountResponse { email: string; suspended: boolean; }; async function getAccount(id: string): PromiseAccountResponse { const resp await fetch(/api/accounts/${id}); if (!resp.ok) { throw new Error(account ${id} request failed); } return resp.json() as AccountResponse; }这个函数没有额外抽象没有参数对象没有createAccountService的中间层。它甚至没有引入一个完整的 API 客户端类。它就在调用点旁边目的明确。AI 看到这种函数后如果继续补代码大概率会在接口和错误处理上贴近你的真实风格而不是另起炉灶生成一套工程模板。当然“少代码”也绝不等于把所有逻辑破坏性地堆在一个文件里放弃类型写any或把所有字段都揉成一个大对象。减少代码的前提是结构仍然清晰只是没有多余的东西。5. 用提示词把“减法”下发给 AI很多人习惯在提示词里写“尽可能完善不要遗漏边界情况”结果触发的是 AI 最糟糕的“过度完成”模式。正确的提示词应该直接把约束写清楚要求最小 diff、限制任务范围、禁止无根据重构。一个可以反复使用的提示词模板是这样的你是本项目的工程师。请只做以下任务 1. 修复函数 loadConfig 对空配置文件报错的问题。 2. 不得改变调用方行为。 3. 不增加新的配置字段、helper 函数或抽象层。 4. 不修改任何与此 bug 无关的代码。 5. 如果现有逻辑存在额外风险请在说明中列出不要直接在本修改中实现。 6. 只输出 diff。这种提示词的价值在于它明确告诉 AI不要“顺便”帮我清理不要“预见性”地加东西。实际经验里限制越明确生成代码越接近审查可用的初稿。除了提示词还可以在 IDE 的代码生成策略里主动设置“更小响应”。比如当 AI 支持“用一句话解释”“只返回改动点”时优先选择简短答案。对需要大段生成的任务先把你认为必要的接口和数据结构写出来让 AI 填充实现而不是让它自由发挥。另外写完代码后要养成主动追问“有哪些是绝对不需要的”的习惯。这一步可以在代码评审阶段进行也可以直接让 AI 反向问请检查我刚才生成的 AI 代码只标记以下问题 1. 存在没有被调用的公共函数或参数 2. 存在与现有项目功能重复的逻辑 3. 存在可被标准库替代的自定义实现 4. 存在因为泛化而增加的条件分支。 请不要建议额外扩展功能。6. AI slop 最常见的三种形态抽象中毒、防御过度、重复发明当你开始养成“减法审查”习惯后会慢慢认出三类高频的 AI slop。第一类叫抽象中毒。AI 看到三个类似场景会自动生成一个抽象父类或者泛型工具。它不理解这三个场景之间是否真的会演变为三种不同业务规则。过早抽象会让后续 bug 修复需要跨越多个层反而不如坚持一小段满足当前需求的代码。第二类叫防御过度。AI 经常为“输入一定是莫名其妙的”做大量防御。它会在每个函数开头检查空指针、空数组、空字符串、错误格式、异常格式然后逐个返回默认值。也许安全编程确实需要防御但在业务调用链里如果每个函数都默认容忍异常输入上层错误就会延迟到无法定位的位置。防御过度反而掩盖了问题的真实来源也是 AI 生成代码的典型通病。第三类叫重复发明。AI 训练集包含大量 Stack Overflow 片段、开源代码和模式库。当你请求“自己实现一个缓存装饰器”它不会告诉你项目中已经有一个现成的装饰器可用而是按概率分布给你生成一个名称可能完全不同的版本。久而久之项目里出现多个相似函数。重复逻辑越多AI 上下文越混乱未来的修复很容易只改其中一个导致行为不一致。针对重复代码可以引入一个简单的查重机制# 使用 jscpd 检测超过 5 行、至少 70 个 token 的重复块 npx jscpd --pattern **/*.{ts,tsx,js,jsx} --min-lines 5 --min-tokens 70 .如果输出的重复结果明显增多就要怀疑是不是多轮 AI 生成后没有人做清理。与其继续让 AI 再写一个通用函数不如先把重复块合并成一个唯一实现。7. 当“代理式 AI”接管任务时控制粒度更细传统 IDE 补全工具已经是 AI 自动生成大量代码但当前更流行的 Agent 式编程则更进一步它允许模型自主运行终端命令、修改跨文件内容、安装依赖甚至提交代码。表面上这个能力很强但如果不限制它就是 AI slop 产生的最大温床。代理式 AI 的目标通常来自一句“帮我实现一个功能”。模型会自动规划出修改列表然后自行执行。它没有能力判断“这个功能到底是不是产品需要的”也不知道你是否有过某种内部历史结论。它只是根据训练分布预测出典型实现因此常常把问题解决得过于普遍化还会把本来简单的小需求扩散成整个工程结构变化。更危险的是代理可能会直接修改配置文件、执行 shell 命令、安装软件包。这些行为如果不加控制就会绕过你已经建立的工程规范。保证安全的第一条原则是禁止 AI 自动执行有副作用的命令。比如它要安装 npm 包必须先输出安装命令由你来确认它要删除一个文件需要人为批准。不要给它“所有者”级别的权限不要让它直接 push 到团队仓库。第二个原则是给 Agent 提供明确的“禁区清单”。例如开发仓库里可能包含不打算被触摸的 legacy 模块、加密配置或者生成文件。你可以在.cursor/rules或CLAUDE.md里写清楚“哪些目录只读”“哪些代码不可重构”。这相当于把业务约定编码成 AI 的约束能有效避免它把长期维护的稳定代码处理成华丽的新模板。第三个原则是执行完批量任务后要重新审视“变化面”。一个正常的人工变更往往只涉及一个功能点和几个相关测试文件。如果模型的变更范围横跨十几个文件还引入了结构型重构那么即使每个文件编译通过也要警惕整体的过度生成。更好的做法是把 Agent 的任务限制在“一次性只处理一个子问题”这既方便审查也符合代码越少越容易控制的原则。8. 合规、数据与安全边界AI 生成代码不是免责挡箭牌关于 AI 生成代码还有一个容易被忽视但必须写进团队流程的维度合规边界。很多开发者会直接把自己公司的私有代码、商业 API 或客户数据粘贴到云端 AI 工具里只为了让代码建议更准确。但私人仓库的代码往往涉及企业知识产权与用户隐私。在契约、许可证和监管发布之前不应在未授权的位置处理这类信息。团队应该提前建立一份可操作的白名单哪些仓库可以被同步给云端模型哪些代码片段可以发给外部工具哪些字符串必须脱敏如果条件允许优先使用本地部署或企业私有模型的代码助手。此外AI 生成的代码普遍来自大量开源训练数据其许可证归属、作者归属和来源都并非透明。如果你在一个需要特别注意许可证的项目中混用大量 AI 代码就必须建立更严格的记录机制保留提示词、生成时间、使用工具和后续人工修改记录。不同公司对 AI 生成代码的开源义务、版权归属有不同的判断不要因为模型生成了看起来像自己写的代码就默认它是完全原创结果。从内容安全角度看AI 工具生成代码时也可能会输出侵犯版权的内容、已知漏洞的相似实现、或带有误导性注释的改动。代码评审不能只看“是否工作正常”还要看“这段代码是否应该存在”“它是否有意避开现有 API 规范”。在正式提交前应对所有 AI 生成的代码执行一次人工安全和数据合规复查尤其要关注是否访问了不该访问的环境变量是否输出没有权限读取的文件是否调用了意外端口是否泄漏了测试数据结构中的敏感信息。9. 团队落地把“减少代码量”变成可持续的工程指标如果只是个人开发者控制 AI slop 相对容易因为你熟悉项目里的所有角落。但对于团队事情要复杂得多。不同开发者在同一段代码里加入自己的“AI 风味”最终会造成不可控制的多样性。一个可行的做法是在团队编码规范中显式增加“AI 代码使用约束”而不是只在原则讨论中提到。这套约束可以包括允许 AI 辅助生成样板代码但生成的类方法必须能被当前模块直接调用否则应在合并前删除。每次使用 AI 生成代码后都需要在代码说明中回答这个函数相比人工写的版本减少了多少行增加多少复杂性禁止 AI 在无人监督的情况下自动运行测试之外的系统命令。代码评审时需要检查 diff 的“净行数变化”。如果实现一个简单需求导致增加超过 200 行作者必须解释每一部分为什么必要。专门安排阶段性的“代码瘦身日”目标不是增加功能而是删除被 AI 过度填充的方法、配置文件和依赖。代码量虽然不能作为唯一的质量指标但是在 AI 辅助编程已经明显提高产出速度的背景下它是一个反向约束指标。如果没有这个指标团队会不自觉地让行数膨胀。引入“新增行数 vs 删除行数”的粗粒度统计能帮助大家意识到很多新的 AI 代码其实是在复制既有逻辑而不是创造新的价值。同时不要过度依赖“AI 生成的代码通过单元测试”来证明质量。单元测试只是测试了窄功能层面无法检验那部分代码是否值得存在于代码库里。维护成本、认知负荷、接口耦合度在代码规模扩大后才会显现。因此在 AI 代码注释里加入“为什么存在”比“怎么运行”更重要。至少要让后来者知道这段代码不是凭空冒出来的。10. 结尾先少写再让 AI 帮你写得更好这篇文章和你平时看到的“XX 部署教程”“XX 模型显存测试”不同它没有让你下载任何一键包也没有让你改变整个开发框架。它想表达的核心很朴素AI 编码的收益不是在代码量的加法中体现的而是在“让真正需要的代码更快落地”的减法中体现的。如果你正在评估一个 AI 辅助编程工具值得最先验证的不是它能不能生成功能完整的大模块而是它能不能在你要求“只改动一行”的时候真的只改一行。如果你已经在使用这类工具那么下一步应该做的不是向它要更多输出而是尽可能把你需要约束的范围写清楚然后再验证它生成的代码是否值得保留。Matt Pocock 和 Dex Horthy 的观点之所以能引发这么大反应是因为它提醒了大家AI slop 并不可怕可怕的是我们误把代码数量当成了工程成果。与其让 AI 替你写一百个未来的可能不如让它帮你把眼前的代码写短、写准确把节省下来的维护时间花在真正需要设计的产品逻辑上。建议你把这篇文章里“提示词约束模板”“jscpd 重复代码检查”“代码行数回归审查”这三件事先拾到自己的日常工作流里。团队内部也可以按这套思路做一次代码仓库体检把明显属于 AI 过度生产的抽象和重复逻辑清理掉。当你的项目越来越简洁AI 的上下文会被净化它生成的代码自然不再那么“slop”。