为什么结构化输出如此重要 LLM的默认输出是自由文本,但实际工程中我们几乎总是需要结构化数据——API调用需要JSON参数、数据抽取需要表格、Agent决策需要指令。结构化输出的可靠性直接决定了系统能否自动化运行。
目前主流的三种结构化输出方案各有优劣,选对场景才能发挥最大价值。
方案一:JSON Mode 原理与用法 JSON Mode是OpenAI率先引入的功能,强制模型输出合法JSON。它的原理是在解码阶段约束token采样,确保输出符合JSON语法。
from openai import OpenAI client = OpenAI() response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": "你是数据抽取助手,输出JSON格式。"}, {"role": "user", "content": "抽取以下文本的人名和职位:张三是CEO,李四是CTO。"} ], response_format={"type": "json_object"} ) import json result = json.loads(response.choices[0].message.content) # {"people": [{"name": "张三", "title": "CEO"}, {"name": "李四", "title": "CTO"}]} 局限性 JSON Mode只保证语法合法,不保证结构符合预期。它无法约束字段名、类型和嵌套层级。你需要额外验证:
from pydantic import BaseModel, ValidationError class PersonInfo(BasestModel): name: str title: str class ExtractionResult(BaseModel): people: list[PersonInfo] def safe_parse(raw_json: str) -> dict | None: try: data = json.loads(raw_json) return ExtractionResult(**data).model_dump() except (json.JSONDecodeError, ValidationError) as e: # 记录错误,触发修复流程 logger.warning(f"Schema validation failed: {e}") return None 方案二:Function Calling 设计理念 Function Calling让模型"知道"有哪些可用函数及其参数schema,模型负责生成符合schema的调用参数。这是一种约束生成方式,比JSON Mode更严格。
tools = [ { "type": "function", "function": { "name": "search_database", "description": "在产品数据库中搜索", "parameters": { "type": "object", "properties": { "query": {"type": "string", "description": "搜索关键词"}, "category": { "type": "string", "enum": ["电子产品", "服装", "食品"], "description": "限定品类" }, "limit": {"type": "integer", "minimum": 1, "maximum": 50} }, "required": ["query"] } } } ] response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "帮我找3个电子产品类的手机"}], tools=tools, tool_choice={"type": "function", "function": {"name": "search_database"}} ) # 模型生成结构化参数 tool_call = response.choices[0].message.tool_calls[0] args = json.loads(tool_call.function.arguments) # {"query": "手机", "category": "电子产品", "limit": 3} 多函数编排 Function Calling的真正威力在于多函数编排和模型自主决策调用链:
...