框架: P2收口——sweep收割器(审计种子+手动种子)+守卫终形(微信特征/书名行/20%顶下限)+SKILL.md实测定版+README§九刷P2账

This commit is contained in:
zizi 2026-07-13 16:01:46 +08:00
parent 0a3a576704
commit ee372f7ea2
4 changed files with 142 additions and 23 deletions

View File

@ -1,39 +1,45 @@
---
name: clean
description: LLM 辅助正文清洗——MiniMax-M3 按窗口约10万字只输出待删垃圾段原文与理由代码做精确匹配删除并全程留审计example_clean_log。LLM 不改写正文,删不删由四道守卫规则最终裁决。
description: LLM 辅助正文清洗——MiniMax-M3 按窗口约10万字只输出待删垃圾段原文与理由代码做精确匹配删除并全程留审计example_clean_log。LLM 不改写正文,删不删由守卫规则最终裁决。
---
# clean —— LLM 检测 + 代码执行的正文清洗
分工(创始人方案 2026-07-13**规则层**已在 import 解决结构性垃圾(水印正则/重贴章题/目录页/分页尾巴/残破实体);本 skill 处理**语义垃圾**——变体书站广告、作者拉票/PS 段、乱码水印等正则打不全的散落噪声。LLM 只当探测器(输出待删片段逐字原文),删除由脚本执行:零改写、可审计、可回放。探测模型=New-API `MiniMax-M3`创始人拍板,经 llm skill 统一入口调用)。
分工(创始人方案 2026-07-13**规则层**已在 import 解决结构性垃圾(水印正则/重贴章题/目录页/分页尾巴/残破实体);本 skill 处理**语义垃圾**——变体书站广告、作者拉票/PS 段、微信导流、乱码水印等正则打不全的散落噪声。LLM 只当探测器(输出待删片段逐字原文),删除由脚本执行:零改写、可审计、可回放。探测模型=New-API `MiniMax-M3`经 llm skill单窗失败自动降级 `deepseek-v4-flash`,再失败记录跳过——网文正文会触发上游敏感词拦截,实测两处均被备选救回)。
## 流程
```bash
# 1) 备窗口:按章对齐切窗(默认 ~10万字/窗,写 /tmp/muse-clean/<work>/win-*.txt + manifest
.venv/bin/python .claude/skills/clean/scripts/clean_prep.py --work-id 7 --window 100000
# 放量驱动(每书 prep→detect→apply 全链;断点续跑/幂等防重删;可多进程分书并行
.venv/bin/python .claude/skills/clean/scripts/clean_batch.py --work-id 7 --work-id 10 --batch <批次号>
# 2) 探测:每窗一次 M3 调用prompt 内置于脚本;断点续跑,已有产物自动跳过)
.venv/bin/python .claude/skills/clean/scripts/clean_detect.py --work-id 7 [--win 1 --win 2] [--force]
# 单步(调试/演示用)
.venv/bin/python .claude/skills/clean/scripts/clean_prep.py --work-id 7 [--from 1 --to 50] # 切窗
.venv/bin/python .claude/skills/clean/scripts/clean_detect.py --work-id 7 [--win 1] # M3 探测
.venv/bin/python .claude/skills/clean/scripts/clean_apply.py --work-id 7 --batch X --file … [--dry-run] [--report-md docs/清洗-N-书名.md]
# 3) 执行:先 dry-run 对账出删除明细(质检样张),确认后去掉 --dry-run 落库
.venv/bin/python .claude/skills/clean/scripts/clean_apply.py --work-id 7 --batch <批次号> --file /tmp/muse-clean/7/deletions-001.json [--dry-run]
# 收尾收割高频水印全书规则扫净LLM 每窗只报样例,重复水印靠种子收割)
.venv/bin/python .claude/skills/clean/scripts/clean_sweep.py --work-id 7 --batch X # 审计自动种子(重复≥3次且≥20字)
.venv/bin/python .claude/skills/clean/scripts/clean_sweep.py --work-id 4 --batch X --seed "http://m." # 人工确认的碎水印
# 4) 审查:删除对账(理由分布/字数)+ 审计行抽查
.venv/bin/python .claude/skills/db/scripts/db.py query "SELECT reason, count(*), sum(length(removed_text)) FROM example_clean_log WHERE work_id=7 AND batch='<批次号>' GROUP BY reason"
# 审查:审计对账
.venv/bin/python .claude/skills/db/scripts/db.py query "SELECT batch, count(*), sum(length(removed_text)) FROM example_clean_log WHERE work_id=7 GROUP BY batch"
```
## 四道守卫脚本硬闸LLM 建议 ≠ 必删;全部为首窗真跑实测病对症)
⚠️ prep 会覆盖 /tmp/muse-clean/<work>/ 的窗与 manifest——换范围重切前先归档旧产物目录。
## 守卫体系脚本硬闸LLM 建议 ≠ 必删;全部为放量实测病对症)
1. **长度界**`exact` 4500 字;
2. **章题保护**:不得含/命中所在章章题;
3. **单章 20% 顶**:单章累计删除超章长 20% → 整章回退不落库;
4. **行级垃圾特征**exact 每一行必须命中通用垃圾词ps头/感谢/打赏/求票/域名符号…不含书内专名——盗版源会把广告插进正文句子中间M3 会把「广告+被截断正文」拼成一项,无特征行拆行跳过(宁漏删不误删)。
3. **单章顶**:单章累计删除 ≤ max(章长 20%, 120 字)——绝对下限救短章(百字残章按比例删不了任何垃圾);
4. **行级垃圾特征**exact 每一行必须命中通用垃圾词ps头/感谢/求票/微信公众号/域名符号/盗版占位语…不含书内专名)或书名水印豁免(孤行=本书名、行含《本书名》);无特征行拆行跳过(宁漏删不误删——实拦「广告+被截断正文」粘连 3 处);
5. **水印裁剪**:删除段含明确水印模式(百镀一下/一秒记住…免费阅读)且水印前有前缀时只删水印——防「正文行尾粘水印」误删正文头(实测修复 1 例 3 字误删)。
匹配三级(对症 M3 两类实测病):精确命中 → 空白弹性M3 折叠 `\n\n\n``\n\n`)→ 邻章 ±1 容错(长窗内偶发章号偏移)。三级全失败 → 拒绝。每次删除一行审计(原文/理由/模型/批次),源 txt 永远不动(可整书重导回滚);删完刷新 block/work 字数
匹配三级:精确命中 → 空白弹性M3 折叠 `\n\n\n``\n\n`)→ 邻章 ±1 容错(长窗内章号偏移fix 轮还能二次收割邻章重复水印)。三级全失败 → 拒绝。收尾规则:被删 ps 段的前置星号分隔线孤悬章尾则连带清除;被清洗章空行归一。每次删除一行审计(原文/理由/模型/批次),源 txt 永远不动(可整书重导回滚)。
## 量级实测2026-07-13 首窗定标
## P2 全语料实测2026-07-13 收口
- M3 中文 tokenizer ≈ **0.58 token/字**10 万字窗 in≈5.9 万 token、out≈2k、耗时 ~24s
- 机破星河前 50 章12.9 万字2 窗39 条建议 → 40 段删除(拆行后)/2,188 字,误删 0
- 全语料8 书 ≈3,300 万字)≈ **340 窗 ≈ 340 次 M3 调用,输入 ~19M token**
- 8 书 ≈3,300 万字 ≈340 窗M3 中文 ≈0.58 token/字,总输入 ~20M token10 万字窗 in≈5.9 万 token、耗时 1025s
- 总删除 **1,685 段 / 约 6.1 万字**(机破星河 2.4 万最脏、机战无限 1.9 万次之);误删实测 1 例 3 字(已修复+守卫补上)
- 已知残留:作者疲劳话(无通用特征)、「重贴章题+第N更 求月票)」嵌正文行变体(高风险规则,待拍)、感言/请假条整章(结构性存在,段落清洗不动章)

