anti-slop 管代码、no-ai-slop 管文章:"反水货"双雄的分工与边界
【免费下载链接】no-ai-slopRemoves 20+ patterns of AI slop from any piece of writing.项目地址: https://gitcode.com/gh_mirrors/no/no-ai-slop
当大模型把"生成"的成本压到几乎为零,一个反直觉的现象出现了:内容变多了,信息反而变少了。代码里冒出链式as unknown as断言、满屏any与空catch;文章里充斥着"这不是 X,而是 Y""没有人告诉你的是""未来不是正在到来,它已经来了"这类套话。GitHub 上由此长出一整类"反水货"(anti-slop)工具:一类把坏味道写进 lint 规则,拦截 AI 劣质代码;一类把套话写进提示词清单,清洗 AI 味文本。no-ai-slop 就是后者的代表,它靠一条 SKILL.md 把 20 多种 AI 写作模式钉在清单上,被社区反复实测后冲上 GitHub 周榜,Star 超过 2.3k。
本文以 no-ai-slop 仓库源码为主线,对照代码战线的 anti-slop 规则,拆解两条战线各自的打法、共同的价值观,以及那条被很多人忽略的边界。
代码战线:anti-slop 的坏味道清单与 Oxlint 落地
anti-slop 走的是一条"机器可执行"的路线。社区对它的典型描述是一组"反 AI 水货"的代码规则:拒绝链式断言、拒绝unknown泛滥、拒绝无注释的强制转换——逼着开发者写"有依据"的代码。这些规则和 AI 辅助编码的工作流高度相关:模型为了通过类型检查,最常见的偷懒手法就是as unknown as SomeType这种双重断言,规则盯的就是这类"为了编译而编译"的写法。
工程落地上,社区给出的主流方案是用 Oxlint 承载这套规则。Oxlint 的优势在于三点:基于 Rust 实现、性能远高于传统 JS lint、兼容 ESLint 规则生态,因此可以不加缝地接入已有工程。典型配置聚焦在几类高频坏味道上:
- 禁止
any与未标注来源的unknown:逼着开发者写窄类型或显式收窄,杜绝"逃逸舱"式的类型逃生; - 禁止空 catch:要求异常要么处理、要么显式注释原因,消灭"吞错误"的静默行为;
- 严格比较:禁止
==、隐式布尔转换等易被模型糊弄的写法; - 禁止链式断言:每个类型转换都要有可解释的依据,而非"一路断言过去"。
在 Continue 等工具里还能看到它的进阶形态:把 Anti-Slop 检查挂到临时 worktree 上,只对 diff 范围内的增量变更做审查,严格限制修改范围,确保清理的是本次改动引入的低质量模式,而不是对存量代码做大规模重构。其核心原则被总结为八个字:移除仪式感,保留功能性。
这条战线的本质是确定性:规则一旦写死,机器就能逐条执行,结果可复现、可进 CI、可阻塞合并。坏味道是离散的、可枚举的,所以 lint 能抓住它们。
文本战线:no-ai-slop 的"去味"规则与自检闭环
文本不能 lint——至少不能只靠正则。这是 no-ai-slop 和 anti-slop 在设计起点上的分叉。打开仓库核心文件 SKILL.md,它的定位写得很清楚:不是"AI 文本检测器",而是一个"sharp human editor"(敏锐的人类编辑),核心承诺是Remove AI patterns without turning distinctive writing into generic polished prose——去 AI 味,但不抹平个人声音。
两种模式:Edit 与 Detect
SKILL.md 的开篇定义了两种工作模式:
- Edit(默认):用户投喂草稿,技能做"最小有效编辑"(minimum effective edit),输出改后的全文加一段 What changed 说明;
- Detect(审查):用户问"这是不是 AI slop",技能只做模式审计——逐条点名命中的模式、引用原句、用几个词给出修复方向,但不改写、不评分、不猜测是否 AI 所写。
Detect 模式有一段很关键的话:"AI detectors guess. Named patterns are evidence the user can check."(AI 检测器靠猜,命名的模式才是用户能核对的证据。)这句话划出了整个工具家族的重要分界:它拒绝对"作者身份"下判断,只对"文本模式"下判断。输出的是可验证的清单,而不是一个置信度分数。
三层规则:禁词、空话与模式
规则的颗粒度分三层。第一层是直接封禁的词表:delve、foster、leverage、utilize、empower、streamline、robust、cutting-edge、paradigm shift、game changer、tapestry、realm、multifaceted、transformative……这一串词几乎是 LLM 的"指纹词库",训练语料里高频出现、人类写作里几乎不用。
第二层是空副词与空短语:just、literally、simply、actually、fundamentally、it's worth noting、at the end of the day、in today's world、let's dive in。注意这里的规则不是一刀切——SKILL.md 明确写了"Cut them when they add nothing. Keep them when they carry emphasis, uncertainty, contrast, or the writer's natural spoken rhythm"(加不了信息就删;承载强调、不确定、对比或作者口语节奏时就保留)。这层规则的判定权交给了语感,这正是机器 lint 做不到、必须由 LLM 来执行的部分。
第三层是句式与结构模式,一共 18 种,每一种都带"坏例 → 改法"的示范:
| 模式 | 坏例 | 改法 |
|---|---|---|
| Binary contrasts | "这不是 X,而是 Y" | 直接陈述 Y |
| Throat-clearing openers | "Here's the thing" | 删掉开场白,直接说观点 |
| Faux-insight setups | "没人告诉你的是……" | 删掉"独醒"铺垫,让论点自立 |
| Colon reveals | "最棒的部分:它会学习" | 改成普通陈述句 |
| Superficial analysis | "highlighting the team's commitment" | 用具体事实替代 -ing 尾巴 |
| Importance puffery | "标志性时刻""重要证明" | 陈述事实,让读者自己判断 |
| Weasel attribution | "专家一致认为""研究表明" | 点名来源,或删掉该断言 |
| Synonym cycling | 同一件事换着词说三遍 | 正确词就重复用 |
| Dramatic fragmentation | "就这样。就这些。" | 用完整句子 |
| Robotic rhythm | 重复句式、堆砌短句 | 只在必要时变化节奏 |
| Rhetorical setups | "如果我告诉你……""想一下:" | 删掉设问,直接给结论 |
| Fake-profound kickers | "未来不是正在到来,它已经来了" | 直接删掉,删完不补新比喻 |
| Summary-recap endings | "总之""总而言之" | 结束在最后一个具体点上 |
| Formatting slop | 标题加 emoji、句中加粗 | 格式跟随内容 |
| Em dashes | 破折号当节奏拐杖 | 短文本零个,长文本 1-2 个封顶 |
其中几条很见功力。Portability test(可移植性测试):如果一个句子能原样搬到另一个人、另一家公司、另一个产品里,那它就是填充物——这是判断"空话"的通用判据。"Protect the specific fact":"The tool significantly improves engineering productivity" 要改成 "The tool cut review time from 30 minutes to 8"——把抽象拔高换成可核验的数字。这和 anti-slop 拒绝any的逻辑如出一辙:不是不给宽松,而是要求每处表达都有事实依据。
eval.md:编辑器与验收单合一
no-ai-slop 没有把"改完了"当作终点。仓库里的 eval.md 是一份自检清单,SKILL.md 的工作流规定:编辑完成后必须逐项对照它做 pass/fail 检查,任何一项不通过都要回去改。检查项包括:是否保留作者的核心观点与独特词汇、节奏、锋芒;是否让强人类句原样保留;删减幅度是否与实际的 slop 量成比例;是否存在"机器人式对称"(robotic symmetry)和重复句式;最终输出是否带 What changed 说明。
这份清单本身也在反 AI slop:它专门设了一关"would the writer recognize the edited draft as their own voice"(作者能否认出这是自己的文章),防止去味工具把文章改造成另一种更高级的模板。
工程化:从 Skill 到插件
文本规则虽然靠 LLM 执行,但工程化程度并不低。README 给出了两条安装路径:在 ChatGPT、Claude Code、Codex 里粘贴一句Install the /no-ai-slop skill globally,或执行npx skills add petergyang/no-ai-slop --skill no-ai-slop --global --yes。仓库里还有 scripts/build_plugin.py:它读取.codex-plugin/plugin.json清单,把 SKILL.md、eval.md、图标、LICENSE、PRIVACY.md、TERMS.md 打包成 zip,并做三件事的校验——清单字段完整性、打包文件集合与预期完全一致、包内文件与仓库源文件逐字节相同。这意味着"去 AI 味"的规则集本身也被当作正式发布的软件制品来管理,而不是一段随手粘贴的提示词。
两条战线的共同内核与各自边界
把 anti-slop 与 no-ai-slop 摆在一起,能看出三层共同的价值观。
第一层:清单化是共同的方法论。两边都不搞"玄学检测",而是把坏味道显式枚举出来——anti-slop 是 lint 规则集,no-ai-slop 是 18 种模式加三层词表。可枚举,才可讨论、可迭代、可版本化。
第二层:证据优先于猜测。anti-slop 拒绝"无依据的类型断言";no-ai-slop 的 Detect 模式明说"命名模式是证据,猜测是检测器的事"。两边都把"可核验"当作底线,拒绝为"看起来像"买单。
第三层:具体优于抽象。anti-slop 要类型有依据,no-ai-slop 要句子有事实——"cut review time from 30 minutes to 8" 胜过 "significantly improves productivity"。抽象是水货的共同温床,这是两条战线识别出的同一种病。
边界也同样清晰,而且值得从业者想清楚:
- 执行主体不同。anti-slop 是确定性的:规则一写死,机器逐条执行,能进 CI、能阻塞合并。no-ai-slop 是语义性的:禁词可硬匹配,但"这句空话是否承载作者的语气"必须交给 LLM 判断,所以它设计成 Skill 而非检测器。
- 判定对象不同。anti-slop 对"代码"下结论,no-ai-slop 对"文本模式"下结论——前者判定代码质量,后者刻意回避"这段文字是不是 AI 写的"这一身份问题,因为身份不可由模式推断。
- 改造策略不同。代码 lint 倾向"硬拦截"(fail the build),文本去味倾向"最小有效编辑"(保留个人声音),因为代码的坏味道几乎总是有害的,而文本的"不标准"常常是风格本身。
结语:反水货不是反 AI,而是反"无依据"
把两条战线放在一起看,结论其实很朴素:社区对 AI 输出的态度正在从"能用"转向"可核验"。anti-slop 与 no-ai-slop 的分工不是"代码归代码、文章归文章"这么简单,而是同一价值观在不同载体上的两种落地方式——代码要类型有依据,文章要句子有依据;能机器判定的交给 lint,需要语感判定的交给带自检闭环的 Skill。
当一个项目能用 SKILL.md 定义"什么是水货"、用 eval.md 定义"什么叫改好了"、用 build_plugin.py 把整套规则打包成可复现的制品时,它实际上示范了一件事:给 AI 输出立规矩这件事本身,也可以被工程化。这或许比任何一条具体的禁词规则都更有价值。
【免费下载链接】no-ai-slopRemoves 20+ patterns of AI slop from any piece of writing.项目地址: https://gitcode.com/gh_mirrors/no/no-ai-slop
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考