为什么需要结构化输出?

AI的输出如果给人看,自然语言就够了。但如果输出要被程序处理——存入数据库、传给下一个API、渲染到页面——就必须是机器可读的结构化格式。否则你的代码要写大量的字符串解析逻辑,脆弱且难维护。

强制JSON输出的3种方法

方法1:Prompt约束(最通用)

从文本中提取以下信息,只输出JSON,不要任何解释:
{
  "name": "人名",
  "age": 年龄数字,
  "city": "城市"
}

文本:张三,28岁,来自上海

方法2:JSON Mode(OpenAI/部分国产模型支持)

response = client.chat.completions.create(
    model="gpt-4o",
    response_format={"type": "json_object"},  # 强制JSON输出
    messages=[{"role": "user", "content": "提取人名和年龄..."}]
)

方法3:Function Calling(最稳定)

tools = [{
    "type": "function",
    "function": {
        "name": "extract_person",
        "parameters": {
            "type": "object",
            "properties": {
                "name": {"type": "string"},
                "age": {"type": "integer"},
                "city": {"type": "string"}
            },
            "required": ["name", "age"]
        }
    }
}]

处理非法JSON的容错方案

import json, re

def safe_parse_json(text: str) -> dict:
    # 1. 直接解析
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        pass
    # 2. 提取代码块中的JSON
    match = re.search(r'```(?:json)?\s*([\s\S]+?)\s*```', text)
    if match:
        try:
            return json.loads(match.group(1))
        except:
            pass
    # 3. 找最外层的{}
    match = re.search(r'\{[\s\S]+\}', text)
    if match:
        try:
            return json.loads(match.group())
        except:
            pass
    return {}  # 兜底返回空字典

XML vs JSON:选择场景

Markdown结构化输出

当输出要给人读但又需要结构时,Markdown是最好的中间格式:

请按以下Markdown格式输出分析报告:
## 摘要
[2-3句话总结]

## 优点
- 优点1
- 优点2

## 风险
- 风险1

## 建议
[具体操作建议]
最终建议:优先用Function Calling(最稳定),不支持时用JSON Mode,都不支持则用Prompt约束+容错解析。