目录
Ollama 结构化输出教程:让模型返回固定格式的 JSON
将模型集成到程序时,我们通常需要的不是一段文字,而是程序可以直接读取的数据。例如,从一封投诉邮件中提取姓名、订单编号和问题类型。
Ollama 的 format 参数可以强制模型的输出符合你指定的 JSON 格式。
最简单的方式:只要求 JSON
curl http://localhost:11434/api/chat -d '{
"model": "qwen3:8b",
"messages": [{ "role": "user", "content": "列出中国台湾的三个城市和人口,用 JSON 回答" }],
"format": "json",
"stream": false
}'
输出保证是合法的 JSON,但字段名称和结构由模型自行决定,每次可能都不同。
指定 JSON Schema
将 JSON Schema 放进 format,就能精确规定字段:
curl http://localhost:11434/api/chat -d '{
"model": "qwen3:8b",
"messages": [{ "role": "user", "content": "介绍台北市" }],
"format": {
"type": "object",
"properties": {
"city": { "type": "string" },
"population": { "type": "integer" },
"landmarks": { "type": "array", "items": { "type": "string" } }
},
"required": ["city", "population", "landmarks"]
},
"stream": false
}'
message.content 会是一个符合格式的 JSON 字符串。
Python:使用 Pydantic 定义格式
from ollama import chat
from pydantic import BaseModel
class Complaint(BaseModel):
customer_name: str
order_id: str | None
category: str # 例如:物流、质量、退款、其他
urgency: int # 1~5
summary: str
email = """
您好,我是王小美,订单编号 A20261012-88 的吹风机收到时外包装破损,
插电后完全没有反应。下周要出国,情况很紧急,请尽快处理退换货,谢谢。
"""
response = chat(
model="qwen3:8b",
messages=[
{"role": "system", "content": "从投诉内容中提取信息。category 只能是:物流、质量、退款、其他。"},
{"role": "user", "content": email},
],
format=Complaint.model_json_schema(),
options={"temperature": 0},
)
data = Complaint.model_validate_json(response.message.content)
print(data)
print(data.urgency)
customer_name='王小美' order_id='A20261012-88' category='质量' urgency=4 summary='吹风机外包装破损且无法通电,要求尽快退换货'
4
model_validate_json 会再次验证类型,确保程序拿到的数据正确。
限定选项:使用 Literal 或 Enum
from typing import Literal
class Complaint(BaseModel):
category: Literal["物流", "质量", "退款", "其他"]
这样模型只能从这四个值中选择一个,比在提示词中说明更可靠。
JavaScript:使用 Zod 定义格式
npm install ollama zod
import ollama from "ollama";
import { z } from "zod";
const Product = z.object({
name: z.string(),
price: z.number(),
tags: z.array(z.string()),
});
const response = await ollama.chat({
model: "qwen3:8b",
messages: [{ role: "user", content: "这款 iPhone 手机壳售价 590 元,防摔、轻薄、支持 MagSafe" }],
format: z.toJSONSchema(Product),
});
const product = Product.parse(JSON.parse(response.message.content));
console.log(product);
(Zod 4 内置 z.toJSONSchema;旧版 Zod 3 可以使用 zod-to-json-schema 包。)
示例:批量分类
from typing import Literal
from ollama import chat
from pydantic import BaseModel
class Review(BaseModel):
sentiment: Literal["正面", "负面", "中立"]
topics: list[str]
reviews = [
"饭菜很好吃,但是等了快一个小时。",
"服务人员态度很好,下次还会再来!",
"价格一般,味道也一般。",
]
for text in reviews:
r = chat(
model="qwen3:8b",
messages=[{"role": "user", "content": f"分析这条评论:{text}"}],
format=Review.model_json_schema(),
options={"temperature": 0},
)
print(text, "→", Review.model_validate_json(r.message.content))
从图片中提取数据
搭配视觉模型,可以从发票、名片和截图中提取结构化数据:
class BusinessCard(BaseModel):
name: str
company: str | None
title: str | None
phone: str | None
email: str | None
r = chat(
model="gemma3",
messages=[{"role": "user", "content": "提取名片上的信息", "images": ["./card.jpg"]}],
format=BusinessCard.model_json_schema(),
options={"temperature": 0},
)
print(BusinessCard.model_validate_json(r.message.content))
提高准确率的技巧
- 将 temperature 设为 0,让输出更稳定。
- 在提示词中也说明格式和字段含义,不要只依赖 schema。例如:“urgency 是 1~5 的整数,5 表示最紧急”。
- 字段名称要清晰易懂(
order_id比oid好)。 - 可能没有数据的字段设为可空(
str | None),避免模型为了填充字段而编造内容。 - 结构化输出保证的是格式,不保证内容正确。重要数据仍然需要验证。
更新于 2026年10月12日