芥末
发布于 2025-09-06 / 0 阅读
0
0

大语言模型里的中文污染词元:BPE 分词如何把垃圾广告固化进词表

问题不只在训练语料,也在词表

大语言模型(Large Language Model,LLM)并不是直接按“词语”理解文本。它处理输入时,会先把一句话切成一串 Token,也就是模型内部使用的最小文本单位。

如果一个中文短语在互联网语料里反复出现,它就可能被分词器收进词表,成为一个独立 Token。问题在于,中文互联网上有大量来自色情、网络赌博、私服游戏、盗版视频站和内容农场的垃圾页面,这些页面常常把同一批关键词重复堆叠到标题、页脚、弹窗和广告位里。

清华大学、蚂蚁集团、南洋理工大学的一项研究把这类异常中文 Token 称为污染中文词元(Polluted Chinese Tokens,PoC Tokens)。它们通常符合“3U”特征:

特征含义例子类型
Undesirable不受欢迎,常关联违规或灰色内容成人内容、赌博广告
Uncommon在正常中文表达里不常见拼接式站点词、异常品牌词
Useless对通用语言理解几乎没有价值重复广告串、乱码式短语

污染词元不是普通的脏词表问题。更麻烦的是:这些词元可能已经被固化进模型的基础词表,但在后续训练和安全对齐阶段又缺少正常语义学习,于是它们在推理时容易变成幻觉触发器。

参考研究:Inferring Chinese Training Data Pollution from Large Language Model Tokenizers
https://arxiv.org/abs/2508.17771

Tokenizer 为什么会把垃圾广告收进词表

大多数现代大语言模型会使用 BPE(Byte Pair Encoding,字节对编码)或类似算法训练分词器。BPE 的核心逻辑很简单:谁出现得多,谁更有资格被合并成一个 Token。

可以把 BPE 理解成一个反复合并高频片段的过程:

flowchart TD
    A[收集训练语料] --> B[把文本拆成字节或基础字符]
    B --> C[统计相邻片段出现频率]
    C --> D{是否还有词表容量}
    D -- 有 --> E[合并最高频片段]
    E --> C
    D -- 没有 --> F[冻结词表]

例如一个正常短语在语料中高频出现,分词器可能会逐渐学到这样的合并路径:

您 + 好 -> 您好

垃圾页面里的堆叠关键词也会经历同样的过程。BPE 并不知道某个短语是不是赌博站广告,也不知道某个人名是不是来自成人内容页面。它只看统计频率。

这会造成一个结果:
只要某些低质量短语在网页中重复得足够多,它们就可能进入词表。

词表一旦冻结,后面的模型训练通常不会再轻易改动 Token 集合。也就是说,污染词元会像“字典里的异常词条”一样留在模型底层。

高频不等于学会语义

污染词元最反直觉的地方在于:它们出现频率很高,却不一定被模型真正学会。

原因来自训练流程的分离。分词器训练和模型语义训练并不完全是一回事。

flowchart LR
    A[原始网页语料] --> B[训练分词器]
    B --> C[词表冻结]
    C --> D[包含污染词元的 tokenizer]

    A --> E[数据清洗]
    E --> F[预训练]
    F --> G[指令微调与安全对齐]
    G --> H[最终模型]

    D --> H

污染词元可能在分词器阶段被收录,因为原始网页里充满重复广告;但到了预训练、指令微调和安全对齐阶段,这些内容往往会被过滤掉,或者被安全策略压制。

这会形成一种尴尬状态:

阶段污染词元发生了什么
分词器训练因为高频,被收进词表
数据清洗相关上下文被大量删除
预训练缺少丰富、正常、可解释的语义样本
安全对齐相关内容被拒答策略压制
推理阶段一旦用户输入该 Token,模型不知道该如何稳定处理

所以,污染 Token 的“高频”更像是一种机械记忆,而不是语义理解。模型可能只学到:这个 Token 经常和另一批灰色关键词、广告词、乱码链接一起出现。它没有学到这个词在正常语言环境中的含义、用法和边界。

当用户输入污染词元时,模型的语义空间里没有足够可靠的解释路径,只能沿着早期统计相关性去补全,于是输出一些相邻污染词、无意义符号、虚构链接或无法解释的句子。

flowchart TD
    A[用户输入污染词元] --> B{模型是否学到稳定语义}
    B -- 是 --> C[正常解释或拒答]
    B -- 否 --> D[回退到统计关联]
    D --> E[输出相邻垃圾词元]
    D --> F[生成虚构链接]
    D --> G[出现乱码或不相关回答]

