模型 API、消息角色与结构化输出

# 模型 API、消息角色与结构化输出

本篇目标

理解模型 API 的请求和响应结构,分清 Instructions、用户输入、流式输出与结构化输出,并完成一次可运行的 Python 调用。

调用模型 API分清消息角色处理流式事件校验结构化结果

# 先记住一句话

模型 API 是应用与模型服务之间的协议边界:应用提交模型、指令和输入,模型返回输出、状态与用量;返回成功只代表请求完成,不代表业务结果一定正确。

# 模型 API 解决什么问题

直接部署大型模型需要 GPU、推理框架、容量管理和版本运维。模型 API 把这些能力封装成远程服务,应用通过 HTTP 或官方 SDK 调用。

业务代码
  ↓ 调用本地 ModelClient
提供方 SDK
  ↓ HTTPS 请求
模型 API
  ↓ 调度推理服务
模型生成结果
  ↓ 返回状态、输出和 Usage
业务代码校验并继续处理
1
2
3
4
5
6
7
8
9

SDK 只是对 HTTP API 的封装。它可以帮助序列化参数、鉴权和解析响应,但不会替你完成用户授权、业务校验、幂等写入或质量评测。

# Instructions、Input 和消息角色

内容 含义 应放什么
Instructions / Developer 应用提供的稳定规则 职责、边界、输出要求
User 当前用户的请求 问题、文章、任务参数
Assistant 模型此前生成的消息 需要保留的对话结果
Tool 工具执行后返回的真实结果 查询数据、执行状态、错误

高优先级指令可以约束模型行为,但不能代替服务端权限。例如 Instructions 可以写 “只能读取当前用户的笔记” ,真正的数据库查询仍必须带用户条件。

不同提供方对 System 和 Developer 的命名或优先级可能不同。接入时应读取对应 API 文档,不要把一个 SDK 的字段名当作行业统一规范。

# 最小完整调用

下面示例使用 OpenAI Python SDK 和 Responses API。先安装依赖,并把密钥放入环境变量:

pip install openai
export OPENAI_API_KEY="你的 API Key"
1
2

不要把真实密钥写进源码、笔记或 Git 仓库。

# 文件位置:examples/summarize.py
from openai import OpenAI


# SDK 默认从 OPENAI_API_KEY 环境变量读取密钥。
client = OpenAI()


def summarize_note(note: str) -> str:
    if not note.strip():
        raise ValueError("笔记内容不能为空")

    response = client.responses.create(
        # 示例模型来自当前官方文档;生产项目应使用配置并固定经过评测的版本。
        model="gpt-6-astra",
        instructions="请把技术笔记压缩成三句话,不补充原文没有的事实。",
        input=note,
    )

    # output 可能含有多种项目,使用 SDK 聚合后的 output_text 更安全。
    if not response.output_text:
        raise RuntimeError("模型没有返回文本结果")
    return response.output_text


if __name__ == "__main__":
    result = summarize_note("连接池应长期复用,并设置最大连接数和等待监控。")
    print(result)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

OpenAI 官方文档特别说明,output 数组可能同时包含消息、工具调用和推理信息,不能假定文本永远位于 output[0].content[0].text。官方 SDK 提供的 output_text 会聚合文本输出,适合普通文本场景。

# 普通文本和结构化输出怎样选择

  • 给人阅读的回答、解释和文章可以返回普通文本;
  • 需要写数据库、渲染固定 UI 或驱动后续代码时,应优先使用结构化输出;
  • 只在 Prompt 中要求 “返回 JSON” 不能保证字段完整和类型正确;
  • Structured Outputs 会按照提供的 JSON Schema 约束结构,但业务含义仍需应用校验。

下面把模型输出直接解析成 Pydantic 对象:

# 文件位置:examples/extract_topic.py
from openai import OpenAI
from pydantic import BaseModel, Field


