API 多轮对话怎么接?保存历史、发送上下文与状态核对
多轮对话需要让下一次请求拿到前文。应用可以自己保存历史,每轮发送所需上下文;也可以在目标服务支持时,用响应 ID 或会话对象续接。复用 API Key、模型名,或只把聊天记录显示在页面上,都不能单独证明服务端已收到前文。
本文面向自己写程序的开发者,官方资料核对日期为 2026 年 10 月 24 日。配套资源只做离线核对,没有发起真实请求;Claude Code 的恢复与交接另见长任务续接教程。
先选一种历史传递方式
| 接口与方式 | 下一轮带什么 | 应用要核对什么 |
|---|---|---|
| Chat Completions 手动历史 | messages 中的前文与新问题 |
角色、顺序、内容是否完整 |
| Responses 手动历史 | input 中可回传的历史条目与新输入 |
不要只保存显示用的文本 |
| 支持状态管理的 Responses 服务 | 新输入,以及适用的响应 ID 或 conversation | 服务能力、标识所属会话及可用状态 |
OpenAI 文档分别介绍手动历史、previous_response_id 和 Conversations;最后一种是独立会话对象,并非把任意本地会话编号填进请求。使用状态机制前,应核对该服务的保存、获取和删除规则。OpenAI 会话状态
同名接口也有差异:DeepSeek 当前明确不支持 Responses 的 previous_response_id、conversation 和 store。因此,不能从“能调用 /responses”推断“已经自动保存上下文”。DeepSeek 兼容说明
手动历史:第二轮不只发送“继续”
下面是自己构造的纯文本 messages 片段,不是完整请求,也不是模型实测结果:
[
{"role":"user","content":"这份通知面向新同事,语气简洁。"},
{"role":"assistant","content":"请提供通知要包含的事项。"},
{"role":"user","content":"周五下午三点开会,请按刚才的要求写一句通知。"}
]
第一条保留受众与语气,第二条保留先前回复,第三条才是新输入。实际程序应保存对应轮次的真实消息,不要照抄这里的人为回复。只发送第三条,会丢掉“刚才的要求”;把 assistant 改成 user,也改变了消息含义。DeepSeek 的无状态多轮示例采用先追加模型回复、再追加新问题的顺序。DeepSeek 多轮对话
不要把所有接口都转成这个简单数组。Claude Messages 也支持无状态多轮,但内容块与请求参数要按它自己的定义保存;Responses 的 output 可能包含推理项、工具调用和消息字段,手动续接须按当前接口要求保留可回传条目,不能仅取 output_text。Claude Messages、Responses 历史管理
出现工具调用时,还需保留调用与结果的关联;具体配对见工具执行与回传流程,不要把工具结果随意改成普通聊天文本。
保存历史时,分开会话、请求和完成状态
建议在应用中采用以下记录流程;这是实现核对建议,不是供应商自动提供的存储功能。
- 给每个用户的每个对话分配独立的应用会话标识,读取历史前核对归属。不要让所有人共用一个全局消息数组。
- 保存本轮使用的历史版本、协议、模型和新输入。请求 ID 用于查日志,响应 ID 用于对应输出;两者不能混填。
- 收到结果后,记录完成、失败、未完成等原始状态。半截流式文本可以显示为草稿,但不应悄悄记成成功回复,结束判断见 SSE 接收检查。
- 按应用规则提交本轮历史,再开始下一轮。同一会话有并发请求时,可以串行处理或检查版本冲突,避免后返回的旧结果覆盖新状态。
对于 OpenAI 的 ID 续接,上一响应的 instructions 不会因传了 previous_response_id 自动带到下一次;本轮仍需要的规则应明确提供。previous_response_id 与 conversation 也不能在同一请求中混用。Responses 参数说明
采用服务端状态时,保存应用会话与服务端标识的对应关系;不要把其他账号、其他服务的 ID 拿来复用。标识失效时先查错误和保存条件,再决定是否用可核验历史重新开始,不能靠编造一个 ID 恢复对话。
用三种情形验收,别只听模型说“记得”
下载多轮上下文核对包,包含发送前清单、合成历史对照和空白 CSV。它不执行请求、不存储真实聊天,也不证明云岚API的某条渠道支持状态续接。
| 核对情形 | 应检查的证据 |
|---|---|
| 第二轮引用第一轮的受众、格式或约束 | 发出的历史确实含这些要求,最终回答符合要求 |
| 两个会话分别使用不同任务条件 | 两份请求互不混入另一会话的消息或标识 |
| 程序重启后继续已有任务 | 恢复的记录版本、消息顺序、状态标识与原会话一致 |
先用合成数据检查序列化结果,再按自己的授权与测试环境核对真实请求。若回答遗漏约束,先看发出的内容,再看上下文裁剪与模型输出;一次答对不能证明所有长对话都可靠。记录里只留必要的脱敏证据,不放 Key。
常见问题
用同一个 API Key,为什么还会忘记前文?
Key 用于认证,不是应用会话历史。先确认实际请求带了前文,或使用了已验证可用的状态机制;网页上仍能看到旧消息,不代表后台把它们发出去了。
用 previous_response_id,是不是不用再付历史输入费?
不是。OpenAI 说明该方式仍对链中的历史输入计费;具体缓存与费率要按当次接口核对。请求体变短不等于计费输入变少,账单拆分见输入与缓存对账。官方计费提示
历史很长,能直接只保留最近几条吗?
可以设计裁剪策略,但应先标出仍有效的规则、事实和未完成项,再验收是否丢失。摘要也可能漏细节;上下文窗口、自动裁剪或压缩能力都要按模型与接口确认,不能保证无限记忆或无损压缩。
换成云岚API,只改地址就能保留会话吗?
不能据此保证。需核对所选模型、协议及渠道是否支持状态参数。尚未有 Key 可先完成首次接入;已有 Key 则对照 base URL 与协议,从手动历史和一组清楚的验收条件开始。
用 LangChain 管理调用时,历史消息怎样进入模型?
历史消息仍须按本篇的角色和顺序组织,再交给具体客户端。使用 Python ChatOpenAI 时,继续看 LangChain 消息输入与返回结果检查,确认传入的消息、返回的 AIMessage,以及文本和工具分支的不同处理;保留一个返回对象不等于下一次请求已自动包含全部历史。
历史越来越长,怎样在发送前检查上下文预算?
先保留完成任务所需的消息和工具配对,再按 上下文窗口与输入预算检查核对完整请求、输出预留和无法精确计数的部分。裁剪后用原任务的合格标准验收,不把没有报错等同于信息没有丢失。
