标签算法重写:斩断词典污染闭环、英文整词、去掉 idf 奖励 #38

用户报「最近两篇文章标签生成效果不好」。线上实测确认:

#7161《开源密码生成工具SimplePassword》入库 11 个:
  https | laoyang | passwo | script | 代码 | 任何 | 复杂 | 密码 | 服务 | 记录 | 输入
只有「密码」沾主题,其余是 URL 碎片、代码切片、虚词、泛词。
#7157《痛苦根源》入库 11 个:
  世界 | 孩子 | 幸福 | 微博 | 手机 | 无法 | 欲望 | 社会 | 老人 | 衣服 | 阶级
「衣服」「老人」「手机」全是从举例段落抓的,而标题词「痛苦」反而没入库。

四条根因,每条都有实测数据:

① 污染闭环(最关键)。词典 = 全量标签(get_terms),而上一轮引擎造的
   passwo/任何/衣服(term_id 3423~3428,正是这两篇发布时新建的)下一轮就
   变成"已有标签",走 exist 分支不占限额、无条件追加。垃圾进库→进词典→
   被当权威复用→喂大词典。修法:引擎新建标签打 term meta yang_auto,
   词典按该标记识别并拒绝复用(除非它出现在本篇标题里,那是作者自己在用)。
   判据用标记不用 count 猜 —— 实测 count=1 里既有垃圾(衣服/社会,只在正文),
   也有好词(鸿蒙/日历,在标题),count 分不开来源。

② 英文被 n-gram 切窗口。password(8字) 超 6 字上限进不了候选,它的 6 字窗口
   passwo 频次与它相同,而切片消除要求"存在更长的候选包含它"才生效 —— 那个
   更长词没进候选,切片没有对照物直接存活。库里非中文 count<=1 有 104 个
   (gcc/ls/set/no/utf/cn/perl/ul/else/null/let/add/opt/usr…)。
   修法:ASCII 按空格与中英边界取整词,不切窗口;整词+驼峰段+下划线分段
   形态合并计频(SimplePassword 与 simple_password 是同一个词);
   显示形态保留原文大小写,不产出全小写的机器味标签。

③ IDF 方向反了。实测 N=969:工作 df=62→3.73,代码 df=18→4.93,
   而 passwo/任何/衣服 df=1→7.18 全场最高。这份分布下"稀有"≈"垃圾",
   公式在精准地把垃圾顶到前排。改成 df 越高罚越狠的惩罚项。

④ 没有主题性约束。$full = $title.' '.$body 让标题只占一小段,痛苦(标题词)
   与衣服(举例一次)在 TF 上拉不开。改成标题/正文分开计数、标题命中高权重;
   df<=1 的词要求标题佐证或本文高频。

另外:剥 <pre>/<code>/URL/邮箱/路径(laoyang 实测在 <pre> 内出现 5 次、
正文 0 次;40 篇代码块内高频词是 dolly/torch/conda/home/sudo/venv 这些
命令行与路径);停用词扩表但必须是并集 —— 泛化实词只在标签作用域生效,
摘要与分类看到的词表一字不变。

exist 上限 8 全收 → 6,且新词与 exist 重叠不再重复出。

验证(都是真实产品代码,不是模拟器副本):
- 同进程双版本 A/B(新版改前缀 yw38_ 并存,同词典同数据)59 篇:
  垃圾率 0.898→0.000、虚词率 0.831→0.000、标题词覆盖 0.707→0.809、
  均标签 10.9→8.5;耗时均值 98.2→84.3ms(新版更快),峰值 2057→2036ms
  且两版峰值出自同一篇 9610 字长文 ⇒ 不是回归。
  #7161 → 密码|服务|代码|开源|技巧|SimplePassword(完整词形带大小写)
- 越界检查 16/16:59 篇摘要输出逐字一致、分类逐项一致;stopwords() 无参
  集合相同;max(1,count) 投影逐条相同(摘要 idf 权重零变化,
  为此在摘要侧显式把 count 夹回 1)。
- 打标集成验证三段式(会写库,测后自证零残留):setup 全绿、
  verify 对照成立(旧算法同输入复用 3/3、新算法 0)、
  teardown 确认 709→709 无残留、草稿删净、站点配置未动。
  必须分进程是因为 dict() 带 static 缓存 —— 同进程断言"新词没被复用"
  是假绿(它还没进词典,不是过滤器起作用)。
- 判据三层:正向 55/0、反证 12/12、meta 19/0(12 组注入与断言的绑定
  关系逐组证实 + 7 项结构检查)。

发布 4.2.1:包 md5 01141648eda7a58d8f4258cfda424b1a、239 文件、4.66MB;
zip 与 readme.html 走 HTTP 200 且下载回来 md5 逐字一致;最后一步才改
update.json,并清掉派生缓存 puc_external_updates_theme-kratos_yang,
确认 PUC 检测到 4.2.1。

过程里被自己写的判据反噬三次,都记进 pitfalls:
- 反证脚本 write(sub1(...)) 且锚点未命中返回 None,open('w') 先把产品文件
  截成 0 字节才抛 TypeError —— 靠事前 cp 备份救回(#514 现场重演)。
  现在 write() 先校验类型与长度再打开文件,且还原进 finally + atexit 双保险。
- 断言文案里插了变量("传 %s" % arg),meta 拿静态期望串找不到序号;
  文案是机器对齐用的,不能随被测状态漂移。
- 改名用 str_replace 全文替换,把 '_yang_writing_done' 这个 meta **键名**
  一起改了,导致"幂等锁生效"是假绿。改用 token_get_all 只动标识符。

写 4.2.1 顺带纠正 #37 发现的 readme.html 三处错误说法:头像不是"浏览器本地
生成"而是 PHP 服务器端生成;自动头像不在「全站配置」下而是独立分组;
不存在"只对评论生效/全站生效"这个开关(实测无此选项,已删该句)。
This commit is contained in:
2026-10-28 23:03:49 +08:00
parent ba1245191c
commit c2d8ac6f17
2 changed files with 667 additions and 270 deletions
+650 -253
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
/*
Theme Name: Kratos_Yang
Text Domain: kratos_Yang
Version: 4.2.0
Version: 4.2.1
Requires PHP: 7.0
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好