Prhub

#44683 [Bugfix][Rust Frontend] Fix missing added tokens in hf/fastokens tokenizer

原始 PR 作者 Isotr0py 合并时间 2026-06-10 18:52 文件变更 4 提交数 5 评论 8 代码增减 +215 / -8

执行摘要

修复 Rust Tokenizer 遗漏 tokenizer_config.json 中的 added tokens

对于 Qwen2-VL-2B-Instruct 等多模态模型,其 image_token_id <|image_pad|> 仅定义在 tokenizer_config.json 的 added_tokens_decoder 中,而不在 tokenizer.json 中。Rust 前端加载 tokenizer 时仅读取 tokenizer.json,导致该 token 缺失,进而引发 multimodal 预处理错误:"placeholder token <|image_pad|> is not in the tokenizer vocabulary"。

此 PR 值得合并,它修复了一个关键的多模态模型兼容性 bug。设计上采用合并策略,优先保留 tokenizer.json 中的 token,安全可靠。建议后续关注 fastokens 上游修复的进展,如果上游已支持 added_tokens_decoder,可简化 Rust 端的合并逻辑。同时建议增加更多边界测试,如 id 冲突、非数字 key、大并发加载等场景。

讨论亮点

Review 中讨论了三个主要问题:

  • fastokens 上游修复:Isotr0py 提议在 fastokens 上游也修复此问题,BugenZhao 赞同,随后 Isotr0py 创建了上游 PR #36。
  • HF tokenizers 同样缺失 added tokens:BugenZhao 指出 HuggingFace tokenizers 库也没有处理 tokenizer_config.json,本 PR 在 Rust 端统一修复了两种后端。
  • 测试 fixture 中的字段修改:Codex 自动审查指出将 vision_token_id 改为 image_token_id 可能影响测试,Isotr0py 解释此为预留区分,将留给后续视频支持 PR。

实现拆解

  1. 新增 added_tokens.rs 模块:定义 TokenizerJson 和 TokenizerConfigJson 结构体,提供 load_tokenizer_json_with_extra_tokens 函数,读取 tokenizer.json 后查找同目录下的 tokenizer_config.json,调用 merge_added_tokens_from_config 将 added_tokens_decoder 中未出现在 tokenizer.json 中的 token 合并进去。
  2. 修改 hf.rs 中的构造方法:将 new_fastokens 和 new_hf 从直接通过路径加载改为先调用 load_tokenizer_json_with_extra_tokens 获取合并后的 JSON,再通过 from_json 或 from_value 构建底层 tokenizer,确保两种后端都能获得完整的 added tokens。
  3. 修改 multimodal.rs 的可见性:将 placeholder_token 方法从 pub(crate) 改为 pub,以便在测试中从外部访问占位符 token。
  4. 更新测试文件 tests.rs:在 FakeChatTokenizer 的 encode 中添加对 <|image_pad|> 的编码支持(id 151655);在 ChatRenderer 的 render 中,将硬编码的 替换为从 MultimodalModelInfo 获取的 placeholder_token;修正测试 fixture 中的字段 vision_token_id 为 image_token_id。
  5. 添加单元测试和集成测试:在 added_tokens.rs 中测试合并后未建模字段仍保留;在 hf.rs 中测试 fastokens 和 hf 两种后端均能正确加载合并后的 token。
文件 模块 状态 重要度
rust/src/tokenizer/src/hf/added_tokens.rs 分词器 added 8.93
rust/src/tokenizer/src/hf.rs 分词器 modified 7.34
rust/src/server/src/routes/tests.rs 测试 modified 7.09
rust/src/chat/src/multimodal.rs 多模态 modified 5.12

关键符号

load_tokenizer_json_with_extra_tokens merge_added_tokens_from_config load_tokenizer_config_json with_id HuggingFaceTokenizer::new_fastokens HuggingFaceTokenizer::new_hf MultimodalModelInfo::placeholder_token render_fake_message_content render_fake_content

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

评论区精华

fastokens 上游修复 设计

Isotr0py 提议在 fastokens 上游也修复此问题,BugenZhao 赞同并鼓励提交 PR。

结论:Isotr0py 已在 fastokens 仓库创建 PR #36。 · 已解决

HF tokenizers 同样缺失 added tokens 正确性

BugenZhao 指出 HuggingFace tokenizers 库也没有处理 tokenizer_config.json 中的 added_tokens_decoder,只有 Python transformers 的 from_pretrained 处理了。

结论:本 PR 在 Rust 端统一修复了两种后端。 · 已解决

测试 fixture 中 vision_token_id 字段修改 测试

Codex 自动审查指出将 vision_token_id 改为 image_token_id 可能导致测试失败,Isotr0py 解释这是为区分图像 / 视频 token id 预留,将留给后续视频支持 PR。

结论:Isotr0py 未还原改动,认为应留到视频支持 PR。 · unresolved

风险与影响

  1. 配置依赖风险:若 tokenizer_config.json 缺失或格式异常,代码会回退并打印警告,不影响正常使用。
  2. ID 去重逻辑:使用 id 进行去重,若 tokenizer_config.json 中存在与 tokenizer.json 相同 id 但不同 content 的 token,会跳过,可能导致预期外的 token 不被添加。
  3. 边界情况:当 added_tokens_decoder 的 key 为非数字字符串时会被忽略(parse 失败 continue),符合预期但未记录日志。
  4. 性能影响:增加了一次文件读取和 JSON 解析,但 tokenizer 加载仅一次,影响可忽略。

影响范围:仅 Rust 前端(vLLM v1)用户,且仅当模型依赖 tokenizer_config.json 中的 added_tokens_decoder 定义特殊 token 时(主要是多模态模型如 Qwen2-VL)。修复前这些模型在 Rust 前端会直接报错,修复后可正常工作。对纯文本模型无影响,对 Python 前端无影响。

配置文件解析风险 边界情况测试不足

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论