事情本身不复杂,线索都在日志里。后端把消息和 run 一起提交后等着取结果,十分钟过去 run.status 一直是 in_progress,日志里只有一次 create 请求,中间没有任何 retrieve,assistant 那边其实早就答完了。
第一反应是「线程里挂着 requires_action,一直在等服务端提交工具结果」,验证下来不成立。
原因不止一个,得分开看。run 是异步执行的,创建后要靠 retrieve 轮询才会推进到终态。也可能是用了 stream=true 但没有把事件流消费完,run 停在半路不前进。
不容易想到的是,轮询代码把 queued 当成异常分支直接跳出循环,再没继续查。
上来先按固定间隔轮询直到出现终态
for i in $(seq 1 20); do s=$(curl -s https://api.openai.com/v1/threads/thr_abc/runs/run_abc -H "Authorization: Bearer $OPENAI_API_KEY" -H "OpenAI-Beta: assistants=v2" | jq -r .status); echo $s; [ "$s" = "completed" ] && break; sleep 2; done
结束后取最新一条助手消息
curl -s "https://api.openai.com/v1/threads/thr_abc/messages?order=desc&limit=1" -H "Authorization: Bearer $OPENAI_API_KEY" -H "OpenAI-Beta: assistants=v2" | jq -r '.data[0].content[0].text.value'
随后看 run 是不是在等工具结果
curl -s https://api.openai.com/v1/threads/thr_abc/runs/run_abc -H "Authorization: Bearer $OPENAI_API_KEY" -H "OpenAI-Beta: assistants=v2" | jq '{status,required_action}'
剩下的就是改用流式创建并完整读到结束事件
curl -N https://api.openai.com/v1/threads/thr_abc/runs -H "Authorization: Bearer $OPENAI_API_KEY" -H "OpenAI-Beta: assistants=v2" -H "Content-Type: application/json" -d '{"assistant_id":"asst_abc","stream":true}'
恢复的判定其实很直接。轮询第一次就打印 completed 并跳出循环,消息接口取到的文本非空,run 详情里 required_action 为 null,日志中出现 retrieve 请求记录。
这里还有个坑。把 run 当成同步接口是这类卡死的主因,创建和取结果本来就是两步,客户端超时时间设得再长也不会让状态自己前进。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。