展开本页目录
开始前准备什么
- Python 3.10+ 与当前 OpenAI Python SDK
- 令牌可用的准确模型 ID,分别确认 Chat 与 Responses 接口
- 一组旧接口已有验收答案的脱敏测试输入
- 跑通旧接口
- 替换请求与输出
- 验证多轮和失败
- 小流量切换
Chat、Responses 与手动上下文三次调用;无内置 Key。
请求和输出,分别改什么
Chat 发送 messages,常用文本在 choices[0].message.content;Responses 发送 input,SDK 的 output_text 用于聚合文本。output 数组还可能包含推理、工具调用等不同类型的项,不要只取 output[0] 就假定它是回答。
同一个模型名能在 Chat 调用成功,不能证明当前渠道支持 Responses。先从模型广场确认接口,再用下面脚本单独验证。
| 已有 Chat 代码 | Responses 对应处理 |
|---|---|
| messages | input;应用规则可用 instructions |
| max_completion_tokens / max_tokens | max_output_tokens,仍需核对具体模型 |
| choices[0].message.content | output_text;非文本流程读取有类型的 output |
| response_format | text.format,配置结构也要修改 |
| tool_call_id | function_call_output 使用 call_id |
- 已有 Chat 代码
- messages
- Responses 对应处理
- input;应用规则可用 instructions
- 已有 Chat 代码
- max_completion_tokens / max_tokens
- Responses 对应处理
- max_output_tokens,仍需核对具体模型
- 已有 Chat 代码
- choices[0].message.content
- Responses 对应处理
- output_text;非文本流程读取有类型的 output
- 已有 Chat 代码
- response_format
- Responses 对应处理
- text.format,配置结构也要修改
- 已有 Chat 代码
- tool_call_id
- Responses 对应处理
- function_call_output 使用 call_id
准备一个可回退的测试入口
保留旧调用函数,新增 Responses 调用函数,用应用配置选择入口。首次测试不启用联网、文件搜索或后台任务,减少迁移变量。脚本会产生三次请求:一次 Chat、一次 Responses、一次携带上下文的 Responses;每次都可能计费。
bash
python -m pip install -U openai
export tokenba_MODEL="REPLACE_WITH_SUPPORTED_MODEL_ID"
# tokenba_API_KEY 通过你的终端或部署环境设置
python developer-responses-migration.py完整 Python 示例:文本与第二轮
示例不依赖服务端保存的 response ID:store=False,再将上一轮的 output 项带回下一轮。若网关拒绝某类项,记录具体错误并停在这个测试,不要删除推理或工具项后声称完整多轮兼容。
developer-responses-migration.py
import os
from openai import OpenAI
def main():
model = os.environ["tokenba_MODEL"]
client = OpenAI(api_key=os.environ["tokenba_API_KEY"],
base_url="https://api.apizt.com/v1", timeout=60, max_retries=0)
prompt = "用一句话说明幂等操作,不调用任何工具。"
chat = client.chat.completions.create(
model=model, messages=[{"role": "user", "content": prompt}])
if chat.choices[0].finish_reason != "stop":
raise RuntimeError("Chat result is not complete")
print("Chat:", chat.choices[0].message.content)
print("Chat usage:", chat.usage)
response = client.responses.create(model=model, input=prompt, store=False,
max_output_tokens=1024)
if response.status != "completed" or not response.output_text:
raise RuntimeError("Responses result is incomplete or has no text")
print("Responses:", response.output_text)
print("Responses usage:", response.usage)
second = client.responses.create(
model=model, store=False, max_output_tokens=1024,
input=[{"role": "user", "content": prompt},
*[item.model_dump(exclude_none=True) for item in response.output],
{"role": "user", "content": "给一个 HTTP 方法的例子。"}])
if second.status != "completed" or not second.output_text:
raise RuntimeError("Second turn did not complete")
print("Second turn:", second.output_text)
print("Second usage:", second.usage)
if __name__ == "__main__":
main()
上下文策略要单独选择
简单客服或摘要可由应用保存输入与输出。previous_response_id、Conversations API、加密推理项属于不同的状态功能;官方接口有这些能力,不代表你的网关渠道全部开放。需要这些功能时,额外验证创建、续接、删除及保留策略。
store=False 是请求层的存储选项,不是整个路由链零留存的保证。敏感数据仍按自己的业务要求脱敏,并核实网关及上游数据处理规则。
工具、流式、Schema 逐项加回
- 先迁移函数定义与结果回传,核对 call_id,不把 Chat 的嵌套 function 定义直接照搬。
- 把文本流消费者改为识别 response.output_text.delta 与完成、失败、未完成事件。
- Schema 从 response_format 迁到 text.format 后,用本地校验与业务规则复验。
- 把新增功能分开验收;某一项通过不能替其他项背书。
400、404 与未完成结果怎么处理
404 先检查实际请求是否为 /v1/responses,避免重复 /v1 或把完整 endpoint 填给 SDK。400 先移除未经确认的高级字段,从最小 input 恢复;不静默改回 Chat 后把错误隐藏。
response.status 不是 completed、文本为空或输出被截断,都应进入失败分支。超时后先核对控制台请求记录,避免再次提交同一付费任务。
上线前比较真实业务结果
选择 10–20 条已有人工答案的业务样本,对比答案是否完整、字段是否正确、多轮是否记住约束、所有尝试的 usage 和实际扣费。接口迁移不是质量提升或折扣的保证。
先让少量请求进入新入口。错误率或任务验收下降时,配置切回旧函数并保存失败样本;不要同时换模型、提示词和接口,难以定位差异。
怎样确认已经完成
- 三次调用都有独立 usage,第二轮理解第一轮问题
- Responses 返回 completed 且 output_text 非空
- 截断、400、404、超时触发明确失败分支
- 保留旧入口,可通过配置回滚
常见问题
迁移后是否一定更便宜?
不能保证。模型、渠道、输出长度和缓存计费都会影响费用,比较控制台中同类任务全部尝试的实际扣费。
可以直接把 messages 改成 input 吗?
纯文本可能很接近,但输出类型、多轮状态、函数定义、Schema 与流式事件都要分别检查。