Skip to content

Commit 22684b5

Browse files
chore: add docs on native async
1 parent 3e3b9df commit 22684b5

File tree

3 files changed

+277
-33
lines changed

3 files changed

+277
-33
lines changed

docs/en/concepts/crews.mdx

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -307,12 +307,27 @@ print(result)
307307

308308
### Different Ways to Kick Off a Crew
309309

310-
Once your crew is assembled, initiate the workflow with the appropriate kickoff method. CrewAI provides several methods for better control over the kickoff process: `kickoff()`, `kickoff_for_each()`, `kickoff_async()`, and `kickoff_for_each_async()`.
310+
Once your crew is assembled, initiate the workflow with the appropriate kickoff method. CrewAI provides several methods for better control over the kickoff process.
311+
312+
#### Synchronous Methods
311313

312314
- `kickoff()`: Starts the execution process according to the defined process flow.
313315
- `kickoff_for_each()`: Executes tasks sequentially for each provided input event or item in the collection.
314-
- `kickoff_async()`: Initiates the workflow asynchronously.
315-
- `kickoff_for_each_async()`: Executes tasks concurrently for each provided input event or item, leveraging asynchronous processing.
316+
317+
#### Asynchronous Methods
318+
319+
CrewAI offers two approaches for async execution:
320+
321+
| Method | Type | Description |
322+
|--------|------|-------------|
323+
| `akickoff()` | Native async | True async/await throughout the entire execution chain |
324+
| `akickoff_for_each()` | Native async | Native async execution for each input in a list |
325+
| `kickoff_async()` | Thread-based | Wraps synchronous execution in `asyncio.to_thread` |
326+
| `kickoff_for_each_async()` | Thread-based | Thread-based async for each input in a list |
327+
328+
<Note>
329+
For high-concurrency workloads, `akickoff()` and `akickoff_for_each()` are recommended as they use native async for task execution, memory operations, and knowledge retrieval.
330+
</Note>
316331

317332
```python Code
318333
# Start the crew's task execution
@@ -325,19 +340,30 @@ results = my_crew.kickoff_for_each(inputs=inputs_array)
325340
for result in results:
326341
print(result)
327342

328-
# Example of using kickoff_async
343+
# Example of using native async with akickoff
344+
inputs = {'topic': 'AI in healthcare'}
345+
async_result = await my_crew.akickoff(inputs=inputs)
346+
print(async_result)
347+
348+
# Example of using native async with akickoff_for_each
349+
inputs_array = [{'topic': 'AI in healthcare'}, {'topic': 'AI in finance'}]
350+
async_results = await my_crew.akickoff_for_each(inputs=inputs_array)
351+
for async_result in async_results:
352+
print(async_result)
353+
354+
# Example of using thread-based kickoff_async
329355
inputs = {'topic': 'AI in healthcare'}
330356
async_result = await my_crew.kickoff_async(inputs=inputs)
331357
print(async_result)
332358

333-
# Example of using kickoff_for_each_async
359+
# Example of using thread-based kickoff_for_each_async
334360
inputs_array = [{'topic': 'AI in healthcare'}, {'topic': 'AI in finance'}]
335361
async_results = await my_crew.kickoff_for_each_async(inputs=inputs_array)
336362
for async_result in async_results:
337363
print(async_result)
338364
```
339365

340-
These methods provide flexibility in how you manage and execute tasks within your crew, allowing for both synchronous and asynchronous workflows tailored to your needs.
366+
These methods provide flexibility in how you manage and execute tasks within your crew, allowing for both synchronous and asynchronous workflows tailored to your needs. For detailed async examples, see the [Kickoff Crew Asynchronously](/en/learn/kickoff-async) guide.
341367

342368
### Streaming Crew Execution
343369

docs/en/learn/kickoff-async.mdx

Lines changed: 207 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,28 @@ mode: "wide"
77

88
## Introduction
99

10-
CrewAI provides the ability to kickoff a crew asynchronously, allowing you to start the crew execution in a non-blocking manner.
10+
CrewAI provides the ability to kickoff a crew asynchronously, allowing you to start the crew execution in a non-blocking manner.
1111
This feature is particularly useful when you want to run multiple crews concurrently or when you need to perform other tasks while the crew is executing.
1212

