스트리밍과 SSE 끊김: 중복 없이 복구하기
SSE 끊김을 구분하고 partial output을 보존하며 부작용을 중복하지 않는 안전한 재시도 방법입니다.
Streaming과 SSE 끊김: 중복 없이 복구하기
Streaming API는 프로토콜의 terminal event를 받아야 끝난 것입니다. socket 종료, client timeout, 마지막 text fragment는 완료 증거가 아닙니다. 끊기면 받은 event, Request ID, 작업 상태를 보존하고 부작용을 확인한 뒤에만 retry합니다. 마지막 token부터 재개하는 보편적 방법은 없으며, 무작정 재시도하면 tool을 두 번 실행할 수 있습니다.
정상 종료와 실제 끊김
completed는 성공 terminal event, failed는 stream 안의 오류, disconnected는 확인된 끝 없이 transport가 끝난 상태입니다. OpenAI Responses는 response.created, output fragment, response.completed를, Anthropic Messages는 message_start, content block event, message_delta, message_stop를 사용합니다. 한 parser에 두 규약의 event 이름을 섞지 마세요.
BetterToken 계정과 API Key를 만들고 API 참조를 열어 tool 없는 짧은 stream부터 시험합니다. 시간, model, status를 Dashboard와 대조하고 terminal event와 partial output을 확인한 후에만 제한된 retry를 추가합니다.
끊길 때 저장할 데이터
API Key, 전체 prompt, tool 인수, 민감한 응답은 저장하지 않습니다. partial text는 정책이 허용할 때만 보관합니다. 운영에서는 operation hash, event 수, 마지막 안전 sequence marker가 유용합니다. Request ID는 header나 event에서 오므로 stream 종료 뒤가 아니라 즉시 기록합니다.
네트워크 전에 parser 확인하기
여러 data: 줄, 빈 줄, UTF-8 chunk 경계, 알 수 없는 event, HTTP 200 뒤 error event, 마지막 delta 없는 terminal event, 분할된 tool 인수를 처리해야 합니다. TCP chunk는 SSE event가 아닙니다. 완전한 SSE frame을 만든 뒤 JSON을 parse합니다.
is_terminal_success와 is_terminal_failure는 Responses, Chat Completions, Messages별로 분리합니다.
각 계층의 timeout 확인
SDK/HTTP client, 앱 idle/read timeout, reverse proxy, load balancer 또는 ingress, 기업 proxy, 모바일·가정 네트워크, server-side generation limit을 확인합니다. request timeout과 idle timeout은 다릅니다. proxy buffering은 text를 오래 숨긴 뒤 큰 block이나 timeout을 만들 수 있으므로, 첫 event 시간과 event 간격을 로컬·proxy 뒤·운영에서 비교합니다.
partial output 표시, 저장, 폐기
중간 text는 유용하지만 완료로 표시하지 않습니다. 상태는 streaming, complete, partial, failed, cancelled로 구분합니다. partial text는 새 generation과 분리합니다. 자동으로 이어 붙이면 반복, 표현 변경, 다른 tool 호출 순서가 생길 수 있습니다.
요청을 반복할 수 있는 경우
안전성은 작업에 따라 다릅니다.
외부 작업 없는 텍스트
짧은 text request는 횟수를 제한해 반복할 수 있습니다. 이전 결과는 partial, 새 결과는 별도 generation으로 표시하거나 명시 확인 뒤 대체합니다.
Tool Call과 트랜잭션
retry 전에 tool이 이미 실행됐는지 확인합니다. command 뒤 끊기면 두 번째 request가 issue, 이메일, 결제를 다시 만들 수 있습니다. tool 수준 Idempotency Key, 자체 Operation ID, 완료 작업 log를 사용합니다.
긴 Agent 작업
“마지막 token부터 계속”은 대개 프로토콜이 보장하지 않습니다. 확인된 message, tool result, 마지막 완료 step을 포함한 저장 application state에서 복구합니다. raw text fragment는 일관된 agent state가 아닙니다.
backoff를 둔 제한 retry
retry 가능성은 protocol error, HTTP status, terminal event, 부작용으로 판단합니다. 401, 잘못된 Model ID, invalid JSON은 기다려도 해결되지 않습니다. 429, 일시적 5xx, transport failure는 provider header를 고려한 제한 retry만 허용할 수 있습니다.
최소 테스트
- tool 없는 짧은 stream을 보낸다.
- event type과 terminal event를 기록한다.
- 여러 event 뒤 client를 인위적으로 끊는다.
- 결과가
partial인지 확인한다. - 제한 retry를 한 번 시험한다.
- 운영 proxy 뒤에서도 반복한다.
- Dashboard에서 시간, model, status를 대조한다.
OpenAI Streaming Responses와 Anthropic Messages Streaming에서 정확한 event type을 확인합니다.
FAQ
마지막 token부터 stream을 계속할 수 있나요?
보편적 방법은 없습니다. partial result와 application state를 저장하고 해당 API 기능을 따릅니다.
HTTP status가 200인데 왜 오류로 끝나나요?
header는 generation 완료 전에 옵니다. 나중에 protocol event 또는 transport 끊김으로 오류가 나타날 수 있습니다.
모든 disconnect 뒤에 반복해야 하나요?
아니요. terminal event, error, Request ID, 부작용을 먼저 확인합니다. Tool Call retry에는 idempotency가 필요합니다.
로컬에서는 되면 어디를 보나요?
reverse proxy, load balancer, idle timeout, buffering, 기업 network와 각 계층 전후 event 간격을 확인합니다.
BetterToken에서 무엇을 확인하나요?
Dashboard에서 시간, model, status, usage를 대조합니다. API 참조를 확인하고 완전한 API Key나 민감한 prompt를 support에 보내지 마세요.