快速结论:这个报错通常出现在 5.x 版本用 AutoTokenizer 加载 llama 风格、但词表实际为 ByteLevel-BPE(用 Ġ 做词边界)的模型时,例如 deepseek-ai/deepseek-math-7b-rl:编码会静默丢掉空格,解码输出 'weneedtoadd9and6',生成时还会把 Ġ/Ċ 当作可见字符输出。优先核对你加载后的 tokenizer 组件是否被替换成了 sentencepiece/Metaspace 流程。
适用环境:Issue 中已确认:transformers 5.15.1(4.46.3 无此问题)、tokenizers 0.22.2、Python 3.12、Linux x86_64(另有 Windows 复现);模型 deepseek-ai/deepseek-math-7b-rl,属于 llama 风格 ByteLevel-BPE tokenizer 家族。CUDA、显卡型号未在 Issue 中提供。
最快修复方案:先用绕过方案:改为直接加载仓库原版 tokenizer.json,即用 PreTrainedTokenizerFast(tokenizer_file="<path>/tokenizer.json"),再把 chat_template / bos / eos 从原(有问题的)AutoTokenizer 加载结果上移植过来。Issue 中已验证该方式行为正确,且与 4.46.3 的 AutoTokenizer 输出 token 完全一致(约 4000 条 prompt 验证)。
注意事项:该绕过方案需要在原有流程中手动补回 chat_template、bos、eos 等配置,替换时要确认这一部分没有遗漏。恢复正常 AutoTokenizer 加载的修复方案在 Issue 中未见最终确认版本,升级或打补丁前建议先用下面的验证方法确认 round-trip 是否恢复。
问题场景
用户在 5.x 版本中用 AutoTokenizer.from_pretrained("deepseek-ai/deepseek-math-7b-rl") 加载 tokenizer,然后对普通文本做 encode/decode round-trip,或在生成流程中解码输出时触发问题。表现是编码结果对应的是“去掉空格后的字符串”,解码不能还原空格;在生成管线里,Ġ、Ċ 这类 byte-level 标记会以字面字符出现在解码文本中。该问题静默发生,没有告警,Issue 作者提到它直接导致一整轮评测结果失效。
报错原文
'weneedtoadd9and6'
['w', 'ene', 'ed', 'to', 'add', '9', 'and', '6']
同时对比同一份 tokenizer.json 的原始加载结果:
raw tokenizer.json -> ['we','Ġneed','Ġto','Ġadd','Ġ','9','Ġand','Ġ','6'] decode: 'we need to add 9 and 6'
AutoTokenizer -> ['w','ene','ed','to','add','9','and','6'] decode: 'weneedtoadd9and6'
原因分析
Issue 评论中给出了较明确的机制:同一个 tokenizer.json,原始 Tokenizer.from_file 加载正常,而 AutoTokenizer.from_pretrained 加载后组件被替换。对比 tok._tokenizer.to_str() 与文件内容可见:
pre_tokenizer:文件中是 ByteLevel BPE 的SequenceofSplit,加载后变成Metaspace(replacement="▁"、prepend_scheme="always"、split=false);decoder:文件中是ByteLevel,加载后变成Sequence[Replace("▁"→" "), ByteFallback, Fuse, …];normalizer:文件中是空的Sequence,加载后变成null。
也就是说,被套上的是 Llama 的 sentencepiece 流程,而词表本身是 byte-level、词边界标记是 Ġ 而不是 ▁。Metaspace 预分词找不到 ▁,于是没有 token 携带边界标记、空格被丢弃,得到 ['w','ene','ed',...];解码端的 ▁→" " 规则没有可替换内容,因此无法还原空格,生成时原始 Ġ/Ċ 标记还会直接暴露出来。
两个可用于定位的细节:仓库中没有 tokenizer.model(hf_hub_download(..., "tokenizer.model") 返回 404),只有 4.6 MB 的 tokenizer.json,却被合成了 sentencepiece 流程;tokenizer_config.json 中写着 "tokenizer_class": "LlamaTokenizerFast",返回对象 is_fast=True、类名为 LlamaTokenizer,说明不是 fast/slow 回退,而是 fast 路径本身替换了组件。
环境排查
- 确认
transformers版本:5.15.1 复现,4.46.3 正常; - 确认
tokenizers版本:评论复现环境为 0.22.2; - 确认 Python 版本:Issue 为 3.12;
- 确认操作系统:Linux x86_64(Windows 亦有复现);
- 确认模型:
deepseek-ai/deepseek-math-7b-rl,或其他 llama 风格但使用 ByteLevel-BPE(Ġ词边界)词表的模型; - 确认模型仓库是否只有
tokenizer.json、没有tokenizer.model; - 确认
tokenizer_config.json中的tokenizer_class字段值; - 确认加载后 tokenizer 的 pre_tokenizer / decoder / normalizer 类型(可用
tok._tokenizer.to_str()对比文件内容)。
解决步骤
- 先做最小复现:用
AutoTokenizer.from_pretrained编码"we need to add 9 and 6",convert_ids_to_tokens看是否缺少带Ġ前缀的 token,decode看是否变成'weneedtoadd9and6'。 - 同时用
tokenizers.Tokenizer.from_file直接加载同一份tokenizer.json(可用hf_hub_download取路径),做同样编码。若原始加载结果含Ġ边界 token、decode 能还原空格,说明问题在AutoTokenizer的重建流程,而不是文件本身。 - 可优先尝试绕过方案:改用
PreTrainedTokenizerFast(tokenizer_file="<path>/tokenizer.json")加载,再把 chat_template、bos、eos 等从原来的AutoTokenizer加载结果移植过来。 - 若无法替换 tokenizer 加载方式,可在升级/回退
transformers版本前,先用原始tokenizer.json的加载结果作为基准,验证新版本AutoTokenizer的 round-trip 是否恢复正常。 - 不要指望通过
use_fast参数规避:Issue 中use_fast=True和use_fast=False都产生损坏输出。
验证方法
用修复后的 tokenizer 重新编码 "we need to add 9 and 6",要求 decode(input_ids) 输出 'we need to add 9 and 6',且 convert_ids_to_tokens 中出现带 Ġ 前缀的词边界 token(例如 Ġneed、Ġto),而不是 ['w','ene','ed',...] 这种去空格切分。再跑若干条真实 prompt,确认生成结果里不再出现字面的 Ġ、Ċ 字符。
参考来源
huggingface/transformers #48206
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