13-
## Asynchronous Crew Execution
13+
CrewAI offers two approaches for async execution:
1414

15-
To kickoff a crew asynchronously, use the `kickoff_async()` method. This method initiates the crew execution in a separate thread, allowing the main thread to continue executing other tasks.
15+
| Method | Type | Description |
16+
|--------|------|-------------|
17+
| `akickoff()` | Native async | True async/await throughout the entire execution chain |
18+
| `kickoff_async()` | Thread-based | Wraps synchronous execution in `asyncio.to_thread` |
19+
20+
<Note>
21+
For high-concurrency workloads, `akickoff()` is recommended as it uses native async for task execution, memory operations, and knowledge retrieval.
22+
</Note>
23+
24+
## Native Async Execution with `akickoff()`
25+
26+
The `akickoff()` method provides true native async execution, using async/await throughout the entire execution chain including task execution, memory operations, and knowledge queries.
1627

1728
### Method Signature
1829

1930
```python Code
20-
def kickoff_async(self, inputs: dict) -> CrewOutput:
31+
async def akickoff(self, inputs: dict) -> CrewOutput:
2132
```
2233

2334
### Parameters
@@ -28,69 +39,186 @@ def kickoff_async(self, inputs: dict) -> CrewOutput:
2839

2940
- `CrewOutput`: An object representing the result of the crew execution.
3041

31-
## Potential Use Cases
42+
### Example: Native Async Crew Execution
43+
44+
```python Code
45+
import asyncio
46+
from crewai import Crew, Agent, Task
47+
48+
# Create an agent
49+
coding_agent = Agent(
50+
role="Python Data Analyst",
51+
goal="Analyze data and provide insights using Python",
52+
backstory="You are an experienced data analyst with strong Python skills.",
53+
allow_code_execution=True
54+
)
55+
56+
# Create a task
57+
data_analysis_task = Task(
58+
description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
59+
agent=coding_agent,
60+
expected_output="The average age of the participants."
61+
)
62+
63+
# Create a crew
64+
analysis_crew = Crew(
65+
agents=[coding_agent],
66+
tasks=[data_analysis_task]
67+
)
68+
69+
# Native async execution
70+
async def main():
71+
result = await analysis_crew.akickoff(inputs={"ages": [25, 30, 35, 40, 45]})
72+
print("Crew Result:", result)
73+
74+
asyncio.run(main())
75+
```
76+
77+
### Example: Multiple Native Async Crews
78+
79+
Run multiple crews concurrently using `asyncio.gather()` with native async:
3280

33-
- **Parallel Content Generation**: Kickoff multiple independent crews asynchronously, each responsible for generating content on different topics. For example, one crew might research and draft an article on AI trends, while another crew generates social media posts about a new product launch. Each crew operates independently, allowing content production to scale efficiently.
81+
```python Code
82+
import asyncio
83+
from crewai import Crew, Agent, Task
84+
85+
coding_agent = Agent(
86+
role="Python Data Analyst",
87+
goal="Analyze data and provide insights using Python",
88+
backstory="You are an experienced data analyst with strong Python skills.",
89+
allow_code_execution=True
90+
)
91+
92+
task_1 = Task(
93+
description="Analyze the first dataset and calculate the average age. Ages: {ages}",
94+
agent=coding_agent,
95+
expected_output="The average age of the participants."
96+
)
97+
98+
task_2 = Task(
99+
description="Analyze the second dataset and calculate the average age. Ages: {ages}",
100+
agent=coding_agent,
101+
expected_output="The average age of the participants."
102+
)
103+
104+
crew_1 = Crew(agents=[coding_agent], tasks=[task_1])
105+
crew_2 = Crew(agents=[coding_agent], tasks=[task_2])
106+
107+
async def main():
108+
results = await asyncio.gather(
109+
crew_1.akickoff(inputs={"ages": [25, 30, 35, 40, 45]}),
110+
crew_2.akickoff(inputs={"ages": [20, 22, 24, 28, 30]})
111+
)
34112

35-
- **Concurrent Market Research Tasks**: Launch multiple crews asynchronously to conduct market research in parallel. One crew might analyze industry trends, while another examines competitor strategies, and yet another evaluates consumer sentiment. Each crew independently completes its task, enabling faster and more comprehensive insights.
113+
for i, result in enumerate(results, 1):
114+
print(f"Crew {i} Result:", result)
36115

37-
- **Independent Travel Planning Modules**: Execute separate crews to independently plan different aspects of a trip. One crew might handle flight options, another handles accommodation, and a third plans activities. Each crew works asynchronously, allowing various components of the trip to be planned simultaneously and independently for faster results.
116+
asyncio.run(main())
117+
```
38118

