사용자가 답을 기다리는 화면이라면 스트리밍을 켜서 첫 토큰부터 보여 주세요. 배치 작업이라면 끄는 편이 코드가 단순합니다.
예제
stream: true를 넣습니다. 마지막에 사용량까지 받으려면 stream_options.include_usage: true도 넣으세요. 환경변수는 퀵스타트와 같습니다.
Python
python
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()Node.js
javascript
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.everyais.com/v1",
apiKey: process.env.EVERYAIS_API_KEY,
timeout: 240_000,
});
const stream = await client.chat.completions.create({
model: process.env.EVERYAIS_MODEL,
messages: [{ role: "user", content: "Hello!" }],
stream: true,
stream_options: { include_usage: true },
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
if (chunk.usage) console.log("\nUsage:", chunk.usage.total_tokens);
}주의할 점
- 마지막 사용량 청크는
choices가 빈 배열입니다.choices[0]을 바로 읽으면 오류가 납니다. - Chat 스트림은
data: [DONE]으로 끝납니다. 이 신호 없이 연결이 끊기면 답변이 잘린 것이니 실패로 처리하세요. - HTTP 200으로 시작한 뒤에도 오류가 스트림 안의 이벤트로 올 수 있습니다. 오류 이벤트와 SDK 예외도 실패로 처리하세요.
- 사용자가 중간에 멈추면 스트림을 닫으세요(Python은
stream.close(), Node.js는AbortController). 연결을 끊어도 이미 시작된 생성은 청구될 수 있습니다.
SSE 직접 파싱
SDK 없이 HTTP로 받을 때만 필요합니다.
- 이벤트는
data: {...}줄로 오고, 빈 줄이 이벤트의 끝입니다. : ok처럼 콜론으로 시작하는 줄은 heartbeat입니다. 건너뛰세요.- 네트워크 조각과 이벤트 경계는 다릅니다. 빈 줄이 나올 때까지 모아서 처리하세요.
- 한글 같은 멀티바이트 글자가 조각 경계에서 잘릴 수 있으니 스트림 UTF-8 디코더를 쓰세요.
Messages와 Responses의 스트림
두 API는 Chat과 이벤트 형식이 다릅니다. 각 SDK의 스트림 처리 방식을 쓰세요.
| API | 주요 이벤트 |
|---|---|
/v1/messages | message_start · content_block_delta · message_delta · message_stop (Anthropic 형식) |
/v1/responses | response.output_text.delta · response.completed (Responses 형식) |
Responses에 background: true를 주면 스트림 대신 작업 정보를 JSON으로 돌려줍니다. 비동기 작업을 보세요.
재시도 전 확인
Idempotency-Key는 끝난 스트림을 다시 재생하지 않고, 같은 키로 다시 보내면 409입니다. 끊긴 스트림을 다시 요청하기 전에 이미 받은 내용과 청구 내역을 확인하세요.
웹 검색의 출처와 검색 건수는 스트림 맨 끝에 옵니다(웹 검색).