关键词:聚合 API、OpenAI 兼容、结构化输出、JSON Mode、数据抽取、Pydantic 校验

做 AI 应用的同学大多绕不开一件事:从非结构化文本里抽结构化字段

  • 客服对话 → 订单号、商品、联系人
  • 简历 → 姓名、年限、技能
  • 公告 → 时间、地点、主办方

很多人第一反应是写正则。但正则又脆又难维护:措辞一变就失配,换一种格式就重写。其实大模型原生支持结构化输出,你只要描述清楚字段,它就稳定吐 JSON,后面直接 json.loads 用。

本文用 TokenPortal 聚合 API(一个 base_url + 一个 Key 接 150+ 大模型,OpenAI 兼容)演示,核心结论先放这:

同一个抽取逻辑,换 deepseek / qwen / glm 等任何模型,只改一个 model 字段,代码一行不用动。


一、核心做法:response_format 一把梭

OpenAI 兼容接口支持 response_format={"type": "json_object"},强制模型只输出 JSON。配合清晰的 system 指令,基本不会跑偏。

import os
import json
from openai import OpenAI

# 控制台获取:https://tokenportal.ai (BASE_URL / API_KEY 以控制台为准)
BASE_URL = "https://api.tokenportal.ai/v1"          # 发布前替换为你的真实网关地址
API_KEY  = os.getenv("TP_API_KEY", "YOUR_TOKENPORTAL_KEY")

client = OpenAI(base_url=BASE_URL, api_key=API_KEY)

def extract_order(text: str) -> dict:
    resp = client.chat.completions.create(
        model="deepseek-v4-pro",   # 控制台模型广场中的模型 ID,可按需替换
        messages=[
            {"role": "system", "content": "你是订单信息抽取助手。只输出 JSON,不要任何额外说明、不要 markdown 代码块。"},
            {"role": "user",   "content": f"请从下面这段客服对话中提取订单信息:\n{text}"}
        ],
        response_format={"type": "json_object"},
        temperature=0
    )
    return json.loads(resp.choices[0].message.content)

text = "你好,我想查下订单,单号 TD20260821 是昨天下的,买了 2 件黑色 T 恤,联系人是张伟,电话 138****0011。"
print(extract_order(text))

典型输出:

{
  "order_id": "TD20260821",
  "quantity": 2,
  "product": "黑色T恤",
  "contact": "张伟",
  "phone": "138****0011",
  "date": "昨天"
}

temperature=0 让结果更稳定;system 里强调"只输出 JSON、不要代码块"能挡掉大部分格式意外。


二、加一层校验兜底:Pydantic

模型偶尔会多塞字段或类型不对。用 Pydantic 做结构校验,失败就重试或走兜底,比裸 json.loads 稳得多。

from pydantic import BaseModel, ValidationError

class Order(BaseModel):
    order_id: str
    quantity: int
    product:  str
    contact:  str
    phone:    str

raw = extract_order(text)
try:
    order = Order(**raw)
    print("校验通过:", order)
except ValidationError as e:
    print("模型输出不符合预期,需重试或兜底:", e)

三、换模型零改动:一套代码跑多家

这正是聚合 API 的价值。把同一段抽取逻辑依次跑在不同厂商模型上,只改 model 字段即可:

def extract_with(text: str, model: str) -> dict:
    resp = client.chat.completions.create(
        model=model,
        messages=[
            {"role": "system", "content": "你是订单信息抽取助手。只输出 JSON,不要任何额外说明。"},
            {"role": "user",   "content": f"请提取订单信息:\n{text}"}
        ],
        response_format={"type": "json_object"},
        temperature=0
    )
    return json.loads(resp.choices[0].message.content)

for model in ["deepseek-v4-pro", "qwen3.7-max", "glm-5.2"]:
    print(model, "->", extract_with(text, model))

不同模型字段一致、可直接进同一条业务管线。不必为每个厂商单独适配 SDK、单独处理返回格式——这是接聚合网关最省心的地方。

注:部分模型还支持更强的 json_schema 强约束(在 response_format 里给定字段类型与必填项),可按你用的模型在控制台确认是否支持;本文用兼容性最好的 json_object 兜底。


四、三个高频落地场景

  1. 工单/客服结构化:把用户自然语言报障转成 {优先级, 模块, 复现步骤},直接写库。
  2. 简历/名片解析:PDF 文本喂进去,吐出标准字段,进 ATS。
  3. 公告/合同要点抽取:从长文里摘出时间、金额、责任方,做比对与提醒。

这些都只需要"描述字段 + response_format"两步,比正则维护成本低一个数量级。


五、小结

  • 结构化抽取用 response_format={"type":"json_object"} + 清晰 schema 描述,比正则稳。
  • 加 Pydantic 校验做兜底,异常就重试。
  • 聚合 API 下换模型只改 model 字段,业务代码零改动。

如果这篇对你有启发,来我主页看看更多聚合 API 实战。一个接口接 150+ 大模型,官方货源、正规可开票、稳定,代码不用为每个厂商重写。

更多推荐