짧은 답변
세 문장입니다:
- streaming vs non-streaming은 전적으로 사용자의 코드로 결정됩니다—즉 요청 본문의
stream필드입니다. 같은 키, 같은 모델, 같은 엔드포인트라면, 이 값이 앞뒤로 바뀐다면 클라이언트 코드(또는 이를 감싼 SDK / 프레임워크)가 바꾸고 있는 것입니다. 게이트웨이는 이를 임의로 전환하지 않습니다. - 두 모드는 최종 콘텐츠가 완전히 동일하며 과금도 동일합니다. 차이는 텍스트를 언제 받는지와 어떻게 파싱하는지만 다릅니다.
- 선택 기준: 사람이 화면을 보고 있다 → streaming; 프로그램이 결과를 소비한다(JSON 파싱, 배치 작업, tools 호출) → non-streaming.
차이점 한눈에 보기
왜 제 요청은 스트리밍과 비스트리밍 사이를 오갑니까?
이것은 가장 흔한 질문이며, 답은 다음과 같습니다: 여러분 쪽의 어떤 것이 이를 바꾸고 있습니다. 아래 목록을 순서대로 점검하십시오 — 거의 항상 그중 하나가 맞습니다:1. `stream`은 코드의 변수 또는 설정값입니다
1. `stream`은 코드의 변수 또는 설정값입니다
전형적인 사례는 다음과 같습니다:
stream=config.get("stream", False) 또는 stream=is_web_request. 서로 다른 진입점이 같은 함수에 서로 다른 값으로 도달하며, 로그상으로는 모드가 무작위로 바뀌는 것처럼 보입니다.확인 방법: 실제로 보내는 요청 본문을 출력하고 stream 필드를 확인하십시오.2. 서로 다른 SDK와 프레임워크는 기본값이 다릅니다
2. 서로 다른 SDK와 프레임워크는 기본값이 다릅니다
같은 비즈니스 로직도 클라이언트에 따라 다르게 동작합니다:
- OpenAI SDK
chat.completions.create(): 기본값은 비스트리밍입니다 client.chat.completions.stream()또는with_streaming_response: 스트리밍- LangChain / LlamaIndex 같은 래퍼:
invoke또는stream중 무엇을 호출하는지, 그리고 모델 객체를 생성할 때streaming=True을 전달했는지에 따라 다릅니다 - 데스크톱 클라이언트, 에이전트 도구, 워크플로 플랫폼: 보통 설정에 “스트리밍 출력” 토글을 제공하며, 기본값은 제각각입니다
3. 여러 애플리케이션이 하나의 키를 공유하는 경우
3. 여러 애플리케이션이 하나의 키를 공유하는 경우
웹 채팅 UI(스트리밍)와 야간 배치 작업(비스트리밍)이 같은 키를 함께 사용하면, 로그를 같이 볼 때 무작위처럼 보입니다.확인 방법: 사용 사례별로 별도의 token을 만드십시오 — 그러면 로그가 자연스럽게 분리됩니다. Token 관리를 참조하십시오.
4. 중간 장비가 스트림을 평탄화했습니다
4. 중간 장비가 스트림을 평탄화했습니다
실제로는
stream: true를 보냈지만, Nginx나 기업 게이트웨이, 또는 어떤 프록시가 응답을 버퍼링했습니다 — 서버는 이를 청크 단위로 보냈고, 프록시는 이를 보관했다가 한 번에 내보냈기 때문에 비스트리밍처럼 느껴집니다.확인 방법: 프록시를 우회하여 한 번 테스트하십시오. Nginx에서 버퍼링을 끄십시오 (proxy_buffering off;). 이 경우 콘솔 로그에는 여전히 is_stream = true가 표시되는데, 이는 게이트웨이가 실제로 스트리밍으로 내보냈기 때문입니다.시나리오별 선택
스트리밍을 사용하십시오
- 채팅 UI와 지원 봇 — 사용자가 즉각적인 피드백을 필요로 합니다
- IDE 플러그인 / 코딩 어시스턴트(Claude Code, Cursor 등)
- 장문 생성(긴 문서, 긴 번역, 큰 코드 블록)
- 긴 추론 모델 작업 — 최소한 진행 상황은 볼 수 있습니다
- 사용자가 생성 도중 “stop”을 누를 수 있는 모든 경우
비스트리밍을 사용하십시오
- 구조화된 출력:
json.loads()을 위해 전체 JSON이 필요합니다 - 함수 호출 / 도구 호출 인자 파싱
- 배치 처리, 오프라인 작업, 예약 작업
- 최종 결과만 중요하고 기다리는 사람이 없는 백엔드 흐름
- 빠른 검증, 디버깅, 테스트 케이스 작성
통합 작업량: 같은 작업, 두 방식 모두
- Python 비스트리밍 방식
- Python 스트리밍 방식
- Node.js 스트리밍 방식
- cURL 나란히 비교
Claude의 기본 형식(
/v1/messages)은 다른 스트리밍 프로토콜을 사용합니다: Anthropic의 named-event SSE (message_start / content_block_delta / message_delta 및 관련 이벤트), OpenAI의 균일한 data: 청크가 아니라, usage는 message_start 및 message_delta 이벤트에 걸쳐 분할됩니다. 전체 파싱 가이드: Claude 기본 형식: 스트리밍 및 비스트리밍 응답.과금과 사용량: 어느 쪽이든 동일합니다
usage와 관련된 두 가지 함정:
- 스트리밍은 기본적으로 usage를 반환하지 않습니다. OpenAI 호환 엔드포인트에서는
stream_options: {"include_usage": true}를 전달해야 합니다. 그러면 usage는 최종 청크에 도착하며(그 청크의choices배열은 비어 있으므로 인덱싱하기 전에 확인하십시오). 이는 APIYI의 여러 모델에서 정상 동작함이 확인되었습니다. - API가 되돌려주는
usage를 기준으로 과금을 정산하지 마십시오. 특히 캐시 관련 필드는 더욱 그렇습니다. 되돌려진 값은 실제 과금과 항상 일치하지 않으며, 캐시 적중 여부는 콘솔 로그의 **“캐시 과금 상세 정보”**로 판단됩니다. 캐시 과금 설명을 참조하십시오.
자주 있는 6가지 오해
1. 스트리밍은 타임아웃을 방지합니다
1. 스트리밍은 타임아웃을 방지합니다
그렇지 않습니다. 스트리밍은 첫 token이 더 빨리 도착하게 할 뿐입니다. 전체 생성 시간을 줄이지도 않고, 데이터가 안정적으로 계속 흐른다는 보장도 없습니다.추론 모델(
gemini-3.1-pro-preview, gpt-5.6-sol, gpt-5.5-pro 등)은 추론 단계 동안 아무것도 전혀 내보내지 않을 수 있으며, 그 경우에도 클라이언트의 읽기 타임아웃이 동일하게 발생합니다.올바른 해결책은 시나리오별 타임아웃 값입니다 — API 타임아웃을 피하는 방법을 참고하십시오.2. 스트리밍이 더 빠릅니다
2. 스트리밍이 더 빠릅니다
첫 바이트는 더 빠르지만, 전체는 그렇지 않습니다. 같은 모델과 prompt를 사용하면 스트리밍과 비스트리밍은 대체로 비슷한 시간에 완료됩니다.스트리밍은 체감 속도를 높여줍니다. 사용자는 30초 동안 로딩 스피너만 바라보는 대신 1초 안에 움직임을 보게 됩니다. 화면을 보는 사람이 없다면 그 가치는 0입니다.
3. 스트리밍은 더 저렴하거나, 받은 만큼만 과금됩니다
3. 스트리밍은 더 저렴하거나, 받은 만큼만 과금됩니다
아닙니다. 위의 “과금 및 사용량”을 보십시오: 과금은 동일하며, 중간에 연결을 끊어도 여전히 과금됩니다.
4. 모든 모델과 엔드포인트가 스트리밍을 지원합니다
4. 모든 모델과 엔드포인트가 스트리밍을 지원합니다
아닙니다. 텍스트 채팅 모델은 일반적으로 지원하지만, 이미지 생성, embedding, rerank 엔드포인트에는 스트리밍 개념이 없으며
stream를 무시하거나 거부합니다.일부 모델은 스트리밍에서 특정 파라미터 조합에 대해 추가 제약이 있습니다. 확실하지 않다면 먼저 비스트리밍으로 호출이 동작하는지 확인한 다음 stream: true를 추가하십시오.5. 비스트리밍이 더 안정적입니다
5. 비스트리밍이 더 안정적입니다
둘 다 각자의 실패 방식이 있습니다.
- 비스트리밍의 위험: 연결이 생성 내내 조용하므로 프록시, CDN, 기업용 게이트웨이가 유휴 타임아웃으로 연결을 끊을 수 있습니다. 매우 큰 응답 본문(base64 이미지 출력은 쉽게 수십 MB에 이릅니다)에서는 멈춘 종료부에 걸릴 수도 있습니다 — 전송은 끝났지만 응답이 오지 않는 요청과 로그에는 완료로 표시되지만 클라이언트는 아무것도 받지 못하는 경우를 참고하십시오.
- 스트리밍의 위험: SSE를 지원하지 않거나 버퍼링을 강제로 적용하는 중간 장비와는 잘 맞지 않습니다. 클라이언트 파싱은 더 복잡하며, 미묘하게 잘못 구현하기 쉽습니다.
api-cf.apiyi.com(CDN 엔드포인트)는 약 100초의 요청 상한이 있으며, 이는 두 모드 모두에 영향을 줍니다. 긴 요청에는 api.apiyi.com 또는 vip.apiyi.com를 사용하십시오 — Base URL 구성 가이드를 참고하십시오.6. 스트림에서 완전한 답변을 얻을 수 없습니다
6. 스트림에서 완전한 답변을 얻을 수 없습니다
얻을 수 있습니다 — 직접 조합하면 됩니다. 각 청크의
delta.content를 순서대로 이어 붙이면 비스트리밍 message.content와 정확히 같습니다.조합된 텍스트가 불완전해 보인다면 세 가지를 확인하십시오: finish_reason를 무시했는지, data: [DONE]를 받기 전에 루프를 종료했는지, 그리고 중간 장비가 응답을 잘라냈는지입니다.스트리밍이 작동하지 않습니까? 네 단계
1
요청 본문에 정말 stream: true가 포함되어 있는지 확인하십시오
실제로 전송하는 JSON을 출력하십시오. 래퍼 라이브러리에서는 “전달했다고 생각했습니다”와 “실제로 전달되었습니다”가 종종 다른 일입니다.
2
curl -N으로 직접 테스트하십시오
위의 “cURL 나란히 보기” 탭에 있는 명령을 사용하여 직접 작성한 코드와 모든 프록시를 우회하십시오. curl에서 청크가 점진적으로 도착하는 것이 보이면 서버 측은 정상이며 문제는 클라이언트 또는 중간 장치에 있습니다.
3
중간 장치 버퍼링을 확인하십시오
Nginx에
proxy_buffering off;를 추가하십시오. 기업용 게이트웨이와 보안 장비는 text/event-stream를 전체 페이로드로 검사할 수 있습니다 — 네트워크 관리자에게 이를 통과하도록 허용해 달라고 요청하십시오.4
파싱 로직을 검토하십시오
SSE를 한 줄씩 읽고, 빈 줄과
:로 시작하는 주석 줄은 건너뛰며, data: [DONE]에서 중단하십시오. usage를 담고 있는 마지막 청크에는 비어 있는 choices 배열이 있으므로, 그 안에 인덱싱하지 마십시오.관련 문서
API 시간 초과를 피하는 방법
시나리오별 시간 초과 값과 스트리밍이 해결하지 못하는 이유
Base URL 설정 가이드
엔드포인트 간 차이와 CDN 노드의 100초 한도
로그에는 완료로 표시되지만 응답이 없음
세그먼트 타이밍을 포함한 전형적인 대용량 비스트리밍 응답 문제
Claude 스트리밍 및 비스트리밍
Anthropic의 네이티브 named-event SSE 프로토콜 구문 분석
텍스트 생성 API
전체 파라미터 목록 및 호출 예시
로그 과금 세부 정보 이해하기
is_stream을 포함하여 콘솔 로그의 각 필드 의미