在 AI 工具、自动化脚本和数据处理项目中,最麻烦的问题之一不是模型不会回答,而是返回内容格式不稳定。本文介绍一种更可靠的处理方式:明确输出结构,再在 Python 中校验结果。

为什么不能直接把模型返回当作 JSON?

很多项目一开始会直接这样处理:

result = response.choices[0].message.content

然后默认 result 一定是 JSON。实际运行时,模型可能返回:

  • JSON 前后带说明文字
  • 字段名称不一致
  • 某个字段缺失
  • 数字变成字符串
  • 多出 Markdown 代码围栏

只要后续代码依赖固定字段,程序就可能直接报错。

更稳的做法是:

  1. 在提示词中明确格式
  2. 对返回结果做解析
  3. 校验必要字段
  4. 失败时给出可处理的错误

一、先明确输出结构

假设我们要让模型提取一段文本中的任务信息,可以先定义目标结构:

{
  "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. 枚举值不统一

例如模型返回 highHigh,可以在业务层建立映射,但要记录转换过程。

4. JSON 结构嵌套太深

先减少不必要的层级。结构越简单,模型越容易稳定返回。


七、适合使用结构化输出的场景

这种方式适合:

  • 文本信息提取
  • 自动分类
  • 标签生成
  • 内容审核结果整理
  • 表单字段生成
  • Agent 工具参数准备
  • 批量数据清洗

只要后续程序需要读取模型结果,就应该考虑结构化输出和校验。


八、结语

让 AI 返回 JSON 只是第一步,真正可靠的流程还包括:

  • 明确字段结构
  • 解析返回内容
  • 校验字段类型
  • 处理异常结果
  • 记录失败原因

对于 Python AI 项目来说,结构化输出可以让模型调用更容易接入后续业务,也能减少因为格式变化带来的异常。

建议先从一个简单的数据结构开始,确认解析和校验稳定后,再逐步扩展字段。

免责声明

本文内容仅用于技术交流与经验分享,具体实现请结合项目实际情况调整。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