OpenAI Responses API 怎样用 previous_response_id 延续多轮对话
来源:17golang原创
时间:2026-10-25 00:48:42 481浏览 收藏
我第一次把 Responses API 接进多轮助手时,最容易误判的一点是:只要把上一轮的 response.id 传给下一轮,就等于拥有了一个永久会话。实际上,previous_response_id 只是把响应串成一条上下文链;应用仍然要负责保存这条链的入口、处理失败恢复,并决定什么时候需要更持久的会话对象。
这篇文章只解决一个问题:怎样用 previous_response_id 延续多轮对话,以及它与手动维护历史、Conversations API 的边界。官方资料入口是 https://developers.openai.com/api/docs/guides/conversation-state,可直接复制打开。
先把三种状态管理方式分开
Responses API 的多轮状态大致有三种组织方式。用 previous_response_id 是“沿着上一条响应继续问”;使用 Conversations API 是“给一段长期会话一个独立的 conversation_id”;手动历史则是应用自己把过去的输入和输出整理成下一次请求的 input。
| 方式 | 适合的压力 | 应用需要保存什么 |
|---|---|---|
previous_response_id | 简单的串行追问、短链路任务 | 最后一次响应 ID 与用户会话的对应关系 |
| Conversations API | 跨请求、跨设备或长期保存的会话 | conversation_id,以及业务侧的权限和归属 |
手动 input 历史 | 需要自己裁剪、脱敏、重排或迁移上下文 | 可重放的消息和输出项,以及裁剪策略 |
这里的关键判断不是“哪个 API 更高级”,而是上下文的所有权在哪里。链式响应把上下文关联交给 API,手动历史把关联交给应用,而 Conversations API 则把长期会话变成一个可以单独管理的资源。

用 response.id 接上下一轮请求
最小链路只有三件事:首轮创建 Response,保存返回对象的 id,下一轮把它放到 previous_response_id。下面的 Node.js 示例故意把状态保存写成函数参数,方便看出业务会话和 API 响应链不是同一个对象。
import OpenAI from "openai";
const client = new OpenAI();
export async function continueConversation(lastResponseId, userText) {
// 首轮没有 ID 时从新的输入开始;有 ID 时让 API 接续上一轮响应。
const params = {
model: process.env.OPENAI_MODEL,
input: [{ role: "user", content: userText }],
store: true,
};
if (lastResponseId) {
// 只关联上一轮响应,不把业务用户 ID 直接当作 API 的响应 ID。
params.previous_response_id = lastResponseId;
}
const response = await client.responses.create(params);
// 调用方应把这个 ID 与自己的会话记录一起保存。
return { text: response.output_text, lastResponseId: response.id };
}
第一次调用时,返回值中的 lastResponseId 会成为第二次调用的输入。第二次调用完成后,要用新的 response.id 覆盖旧值;不要一直保存首轮 ID,否则每次都从相同节点分叉。
这个示例没有把 API key、用户标识或真实响应 ID写进文章,也没有把调用结果当成已经在本机运行过的证据。它只是展示请求字段之间的静态关系。
指令不会因为链式关联自动继承
这是最值得单独提醒的边界:previous_response_id 负责传递上下文关联,并不等于应用层配置会永远沿用。官方文档特别说明,使用 previous_response_id 时,上一轮的 instructions 不会自动带到下一轮。
因此,下面这种“第一轮设定了回答格式,第二轮什么都不补”的写法不适合作为稳定的生产约定:
const next = await client.responses.create({
model: process.env.OPENAI_MODEL,
previous_response_id: previous.id,
// 中文说明:如果本轮仍需遵守输出格式,应在这里再次明确要求。
input: "把刚才的结论改成三条检查清单。",
});
更稳妥的做法是把每一轮都需要的稳定规则放进本轮请求的 instructions,把只属于当前问题的内容放进 input。这样即使以后更换状态载体,也不必依赖“隐藏的上一轮配置”。
store、响应保留与输入成本要一起看
链式调用还有三个经常被混为一谈的概念。
store是响应对象是否由 API 保存的请求选项,不是业务数据库里的会话表。- 保存响应不等于无限期保存;响应对象有默认保留周期,长期会话应评估 Conversations API 或应用自己的持久化策略。
- 即使使用
previous_response_id,链中先前的输入 token 仍会作为输入计费,不能把“少传几段文本”理解为“完全没有上下文成本”。
在服务端,至少应记录用户会话 ID、最后一次响应 ID、状态更新时间和失败状态。用户会话 ID用于找回业务状态,响应 ID用于续接 API 链,两者不要混用。

