
本文介绍三种渐进式方案:强制纯 json 输出、利用函数调用(function calling)机制、以及稳健的后处理提取策略,帮助开发者绕过非结构化文本干扰,直接获取严格校验的 json 数据。
本文介绍三种渐进式方案:强制纯 json 输出、利用函数调用(function calling)机制、以及稳健的后处理提取策略,帮助开发者绕过非结构化文本干扰,直接获取严格校验的 json 数据。
在实际工程中,依赖大语言模型(如 GPT-3.5/4)生成结构化 JSON 时,常遇到「响应混杂说明文字」的问题——例如模型在 JSON 前加一句“好的,这是您要的结果:”,或在末尾补上“希望对您有帮助!”。这种非结构化包裹导致正则提取 + JSON.parse() + Schema 校验的三步法虽可行,但存在边界误匹配、嵌套引号逃逸失败、多 JSON 片段冲突等风险。
✅ 最优实践:优先使用 Function Calling(推荐)
OpenAI 自 gpt-3.5-turbo-0613 和 gpt-4-0613 起正式支持函数调用能力。你只需在请求中定义 functions 数组(含 name、description 和严格描述的 parameters JSON Schema),模型将自动输出格式合规的 function_call.arguments 字符串——它本身就是合法 JSON,且字段名、类型、必填项均由 Schema 约束:
# Python 示例(使用 openai>=1.0)
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4-0613",
messages=[{"role": "user", "content": "提取用户订单信息:姓名张三,商品iPhone 15,金额¥7999"}],
functions=[{
"name": "extract_order",
"description": "解析用户输入中的订单结构",
"parameters": {
"type": "object",
"properties": {
"customer_name": {"type": "string"},
"product": {"type": "string"},
"amount": {"type": "number"}
},
"required": ["customer_name", "product", "amount"]
}
}],
function_call={"name": "extract_order"} # 强制调用指定函数
)
args_json = response.choices[0].message.function_call.arguments
order_data = json.loads(args_json) # 直接解析,无需正则
# → {'customer_name': '张三', 'product': 'iPhone 15', 'amount': 7999}⚠️ 注意:
function_call.arguments是字符串,需json.loads();若未启用function_call参数,模型可能返回自然语言而非函数调用。
✅ 次优方案:系统级约束 + JSON-only 响应
若无法使用函数调用(如旧模型或平台限制),应在 system message 中明确指令,并配合示例强化行为:
System: 你是一个严格的 JSON 生成器。只输出标准 JSON 对象,不包含任何解释性文字、Markdown、代码块符号(如 ```json)或额外空格。你的输出必须能被 JSON.parse() 直接解析。
Assistant: {"status":"ok"}
User: 请返回一个包含 name 和 age 的对象,age 为数字。此时响应大概率是纯 JSON,但仍建议做兜底校验:
import json
import re
def extract_json_from_text(text: str) -> dict:
# 保守提取:找最外层 { } 匹配(支持换行和嵌套)
match = re.search(r'\{(?:[^{}]|(?R))*\}', text, re.DOTALL)
if not match:
raise ValueError("No JSON object found")
try:
return json.loads(match.group())
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON: {e}")
# 后续再用 jsonschema.validate(data, schema) 进行强校验? 关键总结
- 根本解法:用 Function Calling 替代“提示词+正则”——它由模型原生保证结构,避免所有解析歧义;
-
防御性设计:即使使用 JSON-only 模式,也必须保留
try/catch+ Schema 校验,因 LLM 本质是概率模型; -
避免陷阱:勿用贪婪正则
r'\{.*\}'(会跨多个 JSON 错误匹配),改用递归正则或json.loads()配合异常捕获定位起始位置; - 生产建议:将 Schema 校验封装为中间件,失败时自动触发重试(带更严格 system prompt)或降级至人工审核。


















