拓冰建站拓冰建站
首页 / 资讯中心 / 正文

AI Slop泛滥?用“写更少的代码”抵抗AI辅助编程的隐性债务

如果你最近在用 AI 辅助写代码大概率见过这样一个场面需求还没想清楚代码仓库里已经冒出一整层封装每个文件都能跑测试也过了却没人解释为什么需要这个抽象。项目功能没有多多少文件数量却开始膨胀。国外开发者讨论里给这类产出起过一个很直接的名字AI slop。最近关于 AI slop 的讨论里有一个观点特别刺耳但值得认真听减少 AI slop 的办法是写更少的代码。Dex Horthy 在回应 Matt Pocock 的类似观点时也把方向指向了“以删除为中心的编程方式”。这句话不是让大家不写代码。它的真正意思是一段代码只有在“必须存在、能被解释、值得长期维护”的时候才应该进入仓库。AI 辅助编程最大的风险不是它写出了错误的代码而是它让大量“无关紧要但看起来正常”的代码获得了进入仓库的资格。代码量越少AI 产生的幻觉空间越小人类需要解释、测试、审查和维护的面积也就越小。我认同这个判断而且会从实操层面展开讲。1. 先搞清楚代码里的 AI slop为什么比文本里的更难清理1.1 同样叫 slop文本和代码的成本完全不同AI slop 最初更多被用来形容 AI 批量生成的文字、图片和视频内容。它们最大的特点是“量大、营养低、看多了会麻木”。文本 slop 放在信息流里用户可以选择跳过图片 slop 放在搜索结果里用户能快速无感划过。但代码 slop 没有这么好打发。一段进入代码仓库的代码要被编译器解析要被静态检查工具扫描要被测试覆盖要被同事阅读甚至可能被部署到生产环境。它只要存在就会成为后续修改的约束。代码不会因为你删掉了生成它的提示词就从仓库里消失它会一直留在那里等下一个维护者替它收拾残局。所以代码语境里的 AI slop不应该简单理解成“质量差的代码”而应该理解成“语义密度很低的代码”。它能运行但它没有清晰意图它能通过测试但它没有节省任何人的理解成本。1.2 为什么语法正确、测试能过仍然可能是负债传统意义上的“烂代码”通常还能靠代码评审和重构去修复。函数太长可以拆分命名太差可以重命名分支太乱可以整理。这些坏味道是有模式的经验丰富的工程师一眼就能识别。AI slop 更难处理的地方在于它经常长着一副“合格代码”的样子。类名完整、函数分层清楚、注释也齐全甚至错误码都提前定义好了几十个。可一旦你追问“这些错误码分别对应哪些真实场景”“这个抽象层到底屏蔽了什么变化”答案往往是空白。代码的语法正确不能证明它有存在价值测试通过也不能证明它和业务目标一致。测试只能说明“它按照当前的假设运行了”不能说明“这个假设应该存在”。更麻烦的是这种代码没有传统的“负责人”感觉。人类写代码时如果对某个模块不理解至少知道要找谁问。AI 生成的代码则大量采用“看起来最标准”的方案像一条自动装配线一样输出部件没有人对那个部件产生过真正的所有权。于是它进入了一种无人认领的状态能跑没人敢删也没人愿意维护。1.3 把代码量当成产出是问题开始的地方团队复盘时如果只看“新增代码行数”和“提交数量”AI 辅助编程的产出会非常好看。但真实需求不会因为代码多就推进更快。更多时候代码量增加意味着后续的 review 时间更长回归测试范围更大知识交接成本更高。代码不是资产至少不全是资产。它是需要长期偿还的债务读它是成本改它是成本测试它是成本删它也有风险成本。AI 让“创造代码”变得几乎免费同时把成本转移到了所有未来接触这段代码的人身上。这就是为什么“写更少的代码”能成为一种抗 slop 策略。它不是保守不是拒绝新技术而是把注意力从“生产多少”转移到“需要保留多少”。2. 写更少的代码为什么能减少 AI slop2.1 一段代码的隐藏成本远不止编写那几分钟如果只算写代码的时间AI 生成 500 行肯定比人写 50 行快。但代码一旦进入仓库它的生命周期才刚刚开始。每一次功能迭代维护者都要先理解旧逻辑每一次模块重构阅读者都要区分哪些是必要逻辑哪些只是装饰每一次架构升级所有人都要检查这段代码是否还能和新的约束兼容。代码量不是加法而是乘法。500 行代码的维护成本不是 50 行的 10 倍可能是几十倍。因为行数越多概念越多概念之间的耦合也越多。AI 输出大量代码时它不会自动替你消化这些耦合。你只是收到了一份需要用未来所有时间去阅读的长期账单。“写更少代码”的第一个价值就是减少别人需要被迫阅读和理解的面积。如果一个功能用 20 行就能表达清楚就不应该让 AI 生成 200 行再嵌套几层抽象。删除那些没有提供新信息、没有表达新约束、没有隔离变化的部分实际上是在给未来维护者减负。2.2 大模型的输出范围越大幻觉空间也越大从模型行为的角度看这个观点也成立。你让 AI 生成一个独立函数它只需要判断输入、输出和局部逻辑出错的点相对集中。你让 AI 生成一个完整模块它要在几千行里同时维护状态、命名、依赖、异常、配置和边界条件预测难度会迅速上升。实际使用中很容易观察到一种现象让 AI 单独写一个处理字符串的工具函数效果通常不错但让 AI“顺手把 controller、service、dao、model 都写出来”它就会开始填充大量模板化内容。这些内容本身没有语法问题可它会按照训练数据里的“常见示例结构”来猜测业务于是产生大量不存在的接口、永远不会被调用的枚举、为将来准备的空方法。大模型擅长局部生成不擅长对全局进行长期一致性判断。上下文窗口在变大不代表它在几千行代码里建立架构约束的能力同比例变强。把任务切小、把输出范围收紧是减少 AI slop 最直接的手段。这和“上下文管理”很像先给目录再按需展开章节而不是一开始就让 AI 把所有章节都填充完整。2.3 写得更少核心是收敛不是把代码压成一行这里要避免一个误解。“少写代码”不是鼓励用一行极其复杂的表达式实现所有逻辑更不是拒绝在业务确实复杂时增加必要的代码。少指的是删除那些没有回报的部分。一个判断标准是这段代码有没有真实调用者它是否重复表达了一个已有概念它是否为了未来根本不确定的变化而提前通用化如果没有那它就应该被删除。我在实际项目里倾向于把“写少”翻译成“生成前收敛 生成后删除”。生成前先确定任务边界生成后马上做一轮删除。删除不是盲删而是在版本控制保护下先确认调用链然后让没有调用者的函数走完回归测试。这个动作看起来不像是在“写代码”但它才是防止代码仓库被 AI slop 淹没的关键。3. AI 编程里最常见的三类 slop以及怎么识别它们3.1 类型一模糊需求下生成的“模块全家桶”最常见的一种场景是开发者直接对 AI 说“帮我实现一个用户评论模块”。AI 会非常热情地返回一个完整目录Controller、Service、DAO、DTO、Entity、ExceptionEnum、Utility甚至还有几个接口文档用的示例类。问题在于很多类并没有真实调用者。那些代码不是从业务需求里长出来的而是从开源项目模板的统计分布里长出来的。比如一个错误码枚举里定义了 30 种异常业务路径真正用到的不超过 4 种。以后如果要调整错误码协议维护者要在这 30 个选项里逐一判断哪些该删、哪些能用、哪些只是 AI 为了让“错误码看起来完整”而补的。识别方式很简单生成完后先不要看它写了多少先去找每个文件有没有被其他代码引用。如果一个刚生成的文件没有任何真实调用者就要警惕它可能不是在解决需求只是在表演“一个模块应该长这样”。3.2 类型二为一行需求封装的“概念层”另一种 AI slop 更容易混过 code review。代码里本来只有两个函数调用方觉得有点重复于是让 AI“抽象一下”。AI 很快产出一个通用 Pipeline 类把两个函数统一成一个入口通过一个 options 参数控制所有分支。两个调用点需要的最多是一个函数重载但 AI 给出的是一整套“未来扩展框架”。真正的抽象应该源于持续出现的重复和清晰的变化方向而不是为了现在看起来更通用。AI 之所以偏好这种写法是因为它看过的大量开源代码库就是高度抽象的那种风格在训练数据里太常见了。识别方式是问一个问题这个抽象真的消掉了一个重复点还是只是把两个函数并进一个 switch如果去掉新封装的类直接保留原来的两个函数代码会不会更容易读懂很多时候答案是“会”。这种抽象就不是在减少代码而是在增加读者需要解码的概念层。3.3 类型三把教程式示例代码直接送进生产仓库AI 的训练语料里有大量示例代码它的目标通常是展示某个语法、某个库或者某个框架的用法。示例代码的第一使命是“让读者快速看懂”而不是“承担真实业务约束”。所以 AI 生成的代码很容易带上示例风格变量名偏通用错误处理偏简单输入校验偏弱边界条件经常缺失。比如你让 AI 写一个文件读取函数它大概率会返回那种“教程版本”直接 new 一个对象没有处理文件不存在没有处理权限问题也没有释放资源细节。如果你只验证了 happy path代码确实能跑但进入生产环境后所有异常路径都会变成问题。开发者以前手动搜索“C 语言文件读写操作代码”的时候至少还知道自己拿的是示例需要改造后才能用。现在 AI 把这层提醒也去掉了它会把示例包装成“针对你需求的完整答案”。最终进入仓库的很可能是一个教程风格的半成品。这里我建议用一个快速判断矩阵来识别代码:形态典型症状需要问的问题模块全家桶新文件很多但很多没有调用者删掉这个文件现有测试会不会变化过度封装两个函数被统一成复杂 Pipeline这个抽象消除的重复点到底是什么教程式代码只处理正常路径边界靠调用方自行兜底这段代码在异常、失败、超载时会怎样4. 真正有效的不是少写提示词而是建立“收敛式生成”流程既然 AI slop 的本质是“输出的保留成本远大于价值”应对方式就不只是把提示词写短一点。比较有效的做法是建立一套收敛式生成流程让 AI 先产生一个最小的可验证实现然后立刻把多余的部分删除最后只提交一个必要的最小改动。这一套流程我一般拆成五步执行适用于大多数在编辑器里使用 AI 辅助编程的场景。写任务前先用一句话说清“这段代码为什么必须存在”。说不清就不生成代码先继续澄清需求。裁剪输入上下文。不要把所有十几个打开的标签页都作为上下文喂给 AI只把真正相关的函数和数据结构放进去。限制输出形状。明确告诉 AI不新建文件、不新增依赖、不加日志、不做过度封装只修改某个具体函数。生成后做一轮“删除评审”。让 AI 找出没有调用者的路径、无意义中间变量、为未来准备的参数并删除。提交前跑静态检查、单测和代码诊断人再看一遍 diff。这个流程的价值在于它不允许 AI 直接成为“仓库内容决策者”。AI 负责生成候选代码但你能不能活下去仍然要经过删除和验证两道关卡。4.1 在 prompt 里把“输出形状”定死很多人低估了 prompt 里限定输出形状的作用。仅仅说“帮我实现一个功能”AI 会自行决定结构。可一旦加上“不要新建文件不要额外封装只修改某个函数”生成结果会收敛很多。一个比较稳妥的示例结构是这样的不要新建文件不要新增第三方依赖不要添加注释和日志。 只修改 process_order 函数 - 当 status refund 时把 amount 置为 0 - 其他分支保持原样 - 不要为这个逻辑引入新函数。 先输出这份代码再告诉我你删除了哪些分支。虽然不同工具对指令的遵循程度不一样但把“输出边界”写清楚会让模型很难继续生成一整套“全家桶”。如果你用代码方式生成示例比如生成一段带结构的数据也应该用最小的对象而不是完整的系统来验证。4.2 把“优化重复代码删减脚本”这类需求拆成可诊断的小步在真实开发里很多团队会让 AI 做“优化代码”“重复代码删减”之类的任务。这类任务看起来很有价值但对 AI 来说风险很高因为“优化”意味着可以重排逻辑“删减”意味着可以动结构。如果 AI 在理解不完整的情况下直接重写整个文件通常会产生两个问题要么破坏原有行为要么为了让 diff 好看而强行压缩。我的建议是先拆小步执行。第一步只做重复代码检测第二步把重复片段抽成明确函数第三步确认所有调用位置都使用新函数第四步让 AI 再找一次是否还有重复概念。整个流程不是让 AI 一次性完成而是每一个步骤都可以被 diff 审查。这个过程里要用到代码诊断能力。很多编辑器都有问题面板、静态检查、圈复杂度提示、未使用代码提示。这些工具比 AI 自己的审美更稳定。如果 AI 生成的代码无法被编辑器正常索引比如有人抱怨“VS Code 写 C 没有代码提示”那往往不是工具坏了而是生成的代码根本没有进入可分析的上下文中。对于工程代码来说无法被索引就约等于无法被可靠维护。4.3 一份针对 AI 生成代码的排查链路如果你发现仓库里的代码开始变“滑”不要先去改 prompt 风格按下面的链路排查先看现象。是文件数量暴涨还是单个文件越来越长是代码能跑但没人敢改还是开始出现“加一个新需求要绕开三个旧封装”的情况再看输入。最开始的任务描述是不是太模糊是不是直接让 AI“实现一个完整模块”有没有限定输入输出再看环境。生成时是不是把所有文件都拖进了上下文AI 是否在全文件重写模式里运行有没有引入多余依赖再看实现。这段代码有真实调用者吗命名是否依赖“逻辑位置”而不是“业务意图”异常处理和边界条件是否存在最后看验证。生成后有没有跑静态检查和单测有没有在版本控制里保留纯删除的提交如果只是“能编译就提交”slop 基本上已经被放进仓库了。这个排查链路不是为了证明某段代码很差而是为了把问题还原到一个可修改的层面。只要问题定位在“输出太宽”解决方式就不是换一个更强的模型而是改变生成方式。5. 什么时候该让 AI 多写一点什么时候必须保持克制5.1 先学会给任务分层并不是所有代码生成都必须追求极端精简。有些场景让 AI 多写一点反而是合理的使用场景是否适合多写理由一次性脚本或数据准备适合用完即弃保留成本低单元测试模板适合只要断言真实多测几条数据没问题正则表达式 / 数据转换适合逻辑相对封闭便于快速验证教学和语法演示适合目的是理解语法不是进入长期生产核心业务模块不适合需要长期维护每行都要能被业务解释跨服务调用流程不适合失败语义复杂AI 容易把边界想得太简单需要高度一致性的架构改动不适合模型缺乏对全局约束的长期判断上面这张表只提供一个方向不是绝对标准。真正判断时仍然要看这段代码未来会不会被别人反复阅读和修改。如果只是为了学习和验证某种算法比如跑一个自然语言处理相关的小脚本、复现一个多模态模型代码那让 AI 多生成一些完全没问题只要跑完能保存结果就行。但这种代码不要顺手贴合到核心目录里。更好的做法是把实验代码隔离在一个独立目录并写清楚执行方式避免它某一天变成没人敢删的“参考实现”。5.2 给每一段生成代码做一次“防 slop 体检”我经常用五个问题来审查 AI 生成代码是否值得提交这段代码有真实调用者吗如果删除后功能没有变化那么它就是“存在但没有必要”的代码。你能否用三句话解释它的业务意图如果你依赖 AI 生成的注释才能解释说明你自己还没理解它。它是不是重复表达了一个已有概念如果是重复正确动作是先删除旧的再新建而不是同时留两份。如果要求 AI 只返回一个最小输入到输出的实现行数能减少一半吗能说明之前的输出里混入了大量装饰性内容。它是否沿用了项目里现有的异常处理、日志风格和类型约束如果没有即使逻辑正确也需要重写才能符合项目上下文。这五个问题不是为了让每个功能都缩到最短而是要求每一段代码都承担明确的认知责任。AI 生成不是问题问题是我们常常把它当成免检产品。代码评审要处理的不只是正确性还有“代码是否真的需要存在”。5.3 “写更少的代码”最终指向什么回到开头那个观点。Dex Horthy 呼应 Matt Pocock 时强调的不是“少写功能”而是让开发者重新控制代码仓库的入口。AI 确实能写很多代码但你不需要为它写的所有结果负责你要负责的是那些最终被你保留下来的结果。未来 AI 编程工具的进步方向可能也不是无限制地生成更多代码而是帮助开发者理解哪些代码可以被删除、哪些抽象可以被还原、哪些重复可以用更少的结构表达。真正能抵抗 AI slop 的不是某个大模型的推理能力而是人的删除能力和判断力知道什么时候不看生成结果知道什么时候对一段“能跑但没必要”的代码说不。下一次使用 AI 辅助编程前可以试着先写下这个问题这段代码为什么必须存在如果一句话写不出来那就先别急着生成。等想清楚了再用更少的代码把那个“必须存在”的部分实现出来。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门