在本地大模型应用中,“能返回 JSON”并不等于“能稳定交付可用数据”。字段缺失、类型错误、额外说明文字、枚举值漂移,都可能让自动化流程在运行时中断。Ollama 的结构化输出能力可以将 JSON Schema 直接传给模型,再配合应用层校验与重试机制,构建更可靠的数据链路。🧩
一、理解 JSON 模式与 Schema 约束
Ollama 的生成接口和对话接口都支持通过 format 参数控制输出。最简单的方式是将其设置为 json,要求模型返回合法 JSON;更严格的方式则是直接传入 JSON Schema,对对象结构、字段类型、必填项和数组元素进行描述。具体参数和示例可参考 Ollama 结构化输出官方文档。
两种方式的差别很关键:JSON 模式主要解决语法问题,Schema 模式进一步解决结构问题。如果业务只需要临时提取少量信息,JSON 模式已经够用;如果输出要写入数据库、触发工作流或交给其他接口处理,则应优先采用 Schema。
二、设计一个可维护的 Schema
假设需要从文本中提取工单信息,可以定义包含 title、priority、tags 和 need_reply 等字段的对象,并设置相应类型。priority 可通过 enum 限制为 low、medium、high,tags 定义为字符串数组,need_reply 定义为布尔值,同时将核心字段加入 required。
设计时建议遵守以下原则:
- 字段名称明确:使用 need_reply 而不是 flag,减少模型产生歧义的机会。
- 类型尽量稳定:同一字段不要有时返回字符串、有时返回数字。
- 合理设置必填项:只有业务必不可少的字段才放入 required。
- 控制枚举范围:状态、级别、分类等字段优先使用 enum。
- 处理空值:允许缺失的信息应明确设为可空,或提供清晰的默认策略。
Schema 不是越复杂越好。层级过深、条件分支过多,可能增加小模型的生成难度。实践中可以先定义最小可用结构,再根据校验失败记录逐步补充约束。🔧
三、调用 Ollama 获取结构化结果
调用 /api/chat 时,可在请求体中提供 model、messages、stream 和 format。format 放入完整 Schema,stream 通常设置为 false,便于一次性取得完整内容并执行解析。使用 /api/generate 时也可以采用相同思路,其 format 参数支持 json 字符串或 Schema 对象,详见 Generate API 说明。
提示词仍然有价值。即使 format 已经传入 Schema,也可以在提示中说明提取目标、字段含义、未知信息的处理方式,并要求不要补充无法从原文确认的内容。
模型选择同样会影响效果。参数规模较小或指令遵循能力较弱的模型,面对复杂嵌套结构时可能出现字段语义不准确的问题。建议先用真实业务样本测试,再确定 Schema 复杂度和模型配置,而不是只验证一个理想示例。
四、为什么还需要应用层二次校验
Schema 约束能够显著提高输出一致性,但生产系统不能把模型结果直接视为可信输入。正确流程应包括:获取响应、解析 JSON、执行 Schema 校验、检查业务规则,最后才进入存储或调用阶段。🛡️
在 Python 项目中,可以使用 Pydantic 定义数据模型,通过 model_json_schema() 生成 Schema,再用 model_validate_json() 校验响应。这样,接口约束和运行时数据模型来自同一个定义,可减少两份规则不一致的问题。
在 JavaScript 或 TypeScript 项目中,可以使用 Zod 定义对象结构,将其转换为 JSON Schema 后传给 Ollama,再对 JSON.parse() 的结果执行 Zod 校验。对于前后端共享类型的项目,这种模式有助于统一字段约束。
校验应覆盖三个层次
- 语法校验:确认响应能够被标准 JSON 解析器读取。
- 结构校验:检查必填字段、数据类型、枚举值和数组元素。
- 业务校验:检查日期范围、编号格式、字段关联和内容来源。
例如,Schema 可以保证 priority 是字符串,但“退款失败”是否应归类为 high,属于业务规则,不能只依赖 JSON Schema 判断。
五、建立可控的失败重试机制
当校验失败时,不建议无限重复原始请求。更稳妥的做法是保存校验错误,将错误摘要反馈给模型,例如“缺少 need_reply 字段”或“priority 不在允许范围内”,然后进行有限次数的纠正生成。
推荐的处理顺序如下:
- 首次请求使用完整 Schema 和清晰提示词。
- 解析失败时,记录响应原文和 JSON 错误类型。
- 结构失败时,仅反馈必要的字段错误,不附带敏感业务数据。
- 达到重试上限后进入降级流程,如人工审核、返回默认结构或放入待处理队列。
对于要求稳定复现的任务,可以适当降低 temperature,减少随机性,但这并不能替代校验。提示词、Schema、模型版本和运行参数应一起纳入日志,便于定位同一输入为何产生不同结果。
六、常见问题与优化方向
输出包含额外解释:优先使用 format 约束,并在提示中明确“仅填充字段”。不要依赖截取首尾大括号的方式修复,因为正文中也可能出现括号。
数字被返回为字符串:在 Schema 中指定 integer 或 number,并在业务层决定是否允许安全转换。涉及金额时还要明确单位和精度,避免把格式正确误认为含义正确。
字段内容看似完整但属于推测:要求模型对未知值使用 null 或预设状态,并在业务层验证信息是否能从原始材料中找到依据。
复杂对象频繁失败:可以拆成两次提取,先识别基础实体,再补充分类或关联字段。分步调用会增加处理时间,但通常比一次生成超大嵌套对象更容易监控和纠错。
总结
Ollama 结构化输出的核心价值,是把自然语言结果转化为更适合程序消费的数据。可靠实践并不是简单设置 format=json,而是形成“清晰 Schema、明确提示、模型生成、类型校验、业务校验、有限重试、日志追踪”的完整闭环。✅
从最小结构开始,用真实样本持续测试,并把每次失败转化为可观测的错误类型,才能让结构化 JSON 从演示功能真正走向稳定的本地应用。