> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crewai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 스트리밍 런타임 계약

> Flow, 직접 LLM 호출, 대화 턴에서 정렬된 런타임 프레임을 스트리밍합니다.

## 개요

CrewAI는 단순한 텍스트 청크보다 더 많은 정보가 필요한 런타임을 위해 프레임 기반 스트리밍 계약을 제공합니다. 이 계약은 Flow 생명주기 이벤트, 직접 LLM 토큰, 도구 활동, 대화 메시지, 사용자 지정 이벤트에 대해 정렬된 `StreamFrame` 객체를 방출합니다.

UI, 서비스 브리지, 터미널 앱, 배포 런타임을 만들 때 Flow, 채팅 턴, 직접 LLM 호출이 실행되는 동안 안정적인 구조화 이벤트 스트림이 필요하다면 이 API를 사용하세요.

## StreamFrame

모든 프레임은 같은 envelope를 가집니다:

```python theme={null}
from crewai.types.streaming import StreamFrame

frame.id           # 고유 프레임 id
frame.seq          # 사용 가능한 경우 실행 로컬 순서
frame.type         # "flow_started" 같은 원본 이벤트 타입
frame.channel      # "llm", "flow", "tools", "messages", "lifecycle", "custom"
frame.namespace    # 소스/런타임 namespace
frame.timestamp    # 이벤트 timestamp
frame.parent_id    # 사용 가능한 경우 부모 이벤트 id
frame.previous_id  # 사용 가능한 경우 이전 이벤트 id
frame.data         # 이벤트 payload
frame.event        # frame.data의 alias
frame.content      # 토큰류 프레임의 출력 가능한 텍스트, 그 외에는 ""
```

`channel` 필드는 소비자에서 프레임을 라우팅하는 가장 빠른 방법입니다:

| 채널 | 포함 내용 |
| - | - |
| `llm` | LLM 스트리밍 이벤트의 토큰 및 thinking 청크 |
| `flow` | Flow 생명주기, 메서드 실행, 라우팅, pause/resume 이벤트 |
| `tools` | 도구 사용 이벤트 |
| `messages` | 대화 transcript 이벤트 |
| `lifecycle` | 다른 채널에 속하지 않는 런타임 생명주기 이벤트 |
| `custom` | 내장 채널에 매핑되지 않는 이벤트 |

`frame.type`은 원본 이벤트 타입을 보존하므로, 소비자는 채널 안에서 특정 이벤트를 처리할 수 있습니다.

## Flow 스트리밍

Flow에 `stream=True`를 설정하면 `kickoff()`가 stream session을 반환합니다:

```python theme={null}
from crewai.flow import Flow, start


class ReportFlow(Flow):
    @start()
    def generate(self):
        return "done"


flow = ReportFlow(stream=True)
stream = flow.kickoff()

with stream:
    for chunk in stream:
        print(chunk.content, end="", flush=True)
        if chunk.type == "tool_usage_started":
            print(chunk.event["tool_name"])

result = stream.result
```

`stream.result`를 읽기 전에 stream을 소비해야 합니다. 결과를 너무 일찍 접근하면 `RuntimeError`가 발생하여, 소비자가 부분 실행을 완료된 실행으로 잘못 처리하지 않도록 합니다.

Flow 인스턴스에 `stream=True`를 설정하지 않고 단일 호출만 스트리밍하려면 `flow.stream_events(...)`를 직접 호출할 수도 있습니다.

## 채널별 필터링

`StreamSession`은 선택한 채널 안에서 전역 프레임 순서를 보존하는 채널 projection을 제공합니다:

```python theme={null}
stream = flow.stream_events()

with stream:
    for frame in stream.llm:
        print(frame.content, end="", flush=True)

result = stream.result
```

사용 가능한 projection은 다음과 같습니다:

| Projection | 프레임 |
| - | - |
| `stream.events` | 모든 프레임 |
| `stream.llm` | LLM 프레임 |
| `stream.messages` | 대화 메시지 프레임 |
| `stream.flow` | Flow 프레임 |
| `stream.tools` | 도구 프레임 |
| `stream.interleave([...])` | 선택한 채널 집합 |

소비자가 일부 채널만 원하지만 상대 순서도 필요하다면 `stream.interleave(["flow", "llm", "messages"])`를 사용하세요.

## 비동기 스트리밍

비동기 소비자는 `astream()`을 사용하세요:

```python theme={null}
flow = ReportFlow()
stream = flow.astream()

async with stream:
    async for chunk in stream.events:
        print(chunk.channel, chunk.type, chunk.content)

result = stream.result
```

비동기 세션은 동기 세션과 같은 projection을 제공합니다.

## 직접 LLM 호출 스트리밍

`llm.call(...)`은 계속 최종 조립 결과를 반환합니다. 구조화된 이벤트 payload를 유지하면서 청크가 도착하는 대로 반복 처리하려면 `llm.stream_events(...)`를 사용하세요:

```python theme={null}
from crewai import LLM


llm = LLM(model="gpt-4o-mini")
stream = llm.stream_events(
    messages=[
        {
            "role": "user",
            "content": "Explain CrewAI streaming in two short sentences.",
        }
    ]
)

with stream:
    for chunk in stream:
        print(chunk.content, end="", flush=True)

result = stream.result
```

`llm.stream_events(...)`는 감싼 호출 동안 일시적으로 streaming을 활성화하고, 이후 LLM의 이전 `stream` 설정을 복원합니다. provider 통합은 계속 기본 LLM stream 이벤트를 방출하며, 이 helper는 모든 LLM provider에서 그 이벤트 위에 공통 iterator API를 제공합니다.

## 대화 턴

대화형 Flow는 `stream_turn()`으로 사용자 턴 하나를 스트리밍할 수 있습니다:

```python theme={null}
from crewai import Flow
from crewai.flow import ConversationConfig, ConversationState


@ConversationConfig(llm="gpt-4o-mini", defer_trace_finalization=True)
class ChatFlow(Flow[ConversationState]):
    conversational = True


flow = ChatFlow()
stream = flow.stream_turn("What can you help me with?", session_id="session-1")

with stream:
    for frame in stream.events:
        if frame.channel == "llm" and frame.type == "llm_stream_chunk":
            print(frame.content, end="", flush=True)

reply = stream.result
```

`stream_turn()` 중에는 내장 대화 응답 경로가 해당 턴에 대해 LLM 토큰 스트리밍을 활성화하고 이후 LLM의 이전 `stream` 설정을 복원합니다. 자체 agent 또는 LLM 인스턴스를 만드는 사용자 지정 route handler는 토큰 단위 출력이 필요하다면 해당 LLM을 streaming으로 구성해야 합니다.

## 정리

가능하면 세션을 context manager로 사용하세요. stream이 끝나기 전에 클라이언트 연결이 끊기면 세션을 명시적으로 닫으세요:

```python theme={null}
stream = flow.stream_events()

try:
    for frame in stream.events:
        print(frame.type)
finally:
    if not stream.is_exhausted:
        stream.close()
```

비동기 stream에서는 `await stream.aclose()`를 사용하세요.

## 레거시 청크 스트리밍

`stream=True`를 사용하는 Crew 스트리밍은 계속 [스트리밍 Crew 실행](/ko/learn/streaming-crew-execution)에 설명된 청크 중심 `CrewStreamingOutput` API를 반환합니다. 직접 `llm.call(...)` 호출도 계속 최종 LLM 결과를 반환합니다. 프레임 계약은 Flow, 직접 LLM 호출, 대화 턴, 도구, 메시지 전반에서 안정적인 이벤트 envelope가 필요한 런타임을 위한 것입니다.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.