Chat 스트리밍
퀵스타트의 환경변수를 준비하고 stream: true를 지정합니다.
stream_options.include_usage: true이면 마지막에 사용량 청크를 받습니다.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["EVERYAIS_API_KEY"],
base_url="https://api.everyais.com/v1",
timeout=240.0,
)
stream = client.chat.completions.create(
model=os.environ["EVERYAIS_MODEL"],
messages=[{"role": "user", "content": "Hello!"}],
stream=True,
stream_options={"include_usage": True},
)
try:
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="", flush=True)
if chunk.usage:
print("\nUsage:", chunk.usage.total_tokens)
finally:
stream.close()SSE 이벤트 읽기
- Chat은
data: {...}프레임을 보내고data: [DONE]으로 끝납니다. - 마지막 사용량 청크는
choices: []일 수 있습니다.choices[0]을 바로 읽지 마세요. : ok같은 주석 프레임은 연결 유지를 위한 heartbeat입니다. JSON으로 파싱하지 않습니다.- 네트워크 chunk와 SSE 이벤트 경계는 다릅니다. 직접 구현한다면 빈 줄까지 버퍼링하고 UTF-8을 점진적으로 디코딩하세요.
Messages · Responses
| API | 종료와 사용량 |
|---|---|
/v1/messages | message_start · content_block_delta · message_delta · message_stop 등 Anthropic 이벤트 |
/v1/responses | response.output_text.delta · response.completed 등 Responses 이벤트 |
각 SDK의 스트림 소비 방식을 사용하세요. Chat의 [DONE] 처리를 다른 형식에 그대로 적용하면 안 됩니다.
Responses의 background: true는 스트림 대신 작업 JSON을 반환합니다.
오류와 연결 종료
HTTP 200으로 스트림이 시작된 뒤에도 provider 오류가 이벤트 본문으로 도착할 수 있습니다.
오류 이벤트나 예외, 정상 종료 이벤트 없이 끊긴 연결을 성공으로 처리하지 마세요.
요청을 중단할 때는 스트림을 닫고, 재시도 전에 이미 생성된 출력과 청구 내역을 확인하세요.
Idempotency-Key는 완료된 SSE를 재생하지 않습니다.
웹 검색 출처는 마지막 부분에 도착합니다. 웹 검색의 최종 usage와 출처 처리를 함께 확인하세요.