误报归零的秘密:yomiyasu 如何用160篇语料打磨正则表达式
【免费下载链接】yomiyasuAI生成の日本語を自然な日本語へ推敲するAgent Skill / Agent Skill for Refining AI-Generated Japanese into Natural Japanese项目地址: https://gitcode.com/gh_mirrors/yo/yomiyasu
yomiyasu 是一个把 AI 生成的日语推敲成自然可读日语的 Agent Skill,随附一个用正则表达式量化"AI 味"的 linter。这套 linter 最难的地方不是揪出 AI 腔,而是不冤枉人——一个朴素的"壊れる"(坏了)关键词,就能把"胃坏了、饭团、闹钟坏了"全部扫进黑名单。本文拆解 yomiyasu 如何靠 160 篇分层语料,把正则误报一路打磨到零。
为什么"误报"是日语正则 linter 的第一敌人
AI 腔恰好集中在几个高频动词上:壊れる(坏了)、倒す(压倒)、溶かす(溶解)、効く(见效)、握る(握住)……可日语动词多义性极强,这些词同时承载着大量完全正当的日常含义。只要做正则 linter,就绕不开这些词。
yomiyasu 的基准脚本里内置了一组"朴素正则"作为对照组(见 benchmark_corpus.py#L22-L35):
壊れる → 壊(?:れる|れ|れず) 握る → 握(?:る|り|っ|ら) 倒す → 倒(?:す|し|さ)问题立刻暴露:壊(?:れる…)命中"お腹を壊してしまいました"(吃坏了肚子),握(?:…)命中"お握り"(饭团),倒(?:…)命中"卒倒"(过劳晕倒)——这些全是人写的、完全正常的日语。对新手写正则来说,这正是一个经典的陷阱:关键词匹配在"脏语料"上越多越好,在"干净语料"上一次都不能多。
160 篇语料:5 个分组各有分工
误报能不能归零,取决于你有没有一套"标准答案"来反复验证。yomiyasu 在 tests/corpus/ 下组织了一套 160 篇的分层语料:
| 分组 | 篇数 | 职责 |
|---|---|---|
human(人类写作) | 16 | 护栏:真人文章不能被冤枉 |
edge_cases(边界用例) | 48 | 回归测试:每条单句对应一个高危误伤场景 |
raw_ai(原始 AI 输出) | 24 | 真阳性对照:8 类题材 × 3 种语气 |
blacklist_ai(禁词版 AI 输出) | 24 | 验证"禁词法"的局限,检测残余 AI 味 |
yomiyasu_rewritten(推敲后文本) | 48 | 目标输出:应得到满分或极少警告 |
语料由两个脚本生成:build_corpus.py 批量产出 96 篇 AI 文章(原始、禁词版与推敲版),setup_corpus_static.py 生成 16 篇人类文章与 48 篇边界用例。
边界用例:48 句"最容易被冤枉"的日语
边界用例是误报归零的核心武器。每一条都是单句,专门命中一个朴素正则最容易误伤的语境,例如:
| 边界句(节选) | 朴素正则 | 真实含义 |
|---|---|---|
| edge_nigiru_01.md「お昼休みにコンビニでお握りを買って」 | 握(?:る|り|っ|ら) | 饭团 |
| edge_taosu_11.md「同僚が過労で卒倒してしまいました」 | 倒(?:す|し|さ) | 过劳晕倒 |
| edge_tokasu_21.md「ぬるま湯をかけて氷を溶かしました」 | 溶(?:かす|かし|かさ) | 物理融化冰块 |
| edge_kowareru_39.md「暴飲暴食で胃を壊してしまい」 | 壊(?:れる|れ|れず) | 吃坏了胃 |
每次修改正则后重跑基准,只要这 48 篇里出现一次命中,就视为回归失败。
正则打磨三板斧:从关键词匹配到上下文约束
最终的正则规则集中在 yomiyasu_lint.py#L48-L65。对比朴素版,打磨主要做了三件事:
1. 上下文锚定:只认"AI 腔"的搭配
"壊れる"本身无罪,AI 腔的标志是抽象名词 + 壊れる的组合。于是规则从"出现壊れる就报警"变成只在数据、设计、系统这类抽象主语后报警:
朴素版: 壊(?:れる|れ|れず) 打磨版: (データ|仕様|設計|環境|ビルド|システム|秩序)が(静かに)?壊れ这样一来,"時計が壊れた"(闹钟坏了)、"胃を壊す"(吃坏胃)全部自动豁免,而"データが静かに壊れる"(数据被悄悄搞坏)依然命中。
2. 防重复上报:同一个词只扣一次分
"静かに壊れる"(悄悄坏了)既是"壊れる"规则又是"静かに"规则的目标,朴素写法会对同一处扣两次分。yomiyasu_lint.py#L473-L489 用区间记录去重,保证每条命中只计一次。
3. 限定扫描范围:代码与引用不算"正文"
语料里大量出现反例引用(引用块中的 AI 坏例子)、代码块、表格。如果把这些都扫进来,误报必然爆表。yomiyasu_lint.py#L92-L130 的extract_plain_sentences会先剔除代码块、引用、表格、frontmatter 与行内代码,只对真正的正文句子做模式匹配。
基准测试结果:误报归零,真报不丢
benchmark_corpus.py 对 160 篇语料同时运行朴素正则与打磨后的 linter,完整结果存档在 benchmark_results.json:
| 分组 | 篇数 | 朴素正则命中 | linter 命中 | 说明 |
|---|---|---|---|---|
| edge_cases | 48 | 46 | 0 | ✅ 误报抑制率 100%,误报归零 |
| human | 16 | 14 | 10 | 剩余为轻微警告,平均分 97.4 |
| raw_ai | 24 | 7 | 12 | 真阳性比朴素版多抓 5 处 |
| blacklist_ai | 24 | 1 | 13 | 禁词挡不住的 AI 腔被持续检出 |
| yomiyasu_rewritten | 48 | 2 | 22 | 推敲后仅剩轻微格式提示,平均分 97.7 |
这张表讲了一个完整的故事:
- 🛡️干净语料(人类 + 边界用例共 64 篇):朴素正则命中 60 次,打磨后只剩 10 处轻微提示,边界组实现46 → 0的归零;
- 🎯AI 语料:朴素正则 48 篇只命中 8 次(它只会数关键词),打磨后的 linter 因为覆盖了比喩动词、前置废话、过度加粗、文末重复等更多维度,命中 25 次——误报少了,真报反而更多。
三步上手:跑一遍 linter 与基准测试
不需要改任何代码,三条命令就能复现全部流程:
python3 scripts/yomiyasu_lint.py your_article.md # 输出 AI 味评分报告 python3 scripts/yomiyasu_lint.py your_article.md --strict # CI 严格模式,有警告即失败 python3 scripts/benchmark_corpus.py # 重跑 160 篇语料基准新手写正则规则时建议照抄这套工作流:先写一组"脏样本"(该报警的),再手写 40~50 条"干净单句"(不该报警的),让基准脚本双向把关——误报归零之前,真阳性再高也不可信。
写在最后
对任何文本检查工具而言,"抓得多"只是及格线,"不误伤"才是生命线。yomiyasu 用 160 篇分层语料证明:正则表达式不需要更激进,它需要的是上下文约束 + 成体系的回归语料。这套方法不限于日语脱臭,写任何语言的 linter 都适用。更多规则背景可参考 SKILL.md 与 comparison_benchmark.md 中的三方对比数据。
【免费下载链接】yomiyasuAI生成の日本語を自然な日本語へ推敲するAgent Skill / Agent Skill for Refining AI-Generated Japanese into Natural Japanese项目地址: https://gitcode.com/gh_mirrors/yo/yomiyasu
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考