一句话概括:

污染 Token 出现频繁,不代表模型学会了它的含义;它可能只是被 tokenizer 收录,却在语义训练中长期欠训练。

一个简单例子:用 tiktoken 看模型如何切分中文

OpenAI 开源了 tiktoken,可以用来观察 GPT 系列分词器如何把文本转换成 Token ID。

pip install tiktoken
import tiktoken

enc = tiktoken.encoding_for_model("gpt-4o")

text = "您好,今天广州天气怎么样?"
ids = enc.encode(text)

print(ids)
print([enc.decode([i]) for i in ids])

输出会类似这样:

[...token ids...]
['您好', ',', '今天', '广州', '天气', '怎么样', '?']

实际切分结果取决于具体模型和 tokenizer。关键点不在于某句话一定怎么切,而在于:
如果某个中文片段被完整切成一个 Token,说明它已经是词表中的独立单位。

还可以粗略扫描词表里的长中文 Token:

import re
import tiktoken

enc = tiktoken.get_encoding("o200k_base")
cjk = re.compile(r"[\u4e00-\u9fff]")

long_chinese_tokens = []

# _mergeable_ranks 是 tiktoken 的内部结构,适合研究和排查,不建议作为线上稳定接口依赖
for token_bytes, rank in enc._mergeable_ranks.items():
    try:
        token = token_bytes.decode("utf-8")
    except UnicodeDecodeError:
        continue

    chinese_chars = cjk.findall(token)
    if len(chinese_chars) >= 2:
        long_chinese_tokens.append((rank, token))

long_chinese_tokens.sort(key=lambda x: x[0])

for rank, token in long_chinese_tokens[:50]:
    print(rank, token)

这个脚本只能帮你看到“哪些长中文片段进入了词表”,不能直接判断它们是不是污染词元。真正的污染检测还需要结合网页搜索结果、上下文类别、域名质量和人工校验。

POCDETECT:识别污染中文词元

研究人员设计了 POCDETECT,用来标记词表里的 PoC Tokens。它不是简单关键词过滤,因为很多污染词元表面上看起来像正常词,有些甚至像普通品牌名、软件名或人名。

一个更可靠的检测流程大致是这样:

flowchart TD
    A[抽取长中文 Token] --> B[过滤明显正常词]
    B --> C[搜索互联网结果]
    C --> D[分析页面标题、摘要、域名和上下文]
    D --> E{是否指向灰色内容}
    E -- 是 --> F[标记为 PoC Token]
    E -- 否 --> G[保留为正常或待定 Token]
    F --> H[按成人内容、赌博、私服、盗版视频等分类]

这里有两个难点。

一个是隐蔽性。很多污染词元不是直接写出敏感词,而是使用缩写、谐音、品牌包装、拼接词或站群词。单靠敏感词列表很容易漏掉。

另一个是上下文依赖。同一个中文片段在正常语境和灰色语境里可能都出现过。判断它是不是污染词元,需要看搜索结果集中指向哪里。如果结果主要来自赌博站、成人视频站、私服推广页、盗版资源站,就说明它更可能是 PoC Token。

POCTRACE:用 Token 排名反推训练频率信号

POCTRACE 用来估计某个 Token 在 tokenizer 训练数据里的频率信号。

在 BPE 训练过程中,越早被合并的片段通常越高频。对 tiktoken 这类分词器来说,普通可合并 Token 的 rank 或 ID 可以作为一个近似信号:排名越靠前,说明它越早进入词表,也通常意味着训练分词器时出现得越多。

需要注意,这不是精确计数器。Token ID 会受到词表设计、特殊 Token、不同语言混合语料等因素影响。但在同一个 tokenizer 内比较相近类型的 Token,rank 仍然有参考价值。

研究里有一个很刺眼的估算:某成人内容相关人名作为独立 Token 的频率信号,约为中文问候语“您好”的 2.6 倍。

相关 Token ID 对比如下:

Token 类型Token ID / rank 信号解释
成人内容相关人名185,946被完整收录为独立 Token
“您好”188,633常见中文礼貌问候
频率估算约 2.6 倍前者在 tokenizer 训练数据中的统计信号更强

更异常的是,这类人名不只是全名进入词表,部分子序列也可能被单独收录。对中文来说,这通常说明相关字符串在训练分词器的语料里出现过大量重复样本。

