LFM3: any response_format (json_schema or json_object) fails with “Unexpected empty grammar stack after accepting piece: 6 (30)”

在 llama.cpp 的 LFM3 模型(LFM3-1.7B / LFM3-VL-2B)上启用 response_format ( json_schema 或 json_object )时,服务端会因 grammar prefill 失败而返回 500。优先排查 response_format 与

快速结论:在 llama.cpp 的 LFM3 模型(LFM3-1.7B / LFM3-VL-2B)上启用 response_format(json_schema 或 json_object)时,服务端会因 grammar prefill 失败而返回 500。优先排查 response_format 与 LFM3 原生 chat template 的 prefill 组合,尤其是 enable_thinking 相关分支与 </think> 令牌重复处理。

适用环境:工具为 llama.cpp llama-server;模型为 LiquidAI/LFM3-1.7B GGUF(Q8_0),以及 LFM3-VL-2B(Q5_K_M + mmproj-Q8_0);后端为 CUDA 12;测试构建包括 b11946(release binary,master 8ca4060b)与 ghcr.io/ggml-org/llama.cpp:server-cuda12(构建时间 2026-10-28T13:35Z);启动参数涉及 --jinja --reasoning-budget 0 --flash-attn on -ngl -1 --ctx-size 32768。

最快修复方案:Issue 讨论中维护者定位到 llama.cpp 强制追加 </think>、而 chat template 已自行加入该令牌,并提交了修复 PR(ggml-org/llama.cpp#31374)。可在该 PR 合并并发布后升级到包含修复的构建;Issue 内未给出可直接执行的一步命令或确认后的正式版本号。

注意事项:Issue 中提到的临时绕过方式各有副作用:--chat-template chatml 虽能让 grammar 工作,但会丢失 LFM3 的思考抑制,回复中可能泄漏原始 Thinking... 内容;修改模板 else 分支只输出 <think> 会导致思考块未闭合,并触发 Failed to initialize samplers;--reasoning-format none 会使采样器初始化失败并让思考标记泄漏到纯文本输出。修复 PR 在 Issue 关闭时的验证状态请以 PR 讨论为准。

问题场景

用户通过 llama-server 的 OpenAI 兼容接口 /v1/chat/completions 调用 LFM3 架构模型(LiquidAI/LFM3-1.7B GGUF Q8_0,以及 LFM3-VL-2B Q5_K_M + mmproj-Q8_0),请求体中带有 response_format({"type":"json_schema", ...} 或 {"type":"json_object"})时,服务端返回 HTTP 500。去掉 response_format 的相同请求返回 200,且模型能自行输出合法 JSON。同一模型上的工具调用(grammar 约束的函数调用)正常,说明问题集中在 response_format 的 grammar 路径。

报错原文

got exception: Unexpected empty grammar stack after accepting piece: 6 (30)

HTTP 500
{"error":{"code":500,"message":"got exception: Unexpected empty grammar stack after accepting piece: 6 (30)","type":"server_error"}}

原因分析

根据 Issue 讨论,异常抛出点在 src/llama-grammar.cpp 的 llama_grammar_accept_str():当 grammar 的解析栈全部耗尽时被视为致命错误。该函数用于 prefill/强制前缀,而非普通采样,因此更可能是 chat template 的 prefill 内容包含 JSON grammar 无法接受的令牌,而不是采样随机性问题。

维护者最终定位为:llama.cpp 会强制追加 </think>,而 LFM3 的 chat template 已经自行加入了 <think></think>,导致 prefill 中该令牌重复出现,JSON grammar 无法接受,解析栈全部失效并抛出上述异常。用户侧观察到的触发条件为 chat_template_kwargs: {"enable_thinking": false} 与 response_format 同时出现;省略该参数或设为 true 时请求成功。Issue 中还提到纯文本响应下偶发多余 U+2026(…)令牌,可能与模板中的控制/思考令牌被 prefill 有关。另有相关 Issue #29006 报告同类 chat-template 控制令牌导致 JSON Schema grammar 失败的问题。

环境排查

  • 确认使用的模型及量化:LFM3-1.7B Q8_0,或 LFM3-VL-2B Q5_K_M + mmproj-Q8_0。
  • 确认 llama.cpp 构建版本/镜像标签;Issue 中 b11946 与 2026-10-28T13:35Z 的 server-cuda12 镜像均复现,说明不是单一构建回归。
  • 确认启动参数是否包含 --jinja、--chat-template 以及 --reasoning-budget、--reasoning-format 等与思考内容相关的选项。
  • 确认请求是否显式传入 chat_template_kwargs: {"enable_thinking": false},或所用客户端是否默认关闭思考。
  • 确认 response_format 的类型(json_schema 或 json_object),两者在 Issue 中表现一致。
  • 确认后端与 CUDA 版本(Issue 使用 CUDA 12),但未见证据表明问题与 CUDA 版本直接相关。

解决步骤

  1. 先做最小复现:使用 Issue 中的 curl 请求,分别测试带 response_format: {"type":"json_object"} 与不带 response_format 的请求,确认 500 是否只出现在带 grammar 的请求上。
  2. 检查客户端是否传入了 chat_template_kwargs: {"enable_thinking": false};Issue 中省略该参数或设为 true 时请求成功,可作为临时规避手段(可优先尝试)。
  3. 若需要临时让 response_format 可用,可用 --chat-template chatml 启动服务;Issue 中 4/4 成功。但注意该方式会导致 LFM3 思考抑制失效、原始 Thinking... 内容泄漏,不适合生产。
  4. 关注并升级到包含修复 PR ggml-org/llama.cpp#31374 的构建;该 PR 针对 llama.cpp 强制追加 </think>、与模板已加入的令牌重复的问题。
  5. 不要采用“把模板 else 分支改为只输出 <think>”或 --reasoning-format none 作为修复,Issue 中两者分别导致 Failed to initialize samplers 和采样器初始化失败/思考标记泄漏。

验证方法

使用同一模型、同一构建、同一 prompt 和同一 response_format 请求:在启用 enable_thinking: false 的情况下,修复前应为 HTTP 500 并返回 Unexpected empty grammar stack after accepting piece: 6 (30);应用修复后应返回 HTTP 200 和合法 JSON。同时可对照 enable_thinking: true 或省略该参数的成功请求,确认行为一致。

参考来源

ggml-org/llama.cpp #31328

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 31167

发表回复

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