Files
crewAI/docs/edge/en/learn/consuming-streams.mdx
2026-06-30 16:00:38 -07:00

178 lines
4.6 KiB
Plaintext

---
title: Consuming Streams
description: Print LLM chunks, observe tool events, and read final results from CrewAI streams.
icon: square-terminal
mode: "wide"
---
## Overview
Use this guide when you want to subscribe to a CrewAI stream and print or route frames as they arrive.
The basic pattern is:
```python
stream = flow.stream_events(inputs={"topic": "AI agents"})
with stream:
for frame in stream:
...
result = stream.result
```
Always consume the stream before reading `stream.result`.
## Print LLM Output
If you only care about text generated by LLM calls, subscribe to the `llm` projection and print `frame.content`:
```python
stream = flow.stream_events(inputs={"topic": "AI agents"})
with stream:
for frame in stream.llm:
print(frame.content, end="", flush=True)
print()
result = stream.result
```
`frame.content` is an empty string for frames that do not carry printable text, so this is also safe:
```python
with flow.stream_events(inputs={"topic": "AI agents"}) as stream:
for frame in stream.events:
if frame.channel == "llm" and frame.content:
print(frame.content, end="", flush=True)
result = stream.result
```
## Print Tool Activity
Tool events arrive on the `tools` channel. Use `frame.type` to distinguish starts, finishes, and errors.
```python
with flow.stream_events(inputs={"topic": "AI agents"}) as stream:
for frame in stream.events:
if frame.channel == "llm" and frame.content:
print(frame.content, end="", flush=True)
if frame.channel == "tools" and frame.type == "tool_usage_started":
print(f"\nTool started: {frame.event.get('tool_name')}")
if frame.channel == "tools" and frame.type == "tool_usage_finished":
print(f"\nTool finished: {frame.event.get('tool_name')}")
result = stream.result
```
`frame.event` is the structured payload for the source event. Use it for metadata such as tool names, arguments, message roles, and runtime identifiers.
## Watch Flow Progress
Flow lifecycle and method execution frames arrive on the `flow` channel:
```python
with flow.stream_events(inputs={"topic": "AI agents"}) as stream:
for frame in stream.flow:
print(frame.type, frame.namespace)
result = stream.result
```
Use this when you want a progress log instead of token-level output.
## Interleave Selected Channels
Use `interleave()` when you want a subset of channels while preserving their relative order:
```python
with flow.stream_events(inputs={"topic": "AI agents"}) as stream:
for frame in stream.interleave(["llm", "tools"]):
if frame.channel == "llm":
print(frame.content, end="", flush=True)
elif frame.type == "tool_usage_started":
print(f"\nTool: {frame.event.get('tool_name')}")
result = stream.result
```
## Stream a Direct LLM Call
Direct `llm.call(...)` returns the final assembled result. To stream a direct LLM call, use `llm.stream_events(...)`:
```python
from crewai import LLM
llm = LLM(model="gpt-4o-mini")
stream = llm.stream_events("Explain streaming in one sentence.")
with stream:
for frame in stream.llm:
print(frame.content, end="", flush=True)
print()
result = stream.result
```
## Stream a Conversational Turn
Conversational Flows expose `stream_turn()` for one user message:
```python
stream = flow.stream_turn(
"What can you help me with?",
session_id="session-1",
)
with stream:
for frame in stream.interleave(["llm", "messages"]):
if frame.channel == "llm":
print(frame.content, end="", flush=True)
elif frame.channel == "messages":
print(f"\n{frame.event.get('role')}: {frame.event.get('content')}")
reply = stream.result
```
## Async Consumers
Async streams use the same channel projections:
```python
stream = flow.astream(inputs={"topic": "AI agents"})
async with stream:
async for frame in stream.llm:
print(frame.content, end="", flush=True)
result = stream.result
```
## Cleanup
Use the stream as a context manager when possible. If a client disconnects or you stop consuming early, close the stream:
```python
stream = flow.stream_events(inputs={"topic": "AI agents"})
try:
for frame in stream.events:
print(frame.content, end="", flush=True)
finally:
if not stream.is_exhausted:
stream.close()
```
For async streams, call `await stream.aclose()`.
## See Also
- [Streaming](/edge/en/concepts/streaming)
- [Streaming Runtime Contract](/edge/en/learn/streaming-runtime-contract)
- [Streaming Flow Execution](/edge/en/learn/streaming-flow-execution)
- [Streaming Crew Execution](/edge/en/learn/streaming-crew-execution)