Address streaming contract review feedback

This commit is contained in:
lorenzejay
2026-06-29 15:35:18 -07:00
parent 01c7915528
commit 7de7e32bb2
11 changed files with 201 additions and 93 deletions

View File

@@ -11,7 +11,7 @@ mode: "wide"
## كيف يعمل بث التدفق
عند تفعيل البث في تدفق، يلتقط CrewAI ويبث المخرجات من أي أطقم أو استدعاءات LLM داخل التدفق. يقدم البث أجزاء منظمة تحتوي على المحتوى وسياق المهمة ومعلومات الوكيل مع تقدم التنفيذ.
عند تفعيل البث في تدفق، يلتقط CrewAI ويبث المخرجات من أي أطقم أو استدعاءات LLM أو أدوات أو أحداث دورة حياة داخل التدفق. يقدم البث عناصر `StreamFrame` مرتبة تحتوي على محتوى قابل للطباعة وبيانات حدث مهيكلة مع تقدم التنفيذ.
## تفعيل البث
@@ -180,13 +180,14 @@ flow = MultiStepFlow()
streaming = flow.kickoff()
current_step = ""
for chunk in streaming:
for item in streaming:
# Track which flow step is executing
if chunk.task_name != current_step:
current_step = chunk.task_name
print(f"\n\n=== {chunk.task_name} ===\n")
step_name = item.event.get("method_name") or item.event.get("task_name")
if step_name and step_name != current_step:
current_step = step_name
print(f"\n\n=== {step_name} ===\n")
print(chunk.content, end="", flush=True)
print(item.content, end="", flush=True)
result = streaming.result
print(f"\n\nFinal analysis: {result}")
@@ -200,7 +201,6 @@ print(f"\n\nFinal analysis: {result}")
import asyncio
from crewai.flow.flow import Flow, listen, start
from crewai import Agent, Crew, Task
from crewai.types.streaming import StreamChunkType
class ResearchPipeline(Flow):
stream = True
@@ -253,33 +253,35 @@ async def run_with_dashboard():
current_agent = ""
current_task = ""
chunk_count = 0
frame_count = 0
async for chunk in streaming:
chunk_count += 1
async for item in streaming:
frame_count += 1
# Display phase transitions
if chunk.task_name != current_task:
current_task = chunk.task_name
current_agent = chunk.agent_role
task_name = item.event.get("task_name", "")
agent_role = item.event.get("agent_role", "")
if task_name and task_name != current_task:
current_task = task_name
current_agent = agent_role
print(f"\n\n📋 Phase: {current_task}")
print(f"👤 Agent: {current_agent}")
print("-" * 60)
# Display text output
if chunk.chunk_type == StreamChunkType.TEXT:
print(chunk.content, end="", flush=True)
if item.content:
print(item.content, end="", flush=True)
# Display tool usage
elif chunk.chunk_type == StreamChunkType.TOOL_CALL and chunk.tool_call:
print(f"\n🔧 Tool: {chunk.tool_call.tool_name}")
elif item.channel == "tools":
print(f"\n🔧 Tool event: {item.type}")
# Show completion summary
result = streaming.result
print(f"\n\n{'='*60}")
print("PIPELINE COMPLETE")
print(f"{'='*60}")
print(f"Total chunks: {chunk_count}")
print(f"Total frames: {frame_count}")
print(f"Final output length: {len(str(result))} characters")
asyncio.run(run_with_dashboard())
@@ -352,8 +354,8 @@ class StatefulStreamingFlow(Flow[AnalysisState]):
flow = StatefulStreamingFlow()
streaming = flow.kickoff(inputs={"topic": "quantum computing"})
for chunk in streaming:
print(chunk.content, end="", flush=True)
for item in streaming:
print(item.content, end="", flush=True)
result = streaming.result
print(f"\n\nFinal state:")
@@ -373,29 +375,29 @@ print(f"Insights length: {len(flow.state.insights)}")
- **تتبع التقدم**: إظهار المرحلة الحالية من سير العمل للمستخدمين
- **لوحات المعلومات الحية**: إنشاء واجهات مراقبة لتدفقات الإنتاج
## أنواع أجزاء البث
## قنوات إطارات البث
مثل بث الطاقم، يمكن أن تكون أجزاء التدفق من أنواع مختلفة:
ينتج بث التدفق عناصر `StreamFrame` عبر عدة قنوات:
### أجزاء TEXT
### إطارات LLM
محتوى نصي قياسي من استجابات LLM:
```python Code
for chunk in streaming:
if chunk.chunk_type == StreamChunkType.TEXT:
print(chunk.content, end="", flush=True)
for item in streaming:
if item.channel == "llm" and item.content:
print(item.content, end="", flush=True)
```
### أجزاء TOOL_CALL
### إطارات الأدوات
معلومات حول استدعاءات الأدوات داخل التدفق:
```python Code
for chunk in streaming:
if chunk.chunk_type == StreamChunkType.TOOL_CALL and chunk.tool_call:
print(f"\nTool: {chunk.tool_call.tool_name}")
print(f"Args: {chunk.tool_call.arguments}")
for item in streaming:
if item.channel == "tools":
print(f"\nTool event: {item.type}")
print(f"Payload: {item.event}")
```
## معالجة الأخطاء
@@ -407,8 +409,8 @@ flow = ResearchFlow()
streaming = flow.kickoff()
try:
for chunk in streaming:
print(chunk.content, end="", flush=True)
for item in streaming:
print(item.content, end="", flush=True)
result = streaming.result
print(f"\nSuccess! Result: {result}")
@@ -453,7 +455,7 @@ finally:
- يجب التكرار عبر جميع عناصر stream قبل الوصول إلى خاصية `.result`
- يعمل البث مع كل من حالة التدفق المنظمة وغير المنظمة
- يلتقط بث التدفق المخرجات من جميع الأطقم واستدعاءات LLM في التدفق
- يتضمن كل جزء سياقاً حول الوكيل والمهمة التي ولدته
- يتضمن كل إطار سياق حدث مهيكلاً مثل القناة والنوع والنطاق والحمولة
- يضيف البث حملاً ضئيلاً لتنفيذ التدفق
## الدمج مع تصور التدفق
@@ -467,8 +469,8 @@ flow.plot("research_flow") # Creates HTML visualization
# Run with streaming
streaming = flow.kickoff()
for chunk in streaming:
print(chunk.content, end="", flush=True)
for item in streaming:
print(item.content, end="", flush=True)
result = streaming.result
print(f"\nFlow complete! View structure at: research_flow.html")

