LLM 结构化输出总翻车?先关掉思考模式
摘要
AutoSEM 管线的 JSON 输出翻车追到思考模式泄漏进结构化响应——content 返回空字符串。解法:关思考、每批约 20 条、强硬的 system prompt、分层回退解析、prompt 里不放 JSON 示例。
快速答案
结构化调用显式关掉思考模式(如 enable_thinking=False),否则 content 返回空字符串;批次要小;system prompt 强硬声明"只返回合法 JSON";解析分多层回退(直接 → 代码块 → 截断修复 → 逐对象);用户消息里永远不放 JSON 示例。
我们的 AutoSEM 管线靠 LLM 返回干净的 JSON 吃饭——关键词批次、广告组结构、搜索词分析。但连续几周,同一个 bug 反复出现:模型返回空字符串,或者一段夹杂自然语言的 JSON 数组,解析直接失败。翻了 12 条失败记录之后,我们把这些翻车大多追到了一个根因上。这些经验一点都不玄学:失败日志无聊、重复、可修——同样的空字符串、同样的散文夹数组,一遍又一遍。下面这几条,就是让日志安静下来的那几招。
根因:思考模式泄漏进返回内容
现在很多模型默认开启"思考模式"。推理在内部生成,但在结构化输出调用里,推理过程可能被写进响应;更糟的是,因为模型把推理写在了本该是答案的位置,真正的 content 返回了空字符串。你的 JSON 解析器没坏,是模型压根没产出 JSON。
五条把问题修掉的规则
- 显式关掉思考。结构化调用必须关思考——在我们的模型上,这个开关是
enable_thinking=False。不关,content 就会返回空字符串。 - 分批而不是堆量。输入太长,模型就会退回自然语言。我们每批只放约 20 条,让模型始终保持在 JSON 格式上。
- system prompt 要强硬。写死"MUST respond with ONLY a valid JSON",不寒暄、不给备选。
- 多层回退解析。先直接解析,再提取代码块,再截断修复,最后逐对象提取。回退链比重试循环便宜。
- 别给模型看 JSON 示例。我们把示例格式贴进用户消息后,模型学的是示例旁边的说明文字而不是产出数据。示例不要进 prompt。
为什么思考模式比结构化调用更伤
思考是聊天的特性,不是抽取的特性。对抽取任务来说,模型的活是把输入翻译成 schema——一个狭窄任务,加推理只会多花 token、增加延迟和失败面,而不是提高准确率。
可复用清单:可靠 JSON 5 条
- 结构化调用关掉思考。
- 批次足够小,模型不会退回散文。
- system prompt 强硬声明"只返回合法 JSON"。
- 解析分层:直接 → 代码块 → 截断修复 → 逐对象。
- 用户消息里不放示例格式。
这些规则全部来自我们管线自己的失败日志。如果你也在做 LLM 驱动的营销自动化,我们的增长引擎跑的就是这套结构化输出实践。
常见问题
为什么模型会返回空的 content 字段?
开启思考模式时,模型把推理过程写进响应,真正的 content 就返回空。结构化调用我们显式设置 enable_thinking=False。
为什么不能给模型看个 JSON 示例?
我们把示例贴进去后,模型模仿的是示例旁边的说明文字而不是产出数据。用户消息里的示例教会的是格式模仿,而不是抽取。
如果响应还是解析失败怎么办?
把解析器分层:先直接解析,再提取代码块,再截断修复,最后逐对象提取。回退链比重试模型便宜。