mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-04 06:29:22 +00:00
Address streaming contract review feedback
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user