返回

06.5-Responses API与结构化实现.md

10.0 KB · MD · 2026-06-14 11:20

Responses API 与结构化实现

日期:2026-06-14

前面的课程讲的是方法:怎样写清楚任务、怎样设计上下文、怎样使用 RAG、工具和 Agent。本讲补上工程实现层:当你要把提示词放进一个真实应用时,应该怎样选择 API 形态、输出契约、工具调用和评估接口。

本讲以 OpenAI API 为例,但核心思想是通用的:自然语言负责表达任务,API 参数和 schema 负责约束系统行为。

本讲常见术语先按下面理解,详细定义和更多例子见 00.5-术语词典与最小用例

术语 直觉解释 最小例子
Responses API OpenAI 承载生成、工具、多轮状态的主要接口 一次请求里传入 inputtools 和输出格式
Structured Outputs 让模型按 schema 输出可校验结构 返回严格 JSON,不允许额外字段
Reasoning effort 控制推理预算的参数 简单分类用低预算,复杂调研用较高预算
Tool output 工具执行后的结果文本或结构化数据 查询订单后返回 {status: "shipped"}
Cached tokens 被缓存命中的输入 token 稳定系统提示反复使用时降低延迟和成本
SDK 在代码里调用 API 的开发工具包 用 Python SDK 发起 Responses 请求
JSON mode 只约束输出为 JSON 的模式 适合简单 JSON,不等于完整 schema 校验

一、先分清三层

很多学习材料会把 prompt、API 和 Agent 混在一起。工程实现时先分三层:

层级 负责什么 常见形式
Prompt 任务目标、上下文、边界、输出意图 instructions、input、system / developer message
API 参数 模型、推理强度、输出长度、工具、结构化输出 model、reasoning、text / text.format、tools
应用代码 权限、校验、工具执行、日志、重试、评估 backend、worker、eval runner

提示词越成熟,越应该把可机器校验的东西移到 API 或代码层,而不是全塞在自然语言里。

二、Responses API 适合什么

OpenAI 当前主要推荐用 Responses API 承载直接模型请求、工具调用、多轮状态和内置工具。它适合:

  • 文本生成、分析、总结、抽取。
  • 需要结构化输出的任务。
  • 需要 function calling、file search、web search、remote MCP 等工具的任务。
  • 需要 reasoning effort、状态续接或多轮工具链的任务。
  • Agent 原型或应用自管 orchestration 的场景。

一个简单判断:

只要任务涉及 reasoning、tool calling、多轮状态或内置工具,优先考虑 Responses API。

Chat Completions 仍可能出现在旧项目里,但新项目不要为了兼容旧习惯而忽略 Responses API。迁移旧系统时,应先确认现有 SDK、日志、工具调用格式和评估流程能否一起迁移。

三、结构化输出:不要只写“请输出 JSON”

如果输出要被程序消费,单靠提示词要求 JSON 不够稳。更成熟的做法是使用 Structured Outputs 或 JSON Schema。

适合使用 schema 的任务:

  • 信息抽取。
  • 分类。
  • 表单填充。
  • 风险标签。
  • 自动评分。
  • RAG 引用结果。
  • 工具参数生成。

Prompt 里仍然要写清楚语义边界,例如“只基于原文”“缺失写 null”。但字段、类型、必填项、枚举值、是否允许额外字段,应尽量交给 schema。

示例:

{
  "type": "object",
  "additionalProperties": false,
  "required": ["case_id", "parties", "judgment_result", "missing_fields"],
  "properties": {
    "case_id": {
      "type": ["string", "null"]
    },
    "parties": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["role", "name"],
        "properties": {
          "role": {"type": "string"},
          "name": {"type": "string"}
        }
      }
    },
    "judgment_result": {
      "type": "string"
    },
    "missing_fields": {
      "type": "array",
      "items": {"type": "string"}
    }
  }
}

配套 prompt 应该短而明确:

请只基于输入文书抽取字段。
原文没有的信息写 null,并把字段名放入 missing_fields。
不要补充案外事实。

四、Reasoning 参数不是提示词替代品

推理模型通常会在内部完成复杂推理。不要机械要求模型展示完整思维链。更好的方式是:

  • 在 prompt 中写清楚目标和成功标准。
  • reasoning.effort 或平台等价参数控制推理预算。
  • 要求输出“结论、依据、不确定项、核查点”,而不是完整思考过程。
  • 对复杂任务用 Eval 选择合适 effort,而不是凭感觉固定高档。

常见策略:

任务 推理配置思路
简单分类、抽取 低推理预算,重 schema 和规则
长文档总结 中等推理预算,重引用和核查
复杂 Agent / 调研 较高推理预算,重工具 trace 和停止条件
离线评估极限能力 高推理预算,接受更慢和更贵

不要把“更高 reasoning effort”当成万能修复。检索错、schema 错、工具权限错、评估集缺失,都不是单纯加推理能解决的。