39-
## Example: Single Asynchronous Crew Execution
119+
### Example: Native Async for Multiple Inputs
40120

41-
Here's an example of how to kickoff a crew asynchronously using asyncio and awaiting the result:
121+
Use `akickoff_for_each()` to execute your crew against multiple inputs concurrently with native async:
122+
123+
```python Code
124+
import asyncio
125+
from crewai import Crew, Agent, Task
126+
127+
coding_agent = Agent(
128+
role="Python Data Analyst",
129+
goal="Analyze data and provide insights using Python",
130+
backstory="You are an experienced data analyst with strong Python skills.",
131+
allow_code_execution=True
132+
)
133+
134+
data_analysis_task = Task(
135+
description="Analyze the dataset and calculate the average age. Ages: {ages}",
136+
agent=coding_agent,
137+
expected_output="The average age of the participants."
138+
)
139+
140+
analysis_crew = Crew(
141+
agents=[coding_agent],
142+
tasks=[data_analysis_task]
143+
)
144+
145+
async def main():
146+
datasets = [
147+
{"ages": [25, 30, 35, 40, 45]},
148+
{"ages": [20, 22, 24, 28, 30]},
149+
{"ages": [30, 35, 40, 45, 50]}
150+
]
151+
152+
results = await analysis_crew.akickoff_for_each(datasets)
153+
154+
for i, result in enumerate(results, 1):
155+
print(f"Dataset {i} Result:", result)
156+
157+
asyncio.run(main())
158+
```
159+
160+
## Thread-Based Async with `kickoff_async()`
161+
162+
The `kickoff_async()` method provides async execution by wrapping the synchronous `kickoff()` in a thread. This is useful for simpler async integration or backward compatibility.
163+
164+
### Method Signature
165+
166+
```python Code
167+
async def kickoff_async(self, inputs: dict) -> CrewOutput:
168+
```
169+
170+
### Parameters
171+
172+
- `inputs` (dict): A dictionary containing the input data required for the tasks.
173+
174+
### Returns
175+
176+
- `CrewOutput`: An object representing the result of the crew execution.
177+
178+
### Example: Thread-Based Async Execution
42179

43180
```python Code
44181
import asyncio
45182
from crewai import Crew, Agent, Task
46183

47-
# Create an agent with code execution enabled
48184
coding_agent = Agent(
49185
role="Python Data Analyst",
50186
goal="Analyze data and provide insights using Python",
51187
backstory="You are an experienced data analyst with strong Python skills.",
52188
allow_code_execution=True
53189
)
54190

55-
# Create a task that requires code execution
56191
data_analysis_task = Task(
57192
description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
58193
agent=coding_agent,
59194
expected_output="The average age of the participants."
60195
)
61196

62-
# Create a crew and add the task
63197
analysis_crew = Crew(
64198
agents=[coding_agent],
65199
tasks=[data_analysis_task]
66200
)
67201

68-
# Async function to kickoff the crew asynchronously
69202
async def async_crew_execution():
70203
result = await analysis_crew.kickoff_async(inputs={"ages": [25, 30, 35, 40, 45]})
71204
print("Crew Result:", result)
72205

73-
# Run the async function
74206
asyncio.run(async_crew_execution())
75207
```
76208

77-
## Example: Multiple Asynchronous Crew Executions
78-
79-
In this example, we'll show how to kickoff multiple crews asynchronously and wait for all of them to complete using `asyncio.gather()`:
209+
### Example: Multiple Thread-Based Async Crews
80210