View File

@ -32,7 +32,8 @@ GARBAGE_LINE_PAT = re.compile(
r"|(?:月|推荐|评价|催更|票)票|起点币|求(?:收藏|推荐|订阅|票|月票)|拉票|冲榜"
r"|龙套|上架|[aA]签|签约|加更|[一二三四五六七八九十]更|更新时间|码字|存稿|请假|感言"
r"|www|http|[\._]{2,}|→|♂|÷|一秒记住|记住本站|无弹窗|手机版|首发|最新章节|整理|转载"
r"|手打中|稍等片刻|重新刷新|获取最新", # 盗版站占位残留1040-1060 验证窗实测)
r"|手打中|稍等片刻|重新刷新|获取最新" # 盗版站占位残留1040-1060 验证窗实测)
r"|微信|公众号|书名[:]|想听到更多你们的声音|想收到更多你们的建议", # 作者导流/推书段(机战无限/星环实测)
re.I)
# 水印裁剪:盗版源把水印粘在正文行尾(如『“我草!”百镀一下“××”最新章节第一时间免费阅读。』),
@ -122,7 +123,8 @@ def main(work_id, batch, file_, model, dry_run, report_md):
lines = [ln for ln in exact.split("\n") if ln.strip()]
plain = [ln for ln in lines
if not GARBAGE_LINE_PAT.search(ln)
and not (work_title and ln.strip() == work_title)]
and not (work_title and (ln.strip() == work_title
or f"{work_title}" in ln))]
if plain and len(lines) == 1:
stats["拒绝"].append(f"#{no}: 无垃圾特征疑正文 {exact[:24]!r}")
continue
@ -132,7 +134,8 @@ def main(work_id, batch, file_, model, dry_run, report_md):
stats["拒绝"].append(f"#{no}: 拆行跳过疑正文行 {ln[:24]!r}")
units = [(ln, reason + "(拆行)") for ln in lines
if (GARBAGE_LINE_PAT.search(ln)
or (work_title and ln.strip() == work_title))
or (work_title and (ln.strip() == work_title
or f"{work_title}" in ln)))
and MIN_LEN <= len(ln) <= MAX_LEN]
else:
units = [(exact, reason)]
@ -177,7 +180,8 @@ def main(work_id, batch, file_, model, dry_run, report_md):
for no, ch in sorted(chapters.items()):
if not ch["audit"]:
continue
if ch["removed"] > len(ch["orig"]) * MAX_CH_RATIO:
# 20% 顶带绝对下限:短章(如百字残章)按比例几乎删不了任何垃圾,放宽到至少 120 字
if ch["removed"] > max(len(ch["orig"]) * MAX_CH_RATIO, 120):
stats["删除段"] -= len(ch["audit"])
stats["删除字数"] -= ch["removed"]
stats["拒绝"].append(f"#{no}: 累计删除 {ch['removed']} 字超章长20%上限,整章回退")