五、工具调用实现要闭环

Function calling / tool calling 的关键不是“模型会调用工具”,而是应用代码能安全闭环。

最小闭环:

1. 请求模型,并提供可用工具定义。
2. 收到模型生成的工具调用请求。
3. 应用代码校验工具名、权限、参数和风险。
4. 应用代码执行工具。
5. 把工具结果返回给模型。
6. 模型基于工具结果继续回答,或继续请求工具。
7. 达到停止条件后输出最终结果。

应用代码必须处理:

  • 工具不存在。
  • 参数缺失或类型错误。
  • 用户权限不足。
  • 高风险写操作未确认。
  • 工具超时或返回错误。
  • 工具结果包含提示注入。
  • 模型循环调用工具。

提示词不能替代这些校验。

六、内置工具、自定义函数和 MCP 怎么选

需求 首选
查公开网页 平台内置 web search
查上传文件或平台文件库 file search / retrieval
执行业务系统动作 自定义 function calling
连接第三方或内部系统并跨客户端复用 MCP / connector
本地确定性处理 应用代码或脚本

MCP server 可能暴露 resources、tools、prompts。它解决的是连接和复用问题,不自动解决权限、安全和审计问题。

接 MCP 前要问:

  • 这个 server 暴露了哪些 tools、resources、prompts?
  • 认证和 OAuth scope 是否最小化?
  • 是否需要工具 allowlist?
  • 写操作是否需要人工确认?
  • 返回内容是否会泄露密钥、隐私或内部日志?
  • 是否有提示注入测试和审计日志?

七、缓存友好的请求结构

Prompt caching 的基本思路是让重复的大块稳定前缀复用。请求结构应尽量:

稳定系统规则
-> 稳定工具定义
-> 固定示例
-> 固定背景材料
-> 动态用户输入
-> 动态检索结果
-> 动态工具结果

OpenAI 的 prompt caching 通常要求 prompt 至少达到 1024 tokens 才会自动启用缓存。短 prompt 不应该为了缓存强行加废话;只有当稳定内容本来就需要重复传时,才值得围绕缓存优化。

容易破坏缓存的做法:

  • 时间戳、随机 ID、用户 ID 放在最前面。
  • 工具定义每次顺序不同。
  • few-shot 示例随机排序。
  • RAG 动态片段放在稳定前缀前。
  • 每次把无关历史都塞进上下文。

八、API 层最小日志

想要长期优化 prompt,至少记录:

  • prompt 版本。
  • 模型 ID 或模型别名。
  • API 表面:Responses、Chat Completions、Agents SDK 等。
  • reasoning effort、temperature、max output tokens 等关键参数。
  • input tokens、output tokens、reasoning tokens、cached tokens。
  • 工具调用 trace。
  • RAG 索引版本和检索片段编号。
  • 结构化输出是否通过 schema。
  • 用户反馈、人工复核结果、失败原因。

没有这些信息,后面做 Eval、成本优化和回归分析都会变成猜。

九、最小实现练习

做一个“合同字段抽取”小项目:

  1. 准备 5 份短合同片段。
  2. 定义 JSON Schema:合同编号、甲方、乙方、付款期限、违约金、缺失字段。
  3. 写 prompt:只基于原文,缺失写 null。
  4. 调用 Responses API 或你使用平台的等价接口。
  5. 用程序检查 JSON 是否可解析、必填字段是否存在。
  6. 记录失败样例并改 prompt 或 schema。

目标不是一次写出完美 prompt,而是建立“prompt + schema + eval”的最小闭环。

十、常见误区

误区 1:API 参数可以替代任务说明

不对。API 参数控制模型行为边界,prompt 仍要说明业务目标、输入边界和成功标准。

误区 2:写了 JSON 示例就等于结构化输出

不对。JSON 示例能引导模型,但不能像 schema 那样提供机器可校验的契约。

误区 3:用了工具调用就可以相信模型参数

不对。模型生成的是调用请求,不是可信执行命令。应用代码必须校验。

误区 4:最新模型不用 Eval

不对。模型行为会随版本变化。需要稳定输出的应用应固定模型版本或记录模型变更,并跑回归评估。

误区 5:缓存优化就是把 prompt 写长

不对。缓存优化的是重复稳定内容。无意义加长 prompt 会增加成本和干扰。

十一、理解检查

  1. Prompt、API 参数、应用代码分别负责什么?
  2. 为什么程序消费的输出应该优先使用 JSON Schema?
  3. Function calling 的执行权为什么必须在应用代码手里?
  4. Prompt caching 为什么要求稳定内容放前面?
  5. 一个 API-backed prompt 上线前至少要记录哪些日志?

十二、下一步

下一讲建议学习:06.6-安全与Prompt Injection专题.md。当模型能读取外部内容、调用工具、连接 MCP 后,安全边界会比单条 prompt 更重要。