81211
```python Code
82212
import asyncio
83213
from crewai import Crew, Agent, Task
84214

85-
# Create an agent with code execution enabled
86215
coding_agent = Agent(
87216
role="Python Data Analyst",
88217
goal="Analyze data and provide insights using Python",
89218
backstory="You are an experienced data analyst with strong Python skills.",
90219
allow_code_execution=True
91220
)
92221

93-
# Create tasks that require code execution
94222
task_1 = Task(
95223
description="Analyze the first dataset and calculate the average age of participants. Ages: {ages}",
96224
agent=coding_agent,
@@ -103,22 +231,76 @@ task_2 = Task(
103231
expected_output="The average age of the participants."
104232
)
105233

106-
# Create two crews and add tasks
107234
crew_1 = Crew(agents=[coding_agent], tasks=[task_1])
108235
crew_2 = Crew(agents=[coding_agent], tasks=[task_2])
109236

110-
# Async function to kickoff multiple crews asynchronously and wait for all to finish
111237
async def async_multiple_crews():
112-
# Create coroutines for concurrent execution
113238
result_1 = crew_1.kickoff_async(inputs={"ages": [25, 30, 35, 40, 45]})
114239
result_2 = crew_2.kickoff_async(inputs={"ages": [20, 22, 24, 28, 30]})
115240

116-
# Wait for both crews to finish
117241
results = await asyncio.gather(result_1, result_2)
118242

119243
for i, result in enumerate(results, 1):
120244
print(f"Crew {i} Result:", result)
121245

122-
# Run the async function
123246
asyncio.run(async_multiple_crews())
124247
```
248+
249+
## Async Streaming
250+
251+
Both async methods support streaming when `stream=True` is set on the crew:
252+
253+
```python Code
254+
import asyncio
255+
from crewai import Crew, Agent, Task
256+
257+
agent = Agent(
258+
role="Researcher",
259+
goal="Research and summarize topics",
260+
backstory="You are an expert researcher."
261+
)
262+
263+
task = Task(
264+
description="Research the topic: {topic}",
265+
agent=agent,
266+
expected_output="A comprehensive summary of the topic."
267+
)
268+
269+
crew = Crew(
270+
agents=[agent],
271+
tasks=[task],
272+
stream=True # Enable streaming
273+
)
274+
275+
async def main():
276+
streaming_output = await crew.akickoff(inputs={"topic": "AI trends in 2024"})
277+
278+
# Async iteration over streaming chunks
279+
async for chunk in streaming_output:
280+
print(f"Chunk: {chunk.content}")
281+
282+
# Access final result after streaming completes
283+
result = streaming_output.result
284+
print(f"Final result: {result.raw}")
285+
286+
asyncio.run(main())
287+
```
288+
289+
## Potential Use Cases
290+
291+
- **Parallel Content Generation**: Kickoff multiple independent crews asynchronously, each responsible for generating content on different topics. For example, one crew might research and draft an article on AI trends, while another crew generates social media posts about a new product launch.
292+
293+
- **Concurrent Market Research Tasks**: Launch multiple crews asynchronously to conduct market research in parallel. One crew might analyze industry trends, while another examines competitor strategies, and yet another evaluates consumer sentiment.
294+
295+
- **Independent Travel Planning Modules**: Execute separate crews to independently plan different aspects of a trip. One crew might handle flight options, another handles accommodation, and a third plans activities.
296+
297+
## Choosing Between `akickoff()` and `kickoff_async()`
298+
299+
| Feature | `akickoff()` | `kickoff_async()` |
300+
|---------|--------------|-------------------|
301+
| Execution model | Native async/await | Thread-based wrapper |
302+
| Task execution | Async with `aexecute_sync()` | Sync in thread pool |
303+
| Memory operations | Async | Sync in thread pool |
304+
| Knowledge retrieval | Async | Sync in thread pool |
305+
| Best for | High-concurrency, I/O-bound workloads | Simple async integration |
306+
| Streaming support | Yes | Yes |

0 commit comments

Comments
 (0)