View File

@ -0,0 +1,108 @@
#!/usr/bin/env python3
"""clean skill高频水印全书规则收割LLM 探测样例 → 代码全书扫净)。
M3 按窗探测对每章重复的固定水印只会报样例章窗内看到逐章报全残留由本脚本收割
- 种子=example_clean_log 中该书重复删除段相同 removed_text 出现 min-occur 长度 min-len
种子都是已过全部守卫的真垃圾 20+ 字逐字重复 3+ 次的段不可能是正文
- 全书逐章 replace 删除含空白弹性审计入库20% 顶守卫保留
"""
import re
import sys
import click
import psycopg
DSN = ("postgresql://root:f6710e2d0294eb1c10e26a805a64bc54@100.64.0.8:5433/muse-example"
"?keepalives=1&keepalives_idle=15&keepalives_interval=5&keepalives_count=3")
TENANT, ACTOR = 1, "1"
def flex_pattern(exact):
"""空白弹性正则(与 clean_apply 同构:文字逐字、空白段弹性)。"""
parts = [p for p in re.split(r"\s+", exact) if p]
return re.compile(r"\s+".join(re.escape(p) for p in parts)) if parts else None
@click.command()
@click.option("--work-id", type=int, required=True)
@click.option("--batch", required=True, help="收割批次号(审计标注)")
@click.option("--min-occur", type=int, default=3, show_default=True, help="种子最小重复次数")
@click.option("--min-len", type=int, default=20, show_default=True, help="种子最小长度")
@click.option("--seed", "manual_seeds", multiple=True,
help="手动种子(替代审计自动发现;用于人工确认过的碎水印,如孤行网址)")
@click.option("--dry-run", is_flag=True)
def main(work_id, batch, min_occur, min_len, manual_seeds, dry_run):
with psycopg.connect(DSN) as conn:
# 种子:手动指定(人工确认的碎水印),或该书审计里的重复删除段(已过全部守卫的真垃圾)
seeds = list(manual_seeds) or [r[0] for r in conn.execute(
"""SELECT removed_text FROM example_clean_log
WHERE tenant_id=%s AND work_id=%s AND length(removed_text)>=%s
GROUP BY removed_text HAVING count(*)>=%s
ORDER BY count(*) DESC""",
(TENANT, work_id, min_len, min_occur)).fetchall()]
if not seeds:
click.echo(f"work={work_id} 无重复水印种子")
return
click.echo(f"work={work_id} 种子 {len(seeds)} 个:")
for s in seeds:
click.echo(f" · {s[:50]!r}")
rows = conn.execute(
"""SELECT c.order_no, c.id, b.id, b.content_text
FROM muse_content_chapter c JOIN muse_content_block b ON b.chapter_id=c.id AND b.deleted=FALSE
WHERE c.tenant_id=%s AND c.work_id=%s AND c.deleted=FALSE ORDER BY c.order_no""",
(TENANT, work_id)).fetchall()
n_del = n_ch = chars = 0
for no, ch_id, blk_id, text in rows:
new_text, audit = text, []
for seed in seeds:
n = new_text.count(seed)
how = ""
if n:
new_text = new_text.replace(seed, "")
else:
pat = flex_pattern(seed)
if pat:
new_text, n = pat.subn("", new_text)
how = "(空白弹性)"
if n:
audit.append((seed, n, f"高频水印全书收割{how}"))
if not audit:
continue
removed = len(text) - len(new_text)
# 20% 顶守卫(绝对下限 120 字,与 clean_apply 一致)
if removed > max(len(text) * 0.20, 120):
click.echo(f" [拒] #{no}: 收割 {removed} 字超顶,整章回退")
continue
new_text = re.sub(r"(?:\s*\n\s*[*]{3,}\s*)+$", "\n", new_text)
new_text = re.sub(r"\n{3,}", "\n\n", new_text)
n_ch += 1
n_del += sum(a[1] for a in audit)
chars += removed
if dry_run:
continue
wc = len(re.sub(r"\s", "", new_text))
conn.execute("UPDATE muse_content_block SET content_text=%s, word_count=%s, updater=%s WHERE id=%s",
(new_text, wc, ACTOR, blk_id))
for seed, n, note in audit:
conn.execute(
"""INSERT INTO example_clean_log (work_id, chapter_id, batch, removed_text, occurrences,
reason, model, creator, updater, tenant_id)
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)""",
(work_id, ch_id, batch, seed, n, note, "rule-sweep", ACTOR, ACTOR, TENANT))
if not dry_run:
conn.execute(
"""UPDATE muse_content_work w SET word_count=(
SELECT COALESCE(sum(b.word_count),0) FROM muse_content_block b
WHERE b.tenant_id=%s AND b.work_id=w.id AND b.deleted=FALSE), updater=%s
WHERE w.id=%s""", (TENANT, ACTOR, work_id))
conn.commit()
mode = "dry-run" if dry_run else ""
click.echo(f"收割{mode}: {n_ch} 章 / {n_del} 处 / {chars:,}")
if __name__ == "__main__":
try:
main()
except psycopg.Error as e:
click.echo(f"[db错误] {type(e).__name__}: {e}", err=True)
sys.exit(1)

