Python 如何让 AI 返回稳定的 JSON:结构化输出与结果校验实战
在 AI 工具、自动化脚本和数据处理项目中,最麻烦的问题之一不是模型不会回答,而是返回内容格式不稳定。本文介绍一种更可靠的处理方式:明确输出结构,再在 Python 中校验结果。
为什么不能直接把模型返回当作 JSON?
很多项目一开始会直接这样处理:
result = response.choices[0].message.content
然后默认 result 一定是 JSON。实际运行时,模型可能返回:
- JSON 前后带说明文字
- 字段名称不一致
- 某个字段缺失
- 数字变成字符串
- 多出 Markdown 代码围栏
只要后续代码依赖固定字段,程序就可能直接报错。
更稳的做法是:
- 在提示词中明确格式
- 对返回结果做解析
- 校验必要字段
- 失败时给出可处理的错误
一、先明确输出结构
假设我们要让模型提取一段文本中的任务信息,可以先定义目标结构:
{
"title": "任务标题",
"priority": "high",
"tags": ["python", "api"]
}
然后在提示词中明确要求:
prompt = """
请从下面内容中提取任务信息。
只返回合法 JSON,不要添加 Markdown 标记或解释文字。
字段必须包含:title、priority、tags。
内容:
用户需要整理 Python API 接入文档,并优先处理错误排查。
"""
输出要求越清楚,后续解析越容易。
二、使用 Python 解析 JSON
可以先使用标准库 json:
import json
text = '{"title": "API 文档", "priority": "high", "tags": ["python", "api"]}'
data = json.loads(text)
print(data["title"])
print(data["tags"])
但是,真实返回内容可能不符合要求,所以不能只写 json.loads(),还要处理异常。
import json
def parse_json(text: str) -> dict:
try:
value = json.loads(text)
except json.JSONDecodeError as exc:
raise ValueError(f"返回内容不是合法 JSON:{exc}") from exc
if not isinstance(value, dict):
raise ValueError("返回结果必须是 JSON 对象")
return value
三、校验必需字段
解析成功不代表数据完整。可以继续校验字段:
def validate_task(data: dict) -> dict:
required = ["title", "priority", "tags"]
for key in required:
if key not in data:
raise ValueError(f"缺少字段:{key}")
if not isinstance(data["title"], str):
raise ValueError("title 必须是字符串")
if data["priority"] not in {"low", "medium", "high"}:
raise ValueError("priority 不是有效值")
if not isinstance(data["tags"], list):
raise ValueError("tags 必须是数组")
return data
这样可以把格式问题尽早暴露出来,而不是让错误一路传到业务层。
四、组合成一个完整函数
import json
def parse_and_validate(text: str) -> dict:
try:
data = json.loads(text)
except json.JSONDecodeError as exc:
raise ValueError("模型返回的内容无法解析为 JSON") from exc
if not isinstance(data, dict):
raise ValueError("模型返回结果必须是对象")
required = {"title", "priority", "tags"}
missing = required - data.keys()
if missing:
raise ValueError(f"缺少字段:{', '.join(sorted(missing))}")
if data["priority"] not in {"low", "medium", "high"}:
raise ValueError("priority 值不合法")
if not isinstance(data["tags"], list):
raise ValueError("tags 必须是列表")
return data
调用时:
content = response.choices[0].message.content
try:
task = parse_and_validate(content)
except ValueError as exc:
print(f"结果校验失败:{exc}")
else:
print(task["title"])
五、用 Pydantic 管理复杂结构
当字段变多时,手动校验会越来越长,可以使用 Pydantic:
pip install pydantic
from pydantic import BaseModel, Field
class Task(BaseModel):
title: str
priority: str = Field(pattern="^(low|medium|high)$")
tags: list[str]
解析数据:
import json
raw = response.choices[0].message.content
task = Task.model_validate(json.loads(raw))
print(task.title)
如果字段缺失或类型错误,Pydantic 会抛出明确的校验异常。
六、常见问题和处理方式
1. 返回内容带 Markdown 围栏
可以在提示词中明确要求只返回 JSON。不要优先用复杂字符串替换,因为可能误删正文内容。
2. 字段偶尔缺失
把必需字段写进提示词,并在代码中再次校验。
3. 枚举值不统一
例如模型返回 高、high、High,可以在业务层建立映射,但要记录转换过程。
4. JSON 结构嵌套太深
先减少不必要的层级。结构越简单,模型越容易稳定返回。
七、适合使用结构化输出的场景
这种方式适合:
- 文本信息提取
- 自动分类
- 标签生成
- 内容审核结果整理
- 表单字段生成
- Agent 工具参数准备
- 批量数据清洗
只要后续程序需要读取模型结果,就应该考虑结构化输出和校验。
八、结语
让 AI 返回 JSON 只是第一步,真正可靠的流程还包括:
- 明确字段结构
- 解析返回内容
- 校验字段类型
- 处理异常结果
- 记录失败原因
对于 Python AI 项目来说,结构化输出可以让模型调用更容易接入后续业务,也能减少因为格式变化带来的异常。
建议先从一个简单的数据结构开始,确认解析和校验稳定后,再逐步扩展字段。
免责声明
本文内容仅用于技术交流与经验分享,具体实现请结合项目实际情况调整。
更多推荐


所有评论(0)