View File

@@ -11,7 +11,7 @@ CrewAI Flows support streaming output, allowing you to receive real-time updates
## How Flow Streaming Works
When streaming is enabled on a Flow, CrewAI captures and streams output from any crews or LLM calls within the flow. The stream delivers structured chunks containing the content, task context, and agent information as execution progresses.
When streaming is enabled on a Flow, CrewAI captures and streams output from any crews, LLM calls, tools, and lifecycle events within the flow. The stream delivers ordered `StreamFrame` items with printable content plus structured event data as execution progresses.
## Enabling Streaming
@@ -180,13 +180,14 @@ flow = MultiStepFlow()
streaming = flow.kickoff()
current_step = ""
for chunk in streaming:
for item in streaming:
# Track which flow step is executing
if chunk.task_name != current_step:
current_step = chunk.task_name
print(f"\n\n=== {chunk.task_name} ===\n")
step_name = item.event.get("method_name") or item.event.get("task_name")
if step_name and step_name != current_step:
current_step = step_name
print(f"\n\n=== {step_name} ===\n")
print(chunk.content, end="", flush=True)
print(item.content, end="", flush=True)
result = streaming.result
print(f"\n\nFinal analysis: {result}")
@@ -200,7 +201,6 @@ Here's a complete example showing how to build a progress dashboard with streami
import asyncio
from crewai.flow.flow import Flow, listen, start
from crewai import Agent, Crew, Task
from crewai.types.streaming import StreamChunkType
class ResearchPipeline(Flow):
stream = True
@@ -253,33 +253,35 @@ async def run_with_dashboard():
current_agent = ""
current_task = ""
chunk_count = 0
frame_count = 0
async for chunk in streaming:
chunk_count += 1
async for item in streaming:
frame_count += 1
# Display phase transitions
if chunk.task_name != current_task:
current_task = chunk.task_name
current_agent = chunk.agent_role
task_name = item.event.get("task_name", "")
agent_role = item.event.get("agent_role", "")
if task_name and task_name != current_task:
current_task = task_name
current_agent = agent_role
print(f"\n\n📋 Phase: {current_task}")
print(f"👤 Agent: {current_agent}")
print("-" * 60)
# Display text output
if chunk.chunk_type == StreamChunkType.TEXT:
print(chunk.content, end="", flush=True)
if item.content:
print(item.content, end="", flush=True)
# Display tool usage
elif chunk.chunk_type == StreamChunkType.TOOL_CALL and chunk.tool_call:
print(f"\n🔧 Tool: {chunk.tool_call.tool_name}")
elif item.channel == "tools":
print(f"\n🔧 Tool event: {item.type}")
# Show completion summary
result = streaming.result
print(f"\n\n{'='*60}")
print("PIPELINE COMPLETE")
print(f"{'='*60}")
print(f"Total chunks: {chunk_count}")
print(f"Total frames: {frame_count}")
print(f"Final output length: {len(str(result))} characters")
asyncio.run(run_with_dashboard())
@@ -352,8 +354,8 @@ class StatefulStreamingFlow(Flow[AnalysisState]):
flow = StatefulStreamingFlow()
streaming = flow.kickoff(inputs={"topic": "quantum computing"})
for chunk in streaming:
print(chunk.content, end="", flush=True)
for item in streaming:
print(item.content, end="", flush=True)
result = streaming.result
print(f"\n\nFinal state:")
@@ -373,29 +375,29 @@ Flow streaming is particularly valuable for:
- **Progress Tracking**: Show users which stage of the workflow is currently executing
- **Live Dashboards**: Create monitoring interfaces for production flows
## Stream Chunk Types
## Stream Frame Channels
Like crew streaming, flow chunks can be of different types:
Flow streaming yields `StreamFrame` items across several channels:
### TEXT Chunks
### LLM Frames
Standard text content from LLM responses:
```python Code
for chunk in streaming:
if chunk.chunk_type == StreamChunkType.TEXT:
print(chunk.content, end="", flush=True)
for item in streaming:
if item.channel == "llm" and item.content:
print(item.content, end="", flush=True)
```
### TOOL_CALL Chunks
### Tool Frames
Information about tool calls within the flow:
```python Code
for chunk in streaming:
if chunk.chunk_type == StreamChunkType.TOOL_CALL and chunk.tool_call:
print(f"\nTool: {chunk.tool_call.tool_name}")
print(f"Args: {chunk.tool_call.arguments}")
for item in streaming:
if item.channel == "tools":
print(f"\nTool event: {item.type}")
print(f"Payload: {item.event}")
```
## Error Handling
@@ -407,8 +409,8 @@ flow = ResearchFlow()
streaming = flow.kickoff()
try:
for chunk in streaming:
print(chunk.content, end="", flush=True)
for item in streaming:
print(item.content, end="", flush=True)
result = streaming.result
print(f"\nSuccess! Result: {result}")
@@ -453,7 +455,7 @@ After cancellation, `streaming.is_cancelled` and `streaming.is_completed` are bo
- You must iterate through all stream items before accessing the `.result` property
- Streaming works with both structured and unstructured flow state
- Flow streaming captures output from all crews and LLM calls in the flow
- Each chunk includes context about which agent and task generated it
- Each frame includes structured event context such as channel, type, namespace, and payload
- Streaming adds minimal overhead to flow execution
## Combining with Flow Visualization
@@ -467,8 +469,8 @@ flow.plot("research_flow") # Creates HTML visualization
# Run with streaming
streaming = flow.kickoff()
for chunk in streaming:
print(chunk.content, end="", flush=True)
for item in streaming:
print(item.content, end="", flush=True)
result = streaming.result
print(f"\nFlow complete! View structure at: research_flow.html")