Misc. bug: llama_detokenize removes the space preceding “!”, “?”, “.”, “,”, and prior to “‘s”, “‘re” for Gemma 4 and other vocabs whose Hugg

当 GGUF 词表对应的 Hugging Face tokenizer 不需要清理空格时,llama.cpp 仍对 BPE 词表启用了 clean_spaces,导致 llama_detokenize 删掉 “!”“?”“.”“,” 前面的空格以及 “'s”“'re” 前面的空格,表现为解码文本与原

快速结论:当 GGUF 词表对应的 Hugging Face tokenizer 不需要清理空格时,llama.cpp 仍对 BPE 词表启用了 clean_spaces,导致 llama_detokenize 删掉 “!”“?”“.”“,” 前面的空格以及 “’s”“’re” 前面的空格,表现为解码文本与原文不一致。优先排查词表的 pretokenizer 类型是否被错误地开启了 clean_spaces。

适用环境:llama.cpp b11769-14-g339f3242c(Mac 上报告);Linux master 0a1ef309c 已复现。涉及 libllama 的 llama_tokenize 与 llama_detokenize。受影响模型包括 Gemma 4、GLM-4.x/5.x、LFM2、Mellum2、Nemotron(pixtral)、Granite 4.1(dbrx)、MiniCPM5。其他随附版本未在 Issue 中确认。

最快修复方案:暂无确认的一步修复方案。Issue 中已验证的折中办法是在 Gemma 4 分支的 pretokenizer 配置里加上 clean_spaces = false;,评论者报告该修改可修复问题且 test-tokenizer-0 仍通过;作者已计划在转换脚本与加载器中一并调整,但 Issue 关闭时没有给出可直接套用的完整补丁。

注意事项:直接改默认值只对 Issue 列出的 pretokenizer 生效,不能自动适配所有词表;如果模型自带的 Hugging Face 配置明确设置了 clean_up_tokenization_spaces,GGUF 当前并未保存该设置,因此单改默认值可能仍与实际配置不一致。流式输出不受影响,问题主要体现在重新分词或调用 llama_detokenize 的场景。

问题场景

在 llama.cpp 中使用 Gemma 4 等模型的 GGUF 词表时,先调用 llama_tokenize 编码,再调用 llama_detokenize 解码,得到的文本与输入不一致。Issue 中的复现脚本通过 llama_tokenize + llama_detokenize 的 harness 对比 Hugging Face tokenizer 的输出。用户可见的场景包括 llama-mtmd-cli 的聊天历史(后续会重新分词)、server 的 prompt 字段,以及任何直接调用 llama_detokenize 的应用。

报错原文

'if (x != y) {' -> 'if (x!= y) {'
'x = a ? b : c' -> 'x = a? b : c'
"It 's fine" -> "It's fine"

MISMATCH

原因分析

最可能的原因是 llama-vocab.cpp 对每个 BPE 词表都设置了 clean_spaces = true,而只为部分 pretokenizer(qwen2、deepseek、qwen35、command-r)关闭了该选项。Hugging Face 的 clean_up_tokenization_spaces 设置没有被存入 GGUF,Gemma 4 等模型的 tokenizer 实际不清理这些空格,于是 llama.cpp 的解码结果与 Hugging Face 不一致。该清理逻辑并非回归,最早由 #8039(2024 年 7 月)引入。

环境排查

  • 确认 llama.cpp 版本或提交号,Issue 涉及 b11769-14-g339f3242c 与 master 0a1ef309c。
  • 确认所用 GGUF 词表及其 pretokenizer 类型,重点看 gemma4、lfm2、glm4/glm5、mellum2、minicpm5、dbrx 等分支是否开启了 clean_spaces。
  • 对照同一模型的 Hugging Face tokenizer,检查 clean_up_tokenization_spaces 是否未设置或为 false。
  • 确认问题是否出现在 llama_detokenize、llama-mtmd-cli 聊天历史或 server prompt 字段中,而流式输出正常。
  • 如果自行修改源码,运行 test-tokenizer-0 确认现有分词行为未被破坏。

解决步骤

  1. 先用 Issue 中的方法或自己的 harness 对比同一字符串在 llama.cpp 与 Hugging Face tokenizer 下的解码结果,确认空格消失的位置。
  2. 定位到 llama-vocab.cpp 中对应模型的 pretokenizer 分支,例如 gemma4 分支。
  3. 可优先尝试在该分支增加 clean_spaces = false;。Issue 评论者验证此修改可修复 Gemma 4,且 test-tokenizer-0 通过。
  4. 对 Issue 列出的其他受影响模型,按其 pretokenizer 分支分别评估是否需要关闭清理;不要在未验证的情况下全局关闭。
  5. 若需要长期修复,关注作者计划的方案:转换脚本在 tokenizer_config.json 设置 clean_up_tokenization_spaces 时写入新键 tokenizer.ggml.clean_spaces,加载器优先读取该键,缺省时保留各 pretokenizer 的默认值。
  6. 重新编译后,用相同字符串再次执行编码与解码对比。

验证方法

用相同输入分别执行 llama.cpp 的 llama_tokenize + llama_detokenize 与 Hugging Face tokenizer 的 encode/decode,确认 'if (x != y) {'、'x = a ? b : c'、"It 's fine" 等字符串解码后与原文完全一致,且 test-tokenizer-0 通过。

参考来源

ggml-org/llama.cpp #30905

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29668

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注