尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Assistants API将停止服务:Python迁移Responses API实战

Assistants API将停止服务:Python迁移Responses API实战
📅 发布时间:2026/8/1 14:15:39

凌晨两点,线上客服机器人仍在不断创建 Thread、启动 Run、轮询状态。日志没有报错,接口也能正常返回,但这套代码已经进入倒计时。

OpenAI 已明确宣布:Assistants API 将于 2026年8月26日停止服务。它不是一次普通的 SDK 方法改名,而是把原来的 Assistant、Thread、Run 模型改成 Prompt、Conversation、Response 和 Item。

官方迁移指南:
https://developers.openai.com/api/docs/assistants/migration

如果项目里还能搜到下面这些调用,现在就应该开始处理:

client.beta.assistants client.beta.threads client.beta.threads.messages client.beta.threads.runs

一、先理解变化:迁移的不是一个接口

新旧对象可以这样对应:

Assistants APIResponses API体系主要变化
AssistantPrompt或请求配置模型、指令、工具配置不再依赖Assistant对象
ThreadConversation不只保存消息,还可以保存工具调用和输出等Item
RunResponse输入与输出结构更直接,不再依赖Run轮询读取结果
Run stepItem消息、函数调用、工具输出都以不同Item类型存在

官方迁移指南将其概括为“输入Items,返回输出Items”。其中最容易踩坑的是:Thread不能直接当作Conversation ID继续使用。

官方目前没有提供自动迁移全部Thread的工具,建议让新会话直接进入Conversations,旧会话再按实际访问需求回填,而不是一次性迁移所有历史数据。

二、旧代码为什么不能只改方法名

典型的Assistants API调用通常需要四步:

importosimporttimefromopenaiimportOpenAI client=OpenAI()thread=client.beta.threads.create()client.beta.threads.messages.create(thread_id=thread.id,role="user",content="帮我检查这段代码中的并发问题",)run=client.beta.threads.runs.create(thread_id=thread.id,assistant_id=os.environ["OPENAI_ASSISTANT_ID"],)whilerun.statusin("queued","in_progress"):time.sleep(1)run=client.beta.threads.runs.retrieve(thread_id=thread.id,run_id=run.id,)messages=client.beta.threads.messages.list(thread_id=thread.id,order="desc",limit=1,)print(messages.data[0].content)

这段代码把“存储消息”“启动任务”“查询任务状态”“读取结果”拆成了多个对象。

迁移到Responses API后,同一个同步请求可以直接返回Response;SDK还提供了output_text辅助属性,不必假定文本一定在output[0].content[0]中。

Responses API迁移说明:
https://developers.openai.com/api/docs/guides/migrate-to-responses

三、先跑通最小Responses调用

升级Python SDK:

python-mpipinstall-Uopenai

配置环境变量:

exportOPENAI_API_KEY="你的API Key"exportOPENAI_MODEL="你的项目准备使用的模型ID"

最小调用代码:

importosfromopenaiimportOpenAI client=OpenAI()response=client.responses.create(model=os.environ["OPENAI_MODEL"],instructions="你是一名代码审查助手,只指出可以复现的问题。",input=[{"role":"user","content":"请检查这段Python代码是否存在并发安全问题。",}],)print(response.output_text)

第一轮改造建议保持原模型、原指令和原业务输入不变,只替换API编排方式。否则同时更换模型、提示词和接口,一旦输出发生变化,很难判断是哪项修改造成的。

四、多轮会话:用Conversation替代Thread

创建Conversation:

conversation=client.conversations.create(metadata={"user_id":"user-42"})print(conversation.id)

发送第一轮消息:

response=client.responses.create(model=os.environ["OPENAI_MODEL"],conversation=conversation.id,instructions="你是一名Python代码审查助手。",input=[{"role":"user","content":"解释一下什么是竞态条件。",}],)print(response.output_text)

第二次请求继续传入同一个conversation.id:

response=client.responses.create(model=os.environ["OPENAI_MODEL"],conversation=conversation.id,instructions="你是一名Python代码审查助手。",input=[{"role":"user","content":"结合刚才的解释,再给一个线程安全的修改示例。",}],)print(response.output_text)

Conversation可以保存消息、工具调用和工具输出等Item,其定位比只保存消息的Thread更宽。

Conversations API文档:
https://developers.openai.com/api/reference/resources/conversations/methods/create

如果项目只是短链式对话,也可以使用previous_response_id:

first=client.responses.create(model=os.environ["OPENAI_MODEL"],input="解释Python中的竞态条件。",store=True,)second=client.responses.create(model=os.environ["OPENAI_MODEL"],input="给一个线程锁修复示例。",previous_response_id=first.id,store=True,)

不过需要注意:使用previous_response_id并不代表旧输入不再计费,官方说明响应链中的历史输入Token仍会作为输入计算。对于需要长期绑定用户会话的系统,Conversation通常更容易管理。

五、不要把SDK调用散落在业务代码里

