快速结论:在 llama.cpp 的 llama-server 开启 Jinja 模板(LLAMA_ARG_JINJA=1)并使用支持工具调用的模型时,模型偶尔会把工具调用以 JSON 字符串形式写进 content 字段(finish_reason: stop),而不是生成规范的 tool_calls 数组(finish_reason: tool_calls)。优先确认模型输出本身是否已经跑偏,再排查 llama.cpp 的模板/解析逻辑。
适用环境:Issue 中确认的环境为:macOS(Darwin 24.5.0,arm64)、Apple clang 17.0.0 编译、Metal 后端、llama.cpp version 5894 (494c5899)、Mac Studio 64GB(10 CPU / 32 GPU)。模型为 Devstral-Small-2507-UD-Q8_K_XL.gguf,服务端为 llama-server,关键参数包括 LLAMA_ARG_CTX_SIZE=16384、LLAMA_ARG_JINJA=1、LLAMA_ARG_FA=1、tool_choice: auto。评论中还提到 Mistral-Small-3.2-24B-Instruct-2506、Qwen2.5-Coder-3B-Instruct 等模型出现类似现象。Python、CUDA、PyTorch 版本在 Issue 中没有给出。
最快修复方案:暂无确认的一步修复方案。该 Issue 以 stale 状态关闭,评论明确指出“this was not completed”,后续仍有多位用户报告同类问题,因此没有经过验证的修复步骤。
注意事项:目前无法仅从服务端配置断定问题一定来自 llama.cpp。评论提出两种可能:模型本身被训练成偶尔在 content 中输出工具调用,或者 llama.cpp 在解析/模板处理时偶发失败。由于故障是间歇性的(同一配置下有时正常、有时异常),单次成功不能证明已修复;需要有失败样本才能进一步定位。
问题场景
用户通过 llama-server 提供 OpenAI 兼容 API,开启 LLAMA_ARG_JINJA=1,加载 Devstral-Small-2507 GGUF 模型,并在请求中传入多个 OpenAI 格式的 tools 定义及 tool_choice: auto。期望返回符合 OpenAI 结构的 tool_calls 数组,但实际有时返回的 message.content 是一段 JSON 字符串,其中包含 tool_calls 字段,finish_reason 为 stop。评论区的复现显示:同一会话里前一次工具调用解析正常,后一次却退化成 content 中的 JSON 文本。
报错原文
Eval bug: Regression: Tool calls still returned in content field as JSON string instead of tool_calls array
finish_reason: stop
content: "{\n \"tool_calls\": [\n {\n \"name\": \"json_set\",\n \"arguments\": {\n \"path\": \"$.game_scores.G02.scores.Sottocastello\",\n \"value\": 45.12\n },\n \"id\": \"74e27f938\"\n }\n ]\n}"
expected:
finish_reason: tool_calls
message:
content: null
tool_calls:
- type: function
function:
name: json_set
arguments: '{"path":"$.game_scores.G02.status","value":"completed"}'
id: i011r411j
原因分析
可能的根因有两类。第一类:模型在生成时偶尔没有按 chat template 期望的格式输出工具调用,而是把一段看起来像 tool_calls 的 JSON 写进了普通回复内容,llama.cpp 因此按普通文本处理,返回 finish_reason: stop。评论中观察到的现象(一次正常的 ToolCall,紧接着一次 Message 包裹的 JSON 字符串)也支持“模型输出本身漂移”这一可能。第二类:llama.cpp 在 Jinja 工具模板渲染或工具调用解析环节偶发判断失败,导致本应识别为工具调用的输出被当成 content。由于 Issue 未附带 first bad commit,也没有维护者给出确认结论,无法断定属于哪一种。
环境排查
- 确认
llama-server --version输出,记录具体 build 版本(Issue 为 5894 / 494c5899)。 - 确认
LLAMA_ARG_JINJA是否开启,以及所用模型是否带有可用的工具调用 chat template。 - 确认模型文件及来源(Issue 使用 unsloth/Devstral-Small-2507-GGUF;评论涉及 Mistral-Small-3.2-24B-Instruct-2506、Qwen2.5-Coder-3B-Instruct 等)。
- 确认请求中的
tools和tool_choice是否为 OpenAI 兼容格式、是否被完整传入。 - 确认
LLAMA_ARG_CTX_SIZE等上下文参数,Issue 使用 16384。 - 确认操作系统与后端(Issue 为 macOS + Metal);如在其他平台复现,需分别记录。
解决步骤
- 先固定复现条件:使用与 Issue 相同的模型、Jinja 开启配置和包含多个
tools的 OpenAI 格式请求,连续多次调用,记录每次响应的finish_reason与message.content,确认是否为间歇性出现。 - 保留至少一份失败请求/响应样本(与 Issue 中 request/response YAML 类似),以及对应的
llama-server日志,便于判断是模型输出格式问题还是解析问题。 - 观察模型原始输出:如果失败样本中模型本身已经生成
{"tool_calls": [...]}这样的文本,则更可能是模型输出漂移;如果模型输出符合模板格式但仍被放进 content,则更可能是 llama.cpp 解析问题。此步骤为排查方向,Issue 中未给出确认结论。 - 对照 Issue #12256、PR #12291 的相关修复,确认当前 build 是否包含对应改动;如不确定,可优先尝试升级到包含该修复的较新版本(可优先尝试,Issue 未验证)。
- 若无法升级,可优先尝试在应用侧检测
finish_reason: stop且 content 可解析为包含tool_calls的 JSON 时,做兼容性后处理(可优先尝试,属于规避手段,不是根因修复)。 - 将失败样本和日志补充到 Issue 或新开 Issue,说明 build 版本、模型、请求内容与失败频率,帮助维护者定位。
验证方法
在相同模型、相同 Jinja 配置和相同请求下连续执行多次工具调用请求,确认每次响应均为 finish_reason: tool_calls、content: null,且工具调用位于 tool_calls 数组中,不再出现 content 内嵌 JSON 字符串的情况。由于问题是间歇性的,建议至少多次重复并覆盖此前出现过失败的同类请求,单次成功不足以确认修复。
参考来源
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。

![[Bug]: [Usage]: RTX PRO 5000 (SM120) deadlocks at 3-4W during vLLM 0.32.0 startup with 70B NVFP4 model, even with --enforce-eager](https://www.chat-gpts.plus/wp-content/uploads/2026/10/63536-a00b257b-768x403.jpg)
