Eval bug: gemma4 thinking starts to emit progressivly long trailing garbage

该报错通常出现在 llama.cpp 使用 peg-gemma4 聊天模板运行 Gemma 4 thinking 模型、且单轮对话中连续触发多次工具调用时,reasoning 尾部会逐渐累积换行和乱码,最终可能导致解析失败甚至模型返回 500。优先排查 chat template 中 thinkin

快速结论:该报错通常出现在 llama.cpp 使用 peg-gemma4 聊天模板运行 Gemma 4 thinking 模型、且单轮对话中连续触发多次工具调用时,reasoning 尾部会逐渐累积换行和乱码,最终可能导致解析失败甚至模型返回 500。优先排查 chat template 中 thinking 段的拼接方式,尤其是末尾多余的换行。

适用环境:Issue 中确认的环境为 Linux x86_64、llama.cpp 0.4.0-dev(build 10909,commit a2878d30d)、Vulkan 后端,硬件为 AMD Radeon RX 9070 XT 与 Tesla P40 混用,模型为 google_gemma-4-31B-it-Q8_0.gguf。用户侧通过自建 harness/CLI 经 OpenAI API 调用,Python 侧使用 pydantic 库。后经 llama-b10935 复测问题仍存在,仅出现时间推迟。

最快修复方案:更换 Gemma 4 的 chat_template.jinja,将 thinking 段的拼接改为对 thinking_text 做 trim 处理;即把 {{- '<|channel>thought\n' + thinking_text + '\n<channel|>' -}} 改为 {{- '<|channel>thought\n' + (thinking_text | trim) + '<channel|>' -}}。Issue 中报告修改后乱码与 token 被大量消耗的问题消失。

注意事项:该修复只影响 reasoning 内容,不改变最终输出和工具调用;trim 仅去除尾部空白,报告者表示可接受。维护者说明 trim 属于保险措施,主要怀疑点是 \n<channel|> 中前置的 \n 在后续请求中被注入,导致模型在上下文中学会并逐渐发散,但这一点属于推测,尚未被严格验证。

问题场景

用户在 llama.cpp 中启动 llama-server,加载 Gemma 4 31B 指令微调模型(Q8_0 量化),开启 --jinja 与 --chat-template-kwargs {"enable_thinking": true},通过自建 harness 走 OpenAI API 交互。当单个回合内触发多个工具调用、且 assistant 消息回传 reasoning_content 时,reasoning 尾部开始不断追加多余的 \n,随后出现星号、<BR> 等无意义内容,token 消耗明显变大,最终有时触发 500 模型错误。

报错原文

Eval bug: gemma4 thinking starts to emit progressivly long trailing garbage
common_chat_peg_parse: unparsed peg-gemma4 output

原因分析

最可能的原因是聊天模板在拼接 thinking 段时,在 <channel|> 前加入了一个模型本身不会生成的 \n。该换行被写入后续请求的对话历史后,模型在上下文中看到并模仿这一模式,逐步放大为尾部空白和乱码,影响 peg-gemma4 解析。评论中另一位参与者指出,主因可能是这个前置 \n 的注入,trim 只是出于谨慎的附加处理;该判断为推测。

环境排查

  • 确认 llama.cpp 构建版本与 commit,Issue 中为 0.4.0-dev build 10909(a2878d30d),且 9000 以上构建(约 9800 区间)开始出现。
  • 确认后端为 Vulkan,显卡为混用品牌(AMD RX 9070 XT + Tesla P40),模型全部 offload 到 GPU。
  • 确认使用的是 peg-gemma4 聊天格式,日志中应能看到 chat format: peg-gemma4。
  • 确认客户端每轮 assistant 消息都正确回传 reasoning_content,且格式符合该模型要求。
  • 检查当前 --chat-template 或 GGUF 内置模板的 thinking 段是否包含 thinking_text + '\n<channel|>'。
  • 确认 Python 侧(pydantic 等)构造请求时未额外添加尾部空白。

解决步骤

  1. 定位当前使用的 Gemma 4 chat_template.jinja,可参考 google/gemma-4-31B-it 官方模板。
  2. 找到拼接 thinking 段的那一行:{{- '<|channel>thought\n' + thinking_text + '\n<channel|>' -}}。
  3. 将其替换为:{{- '<|channel>thought\n' + (thinking_text | trim) + '<channel|>' -}},去掉 <channel|> 前注入的换行,并对 thinking_text 做 trim。
  4. 使用修改后的模板重新启动 llama-server,或在客户端通过 --chat-template 指定该模板(可优先尝试)。
  5. 使用此前会触发问题的场景(单回合多次工具调用)复测,观察 reasoning 尾部是否仍持续累积空白或乱码。

验证方法

重新运行原先触发多工具调用的对话,检查日志中是否还出现 common_chat_peg_parse: unparsed peg-gemma4 output;确认 reasoning 尾部不再逐渐变长、无多余 \n 或 <BR> 类乱码,token 消耗恢复正常,且不再出现 500 错误。Issue 报告者在修改模板后确认问题消失并关闭了该 Issue。

参考来源

ggml-org/llama.cpp #28827

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29691

发表回复

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