class NoteTopic(BaseModel):
    title: str = Field(description="笔记主题")
    keywords: list[str] = Field(description="2~5 个检索关键词")
    needs_review: bool = Field(description="内容是否存在需要人工确认的信息")


client = OpenAI()


def extract_topic(note: str) -> NoteTopic:
    response = client.responses.parse(
        model="gpt-6-astra",
        input=[
            {"role": "system", "content": "从技术笔记中提取主题,不补充外部事实。"},
            {"role": "user", "content": note},
        ],
        # SDK 根据 Pydantic 模型生成并解析结构化输出。
        text_format=NoteTopic,
    )

    if response.output_parsed is None:
        raise RuntimeError("模型未返回可解析的主题")
    return response.output_parsed


if __name__ == "__main__":
    topic = extract_topic("Go 的 sql.DB 是并发安全的连接池,应长期共享。")
    print(topic.model_dump())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

Schema 只能保证 needs_review 是布尔值,不能保证模型对内容风险的判断一定正确。关键业务条件还要使用程序规则、真实数据或人工审核。

# 流式输出是什么

非流式调用要等模型完成后一次性返回。流式调用会在生成过程中持续发送事件,常见传输方式是 Server-Sent Events(SSE)。

请求开始
  ↓
response.created
  ↓
response.output_text.delta  多次到达
  ↓
response.completed 或错误事件
1
2
3
4
5
6
7

客户端不能只拼接文本增量,还要处理完成、拒绝、取消和错误事件。用户断开时应取消上游模型请求,防止页面已经关闭,服务端仍继续消耗 Token。

# 错误应该怎样分类

类型 例子 处理方式
参数错误 Schema 不支持、输入超限 修正请求,不要盲目重试
认证与权限 Key 无效、项目无权限 停止并检查配置
限流 请求数或 Token 超额 读取重试提示并退避
暂时性故障 超时、服务端错误 有上限地重试
安全拒绝 模型拒绝处理内容 作为明确业务状态返回
解析失败 输出缺失或不符合预期 记录原始状态并安全失败

模型调用可能已经执行成功,但客户端因为网络中断没有收到结果。会产生费用或副作用的操作需要幂等键、请求记录或提供方查询能力,不能把所有超时都直接重放。

# 项目面试怎样表达

我把模型 SDK 封装在独立客户端中,业务层只传任务输入并接收领域结果。调用时设置模型版本、超时和输出预算;普通文本使用聚合字段读取,程序要消费的结果使用 Schema 约束并再次做业务校验。日志记录请求 ID、模型、状态、延迟和 Token,但不记录密钥与完整敏感输入。

# 高频面试题与回答

1. 为什么不能直接读取 output 数组的第一个元素?参考答案

因为一个响应可能包含文本消息、工具调用和推理信息等多种项目,第一个元素不保证就是文本。普通文本场景应使用 SDK 提供的聚合字段,复杂场景则按项目类型逐项处理。

2. Structured Outputs 能保证答案正确吗?参考答案

它主要保证输出符合指定 Schema,例如字段存在、类型和枚举合法,但不能保证字段内容在业务上真实正确。金额、权限和资源状态等关键数据仍要由程序或可信数据源校验。

3. 流式输出为什么不会降低模型总计算量?参考答案

流式输出只是把已经生成的增量更早发送给客户端,改善首字显示时间和用户体验。模型仍然要逐 Token 完成生成,因此总计算量和最终 Token 数不会因为使用流式传输自动减少。

4. 模型 API 返回 200 是否代表业务成功?参考答案

不代表。它只说明 API 请求成功完成,模型仍可能拒绝、返回空内容、产生事实错误或给出不满足业务规则的值。应用还要检查响应状态、解析结果、业务约束和必要证据。

# 接下来学什么

下一篇学习 Temperature、Top P 与输出预算,理解生成参数能控制什么,以及它们为什么不能替代业务校验。

# 参考资料