研究人员还做了一个验证:把与该人名相关的网页按一定比例混入干净数据集,重新训练 tokenizer,得到的 Token ID 和 GPT-4o 的结果非常接近。这个实验支持了一个判断:
污染词元不是偶然切分出来的,而是由训练语料里的重复低质量内容推动形成的。

各模型污染程度差异很大

污染问题不是所有模型都一样严重。研究统计了多个主流大语言模型的中文词表,关注对象主要是“包含两个以上汉字的长中文 Token”。

部分结果可以整理成这样:

模型或系列研究中的污染比例信号需要注意的解读
GPT-4o 相关词表长中文词元中相当一部分落入成人、赌博等类别;部分统计口径超过 23%新 tokenizer 扩展了多语言覆盖,也更容易把高频垃圾短语收进词表
GPT 系列某统计口径最高约 46.6%具体比例与词元长度、分类规则、词表版本有关
Qwen 系列约 1.00%中文词表污染明显更低
GLM-4约 0.25%污染词元占比较低
DeepSeek-V3约 0.17%污染词元占比较低
GPT-4 / GPT-4-turbo / GPT-3.5被标注的长中文 PoC Token 为 0不代表训练语料完全无污染,只说明公开 tokenizer 词表中没有这类被标注长中文污染词元

这些数字不能直接等同于“模型整体质量”。它们更准确地反映了 tokenizer 词表里的长中文 Token 是否混入了大量低质量短语。

一个模型可能词表更干净,但回答能力未必更强;另一个模型可能能力很强,却在某些异常中文 Token 上表现不稳定。污染词元更像是底层输入表示的缺陷,而不是完整能力评测。

为什么中文更容易暴露这个问题

英文 tokenizer 常常以单词、词根、子词为单位,长 Token 往往是专业术语、技术名词、化学名词、医学名词或复合词。中文没有天然空格,BPE 会根据字符组合频率自动合并。

这会让中文高频垃圾短语更容易以“完整短语”的形式进入词表。

语言特点对 tokenizer 的影响
英文有空格分词边界长 Token 更常来自长单词或专业术语
中文没有天然空格高频字符组合容易被合并成短语 Token
中文垃圾广告常重复堆叠关键词赌博、私服、成人内容短语可能被高频合并
灰色站点大量使用站群模板同一批词在标题、页脚、导航、锚文本中反复出现

这并不意味着“中文 Prompt 天生不如英文 Prompt”。更准确的说法是:中文互联网语料的噪声分布、分词机制和数据清洗难度叠加后,会让某些问题更明显地暴露在中文 Token 里。

对实际使用有什么影响

污染词元会带来几类工程风险。

1. 幻觉更容易被异常 Token 触发

用户输入一个表面普通、实际来自灰色语境的短语时,模型可能无法稳定解释,转而输出不相关内容、乱码、虚构链接或错误定义。

这类幻觉不是普通知识缺失,而是输入表示本身已经把模型带进了低质量统计关联区域。

2. 安全策略可能被绕开

安全对齐通常依赖模型理解用户意图。如果污染 Token 在语义空间里欠训练,模型可能无法正确识别它对应的风险类别。攻击者可以利用这些罕见、隐蔽、语义不稳定的 Token 触发异常输出。

3. RAG 系统会受到低质量网页污染

RAG(Retrieval-Augmented Generation,检索增强生成)系统如果直接从搜索引擎或开放网页取资料,可能把内容农场、站群页、AI 生成垃圾内容一起召回。即使底层模型没有相关污染词元,检索上下文也会把垃圾送进提示词。

flowchart LR
    A[用户问题] --> B[检索系统]
    B --> C{召回来源}
    C --> D[可信资料]
    C --> E[内容农场]
    C --> F[站群广告]
    D --> G[模型生成]
    E --> G
    F --> G
    G --> H[答案质量下降或引用错误]

4. AI 生成内容会继续污染互联网

当模型生成低质量内容并被批量发布到网页上,搜索引擎和未来训练数据又会把这些内容重新收集进去。这会形成反馈回路:

flowchart TD
    A[低质量网页] --> B[训练数据]
    B --> C[模型]
    C --> D[批量生成低质量内容]
    D --> E[发布到互联网]
    E --> A

如果缺少来源标记、反垃圾机制和高质量数据筛选,这个循环会让后续模型更难获得干净语料。