比较稳妥的做法是增加一层适配器,让业务代码只认识start()和ask()。

fromdataclassesimportdataclassfromtypingimportAny@dataclass(frozen=True)classReply:text:strresponse_id:strconversation_id:strclassResponsesChat:def__init__(self,client:Any,model:str,instructions:str,)->None:self.client=client self.model=model self.instructions=instructionsdefstart(self,user_id:str)->str:conversation=self.client.conversations.create(metadata={"user_id":user_id})returnconversation.iddefask(self,conversation_id:str,user_text:str,)->Reply:response=self.client.responses.create(model=self.model,conversation=conversation_id,instructions=self.instructions,input=[{"role":"user","content":user_text,}],)returnReply(text=response.output_text,response_id=response.id,conversation_id=conversation_id,)

业务层只保存自己的session_id与OpenAI conversation_id之间的关系:

importosfromopenaiimportOpenAI client=OpenAI()chat=ResponsesChat(client=client,model=os.environ["OPENAI_MODEL"],instructions="你是一名严谨的技术支持助手。",)conversation_id=chat.start(user_id="user-42")reply=chat.ask(conversation_id=conversation_id,user_text="为什么我的异步任务会重复执行?",)print(reply.text)

生产环境不要使用内存字典保存映射。应该写入数据库或Redis,并至少保留以下字段:

business_session_id provider conversation_id created_at updated_at migration_status

这样既能避免应用重启后丢失会话,也方便灰度期间同时识别旧Thread和新Conversation。

六、旧Thread怎么回填

官方建议优先让新会话使用Conversation,旧Thread按需回填。下面是只迁移纯文本消息的简化版本:

fromopenaiimportOpenAI client=OpenAI()defbackfill_text_thread(thread_id:str)->str:messages=[]forpageinclient.beta.threads.messages.list(thread_id=thread_id,order="asc",).iter_pages():messages.extend(page.data)items=[]formessageinmessages:text_parts=[content.text.valueforcontentinmessage.contentifcontent.type=="text"]ifnottext_parts:continuecontent_type=("input_text"ifmessage.role=="user"else"output_text")items.append({"role":message.role,"content":[{"type":content_type,"text":"\n".join(text_parts),}],})conversation=client.conversations.create(items=items)returnconversation.id

这段代码只处理文本。旧Thread中如果含有图片、文件引用、函数调用、工具输出或引用标注,必须分别转换,不能静默丢弃。

更稳妥的策略是:

  1. 新用户会话全部创建Conversation。
  2. 最近仍然活跃的Thread按需回填。
  3. 长期未访问的历史Thread只归档,不主动迁移。
  4. 首次访问旧会话时执行迁移并记录新旧ID。
  5. 对迁移失败的数据保留原始Thread ID和错误日志。

七、给适配层补一个不消耗Token的单元测试

下面的测试使用伪客户端,不需要真实API Key,主要验证请求参数和返回值映射:

fromtypesimportSimpleNamespaceimportunittestclassRecorder:def__init__(self,result):self.result=result self.calls=[]defcreate(self,**kwargs):self.calls.append(kwargs)returnself.resultclassFakeClient:def__init__(self):self.conversations=Recorder(SimpleNamespace(id="conv_test"))self.responses=Recorder(SimpleNamespace(id="resp_test",output_text="迁移成功",))classResponsesChatTest(unittest.TestCase):deftest_start_and_ask(self):client=FakeClient()chat=ResponsesChat(client,"model-from-env","只回答技术问题",)conversation_id=chat.start("user-42")reply=chat.ask(conversation_id,"如何迁移?")self.assertEqual(conversation_id,"conv_test")self.assertEqual(reply.text,"迁移成功")self.assertEqual(client.responses.calls[0]["conversation"],"conv_test",)self.assertEqual(client.responses.calls[0]["input"],[{"role":"user","content":"如何迁移?",}],)if__name__=="__main__":unittest.main()

运行命令:

python-munittest-v

预期结果:

test_start_and_ask ... ok Ran 1 test OK

我对上面的适配器与测试做了本地验证,测试可以通过。验证范围是参数构造、会话ID传递和文本结果映射;真实网络调用仍需要项目自己的API Key、可用模型、工具配置及账户权限。

八、Prompt迁移不能只复制一段instructions

旧Assistant通常还包含:

  • 模型ID;
  • Instructions;
  • File Search或Code Interpreter;
  • 自定义函数Schema;
  • 响应格式;
  • 温度等生成配置。

官方迁移指南支持在控制台中把Assistant转换为Prompt,并通过下面的形式调用:

response=client.responses.create(prompt={"id":os.environ["OPENAI_PROMPT_ID"],},conversation=conversation_id,input=[{"role":"user","content":"检查这段代码。",}],)

不过,当前迁移文档同时提醒开发者关注可复用Prompt对象的弃用时间线。长期项目不要把全部业务逻辑绑定在单一配置对象上,建议继续保留自己的适配层和配置版本号,以便后续替换。

