# Streaming 응답: 작성되는 대로 도착하는 답변

> server-sent events로 chat completion을 stream하세요: stream: true, chunk 형식, 마지막 이벤트의 토큰 사용량, curl, Python, Node.js 예제.

- URL: https://llmwithcrypto.com/ko/docs/streaming/
- 마지막 업데이트: 2026-10-23
- 발행자: LLMwithCrypto (https://llmwithcrypto.com)

`stream: true`을 사용하면 채팅 인터페이스에서 텍스트가 나타나는 것처럼, 모델이 작성하는 대로 답변이 작은 조각으로 도착합니다. 형식은 OpenAI 방식입니다. server-sent events, 이벤트마다 하나의 JSON chunk, 그리고 `[DONE]`입니다.

**빠른 답변 — LLMwithCrypto에서 chat completion을 어떻게 stream하나요?**

`POST https://llmwithcrypto.com/api/v1/chat/completions`의 body에 `"stream": true`를 추가하세요. 그러면 **LLMwithCrypto**이 server-sent events로 응답합니다. 각 `data:` 줄은 `delta.content`에 텍스트 조각을 담은 `chat.completion.chunk`를 가지며, stream은 `data: [DONE]`로 끝납니다. `"stream_options": {"include_usage": true}`을 추가하면 마지막 chunk에서 토큰 수를 받습니다. 2026년 10월 23일 문서 기준으로, 이는 모든 모델에서 동작합니다.

## 굳이 stream하는 이유가 무엇인가요?

사람에게는, 전체 답변이 작성된 뒤가 아니라 잠깐 만에 첫 단어가 나타나기 때문입니다. 큰 모델의 긴 답변은 완성되기까지 수 초가 걸릴 수 있습니다. stream하면 독자는 곧바로 읽기 시작합니다.

프로그램에는 덜 중요합니다. 전체 텍스트가 필요한 스크립트는 streaming에서 얻는 것이 없고 파싱할 것만 많아집니다. 사람이 지켜볼 때는 stream하고, 그 외에는 일반 요청을 보내세요. 가격은 어느 쪽이든 같습니다. 잔액에서 토큰 단위로 결제합니다. 입력 및 출력 토큰은 모델 자체의 tokenizer로 계산되며, 해당 모델의 1M 토큰당 가격으로 청구됩니다. 오류로 끝난 호출은 비용이 들지 않습니다.

*curl: -N은 연결을 버퍼링 없이 유지합니다*

```bash
curl -sN "https://llmwithcrypto.com/api/v1/chat/completions" \
  -H "Authorization: Bearer $LLMWITHCRYPTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "messages": [{"role": "user", "content": "Write a haiku about latency."}],
    "stream": true,
    "stream_options": {"include_usage": true},
    "max_tokens": 120
  }'

```

*Python: 텍스트가 도착하는 대로 출력합니다*

```python
import os

from openai import OpenAI

client = OpenAI(
    base_url="https://llmwithcrypto.com/api/v1",
    api_key=os.environ["LLMWITHCRYPTO_API_KEY"],
)

stream = client.chat.completions.create(
    model="deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Write a haiku about latency."}],
    stream=True,
    stream_options={"include_usage": True},
    max_tokens=120,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage:
        print("\n", chunk.usage.prompt_tokens, "in,", chunk.usage.completion_tokens, "out")

```

*Node.js: chunk에 대해 for await를 사용합니다*

```javascript
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://llmwithcrypto.com/api/v1',
  apiKey: process.env.LLMWITHCRYPTO_API_KEY,
});

const stream = await client.chat.completions.create({
  model: 'deepseek-v4.1-flash',
  messages: [{ role: 'user', content: 'Write a haiku about latency.' }],
  stream: true,
  stream_options: { include_usage: true },
  max_tokens: 120,
});
for await (const chunk of stream) {
  const text = chunk.choices[0]?.delta?.content;
  if (text) process.stdout.write(text);
  if (chunk.usage) console.log(`\n${chunk.usage.prompt_tokens} in, ${chunk.usage.completion_tokens} out`);
}

```

## stream은 wire 상에서 어떻게 보이나요?

각 이벤트는 `data: `로 시작하는 한 줄과 빈 줄로 이루어집니다. 첫 chunk는 보통 `role`을 담고, 다음 chunk들은 각각 `content`의 몇 글자를 담으며, `finish_reason`이 담긴 chunk가 답변을 닫습니다. `include_usage`을 사용하면 빈 `choices` 배열과 `usage` 객체를 담은 chunk가 하나 더 이어집니다. stream은 항상 `data: [DONE]`로 끝납니다. 아래의 id와 수치는 예시입니다.

*짧은 답변 하나의 server-sent events(예시)*

```text
data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}

data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[{"index":0,"delta":{"content":"Packets"},"finish_reason":null}]}

data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[{"index":0,"delta":{"content":" cross the"},"finish_reason":null}]}

data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":19,"total_tokens":33}}

data: [DONE]

```

## stream이 끊기면 어떻게 되나요?

잘못된 키나 잔액 부족처럼 첫 토큰 전에 발견된 오류는 stream이 아니라 JSON body를 담은 일반 HTTP 오류로 돌아옵니다. [errors 페이지](https://llmwithcrypto.com/ko/docs/errors/)에 나열되어 있습니다. 생성 중 오류는 `finish_reason` 없이 stream을 일찍 종료합니다.

연결을 직접 닫으면 생성이 중단됩니다. 그러면 다른 호출과 마찬가지로 입력과 이미 생성된 토큰에 대해 비용을 지불합니다. 코드는 `finish_reason`도 `[DONE]`도 없이 끝난 stream을 불완전한 것으로 처리하고, 전체 답변이 필요하면 요청을 다시 보내야 합니다.

## Streaming: 자주 묻는 질문

### streaming이 더 비싼가요?

아니요. 같은 토큰이 같은 가격으로 청구됩니다. 잔액에서 토큰 단위로 결제합니다. 입력 및 출력 토큰은 모델 자체의 tokenizer로 계산되며, 해당 모델의 1M 토큰당 가격으로 청구됩니다. 오류로 끝난 호출은 비용이 들지 않습니다.

### tool calling과 함께 stream할 수 있나요?

네, tool을 지원하는 모델에서 가능합니다. 함수 이름과 인자는 `delta.tool_calls`에 조각으로 도착하므로 사용 전에 이어 붙여야 합니다. [tool calling 페이지](https://llmwithcrypto.com/ko/docs/tool-calling/)에서는 stream하지 않는 루프를 보여주며, 이쪽이 시작하기에 더 단순합니다.

### stream 호출에서 usage가 왜 안 나오나요?

`"stream_options": {"include_usage": true}`를 추가하세요. 추가하지 않으면 스트림에 토큰 수가 담기지 않습니다. 대시보드에는 여전히 표시됩니다.

---

LLMwithCrypto: LLMwithCrypto는 오픈 웨이트 모델을 위한 OpenAI 호환 LLM API입니다 — DeepSeek V4 Pro, DeepSeek V4.1 Flash, DeepSeek R1, Qwen3.5 397B A17B, Qwen3 235B A22B Instruct, gpt-oss-120b, gpt-oss-20b, GLM-4.7, Llama 3.3 70B Instruct, Gemma 4 31B, Mistral Large 3, Mistral Small 4 — 충전해 둔 암호화폐 잔액에서 토큰 단위로 결제하며, 공개 호스트 가격 중앙값보다 5% 저렴합니다. KYC 없이: 신분증도, 셀피도, 서류도 필요하지 않습니다. 프롬프트와 출력은 저장되지 않습니다.
