学习如何强制 AI API 仅以严格且有效的 JSON 格式回应
Source: Dev.to
结构化输出 :强制 AI 使用 JSON
如果你曾尝试将 AI 的响应直接集成到一个应用(Web 或移动端),一定在服务器日志中看到过这样的错误:
SyntaxError: Unexpected token 'V', "Voici le J"... is not valid JSON
你让 AI 返回一个包含用户姓名和年龄的 JSON 对象,它却回答了:
« Voici le JSON que vous avez demandé :
json { "nom": "Paul", "age": 32 }
J’espère que cela vous aide ! »
后端用 JSON.parse() 解析这段文字时就会崩溃。
开发者不能只满足于 95 % 正确的响应;他们需要确定性。下面介绍如何获得它。
1. Prompt 的局限性
最初,人们会在提示词中加入全大写的指令:
"TU DOIS RÉPONDRE UNIQUEMENT EN JSON. N'AJOUTE AUCUN TEXTE AVANT OU APRÈS."
大多数情况下这能起作用,但在边缘案例中,AI 可能脱离角色,解释为什么不能回答,从而破坏你的代码。
输出格式不能仅仅是文字指令;它必须是 API 级别的技术约束。
2. Structured Outputs 与 Pydantic
自 2024 年中期起,主要供应商(OpenAI、Anthropic 等)提供 Structured Outputs。
你在 API 请求中直接传入 数据模式,模型会自我约束,只生成符合该模式的字符。
在 Python 中,标准工具是 Pydantic,一个数据验证库。
3. 实践 :永不崩溃的代码
抛弃令人焦虑的提示词。下面是一个完整示例,使用 OpenAI API 以 100 % 确定的方式从文本中提取信息。将其保存为 app.py,使用 uv run app.py 运行(依赖会自动安装)。
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "openai",
# "pydantic",
# ]
# ///
import os
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key="sk-...",
)
# 1. 定义数据契约(模式)
class ProfilUtilisateur(BaseModel):
nom: str
age: int
tags_hobbies: list[str]
est_premium: bool
texte_brut = (
"Hier j'ai discuté avec Marc, il vient d'avoir 28 ans. "
"Il adore le tennis et la lecture, mais il refuse toujours de payer l'abonnement pro."
)
# 2. 调用 API 并强制响应格式
response = client.beta.chat.completions.parse(
model="qwen/qwen3-4b:free",
messages=[
{"role": "system", "content": "Extrait les informations du profil utilisateur."},
{"role": "user", "content": texte_brut}
],
response_format=ProfilUtilisateur, # )
# Premium ? : False (Type: )
有了 response_format,AI 物理上不可能在 JSON 之外生成文字或遗漏 tags_hobbies 键。如果没有找到兴趣爱好,它会返回空列表 [],但键始终存在。这样你的业务代码就不再会因解析错误而崩溃。
4. JSON Mode 与 Structured Output 的区别
API 文档常提到一个简单参数:
{"type": "json_object"}
(JSON Mode)。该模式保证响应是合法的 JSON,但不保证包含你期望的键;AI 可能返回 {"utilisateur": "Marc", "annees": 28} 而不是 {"nom": "Marc", "age": 28}。
因此应优先使用 Structured Outputs(通过 Pydantic、JavaScript 的 Zod 等),它们强制每个变量的名称和类型必须完全匹配。
核心要点(3 条)
- ✅ 不要恳求:全大写的 “ONLY JSON” 提示并不是技术保证,只是一个祈愿。
- ✅ 强制模式:使用 API 的 Structured Outputs 来数学上约束 AI 的响应。
- ✅ 强类型:通过强类型模型确保返回的数据结构始终符合预期。
* : 使用 Pydantic(Python)或 Zod(JavaScript)直接将 AI 的响应绑定到内部数据模型。
然后呢?
恭喜,你现在已经会正确调用 AI,管理其记忆,降低成本,并将响应以 JSON 类型化。
进一步思考:如何确保在模型更新或提示词修改后,你的 Pydantic 提取仍然可靠?系列的下一篇文章将讨论使用 Test‑Driven Prompting (Evals) 来保障部署的安全。