九、上线时用双实现和开关控制

不要在一次发布中删除旧实现。可以保留两个后端:

importosdefbuild_chat_backend(client):backend=os.getenv("AI_BACKEND","assistants",)ifbackend=="responses":returnResponsesChat(client=client,model=os.environ["OPENAI_MODEL"],instructions="你是一名技术支持助手。",)returnAssistantsChat(client=client,assistant_id=os.environ["OPENAI_ASSISTANT_ID"],)

推荐的切换顺序:

  1. 盘点所有assistant_id、Thread存储位置和工具调用。
  2. 用统一适配层包住新旧实现。
  3. 内部测试账号先切到Responses。
  4. 对固定测试集做影子请求,不把影子结果返回用户。
  5. 比较答案正确性、工具调用参数、延迟、Token用量和错误率。
  6. 按1%、10%、30%、100%逐步扩大流量。
  7. 在确认稳定前保留旧实现和回滚开关。
  8. 完成切换后再停止创建新Thread。

如果新接口异常,只需调整环境变量并重新部署:

exportAI_BACKEND="assistants"

回滚只能作为迁移期间的临时方案,因为Assistants API到期后旧接口将不再是有效退路。

十、回归测试不要只比较文案是否一样

模型输出具有非确定性,逐字比较很容易误报。更有价值的测试指标包括:

测试项检查方法
基础问答是否包含必要事实与结论
多轮上下文第二轮能否引用第一轮信息
工具调用函数名称、参数和调用次数是否正确
结构化输出JSON是否符合Schema
文件检索是否引用正确文件及片段
异常处理超时、限流、工具报错是否可恢复
数据隔离不同用户是否绑定不同Conversation
成本变化记录输入、输出和总Token
延迟变化对比P50、P95与超时率

尤其要检查工具循环。Assistants API中的Run会替应用管理一部分执行过程,而Responses体系下,开发者需要更明确地处理工具调用与工具输出。只验证普通聊天成功,并不能证明业务已经迁移完成。

十一、别混淆API迁移和ChatGPT会员

这次改造解决的是API项目兼容性,不等同于ChatGPT Plus订阅。团队如果还长期使用ChatGPT Plus、Claude Pro、Gemini Advanced等工具,可以把gpt985作为第三方AI会员充值平台了解;使用前仍要看清套餐说明、账号要求、到账说明和售后规则。工程迁移本身则应直接依据API官方文档完成。

十二、迁移检查清单

  • 代码中已定位全部client.beta调用;
  • 新会话不再创建Thread;
  • 业务会话已映射到Conversation;
  • 输出读取改为response.output_text或遍历typed output;
  • 自定义函数调用完成适配;
  • File Search、Code Interpreter等工具单独验收;
  • 旧Thread制定了按需回填方案;
  • Conversation ID持久化到数据库或Redis;
  • 完成多用户数据隔离测试;
  • 监控错误率、延迟和Token用量;
  • 保留灰度开关和迁移期回滚方案;
  • 团队已记录2026年8月26日停用节点。

Assistants API迁移最危险的做法,是看到旧代码还能运行,就继续把改造排到以后。

真正稳妥的处理方式,是先建立适配层,让新会话进入Responses API,再迁移工具和必要的历史数据,最后用回归测试、灰度流量与监控完成切换。这样即使输出结构或会话逻辑出现差异,也能在影响全部用户之前发现问题。

相关新闻

  • 支付宝消费券回收怎么做?消费券属性与变现流程解析~~ - 京顺回收
  • 2026年 ISO9001认证机构推荐榜单:质量管理体系认证,ISO9001体系认证,ISO9001质量管理体系认证公司优选 - 优企名品
  • C++并发编程实战:基于锁的线程安全数据结构设计与实现

最新新闻

  • 32路Modbus RTU继电器模块:工业自动化集中控制与RS485通信实战
  • MySQL迁移到达梦怎么做?信创数据库低停机迁移实战
  • 国际大一Diploma申请如何筛选教育代理:核验流程与反例拆解 - GrowUME
  • 深入解析PSRR:从电源噪声抑制到芯片稳定工作的关键指标
  • 全栈国产化!itc保伦股份麒麟无纸化会议系统解决方案解锁安全高效会议新范式! - 品牌速递
  • 2026年助听器ODM成本优势明显的公司 - 滚动商讯

日新闻

  • ClickHouse版本管理深度实战:4步构建零风险升级与回滚体系
  • Java 23 种设计模式:从踩坑到精通 | 番外:责任链模式 —— 物流审批流程实战
  • 华硕笔记本性能解放指南:G-Helper轻量级控制工具全面解析

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • ClickHouse版本管理深度实战:4步构建零风险升级与回滚体系
  • Java 23 种设计模式:从踩坑到精通 | 番外:责任链模式 —— 物流审批流程实战
  • 华硕笔记本性能解放指南:G-Helper轻量级控制工具全面解析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号