快速结论:当你在 Ollama 中对思考型模型(如 qwen3、gpt-oss)同时使用 /api/generate 并设置 think: true 和 format(结构化输出/JSON)时,思考过程会被静默忽略,导致返回答案错误或干脆不是合法 JSON,而 /api/chat 的同参数请求正常。优先改用 /api/chat 端点;如果必须用 /api/generate,先取消 format 或关闭 think。
适用环境:Issue 中确认的环境包括 macOS,Ollama 0.32.5(后续评论确认 0.32.9 仍存在),测试模型为 qwen3:0.6b 和 gpt-oss:20b。其他平台和模型未在 Issue 中逐一验证。
最快修复方案:Issue 中明确验证过的变通方案是:当需要使用 format 且模型支持思考时,改用 /api/chat 端点发送同样的请求。/api/generate 侧暂无确认的一步修复方案(Issue 中讨论的 deferral 修复方向只是计划,尚未有已验证的发布版本)。
注意事项:把 think 从 true 改成具体等级(如 medium)并不能绕过问题,这是评论中明确说明的。Issue 返回的是 HTTP 200 加看似合理的文本,不会报错,容易误以为请求成功,需要自行校验 JSON 是否合法以及 thinking 字段是否为空。
问题场景
用户在 Ollama 0.32.5(及后续 0.32.9)中,对支持 thinking 的模型调用 /api/generate,同时在请求体里设置了 think(布尔或等级)和 format(JSON Schema 或 "json")。典型复现场景是让模型做数学题(17 × 23)并返回结构化 JSON,或让模型仅输出合法 JSON(如 {"ok":true})。同一个模型、同一段 prompt、同一个 seed,只切换端点:/api/generate 出现异常,/api/chat 正常。
补充观察:不使用 format 时,/api/generate 的 thinking 输出正常(约 3764 字符),说明触发条件是 think 与 format 同时出现。使用带 builtin parser 的模型(如 gpt-oss:20b)时,故障更严重:推理文本本身被塞进 response,结果完全不是合法 JSON,thinking 为 null。
报错原文
/api/generate silently ignores think when format is set; /api/chat does not
/api/generate think=true format=set -> thinking= 0 chars response={"answer": "user_answer"}
/api/chat think=true format=set -> thinking= 1650 chars content ={ "answer": "391" }
Still present in 0.32.9, and on a model with a builtin parser the failure mode is worse than a degraded answer: the reasoning text itself lands in response, so the result is not valid JSON at all and thinking is null.
/api/generate think=medium format=json -> thinking = None response = 'The user says: ":", " }'
/api/chat think=medium format=json -> thinking= 328 chars content = '{"ok":true}'
注意:该问题不会返回 HTTP 错误码,接口以 HTTP 200 返回,因此不会抛出异常,只能通过比对 thinking 字段和 response/content 内容发现。
原因分析
根据 Issue 作者的分析,根因在服务端路由处理逻辑不一致:
ChatHandler在有 thinking 状态时,会把 grammar(结构化输出约束)推迟到 thinking 结束之后再应用,走的是structuredOutputsState的双请求路径。相关逻辑大意是:当req.Format != nil、结构化输出状态为None、且模型具备CapabilityThinking时,先把currentFormat置为nil,让模型先自由推理,之后再应用格式约束。GenerateHandler同样有builtinParser和thinkingState,但缺少这段等价的推迟逻辑,直接把Format: req.Format透传给Completion。
结果是:/api/generate 从第一个 token 起就套用 JSON grammar,模型没有被留出推理空间,只能填出一个占位答案(例如 "user_answer"),同时 thinking 为空。对于带 builtin parser 的模型,约束方式不同,推理文本直接落入 response,导致非法 JSON。
可能原因(Issue 中未最终定论的部分):GenerateHandler 与 ChatHandler 在结构化输出与 thinking 的状态机处理上未对齐,具体到代码改动是否只需移植 deferral,评论中表示还在做 focused pass,尚未合并。
环境排查
- 确认 Ollama 版本:Issue 中 0.32.5 和 0.32.9 均复现,如使用这两个或相近版本,命中该问题的可能性高。
- 确认模型:支持 thinking 的模型才触发,Issue 中验证过
qwen3:0.6b和gpt-oss:20b。 - 确认请求参数:是否同时出现
think(true或等级)和format(Schema 或"json")。两者只出现其一时不触发。 - 确认端点:同一组参数下
/api/generate与/api/chat表现是否不同。 - 确认响应:检查
thinking字段是否为空/null,response/content是否为预期 JSON。 - 操作系统:Issue 中记录的是 macOS,其他平台未在 Issue 中确认。
解决步骤
- 如果业务允许切换端点:把请求从
/api/generate改到/api/chat。这是 Issue 评论中明确给出的 workaround,适用于所有「支持 thinking 的模型 + 设置了 format」的组合。 - 如果必须使用
/api/generate:暂时不要在同一个请求里同时使用format与think。要么去掉format让 thinking 正常输出,再自行解析模型返回;要么保留format但关闭 thinking(think: false或不传think)。Issue 中未验证后一种组合在所有模型上的准确性,属于可优先尝试的规避手段。 - 不要尝试把
think: true改成具体等级(如think: "medium")。评论中已明确验证这种写法在 0.32.9 下同样无效。 - 如果需要在
/api/generate上彻底修复:关注上游对GenerateHandler移植/api/chat两阶段格式处理的进展。Issue 中作者及评论者表示会先补 request 级别的回归测试,再开 draft PR,属于尚未合并的代码改动,不要直接套用非官方补丁到生产环境。 - 如果正在用旧版本,Issue 中没有给出「升级到某版本即可修复」的结论,因此不建议把升级作为首选修复手段;升级后仍需按上面的验证方法确认。
验证方法
用同一组 prompt、seed、模型和参数分别请求两个端点,对比 thinking 与结构化输出:
curl -s localhost:11434/api/generate -d '{
"model":"qwen3:0.6b","prompt":"What is 17 * 23?","stream":false,"think":true,
"format":{"type":"object","properties":{"answer":{"type":"string"}},"required":["answer"]},
"options":{"seed":1}}' | jq '{thinking,response}'
curl -s localhost:11434/api/chat -d '{
"model":"qwen3:0.6b","messages":[{"role":"user","content":"What is 17 * 23?"}],
"stream":false,"think":true,
"format":{"type":"object","properties":{"answer":{"type":"string"}},"required":["answer"]},
"options":{"seed":1}}' | jq '{thinking:.message.thinking,content:.message.content}'
修复成功的判定标准:/api/generate 的 thinking 不再为空且长度合理,response 是符合 schema 的合法 JSON(例如 {"answer":"391"}),而不是占位字符串或推理文本。对 gpt-oss:20b 这类带 builtin parser 的模型,还应用 format:"json" 和 think:"medium" 跑一遍,确认 response 能被 JSON 解析器成功解析、thinking 非 null。
另需注意:Issue 返回的是 HTTP 200,不能只看状态码判断成功,必须检查响应体内容。
参考来源
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


