我们拿一章 AI 直接写出来的网文初稿,按开源项目 Oh Story 里的去 AI 味 skill(story-deslop)完整跑了一遍。初稿 1881 字,检测脚本报了 6 处阻塞、2 条提示;脚本没报、通读时才发现的问题有 3 处,其中一处是人物前后矛盾。改完 1859 字,阻塞清零,剩下一条提示按语境保留。
Oh Story 是我们团队维护的开源网文写作 skill 包,MIT 协议。这篇只记录这次实际跑出来的输出和改法。
初稿从哪来,去味怎么跑
为了让初稿接近大家平时直接让 AI 写出来的样子,我们另开了一个 Agent,只给一句要求:写一部都市异能网文的第一章,主角是老小区里的修锁匠,约 2000 字。没有加载任何 skill,也没有告诉它后面要检测。它交回的《第一章 锁会说话》能读,开头有钩子,结尾停在悬念上,问题都在细处。
去味这一步由 Agent 读 story-deslop 的 SKILL.md 照做。skill 要求先完整读三份方法:表达(词句和声口)、叙事用笔(篇幅落在哪)、故事逻辑(因果和人物所知),再跑检测脚本,改之前把原稿备份到书目录下的.story/work/去味原稿/,改完复扫,最后整理标点。环境是 macOS、Node 24,skill 取自 GitHub 仓库 main 分支。
读者自己装用 README 的命令:
npx skillsaddzenstory-ai/oh-story-claudecode-y-g装好后在 Agent 里说去 AI 味,或输入/story-deslop加正文路径。
1. 脚本预检:6 处阻塞全是破折号
从 skill 目录跑:
nodescripts/check-ai-patterns.js--check--fail-on=blocking<正文路径>nodescripts/check-degeneration.js--check--fail-on=blocking<正文路径>第一个脚本查句式和用词,第二个查复读、截断、占位符这类生成故障。这次第二个零报错,第一个的输出精简后是这样:
19:1 [blocking] em-dash (——今天早上七点二十) 21:1 [blocking] em-dash (——昨天晚上十一点,) 23:1 [blocking] em-dash (——上个月十五号……) 47:76 [blocking] em-dash (那块掉了漆的招牌——“江记修锁配钥匙) 83:62 [blocking] em-dash (,不是任何人的手——) 109:37 [blocking] em-dash (悉得让他眼眶一热——) 19:1 [advisory] micro-action-tic: 了一下式轻量补语 14 处(10.3/千字) 83:45 [advisory] formulaic-parallelism: 不是钥匙转动的声音,不是任何人的手blocking 要改到净,或者作者明确要保留时登记白名单;advisory 只是提示,回到上下文判断。
2. 破折号按用途改,不一律换句号
脚本给的改法是按破折号的用途处理:打断改成动作或短句,插入说明改成逗号或冒号。这次 6 处里,开头三行是一组,招牌和结尾各一处,剩下一处和否定排比连在一起,放到第 3 节说。
招牌那处是插入说明,直接并进句子:
改前:挂上那块掉了漆的招牌——“江记修锁配钥匙”,一干就是三年。
改后:挂上那块掉了漆的“江记修锁配钥匙”招牌,一干就是三年。
结尾那处引出一句台词,改成冒号。
开头三处最值得说。主角摸锁时能听见锁的记忆,初稿用三行破折号排出来:今天早上谁开过,昨天晚上谁犹豫过,上个月十五号……然后他睁眼开锁。我们去掉破折号,把第三行改成:
再往前是上个月十五号。江迟没再听下去,睁开眼,手腕一拧,“咔哒”一声,门开了。
省略号原本表示他中途不听了,现在由一句动作交代。代价是锁的声音不再有特殊排版,和普通叙述靠得更近。如果作者想把破折号当成这本书里锁说话的固定格式,skill 支持在书目录的.deslop-whitelist里登记,前提是文风文件写明了这个选择,脚本报警不能当作放行的理由。这次没有文风文件,所以按默认改掉。
3. 脚本没报的 3 处
这一步才是去味的主体。skill 明确写了零命中不代表合格,三份方法要逐层读。
第一处是人物前后矛盾。主角开完锁,压低声音问老太太:您孙子昨晚回来过?紧接着叙述说:
这事他不打算多管。……早就学会了一件事:听见了,不代表要说出来。
他刚刚问出口,叙述却说他的原则是不说。我们只改叙述,承认他已经问过:
江迟问到这儿就打住了。……学会的头一件事就是听见了也别往外说,今天已经多嘴了一句。
故事逻辑那份方法规定普通去味只能恢复已有的承接,不能替作者新增事件或改人物决定。这里人物的行为没动,只让叙述和行为对上。
第二处是重复。锁的记忆里已经交代了昨晚十一点的年轻男人,几段后又完整复述一遍,我们把两段合成一段,只留下新信息:孙奶奶的孙子并没有回来。
第三处是套话。原句写一个陌生男人看着铜钥匙,眼神里有种说不出的东西,像是怀念,又像是忌惮。说不出的东西这半句放在任何人身上都成立,删掉;怀念和忌惮暗示他认识这把钥匙的主人,后文要用,保留。
另外,脚本提示的那句否定排比也改了。原文是他碰门锁时听见的不是钥匙转动的声音,不是任何人的手,接着破折号转到门里面的声音。听见一只手本身就说不通,我们改成:
那把锁里一段开门的记忆都没有,只有一个声音,是从门里面传出来的。
这样既去掉了排比,也顺带交代了那扇门二十年没人开过,和前文的设定对上。
4. 复扫:阻塞清零,一条提示保留
改完复扫,check-ai-patterns 和 check-degeneration 都没有 blocking,退出码 0。标点脚本 normalize-punctuation 没再改动任何文件,破折号和省略号已经在语义修改时处理掉了。
剩下一条 advisory:了一下式补语 13 处。逐处看过,转了两圈半、转了一圈是锁的记忆本身,扫了一圈、闪了两下交代动作的范围和次数,这些删了会丢信息。我们只把两处纯标注动作的看了看、推了推改掉,其余保留。skill 写明 advisory 不是完成门槛,不为归零机械改稿。
全章从 1881 字变成 1859 字,少了 22 字。去 AI 味主要是改,删得很少。
跑完的几点看法
- 检测脚本最适合定位确定性的问题,比如破折号、复读、截断。这次 6 处阻塞几分钟就能改完。
- 真正影响阅读的是通读出来的那处矛盾,脚本抓不到。只跑脚本、不按三层方法读一遍,等于只做了一半。
- 去味有边界:可以改表达、调详略、接上已有的因果,不能为了显得像人写的去加新动作、新冲突。人物前后矛盾这种问题,这次能只改叙述解决;如果要改人物的决定,skill 只给方案,等作者同意后再改。
- 想保留的写法用白名单登记,不要靠错字或拆句躲检测。
源码:https://github.com/zenstory-ai/oh-story-claudecode
你用 AI 写的稿子里,最常被读者挑出来的是哪一类问题?