事情本身不复杂,线索都在日志里。用 openai 1.55 把 chat.completions 迁到 /v1/responses,第一轮问答正常,第二轮把上一轮的 id 传进 previous_response_id,模型回话说不知道前面聊过什么,抓包看到第二次请求的 input 里只有新问题一句话。
第一反应是「客户端把 response.id 和 output 里的 message id 记混,传上去的是后者」,验证下来不成立。
把日志和配置对完,能解释这个现象的基本就这几处。previous_response_id 只认同组织同项目下生成的 response,换了 key 就查不到。还有一种是第一轮调用带了 store=false,服务端没有落库,后面自然引用不到。
不容易想到的是,中途换了 base_url 走自建代理,两端的存储不互通。
动手时先把第一轮返回体里的 id 原样打出来核对前缀
python -c "from openai import OpenAI;r=OpenAI().responses.create(model='gpt-4o-mini',input='ping');print(r.id,r.object)"
接着确认这一轮有没有被 store=false 关掉落库
curl https://api.openai.com/v1/responses -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","input":"ping","store":true}'
带上上一轮 id 重发并打印两次的 id
curl https://api.openai.com/v1/responses -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","input":"第二问","previous_response_id":"resp_abc123"}'
末了改成显式拼 input 数组做一组对照
curl https://api.openai.com/v1/responses -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","input":[{"role":"user","content":"第一问"},{"role":"user","content":"第二问"}]}'
恢复的判定其实很直接。第二轮的 output 文本能准确复述第一轮给出的信息,曲线链接的 id 前缀是 resp_ 且与第一轮返回一致,对照组与链式组回答内容对得上。
previous_response_id 是服务端状态,生命周期和项目绑定,跨项目迁移或换 key 时不如自己拼 input 稳妥,生产里两条路最好都留一个开关。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。