模型开发侧如何降低风险

污染词元需要在 tokenizer、语料清洗、训练和评测多个环节处理,单靠安全拒答很难兜住。

环节可行做法解决的问题
tokenizer 训练前先清洗语料,再训练词表避免垃圾短语被固化为基础 Token
词表冻结前扫描长中文 Token,做 PoC 标注提前发现异常高频短语
数据清洗结合域名质量、模板重复度、搜索结果类别过滤站群、赌博、私服、盗版资源站
预训练降低重复垃圾页面权重,增强高质量中文语料减少统计关联偏移
对齐训练加入污染词元触发测试集检查模型是否会乱码、胡编或绕过安全策略
上线评测做 token-level 红队测试找到正常文本测试发现不了的漏洞

一个关键原则是:
不要等模型已经训练完,再希望安全层修复所有污染词元。

如果污染已经进入词表,并且在语义训练阶段欠训练,后期拒答策略只能缓解一部分问题。更稳妥的方式是在 tokenizer 训练前就降低污染语料权重。

应用开发侧如何防守

调用大模型的应用也可以做一些防护,尤其是面向中文开放输入的系统。

建立异常 Token 监控

可以记录用户输入被 tokenizer 切分后的 Token。如果某些请求包含大量罕见长中文 Token、异常拼接词、站点广告词,就可以进入额外审核流程。

def suspicious_token_ratio(text, enc, suspicious_token_set):
    ids = enc.encode(text)
    if not ids:
        return 0.0

    hit = sum(1 for token_id in ids if token_id in suspicious_token_set)
    return hit / len(ids)

这里的 suspicious_token_set 不应该只靠敏感词表生成,更适合结合历史日志、搜索上下文、模型异常输出和人工标注持续维护。

检索增强系统要过滤来源

RAG 系统不要把“能搜到”当成“可信”。至少需要做这些过滤:

检查项作用
域名白名单或信誉评分降低站群和垃圾站进入上下文的概率
内容重复度检测过滤模板化广告页
发布时间和引用关系避免过期或互相搬运的内容
页面主体抽取去掉页脚广告、侧栏推荐、弹窗文本
多来源交叉验证减少单一垃圾来源误导模型

对异常输出做回退

如果模型输出乱码、奇怪链接、无法解释的专有词或大量无关中文短语,可以触发二次策略:

flowchart TD
    A[模型输出] --> B{是否包含异常模式}
    B -- 否 --> C[正常返回]
    B -- 是 --> D[重新检索可信来源]
    D --> E[降低温度重新生成]
    E --> F{仍异常?}
    F -- 否 --> C
    F -- 是 --> G[返回无法确认并请求澄清]

这比直接把异常内容返回给用户更安全。

普通用户该怎么判断

用户不需要理解所有 tokenizer 细节,也可以用几个简单信号判断回答是否可能受污染影响:

现象风险
模型突然输出不相关中文短语可能触发了异常 Token 关联
出现打不开的网站、奇怪域名可能混入垃圾网页记忆或检索结果
对某个冷门词解释得很自信但没有来源高概率是幻觉
引用资料来自内容农场或 AI 聚合页可信度低
同一问题换种说法后答案差异很大模型对该语义不稳定

遇到这种情况,最好要求模型给出可验证来源,或者换用更明确的表达重新提问。对专业问题,不要只看模型回答本身,要看它引用的资料是否可靠。

关键结论

污染中文词元揭示了大语言模型一个很底层的问题:模型的“词表”并不天然干净,它也是从互联网统计中学出来的。

BPE 只关心频率,不理解内容质量。中文互联网里的垃圾广告、灰色站点和重复模板一旦规模足够大,就可能把异常短语推入 tokenizer 词表。后续训练又会清洗或压制这些内容,导致污染词元缺少正常语义学习,最终在推理时表现为乱码、幻觉和安全不稳定。

这件事的工程启示很直接:

  • tokenizer 训练语料必须先清洗,不能只在模型训练阶段清洗;
  • 长中文 Token 需要单独审计,尤其是高频但语义异常的短语;
  • RAG 系统要控制信息来源,否则检索层会把垃圾重新送给模型;
  • 中文模型评测不能只测常规问答,还要测异常 Token、站群词和灰色语境触发。

大语言模型学到的是数据分布。数据分布里有什么,词表和参数里就可能留下什么。模型能力越强,越需要对进入训练管线的中文语料做更细的质量控制。


评论