View File

@ -226,7 +226,8 @@ flowchart LR
- **M3 拍板2026-07-13 创始人)**:清洗与拆书的内容生产 LLM **全部改走 New-API `MiniMax-M3`**llm skill 统一入口密钥入仓主会话Fable5只固化 agent/提示词/skill 与发起调用。清洗范围=**所有书**;删除前创始人质检样张(门①);**拆书先不放量**(试拆 M3 重做后质检=门②B2 硬停等新指令)。执行计划:`docs/2026-07-13-M3清洗拆书执行计划.md`
- **清洗 P0/P1 收口2026-07-13**llm skillM3 入口+json-repair 三级容错)+ clean_detect每窗一调、断点续跑+ clean_apply 四道守卫(长度界/章题/单章20%顶/**行级垃圾特征拆行**——盗版源把广告插进正文句中M3 会拼「广告+截断正文」,已实测拦住)+ 三级匹配(精确/空白弹性/邻章±1。实测定标M3 中文 0.58 token/字10 万字窗 in≈5.9 万 token 耗时 24s全语料 ≈340 调用/~19M token。机破星河前 50 章演示已备40 段/2,188 字待删dry-run误删 0。
- **opus 试拆基准workflow 已完成)**:机动风暴 13 章,范式卡 2 张入库ch2/ch3 各 1 拒 1 越合同)+ch1 脚手架opus 也犯 JSON 中文引号/缺逗号病(已被 llm skill 容错吸收)。此产物只作 M3 对比基准,不算正式拆书。
- **未决**:①门① 清洗样张质检(明细在 /tmp/muse-clean/7/dryrun-00*.txt已呈报→过门后 P2 全语料放量②门② M3 试拆样张质检P3 固化后跑 5 本×前 3 章③B2 放量(硬停,等创始人新指令)。
- **P2 全语料清洗收口2026-07-13**8 书全清(门①创始人放行)——总删 1,685 段/约 6.1 万字(机破星河 2.4 万/机战无限 1.9 万/超神 0.6 万…),审计全在 example_clean_log批次 P2-20260713 主删 + fix/fix2/fix3 补删 + P2-sweep 高频水印收割),全库空行归一 8,786 章。守卫体系放量长成:行级垃圾特征+书名豁免+水印裁剪+20%顶带下限+敏感窗备选模型降级(见 clean/SKILL.md。误删实测 1 例 3 字已修复。已知残留待拍:机动风暴「重贴章题+第N更 求月票)」嵌正文行变体(求票嫌疑 270 处主源)、感言/请假条整章、作者疲劳话散句。
- **未决**:①门② M3 试拆样张质检parse_llm.py 已固化,跑 5 本×前 3 章后呈报②B2 放量(硬停,等创始人新指令)③机动残留变体与感言章处理方式(全局报告中待拍)。
- **教训入档**StructuredOutput 工具 schema 属性名仅限 ASCII中文键 API 400——schema ASCII 键+入库脚本键名归一Tailscale 长事务需 keepalive+批量写(逐行两万往返曾半死 16 分钟)。
## 九·旧2026-07-10 快照,留档)