业务服务怎样保存最后一个响应 ID
可以把续接逻辑包在一个小的状态仓库后面。下面用 Python 写一个最小接口,重点不在数据库选型,而在“成功后才推进指针”:请求失败时不能先把新 ID 写入会话,否则下一次恢复会从一个不存在或未完成的节点继续。
from openai import OpenAI
client = OpenAI()
def ask(session, text):
# session 只保存业务会话和最后一次成功响应 ID,不保存密钥。
params = {
"model": "${OPENAI_MODEL}",
"input": [{"role": "user", "content": text}],
"store": True,
}
if session.get("last_response_id"):
# 中文说明:只从最后一次成功响应继续,避免重复使用旧分支。
params["previous_response_id"] = session["last_response_id"]
response = client.responses.create(**params)
# 中文说明:API 成功返回后再推进本地游标,失败时保留旧游标以便重试。
session["last_response_id"] = response.id
return response.output_text
生产代码还需要给 session 加上并发控制。例如同一个用户同时提交两条消息时,两个请求都读取到相同的旧 ID,就可能形成两个分支。可以采用数据库乐观锁、队列串行化,或明确允许分支并把每个分支单独命名。
什么时候应该改用 Conversations API
如果只是一个页面上的连续追问,previous_response_id 足够直观;如果要让会话跨设备、跨作业或长期存在,Conversations API 更容易表达真实的资源关系。官方文档描述的 conversation 可以保存消息、工具调用和工具输出等 item,后续 Responses 请求通过 conversation 继续使用它。
还有一种情况适合手动历史:你必须在发给模型前做敏感字段脱敏、按租户重排、按预算裁剪,或者要把历史迁移到另一套模型服务。此时应用掌握完整的可重放输入,会比依赖单条响应链更容易审计。
可以用下面的清单做选择:
- 只需把上一轮答案接到下一轮:使用
previous_response_id。 - 需要长期、跨设备管理一个会话资源:优先考虑 Conversations API。
- 需要脱敏、裁剪、重排或跨供应商迁移:自己保存并组装 input 历史。
- 无论选哪种方式,都单独保存业务会话身份、权限和失败恢复状态。
相关问题
previous_response_id 能代替业务数据库吗?
不能。它是 API 请求的上下文关联字段,不包含你的用户权限、租户归属、审计信息和业务状态。
下一轮是否必须再次传完整历史?
使用 previous_response_id 时不需要按手动历史方式重放全部输入,但链式上下文仍然会产生输入 token 成本;如果需要自定义裁剪,就改为手动管理历史。
为什么要保存最新 response.id 而不是首轮 ID?
因为每个响应都是链上的新节点。保存最新 ID 才能让下一轮从最近一次成功状态继续,而不是反复从旧节点分叉。
把 previous_response_id 看成“响应链指针”,而不是“万能会话开关”,多轮对话的设计就会清楚很多:短链路用它,长期资源用 Conversations API,需要控制上下文就自己维护历史。
-
214 收藏
-
478 收藏
-
484 收藏
-
151 收藏
-
396 收藏
-
397 收藏
-
357 收藏
-
119 收藏
-
346 收藏
-
101 收藏
-
246 收藏
-
118 收藏
-
489 收藏
-
469 收藏
-
439 收藏
-
168 收藏
-
239 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习