OpenAI Responses API 多轮写作上下文怎么管理
连续修改文章或提纲时,重复发送整段内容既浪费请求空间,也容易产生版本混淆。OpenAI Responses API 多轮写作上下文怎么管理,关键在于保存上一轮响应 ID,明确上下文保留边界,并…
开始前准备
连续修改一篇文章时,上一轮可能已经确定了标题、提纲、事实边界和语气,下一轮只想调整其中一节。如果每次都重新发送完整原文,输入会越来越长,编辑者也很难确认模型修改的到底是哪一个版本。更合适的做法是把每次请求视为一条有父子关系的任务链:上一轮响应产生一个 ID,下一轮用这个 ID 连接,并在新的输入中只描述本轮变化。
Responses API 的 SDK 接口提供两种需要区分的连接方式。第一种是使用 previous_response_id,把当前请求连接到上一条响应,用于创建多轮请求。第二种是使用 conversation,让响应属于一个会话;该会话中的项目会被放到本次输入项目之前,本次输入和输出项目在响应完成后自动加入会话。两种方式不能在同一个请求中同时使用。
- 使用上一轮响应 ID:适合一篇文章从提纲到初稿、从初稿到改稿的线性流程。应用侧保存最新成功响应 ID,下一轮只提交修改要求。
- 使用会话:适合需要由会话统一承载多组输入和输出的流程。应用侧仍应保存会话标识与每一轮任务记录,不能只依赖界面上的聊天记录。
- 重新发送稳定规则:使用上一轮响应 ID时,前一轮的
instructions不会自动带到下一轮。事实边界、格式要求和审核规则只要仍然有效,就应在新请求中再次传入。 - 区分缓存和上下文:
prompt_cache_key用于相似请求的缓存优化,不应当被当作多轮任务的父子连接标识。连接关系应由响应 ID或会话标识管理。
开始前先定义本轮唯一目标,例如“只修改提纲第三节的顺序”或“只检查事实是否超出资料”。同时准备规则版本、材料版本、当前父响应 ID和验收标准。若还需要整理单轮写作输入,可参考OpenAI Responses API 写作输入怎么组织,但当前流程的重点是如何把连续修改接起来。
分步操作
下面的流程以 previous_response_id 为例。它适合内容运营后台、编辑器或队列任务。每轮成功后才推进父响应指针,失败或结果待确认时不要覆盖上一轮可用版本。
- 选择连接模式:先决定本篇任务使用上一轮响应 ID,还是使用会话。线性改稿尽量保持一种模式,不要一半使用会话、一半切换父响应 ID。
- 拆分稳定规则和本轮输入:把“只使用已确认材料”“输出简体中文”“保留事实边界”等长期规则放进
instructions。把本轮目标、修改范围、材料版本和交付形式放进input。 - 发起第一轮请求:使用
client.responses.create创建提纲或文章初稿,并保存返回对象中的id。这个 ID是下一轮连接所需的父节点。 - 只提交增量修改:下一轮把上一轮响应 ID传给
previous_response_id,输入写成清楚的修改工单,例如“只改第二节,保留事实、标题和篇幅,不重写其他部分”。不要仅写“继续优化”,否则验收范围不明确。 - 更新任务指针:下一轮成功完成后,将新的响应 ID 写入任务记录,作为后续请求的父 ID。若需要并行尝试两种改法,应从同一个父 ID 分出两个分支,分别记录,不要让两个并发任务互相覆盖最新指针。
- 执行结果复核:保存返回对象和应用侧提取出的正文。必要时使用
client.responses.retrieve(response_id)按 ID重新取得响应,核对它是否对应本轮记录,再进行事实、结构和格式检查。 - 处理长度风险:连续请求变长后,检查模型上下文窗口。
truncation默认是disabled,超过上下文窗口时请求会失败;设置为auto后,接口可能从会话开头丢弃项目。只有确认早期资料可以被舍弃时,才考虑自动截断。
from openai import OpenAI
client = OpenAI()
stable_rules = '你是内容编辑助手。只使用已确认资料,不把待核实内容写成事实。每轮只处理输入指定的修改范围。'
first = client.responses.create(
model='YOUR_MODEL',
instructions=stable_rules,
input='任务:根据给定资料生成文章提纲。主题:Responses API 连续改稿。输出:五个章节和每章要点。',
store=True,
)
second = client.responses.create(
model='YOUR_MODEL',
previous_response_id=first.id,
instructions=stable_rules,
input='只修改上一轮提纲的第二节:调整步骤顺序,保留其他章节、已确认事实和输出格式。',
store=True,
)
latest = client.responses.retrieve(second.id)
print(second.id)
这段代码中,第二轮没有重新粘贴第一轮提纲,而是用父响应 ID建立连接。instructions 仍然重复传入,是因为接口定义明确说明上一轮的系统或开发者规则不会随 previous_response_id 自动继承。实际项目中,stable_rules 应从规则版本库读取,避免程序运行时依赖手工复制。
如果改用 conversation,就把会话标识作为唯一会话入口,并让会话自动承载已经完成的输入和输出项目。此时不要再提交 previous_response_id。无论采用哪种模式,都要在自己的数据库中保存任务号、父节点、当前节点和本轮修改目标,否则接口连接存在,团队却无法复盘。
可复制模板
任务记录应同时服务开发者和内容运营。它不要求保存整篇重复内容,但必须能回答四个问题:这轮改了什么、基于哪个版本、用了哪些规则、结果是否通过检查。下面的字段可以直接放进数据库、队列消息或表格。
task_id: [内部任务号]
workflow: [提纲改稿/文章改稿/审核复核]
context_mode: [previous_response_id 或 conversation]
parent_response_id: [上一轮成功响应 ID]
response_id: [本轮成功响应 ID]
conversation_id: [使用会话时填写]
step: [第几轮]
model: [实际使用的模型]
instructions_version: [稳定规则版本]
material_version: [资料版本]
change_request: [本轮唯一修改目标]
keep_rules: [必须保留的事实、结构和格式]
output_requirement: [本轮交付形式]
review_result: [通过/需修正/待确认]
review_notes: [异常、差异或人工判断]
created_at: [创建时间]
completed_at: [完成时间]
每轮的修改输入也可以固定成一份短模板:
本轮目标:[只写一个可观察的修改目标]
修改范围:[章节、段落、字段或审核项目]
必须保留:[事实、标题、语气、格式和不可改变的内容]
本轮材料变化:[新增资料版本或无]
禁止变化:[不允许重写的部分]
输出要求:[返回完整稿件、修改后的章节或问题清单]
验收标准:[完成后如何判断这轮通过]
例如连续改一份提纲时,可以填写:“本轮目标:让第二节步骤更适合开发者执行;修改范围:第二节;必须保留:接口字段名称和事实边界;禁止变化:第一节、第三节标题;输出要求:返回完整提纲;验收标准:第二节包含请求连接、ID保存和异常复核三个动作。”这样模型知道上下文来自上一轮,但本轮边界仍然由输入明确规定。
记录中不建议把整篇原文塞进 API 的 metadata。资料说明 metadata 适合附加短键值信息,最多可附加 16 个键值对,键和值也有长度限制。整篇文章、完整请求和完整响应应保存在应用侧版本库,metadata 只放任务号、规则版本或材料版本等便于检索的短标识。
建议为每个节点保存一份“差异摘要”,而不是只保存最终稿。差异摘要可以写成“删除引言中的价格推断”“将第三节拆成三个步骤”“保留原提纲但替换审核清单”。当内容团队发现结果不对时,先查看差异摘要,再决定回退、重试还是从旧节点分支。
翻车修正
模型像没有看过上一轮:先核对本轮传入的父响应 ID是否确实是上一轮成功结果,而不是任务创建时的初始 ID。再检查是否误把两个并行分支共用一个可变指针。如果父 ID正确但规则丢失,重点检查 instructions 是否在本轮重新传入。
只说“继续改”却改错位置:把模糊指令改成有范围、有保留项和验收条件的任务。至少写清章节或段落、允许改变的内容、必须不变的内容,以及本轮输出是局部结果还是完整稿件。连续上下文只能减少重复材料,不能替代本轮的修改意图。
改一节却整篇语气漂移:检查稳定规则是否版本化,并在每一轮重复传入。对于事实审核、品牌口径和固定 HTML 格式等高约束任务,不要依赖模型从历史内容中自行归纳规则。
长链请求返回 400:先检查输入长度和历史项目是否已经超过上下文窗口。资料确认 truncation 默认为 disabled,因此超限时失败是预期行为。可以先删去重复材料,保留事实表和当前稿件;如果任务确实需要长期运行,也可以评估 client.responses.compact 提供的会话压缩操作。压缩后必须重新检查标题、事实和审核边界,不能把压缩结果直接当成原始上下文的完整替代。
开启自动截断后早期要求消失:auto 会通过丢弃会话开头项目来适配窗口。文章改稿尤其容易把最初的受众、资料来源或禁止项放在开头,因此自动截断只适合早期资料确实不再需要的场景。若早期信息仍重要,应将其整理成短的确认摘要,并在当前请求中重新提供。
请求超时,不知道能不能重试:不要直接把任务标为失败并推进到新父 ID。先将记录标为“待确认”,保留发送时间、父响应 ID、输入摘要和客户端错误。只有确认没有可用响应后,才创建重试;如果产生了新响应,必须以实际返回 ID建立新的节点,不能假设重复请求与原请求等价。
结果看似成功但事实变了:用本轮保存的材料版本逐条回查关键结论,再通过 retrieve 按响应 ID复核对应对象。把问题分成连接错误、规则丢失、材料缺失和生成质量四类,每次只修一类。不要用“更准确一点”替代具体的事实核对要求。
审核者无法判断改了哪里:让任务记录同时保存父响应 ID、本轮响应 ID和差异摘要。若有多个候选版本,为每个分支使用独立任务号。最终采用的节点应标记为发布候选,未采用节点保留为比较依据,避免后续请求误接到旧分支。
完成前检查
发布文章、交给审核或进入下一轮生成前,按下面的清单逐项核对。清单的目的不是证明模型永远不会出错,而是确认每个错误都能定位到具体请求和具体版本。
- 本篇任务是否只选择了一种连接模式,没有同时使用
conversation和previous_response_id。 - 第一轮响应 ID是否已保存,后续请求使用的父 ID是否确实指向上一轮成功节点。
- 每一轮是否保存了新的响应 ID,并且只在结果确认成功后更新当前指针。
- 稳定规则是否放在
instructions中,并在使用上一轮响应 ID时重新传入。 - 本轮
input是否写清修改目标、修改范围、保留项、禁止变化和验收标准。 - 是否避免为连续修改重复发送整篇文章,同时保留必要的新增资料或短事实摘要。
- 是否记录了模型、规则版本、材料版本、任务轮次和完整的差异摘要。
- 是否检查上下文窗口,并明确
truncation使用disabled或auto的理由。 - 若使用自动截断或会话压缩,标题、事实、受众和禁止项是否已重新核对。
- 请求超时或网络异常时,任务是否保持待确认状态,没有盲目推进父节点或重复发布。
- 是否能通过响应 ID重新取得对应响应,并将接口结果与应用侧保存的请求记录对应起来。
- 最终文章是否仍然围绕连续修改文章或提纲这一问题,没有偏移成泛泛的 API 介绍。
多轮改稿的核心不是让接口替你保存所有工作,而是建立一条可追溯的版本链:响应 ID负责连接节点,instructions负责重复声明稳定边界,input负责描述本轮变化,任务记录负责让开发者和审核者共同复核。这样既能减少整段内容的重复发送,也能在上下文丢失、请求超限或结果异常时准确回到出错环节。
下一步
把这篇的方法练一遍
提示词和步骤可以带到创作里直接试做一版。