---
title: Flows
description: CrewAI Flowsλ₯Ό μ¬μ©νμ¬ AI μν¬νλ‘μ°λ₯Ό μμ±νκ³ κ΄λ¦¬νλ λ°©λ²μ μμ보μΈμ.
icon: arrow-progress
mode: "wide"
---
## κ°μ
CrewAI Flowsλ AI μν¬νλ‘μ°μ μμ± λ° κ΄λ¦¬λ₯Ό κ°μννκΈ° μν΄ μ€κ³λ κ°λ ₯ν κΈ°λ₯μ
λλ€. Flowsλ₯Ό μ¬μ©νλ©΄ κ°λ°μλ λ€μν μ½λ© μμ
κ³Ό κ° Crewλ₯Ό ν¨μ¨μ μΌλ‘ κ²°ν©νκ³ μ‘°μ ν μ μμ΄, μ κ΅ν AI μλνλ₯Ό ꡬμΆν μ μλ κ²¬κ³ ν νλ μμν¬λ₯Ό μ 곡ν©λλ€.
Flowsλ ꡬ쑰νλ μ΄λ²€νΈ κΈ°λ° μν¬νλ‘μ°λ₯Ό μμ±ν μ μκ² ν΄μ€λλ€. μ΄λ₯Ό ν΅ν΄ μ¬λ¬ μμ
μ μννκ² μ°κ²°νκ³ , μνλ₯Ό κ΄λ¦¬νλ©°, AI μ ν리μΌμ΄μ
μμ μ€ν νλ¦μ μ μ΄ν μ μμ΅λλ€. Flowsλ₯Ό μ¬μ©νλ©΄ CrewAIμ μ 체 μλμ νμ©νλ λ€λ¨κ³ νλ‘μΈμ€λ₯Ό μμ½κ² μ€κ³νκ³ κ΅¬νν μ μμ΅λλ€.
1. **κ°νΈν μν¬νλ‘μ° μμ±**: μ¬λ¬ Crewμ μμ
μ μμ½κ² μ°κ²°νμ¬ λ³΅μ‘ν AI μν¬νλ‘μ°λ₯Ό λ§λλλ€.
2. **μν κ΄λ¦¬**: Flowsλ₯Ό ν΅ν΄ μν¬νλ‘μ° λ΄μ λ€μν μμ
κ°μ μνλ₯Ό μ½κ³ ν¨μ¨μ μΌλ‘ κ΄λ¦¬ λ° κ³΅μ ν μ μμ΅λλ€.
3. **μ΄λ²€νΈ κΈ°λ° μν€ν
μ²**: μ΄λ²€νΈ κΈ°λ° λͺ¨λΈμ κΈ°λ°μΌλ‘ νμ¬, μλμ μ΄κ³ λ°μμ± λμ μν¬νλ‘μ°λ₯Ό ꡬνν μ μμ΅λλ€.
4. **μ μ°ν μ μ΄ νλ¦**: μν¬νλ‘μ° λ΄μμ 쑰건문, λ°λ³΅λ¬Έ, λΆκΈ° λ±μ ꡬνν μ μμ΅λλ€.
## μμνκΈ°
OpenAIλ₯Ό μ¬μ©νμ¬ ν μμ
μμ 무μμ λμλ₯Ό μμ±νκ³ , κ·Έ λμλ₯Ό μ¬μ©ν΄ λ€λ₯Έ μμ
μμ μ¬λ―Έμλ μ¬μ€μ μμ±νλ κ°λ¨ν Flowλ₯Ό λ§λ€μ΄λ³΄κ² μ΅λλ€.
```python Code
from crewai.flow.flow import Flow, listen, start
from dotenv import load_dotenv
from litellm import completion
class ExampleFlow(Flow):
model = "gpt-4o-mini"
@start()
def generate_city(self):
print("Starting flow")
# Each flow state automatically gets a unique ID
print(f"Flow State ID: {self.state['id']}")
response = completion(
model=self.model,
messages=[
{
"role": "user",
"content": "Return the name of a random city in the world.",
},
],
)
random_city = response["choices"][0]["message"]["content"]
# Store the city in our state
self.state["city"] = random_city
print(f"Random City: {random_city}")
return random_city
@listen(generate_city)
def generate_fun_fact(self, random_city):
response = completion(
model=self.model,
messages=[
{
"role": "user",
"content": f"Tell me a fun fact about {random_city}",
},
],
)
fun_fact = response["choices"][0]["message"]["content"]
# Store the fun fact in our state
self.state["fun_fact"] = fun_fact
return fun_fact
flow = ExampleFlow()
flow.plot()
result = flow.kickoff()
print(f"Generated fun fact: {result}")
```

μ μμ μμλ OpenAIλ₯Ό μ¬μ©νμ¬ λ¬΄μμ λμλ₯Ό μμ±νκ³ , ν΄λΉ λμμ λν μ¬λ―Έμλ μ¬μ€μ μμ±νλ κ°λ¨ν Flowλ₯Ό λ§λ€μμ΅λλ€. μ΄ Flowλ `generate_city`μ `generate_fun_fact`λΌλ λ κ°μ§ μμ
μΌλ‘ ꡬμ±λμ΄ μμ΅λλ€. `generate_city` μμ
μ΄ Flowμ μμμ μ΄λ©°, `generate_fun_fact` μμ
μ΄ `generate_city` μμ
μ μΆλ ₯μ κ°μ§ν©λλ€.
κ° Flow μΈμ€ν΄μ€λ μν(state)μ μλμΌλ‘ κ³ μ μλ³μ(UUID)λ₯Ό λΆμ¬ λ°μ, νλ¦ μ€νμ μΆμ νκ³ κ΄λ¦¬νλ λ° λμμ΄ λ©λλ€. μνμλ μ€ν μ€μ μ μ§λλ μΆκ° λ°μ΄ν°(μ: μμ±λ λμμ μ¬λ―Έμλ μ¬μ€)λ μ μ₯ν μ μμ΅λλ€.
Flowλ₯Ό μ€ννλ©΄ λ€μκ³Ό κ°μ κ³Όμ μ λ°λ¦
λλ€:
1. μνλ₯Ό μν κ³ μ IDλ₯Ό μμ±
2. 무μμ λμλ₯Ό μμ±νμ¬ μνμ μ μ₯
3. ν΄λΉ λμμ λν μ¬λ―Έμλ μ¬μ€μ μμ±νμ¬ μνμ μ μ₯
4. κ²°κ³Όλ₯Ό μ½μμ μΆλ ₯
μνμ κ³ μ IDμ μ μ₯λ λ°μ΄ν°λ νλ¦ μ€νμ μΆμ νκ³ , μμ
κ°μ 컨ν
μ€νΈλ₯Ό μ μ§νλ λ° μ μ©ν©λλ€.
**μ°Έκ³ :** OpenAI API μμ² μΈμ¦μ μν΄ `OPENAI_API_KEY`λ₯Ό `.env` νμΌμ μ€μ ν΄μΌ ν©λλ€. μ΄ ν€λ νμμ
λλ€.
### @start()
`@start()` λ°μ½λ μ΄ν°λ λ©μλλ₯Ό Flowμ μμ μ§μ μΌλ‘ νμνλ λ° μ¬μ©λ©λλ€. Flowκ° μμλλ©΄ `@start()`λ‘ λ°μ½λ μ΄νΈλ λͺ¨λ λ©μλκ° λ³λ ¬λ‘ μ€νλ©λλ€. νλμ Flowμμ μ¬λ¬ κ°μ start λ©μλλ₯Ό κ°μ§ μ μμΌλ©°, Flowκ° μμλ λ μ΄λ€μ λͺ¨λ μ€νλ©λλ€.
### @listen()
`@listen()` λ°μ½λ μ΄ν°λ Flow λ΄μμ λ€λ₯Έ νμ€ν¬μ μΆλ ₯μ μμ νλ 리μ€λλ‘ λ©μλλ₯Ό νμνλ λ° μ¬μ©λ©λλ€. `@listen()`μΌλ‘ λ°μ½λ μ΄μ
λ λ©μλλ μ§μ λ νμ€ν¬κ° μΆλ ₯μ λ΄λ³΄λΌ λ μ€νλ©λλ€. μ΄ λ©μλλ μμ μ΄ λ¦¬μ€λνκ³ μλ νμ€ν¬μ μΆλ ₯μ μΈμλ‘ μ κ·Όν μ μμ΅λλ€.
#### μ¬μ©λ²
`@listen()` λ°μ½λ μ΄ν°λ μ¬λ¬ κ°μ§ λ°©λ²μΌλ‘ μ¬μ©ν μ μμ΅λλ€:
1. **λ©μλ μ΄λ¦μΌλ‘ 리μ€λνκΈ°**: 리μ€λνκ³ μ νλ λ©μλμ μ΄λ¦μ λ¬Έμμ΄λ‘ μ λ¬ν μ μμ΅λλ€. ν΄λΉ λ©μλκ° μλ£λλ©΄, 리μ€λ λ©μλκ° νΈλ¦¬κ±°λ©λλ€.
```python Code
@listen("generate_city")
def generate_fun_fact(self, random_city):
# Implementation
```
2. **λ©μλ μμ²΄λ‘ λ¦¬μ€λνκΈ°**: λ©μλ μ체λ₯Ό μ λ¬ν μλ μμ΅λλ€. ν΄λΉ λ©μλκ° μλ£λλ©΄, 리μ€λ λ©μλκ° νΈλ¦¬κ±°λ©λλ€.
```python Code
@listen(generate_city)
def generate_fun_fact(self, random_city):
# Implementation
```
### Flow μΆλ ₯
Flowμ μΆλ ₯μ μ κ·Όνκ³ λ€λ£¨λ κ²μ AI μν¬νλ‘μ°λ₯Ό λ ν° μ ν리μΌμ΄μ
μ΄λ μμ€ν
μ ν΅ν©νλ λ° νμμ μ
λλ€. CrewAI Flowλ μ΅μ’
μΆλ ₯λ¬Όμ μ½κ² κ°μ Έμ€κ³ , μ€κ° κ²°κ³Όμ μ κ·Όνλ©°, Flowμ μ 체 μνλ₯Ό κ΄λ¦¬ν μ μλ μ§κ΄μ μΈ λ©μ»€λμ¦μ μ 곡ν©λλ€.
#### μ΅μ’
μΆλ ₯κ° κ°μ Έμ€κΈ°
Flowλ₯Ό μ€ννλ©΄, μ΅μ’
μΆλ ₯κ°μ λ§μ§λ§μΌλ‘ μλ£λ λ©μλμ μν΄ κ²°μ λ©λλ€. `kickoff()` λ©μλλ μ΄ λ§μ§λ§ λ©μλμ κ²°κ³Όλ₯Ό λ°νν©λλ€.
μ΅μ’
μΆλ ₯κ°μ νμΈνλ λ°©λ²μ λ€μκ³Ό κ°μ΅λλ€:
<CodeGroup>
```python Code
from crewai.flow.flow import Flow, listen, start
class OutputExampleFlow(Flow):
@start()
def first_method(self):
return "Output from first_method"
@listen(first_method)
def second_method(self, first_output):
return f"Second method received: {first_output}"
flow = OutputExampleFlow()
flow.plot("my_flow_plot")
final_output = flow.kickoff()
print("---- Final Output ----")
print(final_output)
```
```text Output
---- Final Output ----
Second method received: Output from first_method
```
</CodeGroup>

μ΄ μμ μμ `second_method`κ° λ§μ§λ§μΌλ‘ μλ£λ λ©μλμ΄λ―λ‘, ν΄λΉ λ©μλμ κ²°κ³Όκ° Flowμ μ΅μ’
μΆλ ₯κ°μ΄ λ©λλ€.
`kickoff()` λ©μλλ μ΄ μ΅μ’
μΆλ ₯κ°μ λ°ννλ©°, μ΄ κ°μ μ½μμ μΆλ ₯λ©λλ€.
`plot()` λ©μλλ HTML νμΌμ μμ±νλ©°, μ΄λ₯Ό ν΅ν΄ flowλ₯Ό μ½κ² μ΄ν΄ν μ μμ΅λλ€.
#### μνμ μ κ·Όνκ³ μ
λ°μ΄νΈνκΈ°
μ΅μ’
μΆλ ₯μ κ°μ Έμ€λ κ² μΈμλ, Flow λ΄μμ μν(state)μ μ κ·Όνκ³ μ
λ°μ΄νΈν μ μμ΅λλ€. μνλ Flowμ λ€μν λ©μλ κ° λ°μ΄ν°λ₯Ό μ μ₯νκ³ κ³΅μ νλ λ° μ¬μ©ν μ μμ΅λλ€. Flowκ° μ€νλ νμλ, μ€ν μ€μ μΆκ°λκ±°λ μ
λ°μ΄νΈλ μ 보λ₯Ό μ‘°ννκΈ° μν΄ μνμ μ κ·Όν μ μμ΅λλ€.
λ€μμ μνλ₯Ό μ
λ°μ΄νΈνκ³ μ κ·Όνλ λ°©λ²μ μμμ
λλ€:
<CodeGroup>
```python Code
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel
class ExampleState(BaseModel):
counter: int = 0
message: str = ""
class StateExampleFlow(Flow[ExampleState]):
@start()
def first_method(self):
self.state.message = "Hello from first_method"
self.state.counter += 1
@listen(first_method)
def second_method(self):
self.state.message += " - updated by second_method"
self.state.counter += 1
return self.state.message
flow = StateExampleFlow()
flow.plot("my_flow_plot")
final_output = flow.kickoff()
print(f"Final Output: {final_output}")
print("Final State:")
print(flow.state)
```
```text Output
Final Output: Hello from first_method - updated by second_method
Final State:
counter=2 message='Hello from first_method - updated by second_method'
```
</CodeGroup>

μ΄ μμμμ μνλ `first_method`μ `second_method` λͺ¨λμ μν΄ μ
λ°μ΄νΈλ©λλ€.
Flowκ° μ€νλ ν, μ΄λ¬ν λ©μλλ€μ μν΄ μνλ μ
λ°μ΄νΈ λ΄μ©μ νμΈνλ €λ©΄ μ΅μ’
μνμ μ κ·Όν μ μμ΅λλ€.
μ΅μ’
λ©μλμ μΆλ ₯μ΄ λ°νλκ³ μνμ μ κ·Όν μ μλλ‘ ν¨μΌλ‘μ¨, CrewAI Flowλ AI μν¬νλ‘μ°μ κ²°κ³Όλ₯Ό λ ν° μ ν리μΌμ΄μ
μ΄λ μμ€ν
μ μ½κ² ν΅ν©ν μ μκ² νλ©°,
Flow μ€ν κ³Όμ μ λ°μ κ±Έμ³ μνλ₯Ό μ μ§νκ³ μ κ·Όνλ©΄μλ μ΄λ₯Ό μ©μ΄νκ² λ§λλλ€.
## νλ‘μ° μν κ΄λ¦¬
μνλ₯Ό ν¨κ³Όμ μΌλ‘ κ΄λ¦¬νλ κ²μ μ λ’°ν μ μκ³ μ μ§ λ³΄μκ° μ©μ΄ν AI μν¬νλ‘λ₯Ό ꡬμΆνλ λ° λ§€μ° μ€μν©λλ€. CrewAI νλ‘μ°λ λΉμ ν λ° μ ν μν κ΄λ¦¬λ₯Ό μν κ°λ ₯ν λ©μ»€λμ¦μ μ 곡νμ¬, κ°λ°μκ° μμ μ μ ν리μΌμ΄μ
μ κ°μ₯ μ ν©ν μ κ·Ό λ°©μμ μ νν μ μλλ‘ ν©λλ€.
### λΉκ΅¬μ‘°μ μν κ΄λ¦¬
λΉκ΅¬μ‘°μ μν κ΄λ¦¬μμλ λͺ¨λ μνκ° `Flow` ν΄λμ€μ `state` μμ±μ μ μ₯λ©λλ€.
μ΄ λ°©μμ μ격ν μ€ν€λ§λ₯Ό μ μνμ§ μκ³ λ κ°λ°μκ° μν μμ±μ μ¦μμμ μΆκ°νκ±°λ μμ ν μ μλ μ μ°μ±μ μ 곡ν©λλ€.
λΉκ΅¬μ‘°μ μνμμλ CrewAI Flowsλ κ° μν μΈμ€ν΄μ€μ λν κ³ μ μλ³μ(UUID)λ₯Ό μλμΌλ‘ μμ±νκ³ μ μ§ν©λλ€.
```python Code
from crewai.flow.flow import Flow, listen, start
class UnstructuredExampleFlow(Flow):
@start()
def first_method(self):
# The state automatically includes an 'id' field
print(f"State ID: {self.state['id']}")
self.state['counter'] = 0
self.state['message'] = "Hello from structured flow"
@listen(first_method)
def second_method(self):
self.state['counter'] += 1
self.state['message'] += " - updated"
@listen(second_method)
def third_method(self):
self.state['counter'] += 1
self.state['message'] += " - updated again"
print(f"State after third_method: {self.state}")
flow = UnstructuredExampleFlow()
flow.plot("my_flow_plot")
flow.kickoff()
```

**μ°Έκ³ :** `id` νλλ νλ¦μ μ€ν μ 체μ κ±Έμ³ μλμΌλ‘ μμ±λμ΄ λ³΄μ‘΄λ©λλ€. μ΄λ₯Ό μ§μ κ΄λ¦¬νκ±°λ μ€μ ν νμκ° μμΌλ©°, μλ‘μ΄ λ°μ΄ν°λ‘ μνλ₯Ό μ
λ°μ΄νΈν λλ μλμΌλ‘ μ μ§λ©λλ€.
**ν΅μ¬ ν¬μΈνΈ:**
- **μ μ°μ±:** `self.state`μ 미리 μ ν΄μ§ μ μ½ μμ΄ μμ±μ λμ μΌλ‘ μΆκ°ν μ μμ΅λλ€.
- **λ¨μμ±:** μν κ΅¬μ‘°κ° μ΅μμ΄κ±°λ ν¬κ² λ¬λΌμ§λ λ¨μν μν¬νλ‘μ°μ μ΄μμ μ
λλ€.
### ꡬ쑰νλ μν κ΄λ¦¬
ꡬ쑰νλ μν κ΄λ¦¬λ 미리 μ μλ μ€ν€λ§λ₯Ό νμ©νμ¬ μν¬νλ‘ μ λ°μ κ±Έμ³ μΌκ΄μ±κ³Ό νμ
μμ μ±μ 보μ₯ν©λλ€. Pydanticμ `BaseModel`κ³Ό κ°μ λͺ¨λΈμ μ¬μ©νλ©΄ μνμ μ νν ννλ₯Ό μ μν μ μμ΄, κ°λ° νκ²½μμ λ λμ κ²μ¦ λ° μλ μμ±μ΄ κ°λ₯ν©λλ€.
CrewAI Flowsμ κ° μνλ μΈμ€ν΄μ€ μΆμ λ° κ΄λ¦¬λ₯Ό λκΈ° μν΄ μλμΌλ‘ κ³ μ μλ³μ(UUID)λ₯Ό ν λΉλ°μ΅λλ€. μ΄ IDλ Flow μμ€ν
μ μν΄ μλμΌλ‘ μμ±λκ³ κ΄λ¦¬λ©λλ€.
```python Code
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel
class ExampleState(BaseModel):
# Note: 'id' field is automatically added to all states
counter: int = 0
message: str = ""
class StructuredExampleFlow(Flow[ExampleState]):
@start()
def first_method(self):
# Access the auto-generated ID if needed
print(f"State ID: {self.state.id}")
self.state.message = "Hello from structured flow"
@listen(first_method)
def second_method(self):
self.state.counter += 1
self.state.message += " - updated"
@listen(second_method)
def third_method(self):
self.state.counter += 1
self.state.message += " - updated again"
print(f"State after third_method: {self.state}")
flow = StructuredExampleFlow()
flow.kickoff()
```

**ν΅μ¬ ν¬μΈνΈ:**
- **μ μλ μ€ν€λ§:** `ExampleState`λ μν ꡬ쑰λ₯Ό λͺ
νν μ μνμ¬ μ½λ κ°λ
μ±κ³Ό μ μ§λ³΄μμ±μ ν₯μμν΅λλ€.
- **νμ
μμ μ±:** Pydanticμ νμ©νλ©΄ μνμ μμ±μ΄ μ§μ λ νμ
μ μ€μνλλ‘ λ³΄μ₯νμ¬ λ°νμ μ€λ₯λ₯Ό μ€μΌ μ μμ΅λλ€.
- **μλ μμ±:** IDEμμ μ μλ μν λͺ¨λΈμ κΈ°λ°μΌλ‘ λ λμ μλ μμ±κ³Ό μ€λ₯ νμΈμ΄ κ°λ₯ν©λλ€.
### λΉκ΅¬μ‘°μ μν κ΄λ¦¬μ ꡬ쑰μ μν κ΄λ¦¬ μ ννκΈ°
- **λΉκ΅¬μ‘°μ μν κ΄λ¦¬λ₯Ό μ¬μ©ν λ:**
- μν¬νλ‘μ μνκ° λ¨μνκ±°λ λ§€μ° λμ μΌ λ.
- μ격ν μν μ μλ³΄λ€ μ μ°μ±μ΄ μ°μ μλ λ.
- μ€ν€λ§ μ μμ μ€λ²ν€λ μμ΄ λΉ λ₯Έ νλ‘ν νμ΄νμ΄ νμν λ.
- **ꡬ쑰μ μν κ΄λ¦¬λ₯Ό μ¬μ©ν λ:**
- μν¬νλ‘μ μ μ μλκ³ μΌκ΄λ μν κ΅¬μ‘°κ° νμν λ.
- μ ν리μΌμ΄μ
μ μ λ’°μ±μ μν΄ νμ
μμ μ±κ³Ό κ²μ¦μ΄ μ€μν λ.
- λ λμ κ°λ°μ κ²½νμ μν΄ IDEμ μλ μμ± λ° νμ
μ²΄ν¬ κΈ°λ₯μ νμ©νκ³ μ ν λ.
CrewAI Flowsλ λΉκ΅¬μ‘°μ λ° κ΅¬μ‘°μ μν κ΄λ¦¬ μ΅μ
μ λͺ¨λ μ 곡ν¨μΌλ‘μ¨, κ°λ°μλ€μ΄ λ€μν μ ν리μΌμ΄μ
μꡬ μ¬νμ λ§μΆ° μ μ°νλ©΄μλ κ²¬κ³ ν AI μν¬νλ‘λ₯Ό ꡬμΆν μ μλλ‘ μ§μν©λλ€.
## νλ‘μ° μ§μμ±
@persist λ°μ½λ μ΄ν°λ CrewAI νλ‘μ°μμ μλ μν μ§μμ±μ νμ±ννμ¬, νλ‘μ° μνλ₯Ό μ¬μμμ΄λ λ€λ₯Έ μν¬νλ‘μ° μ€ν κ°μλ μ μ§ν μ μλλ‘ ν©λλ€. μ΄ λ°μ½λ μ΄ν°λ ν΄λμ€ μμ€μ΄λ λ©μλ μμ€ λͺ¨λμ μ μ©ν μ μμ΄, μν μ§μμ±μ κ΄λ¦¬νλ λ° μ μ°μ±μ μ 곡ν©λλ€.
### ν΄λμ€ λ 벨 μμμ±
ν΄λμ€ λ 벨μμ @persist λ°μ½λ μ΄ν°λ₯Ό μ μ©νλ©΄ λͺ¨λ flow λ©μλ μνκ° μλμΌλ‘ μμλ©λλ€:
```python
@persist # κΈ°λ³Έμ μΌλ‘ SQLiteFlowPersistence μ¬μ©
class MyFlow(Flow[MyState]):
@start()
def initialize_flow(self):
# μ΄ λ©μλλ μνκ° μλμΌλ‘ μμλ©λλ€
self.state.counter = 1
print("Initialized flow. State ID:", self.state.id)
@listen(initialize_flow)
def next_step(self):
# μν(self.state.id ν¬ν¨)λ μλμΌλ‘ λ€μ λ‘λλ©λλ€
self.state.counter += 1
print("Flow state is persisted. Counter:", self.state.counter)
```
### λ©μλ μμ€μ μ§μμ±
λ μΈλ°ν μ μ΄λ₯Ό μν΄, @persistλ₯Ό νΉμ λ©μλμ μ μ©ν μ μμ΅λλ€:
```python
class AnotherFlow(Flow[dict]):
@persist # Persists only this method's state
@start()
def begin(self):
if "runs" not in self.state:
self.state["runs"] = 0
self.state["runs"] += 1
print("Method-level persisted runs:", self.state["runs"])
```
### μλ λ°©μ
1. **κ³ μ μν μλ³**
- κ° flow μνμλ μλμΌλ‘ κ³ μ ν UUIDκ° ν λΉλ©λλ€.
- μ΄ IDλ μν μ
λ°μ΄νΈ λ° λ©μλ νΈμΆ μμλ μ μ§λ©λλ€.
- ꡬ쑰νλ μν(Pydantic BaseModel)μ λΉκ΅¬μ‘°νλ μν(λμ
λ리) λͺ¨λλ₯Ό μ§μν©λλ€.
2. **κΈ°λ³Έ SQLite λ°±μλ**
- SQLiteFlowPersistenceλ κΈ°λ³Έ μ μ₯ λ°±μλμ
λλ€.
- μνλ μλμΌλ‘ λ‘컬 SQLite λ°μ΄ν°λ² μ΄μ€μ μ μ₯λ©λλ€.
- λ°μ΄ν°λ² μ΄μ€ μμ
μ€ν¨ μ λͺ
νν λ©μμ§λ₯Ό μ 곡νλ κ²¬κ³ ν μ€λ₯ μ²λ¦¬κ° μ 곡λ©λλ€.
3. **μ€λ₯ μ²λ¦¬**
- λ°μ΄ν°λ² μ΄μ€ μμ
μ λν ν¬κ΄μ μΈ μ€λ₯ λ©μμ§κ° μ 곡λ©λλ€.
- μ μ₯ λ° λ‘λ μ€μ μνκ° μλμΌλ‘ κ²μ¦λ©λλ€.
- μ§μμ± μμ
μ λ¬Έμ κ° λ°μν κ²½μ° λͺ
νν νΌλλ°±μ μ 곡ν©λλ€.
### μ€μν κ³ λ €μ¬ν
- **μν μ ν**: ꡬ쑰νλ(Pydantic BaseModel) μνμ λΉκ΅¬μ‘°νλ(λμ
λ리) μν λͺ¨λ μ§μλ©λλ€
- **μλ ID**: `id` νλλ μ‘΄μ¬νμ§ μμ κ²½μ° μλμΌλ‘ μΆκ°λ©λλ€
- **μν 볡ꡬ**: μ€ν¨νκ±°λ μ¬μμλ flowλ μ΄μ μνλ₯Ό μλμΌλ‘ λΆλ¬μ¬ μ μμ΅λλ€
- **컀μ€ν
ꡬν**: νΉμν μ μ₯μ μꡬ μ¬νμ μν΄ μ§μ FlowPersistence ꡬνμ μ 곡ν μ μμ΅λλ€
### κΈ°μ μ μ΄μ
1. **μ μμ€ μ κ·Όμ ν΅ν μ λ°ν μ μ΄**
- κ³ κΈ μ¬μ© μ¬λ‘λ₯Ό μν μμμ± μμ
μ λν μ§μ μ κ·Ό
- λ©μλ μμ€μ μμμ± λ°μ½λ μ΄ν°λ₯Ό ν΅ν μΈλ°ν μ μ΄
- λ΄μ₯λ μν κ²μ¬ λ° λλ²κΉ
κΈ°λ₯
- μν λ³κ²½ λ° μμμ± μμ
μ λν μμ ν κ°μμ±
2. **ν₯μλ μ λ’°μ±**
- μμ€ν
μ₯μ λλ μ¬μμ ν μλ μν 볡ꡬ
- λ°μ΄ν° 무결μ±μ μν νΈλμμ
κΈ°λ° μν μ
λ°μ΄νΈ
- λͺ
νν μ€λ₯ λ©μμ§λ₯Ό μ 곡νλ ν¬κ΄μ μΈ μ€λ₯ μ²λ¦¬
- μν μ μ₯ λ° λ‘λ μμ
μ κ°λ ₯ν κ²μ¦
3. **νμ₯ κ°λ₯ν μν€ν
μ²**
- FlowPersistence μΈν°νμ΄μ€λ₯Ό ν΅ν μ¬μ©μ μ μ κ°λ₯ν μμμ± λ°±μλ
- SQLiteλ₯Ό λμ΄μ νΉμ μ μ₯ μ루μ
μ§μ
- ꡬ쑰νλ(Pydantic) μνμ λΉκ΅¬μ‘°ν(dict) μν λͺ¨λμ νΈν
- κΈ°μ‘΄ CrewAI νλ¦ ν¨ν΄κ³Όμ μνν ν΅ν©
μμμ± μμ€ν
μ μν€ν
μ²λ κΈ°μ μ μ λ°μ±κ³Ό λ§μΆ€ν μ΅μ
μ κ°μ‘°νμ¬, κ°λ°μκ° λ΄μ₯λ μ λ’°μ± κΈ°λ₯μ μ΄μ μ λ리면μ μν κ΄λ¦¬μ λν μμ ν μ μ΄κΆμ μ μ§ν μ μκ² ν΄μ€λλ€.
## νλ¦ μ μ΄
### μ‘°κ±΄λΆ λ‘μ§: `or`
Flowsμμ `or_` ν¨μλ μ¬λ¬ λ©μλλ₯Ό κ°μ§νκ³ μ§μ λ λ©μλ μ€ νλμμ μΆλ ₯μ΄ λ°μνλ©΄ 리μ€λ λ©μλλ₯Ό νΈλ¦¬κ±°ν©λλ€.
<CodeGroup>
```python Code
from crewai.flow.flow import Flow, listen, or_, start
class OrExampleFlow(Flow):
@start()
def start_method(self):
return "Hello from the start method"
@listen(start_method)
def second_method(self):
return "Hello from the second method"
@listen(or_(start_method, second_method))
def logger(self, result):
print(f"Logger: {result}")
flow = OrExampleFlow()
flow.plot("my_flow_plot")
flow.kickoff()
```
```text Output
Logger: Hello from the start method
Logger: Hello from the second method
```
</CodeGroup>

μ΄ Flowλ₯Ό μ€ννλ©΄, `logger` λ©μλλ `start_method` λλ `second_method`μ μΆλ ₯μ μν΄ νΈλ¦¬κ±°λ©λλ€.
`or_` ν¨μλ μ¬λ¬ λ©μλλ₯Ό κ°μ§νκ³ μ§μ λ λ©μλ μ€ νλμμ μΆλ ₯μ΄ λ°μνλ©΄ 리μ€λ λ©μλλ₯Ό νΈλ¦¬κ±°νλ λ° μ¬μ©λ©λλ€.
### μ‘°κ±΄λΆ λ‘μ§: `and`
Flowsμμ `and_` ν¨μλ μ¬λ¬ λ©μλλ₯Ό 리μ¨νκ³ , μ§μ λ λͺ¨λ λ©μλκ° μΆλ ₯μ λ°μμν¬ λλ§ λ¦¬μ€λ λ©μλκ° νΈλ¦¬κ±°λλλ‘ ν©λλ€.
<CodeGroup>
```python Code
from crewai.flow.flow import Flow, and_, listen, start
class AndExampleFlow(Flow):
@start()
def start_method(self):
self.state["greeting"] = "Hello from the start method"
@listen(start_method)
def second_method(self):
self.state["joke"] = "What do computers eat? Microchips."
@listen(and_(start_method, second_method))
def logger(self):
print("---- Logger ----")
print(self.state)
flow = AndExampleFlow()
flow.plot()
flow.kickoff()
```
```text Output
---- Logger ----
{'greeting': 'Hello from the start method', 'joke': 'What do computers eat? Microchips.'}
```
</CodeGroup>

μ΄ Flowλ₯Ό μ€ννλ©΄, `logger` λ©μλλ `start_method`μ `second_method`κ° λͺ¨λ μΆλ ₯μ λ°μμμΌ°μ λλ§ νΈλ¦¬κ±°λ©λλ€.
`and_` ν¨μλ μ¬λ¬ λ©μλλ₯Ό 리μ¨νκ³ , μ§μ λ λͺ¨λ λ©μλκ° μΆλ ₯μ λ°μμν¬ λλ§ λ¦¬μ€λ λ©μλλ₯Ό νΈλ¦¬κ±°νλ λ° μ¬μ©λ©λλ€.
### Router
Flowsμ `@router()` λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νλ©΄ λ©μλμ μΆλ ₯κ°μ λ°λΌ μ‘°κ±΄λΆ λΌμ°ν
λ‘μ§μ μ μν μ μμ΅λλ€.
λ©μλμ μΆλ ₯μ λ°λΌ μλ‘ λ€λ₯Έ κ²½λ‘λ₯Ό μ§μ ν μ μμ΄ μ€ν νλ¦μ λμ μΌλ‘ μ μ΄ν μ μμ΅λλ€.
<CodeGroup>
```python Code
import random
from crewai.flow.flow import Flow, listen, router, start
from pydantic import BaseModel
class ExampleState(BaseModel):
success_flag: bool = False
class RouterFlow(Flow[ExampleState]):
@start()
def start_method(self):
print("Starting the structured flow")
random_boolean = random.choice([True, False])
self.state.success_flag = random_boolean
@router(start_method)
def second_method(self):
if self.state.success_flag:
return "success"
else:
return "failed"
@listen("success")
def third_method(self):
print("Third method running")
@listen("failed")
def fourth_method(self):
print("Fourth method running")
flow = RouterFlow()
flow.plot("my_flow_plot")
flow.kickoff()
```
```text Output
Starting the structured flow
Third method running
Fourth method running
```
</CodeGroup>

μ μμ μμ `start_method`λ λλ€ λΆλ¦¬μΈ κ°μ μμ±νμ¬ stateμ μ μ₯ν©λλ€.
`second_method`λ `@router()` λ°μ½λ μ΄ν°λ₯Ό μ¬μ©ν΄ λΆλ¦¬μΈ κ°μ λ°λΌ μ‘°κ±΄λΆ λΌμ°ν
λ‘μ§μ μ μν©λλ€.
λΆλ¦¬μΈ κ°μ΄ `True`μ΄λ©΄ λ©μλλ `"success"`λ₯Ό λ°ννκ³ , `False`μ΄λ©΄ `"failed"`λ₯Ό λ°νν©λλ€.
`third_method`μ `fourth_method`λ `second_method`μ μΆλ ₯κ°μ κΈ°λ€λ Έλ€κ° λ°νλ κ°μ λ°λΌ μ€νλ©λλ€.
μ΄ Flowλ₯Ό μ€ννλ©΄, `start_method`μμ μμ±λ λλ€ λΆλ¦¬μΈ κ°μ λ°λΌ μΆλ ₯κ°μ΄ λ¬λΌμ§λλ€.
## νλ‘μ°μ μμ΄μ νΈ μΆκ°νκΈ°
μμ΄μ νΈλ νλ‘μ°μ μννκ² ν΅ν©ν μ μμΌλ©°, λ¨μνκ³ μ§μ€λ μμ
μ€νμ΄ νμν λ μ 체 Crewμ κ²½λ λμμΌλ‘ νμ©λ©λλ€. μλλ μμ΄μ νΈλ₯Ό νλ‘μ° λ΄μμ μ¬μ©νμ¬ μμ₯ μ‘°μ¬λ₯Ό μννλ μμμ
λλ€:
```python
import asyncio
from typing import Any, Dict, List
from crewai_tools import SerperDevTool
from pydantic import BaseModel, Field
from crewai.agent import Agent
from crewai.flow.flow import Flow, listen, start
# Define a structured output format
class MarketAnalysis(BaseModel):
key_trends: List[str] = Field(description="List of identified market trends")
market_size: str = Field(description="Estimated market size")
competitors: List[str] = Field(description="Major competitors in the space")
# Define flow state
class MarketResearchState(BaseModel):
product: str = ""
analysis: MarketAnalysis | None = None
# Create a flow class
class MarketResearchFlow(Flow[MarketResearchState]):
@start()
def initialize_research(self) -> Dict[str, Any]:
print(f"Starting market research for {self.state.product}")
return {"product": self.state.product}
@listen(initialize_research)
async def analyze_market(self) -> Dict[str, Any]:
# Create an Agent for market research
analyst = Agent(
role="Market Research Analyst",
goal=f"Analyze the market for {self.state.product}",
backstory="You are an experienced market analyst with expertise in "
"identifying market trends and opportunities.",
tools=[SerperDevTool()],
verbose=True,
)
# Define the research query
query = f"""
Research the market for {self.state.product}. Include:
1. Key market trends
2. Market size
3. Major competitors
Format your response according to the specified structure.
"""
# Execute the analysis with structured output format
result = await analyst.kickoff_async(query, response_format=MarketAnalysis)
if result.pydantic:
print("result", result.pydantic)
else:
print("result", result)
# Return the analysis to update the state
return {"analysis": result.pydantic}
@listen(analyze_market)
def present_results(self, analysis) -> None:
print("\nMarket Analysis Results")
print("=====================")
if isinstance(analysis, dict):
# If we got a dict with 'analysis' key, extract the actual analysis object
market_analysis = analysis.get("analysis")
else:
market_analysis = analysis
if market_analysis and isinstance(market_analysis, MarketAnalysis):
print("\nKey Market Trends:")
for trend in market_analysis.key_trends:
print(f"- {trend}")
print(f"\nMarket Size: {market_analysis.market_size}")
print("\nMajor Competitors:")
for competitor in market_analysis.competitors:
print(f"- {competitor}")
else:
print("No structured analysis data available.")
print("Raw analysis:", analysis)
# Usage example
async def run_flow():
flow = MarketResearchFlow()
flow.plot("MarketResearchFlowPlot")
result = await flow.kickoff_async(inputs={"product": "AI-powered chatbots"})
return result
# Run the flow
if __name__ == "__main__":
asyncio.run(run_flow())
```

μ΄ μμλ νλ‘μ°μμ μμ΄μ νΈλ₯Ό μ¬μ©ν λμ λͺ κ°μ§ μ£Όμ κΈ°λ₯μ 보μ¬μ€λλ€:
1. **ꡬ쑰νλ μΆλ ₯**: Pydantic λͺ¨λΈμ μ¬μ©νμ¬ μμ μΆλ ₯ νμ(`MarketAnalysis`)μ μ μν¨μΌλ‘μ¨ νλ‘μ° μ 체μμ νμ
μμ μ±κ³Ό ꡬ쑰νλ λ°μ΄ν°λ₯Ό 보μ₯ν©λλ€.
2. **μν κ΄λ¦¬**: νλ‘μ° μν(`MarketResearchState`)λ λ¨κ³ κ°μ 컨ν
μ€νΈλ₯Ό μ μ§νκ³ μ
λ ₯κ³Ό μΆλ ₯μ λͺ¨λ μ μ₯ν©λλ€.
3. **λꡬ ν΅ν©**: μμ΄μ νΈλ κΈ°λ₯ κ°νλ₯Ό μν΄ `WebsiteSearchTool`κ³Ό κ°μ λꡬλ₯Ό μ¬μ©ν μ μμ΅λλ€.
## Flowsμ Crews μΆκ°νκΈ°
CrewAIμμ μ¬λ¬ crewsλ‘ flowλ₯Ό μμ±νλ κ²μ κ°λ¨ν©λλ€.
λ€μ λͺ
λ Ήμ΄λ₯Ό μ€ννμ¬ μ¬λ¬ crewsκ° ν¬ν¨λ flowλ₯Ό μμ±νλ λ° νμν λͺ¨λ μ€μΊν΄λ©μ΄ ν¬ν¨λ μ CrewAI νλ‘μ νΈλ₯Ό μμ±ν μ μμ΅λλ€.
```bash
crewai create flow name_of_flow
```
μ΄ λͺ
λ Ήμ΄λ νμν ν΄λ ꡬ쑰λ₯Ό κ°μΆ μ CrewAI νλ‘μ νΈλ₯Ό μμ±ν©λλ€. μμ±λ νλ‘μ νΈμλ μ΄λ―Έ λμ μ€μΈ 미리 ꡬμΆλ crewμΈ `poem_crew`κ° ν¬ν¨λμ΄ μμ΅λλ€. μ΄ crewλ₯Ό ν
νλ¦ΏμΌλ‘ μ¬μ©νμ¬ λ³΅μ¬, λΆμ¬λ£κΈ°, μμ ν¨μΌλ‘μ¨ λ€λ₯Έ crewλ₯Ό λ§λ€ μ μμ΅λλ€.
### ν΄λ ꡬ쑰
`crewai create flow name_of_flow` λͺ
λ Ήμ μ€ννλ©΄ λ€μκ³Ό μ μ¬ν ν΄λ ꡬ쑰λ₯Ό λ³Ό μ μμ΅λλ€:
| λλ ν°λ¦¬/νμΌ | μ€λͺ
|
| :--------------------- | :----------------------------------------------------------------- |
| `name_of_flow/` | flowμ λ£¨νΈ λλ ν°λ¦¬μ
λλ€. |
| βββ `crews/` | νΉμ crewμ λν λλ ν°λ¦¬λ₯Ό ν¬ν¨ν©λλ€. |
| β βββ `poem_crew/` | "poem_crew"μ μ€μ λ° μ€ν¬λ¦½νΈκ° ν¬ν¨λ λλ ν°λ¦¬μ
λλ€. |
| β βββ `config/` | "poem_crew"μ μ€μ νμΌ λλ ν°λ¦¬μ
λλ€. |
| β β βββ `agents.yaml` | "poem_crew"μ agentλ₯Ό μ μνλ YAML νμΌμ
λλ€. |
| β β βββ `tasks.yaml` | "poem_crew"μ taskλ₯Ό μ μνλ YAML νμΌμ
λλ€. |
| β βββ `poem_crew.py` | "poem_crew"μ κΈ°λ₯μ μν μ€ν¬λ¦½νΈμ
λλ€. |
| βββ `tools/` | flowμμ μ¬μ©λλ μΆκ° λꡬλ₯Ό μν λλ ν°λ¦¬μ
λλ€. |
| β βββ `custom_tool.py` | μ¬μ©μ μ μ λꡬ ꡬν νμΌμ
λλ€. |
| βββ `main.py` | flowλ₯Ό μ€ννλ λ©μΈ μ€ν¬λ¦½νΈμ
λλ€. |
| βββ `README.md` | νλ‘μ νΈ μ€λͺ
λ° μλ΄ λ¬Έμμ
λλ€. |
| βββ `pyproject.toml` | νλ‘μ νΈμ μ’
μμ± λ° μ€μ μ μν κ΅¬μ± νμΌμ
λλ€. |
| βββ `.gitignore` | λ²μ κ΄λ¦¬μμ 무μν νμΌκ³Ό λλ ν°λ¦¬λ₯Ό μ§μ ν©λλ€. |
### ν¬λ£¨ λΉλνκΈ°
`crews` ν΄λμμλ μ¬λ¬ κ°μ ν¬λ£¨λ₯Ό μ μν μ μμ΅λλ€. κ° ν¬λ£¨λ μ체 ν΄λλ₯Ό κ°μ§λ©°, μ€μ νμΌκ³Ό ν¬λ£¨ μ μ νμΌμ ν¬ν¨ν©λλ€. μλ₯Ό λ€μ΄, `poem_crew` ν΄λμλ λ€μκ³Ό κ°μ νμΌμ΄ μμ΅λλ€:
- `config/agents.yaml`: ν¬λ£¨μ agentλ₯Ό μ μν©λλ€.
- `config/tasks.yaml`: ν¬λ£¨μ taskλ₯Ό μ μν©λλ€.
- `poem_crew.py`: agent, task, κ·Έλ¦¬κ³ ν¬λ£¨ μ체λ₯Ό ν¬ν¨ν crew μ μκ° λ€μ΄ μμ΅λλ€.
`poem_crew`λ₯Ό 볡μ¬, λΆμ¬λ£κΈ°, κ·Έλ¦¬κ³ νΈμ§νμ¬ λ€λ₯Έ ν¬λ£¨λ₯Ό μμ±ν μ μμ΅λλ€.
### `main.py`μμ Crew μ°κ²°νκΈ°
`main.py` νμΌμ flowλ₯Ό μμ±νκ³ crewλ€μ μλ‘ μ°κ²°νλ κ³³μ
λλ€. `Flow` ν΄λμ€λ₯Ό μ¬μ©νκ³ , `@start`μ `@listen` λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμ¬ μ€ν νλ¦μ μ§μ νμ¬ flowλ₯Ό μ μν μ μμ΅λλ€.
λ€μμ `main.py` νμΌμμ `poem_crew`λ₯Ό μ°κ²°νλ μμ μ
λλ€:
```python Code
#!/usr/bin/env python
from random import randint
from pydantic import BaseModel
from crewai.flow.flow import Flow, listen, start
from .crews.poem_crew.poem_crew import PoemCrew
class PoemState(BaseModel):
sentence_count: int = 1
poem: str = ""
class PoemFlow(Flow[PoemState]):
@start()
def generate_sentence_count(self):
print("Generating sentence count")
self.state.sentence_count = randint(1, 5)
@listen(generate_sentence_count)
def generate_poem(self):
print("Generating poem")
result = PoemCrew().crew().kickoff(inputs={"sentence_count": self.state.sentence_count})
print("Poem generated", result.raw)
self.state.poem = result.raw
@listen(generate_poem)
def save_poem(self):
print("Saving poem")
with open("poem.txt", "w") as f:
f.write(self.state.poem)
def kickoff():
poem_flow = PoemFlow()
poem_flow.kickoff()
def plot():
poem_flow = PoemFlow()
poem_flow.plot("PoemFlowPlot")
if __name__ == "__main__":
kickoff()
plot()
```
μ΄ μμ μμ `PoemFlow` ν΄λμ€λ λ¬Έμ₯ μλ₯Ό μμ±νκ³ , `PoemCrew`λ₯Ό μ¬μ©νμ¬ μλ₯Ό μμ±ν ν, μλ₯Ό νμΌμ μ μ₯νλ flowλ₯Ό μ μν©λλ€. μ΄ flowλ `kickoff()` λ©μλλ₯Ό νΈμΆνμ¬ μμλ©λλ€. `plot()` λ©μλλ‘ PoemFlowPlotμ΄ μμ±λ©λλ€.

### νλ‘μ° μ€ννκΈ°
(μ ν μ¬ν) νλ‘μ°λ₯Ό μ€ννκΈ° μ μ, λ€μ λͺ
λ Ήμ΄λ₯Ό μ€ννμ¬ μμ‘΄μ±μ μ€μΉν μ μμ΅λλ€:
```bash
crewai install
```
λͺ¨λ μμ‘΄μ±μ΄ μ€μΉλλ©΄, λ€μ λͺ
λ Ήμ΄λ₯Ό μ€ννμ¬ κ°μ νκ²½μ νμ±νν΄μΌ ν©λλ€:
```bash
source .venv/bin/activate
```
κ°μ νκ²½μ νμ±νν ν, μλ λͺ
λ Ήμ΄ μ€ νλλ₯Ό μ€ννμ¬ νλ‘μ°λ₯Ό μ€νν μ μμ΅λλ€:
```bash
crewai flow kickoff
```
λλ
```bash
uv run kickoff
```
νλ‘μ°κ° μ€νλλ©΄, μ½μμμ μΆλ ₯μ νμΈν μ μμ΅λλ€.
## νλ‘― νλ‘μ°
AI μν¬νλ‘μ°λ₯Ό μκ°ννλ©΄ νλ‘μ°μ ꡬ쑰μ μ€ν κ²½λ‘μ λν μ€μν μΈμ¬μ΄νΈλ₯Ό μ»μ μ μμ΅λλ€. CrewAIλ νλ‘μ°μ μΈν°λν°λΈ νλ‘―μ μμ±ν μ μλ κ°λ ₯ν μκ°ν λꡬλ₯Ό μ 곡νμ¬ AI μν¬νλ‘μ°λ₯Ό λ³΄λ€ μ½κ² μ΄ν΄νκ³ μ΅μ νν μ μλλ‘ λμμ€λλ€.
### νλ‘―(Plots)μ΄λ 무μμΈκ°μ?
CrewAIμμ νλ‘―(Plots)μ AI μν¬νλ‘μ°μ κ·Έλν½ ννμ
λλ€. νλ‘―μ λ€μν νμ€ν¬μ κ·Έλ€μ μ°κ²°, κ·Έλ¦¬κ³ νμ€ν¬ κ° λ°μ΄ν° νλ¦μ μκ°μ μΌλ‘ 보μ¬μ€λλ€. μ΄λ¬ν μκ°νλ μμ
μμλ₯Ό μ΄ν΄νκ³ , λ³λͺ© νμμ μλ³νλ©°, μν¬νλ‘μ° λ
Όλ¦¬κ° κΈ°λμ λΆν©νλμ§ νμΈνλ λ° λμμ΄ λ©λλ€.
### νλ‘― μμ± λ°©λ²
CrewAIλ νλ‘μ°μ νλ‘―μ μμ±νλ λ κ°μ§ νΈλ¦¬ν λ°©λ²μ μ 곡ν©λλ€:
#### μ΅μ
1: `plot()` λ©μλ μ¬μ©νκΈ°
flow μΈμ€ν΄μ€μ μ§μ μμ
νλ κ²½μ°, flow κ°μ²΄μμ `plot()` λ©μλλ₯Ό νΈμΆνμ¬ νλ‘―μ μμ±ν μ μμ΅λλ€. μ΄ λ©μλλ flowμ μΈν°λν°λΈ νλ‘―μ΄ ν¬ν¨λ HTML νμΌμ μμ±ν©λλ€.
```python Code
# Assuming you have a flow instance
flow.plot("my_flow_plot")
```
μ΄λ κ² νλ©΄ νμ¬ λλ ν 리μ `my_flow_plot.html`μ΄λΌλ νμΌμ΄ μμ±λ©λλ€. μ΄ νμΌμ μΉ λΈλΌμ°μ μμ μ΄μ΄ μΈν°λν°λΈ νλ‘―μ λ³Ό μ μμ΅λλ€.
#### μ΅μ
2: 컀맨λ λΌμΈ μ¬μ©
ꡬ쑰νλ CrewAI νλ‘μ νΈ λ΄μμ μμ
μ€μ΄λΌλ©΄ 컀맨λ λΌμΈμ μ¬μ©νμ¬ νλ‘―μ μμ±ν μ μμ΅λλ€. μ΄λ μ 체 νλ‘μ° μ€μ μ μκ°ννκ³ μ νλ λκ·λͺ¨ νλ‘μ νΈμμ νΉν μ μ©ν©λλ€.
```bash
crewai flow plot
```
μ΄ λͺ
λ Ήμ νλ‘μ°μ νλ‘―μ΄ ν¬ν¨λ HTML νμΌμ μμ±νλ©°, μ΄λ `plot()` λ©μλμ μ μ¬ν©λλ€. νμΌμ νλ‘μ νΈ λλ ν°λ¦¬μ μ μ₯λλ©°, μΉ λΈλΌμ°μ μμ μ΄μ΄ νλ‘μ°λ₯Ό νμν μ μμ΅λλ€.
### νλ‘― μ΄ν΄νκΈ°
μμ±λ νλ‘―μ flow λ΄μ μμ
μ λνλ΄λ λ
Έλμ μ€ν νλ¦μ λνλ΄λ λ°©ν₯μ±μ΄ μλ μ£μ§λ₯Ό νμν©λλ€. νλ‘―μ μΈν°λν°λΈνκ² μ 곡λμ΄, νλ/μΆμλ₯Ό νκ±°λ λ
Έλ μμ λ§μ°μ€λ₯Ό μ¬λ € μΆκ° μ 보λ₯Ό λ³Ό μ μμ΅λλ€.
flowλ₯Ό μκ°ννλ©΄ μν¬νλ‘μ ꡬ쑰λ₯Ό λμ± λͺ
ννκ² μ΄ν΄ν μ μμ΄ λλ²κΉ
, μ΅μ ν, κ·Έλ¦¬κ³ AI νλ‘μΈμ€λ₯Ό λ€λ₯Έ μ¬λλ€μκ² μ€λͺ
νλ λ° λμμ΄ λ©λλ€.
### κ²°λ‘
νλ‘μ°λ₯Ό μκ°μ μΌλ‘ νννλ κ²μ CrewAIμ κ°λ ₯ν κΈ°λ₯μΌλ‘, 볡μ‘ν AI μν¬νλ‘μ°λ₯Ό μ€κ³νκ³ κ΄λ¦¬νλ λ₯λ ₯μ ν¬κ² ν₯μμμΌμ€λλ€. `plot()` λ©μλλ 컀맨λ λΌμΈ μ€ μ΄λ€ λ°©λ²μ μ¬μ©νλλΌλ, νλ‘―μ μμ±νλ©΄ μν¬νλ‘μ°μ μκ°μ ννμ μ»μ μ μμ΄ κ°λ°κ³Ό λ°ν λͺ¨λμ λμμ΄ λ©λλ€.
## λ€μ λ¨κ³
μΆκ°μ μΈ flow μμ λ₯Ό μ΄ν΄λ³΄κ³ μΆμΌμλ€λ©΄, μ ν¬ examples λ ν¬μ§ν 리μμ λ€μν μΆμ² μμ λ₯Ό νμΈνμ€ μ μμ΅λλ€. μλλ κ°κ° κ³ μ ν μ¬μ© μ¬λ‘λ₯Ό 보μ¬μ£Όλ λ€ κ°μ§ ꡬ체μ μΈ flow μμ λ‘, νμ¬ λ¬Έμ μ νμ λ§λ μμλ₯Ό μ°Ύλ λ° λμμ΄ λ κ²μ
λλ€:
1. **μ΄λ©μΌ μλ μλ΅μ Flow**: μ΄ μμ λ λ°±κ·ΈλΌμ΄λ μμ
μ΄ κ³μ μ€νλλ©΄μ μ΄λ©μΌ μλ΅μ μλννλ 무ν 루νλ₯Ό 보μ¬μ€λλ€. μλ κ°μ
μμ΄ λ°λ³΅μ μΌλ‘ μνν΄μΌ νλ μμ
μ μ ν©ν μ¬μ© μ¬λ‘μ
λλ€. [μμ 보기](https://github.com/crewAIInc/crewAI-examples/tree/main/email_auto_responder_flow)
2. **리λ μ μ Flow**: μ΄ flow μμ λ human-in-the-loop νΌλλ°±μ μΆκ°νκ³ routerλ₯Ό μ¬μ©νμ¬ λ€μν 쑰건 λΆκΈ°λ₯Ό μ²λ¦¬νλ λ°©λ²μ 보μ¬μ€λλ€. μν¬νλ‘μ°μ λμ μμ¬κ²°μ κ³Ό μΈκ°μ κ΄λ¦¬Β·κ°λ
μ ν΅ν©νλ λ°©μμ νμΈν μ μλ νλ₯ν μμμ
λλ€. [μμ 보기](https://github.com/crewAIInc/crewAI-examples/tree/main/lead-score-flow)
3. **μ±
μ§ν Flow**: μ΄ μμ λ μ¬λ¬ crewλ₯Ό μ°μμ μΌλ‘ μ°κ²°νλ λ° νμνλ©°, ν crewμ μΆλ ₯ κ²°κ³Όκ° λ€λ₯Έ crewμ μν΄ μ¬μ©λ©λλ€. ꡬ체μ μΌλ‘, ν crewκ° μ 체 μ±
μ κ°μλ₯Ό μμ±νκ³ , λ€λ₯Έ crewκ° κ·Έ κ°μλ₯Ό λ°νμΌλ‘ μ±ν°λ₯Ό μμ±ν©λλ€. κ²°κ΅ λͺ¨λ κ²μ΄ μ°κ²°λμ΄ μμ±λ μ±
μ΄ λ§λ€μ΄μ§λλ€. μ¬λ¬ μμ
κ° μ‘°μ¨μ΄ νμν 볡μ‘ν λ€λ¨κ³ νλ‘μΈμ€μ μ ν©ν flowμ
λλ€. [μμ 보기](https://github.com/crewAIInc/crewAI-examples/tree/main/write_a_book_with_flows)
4. **λ―Έν
μ΄μμ€ν΄νΈ Flow**: μ΄ flowλ νλμ μ΄λ²€νΈκ° μ¬λ¬ νμ μμ
μ νΈλ¦¬κ±°νλλ‘ λΈλ‘λμΊμ€νΈνλ λ°©λ²μ 보μ¬μ€λλ€. μλ₯Ό λ€μ΄, λ―Έν
μ΄ λλ ν Trello 보λλ₯Ό μ
λ°μ΄νΈνκ³ Slack λ©μμ§λ₯Ό μ μ‘νλ©° κ²°κ³Όλ₯Ό μ μ₯ν μ μμ΅λλ€. νλμ μ΄λ²€νΈλ‘λΆν° μ¬λ¬ κ²°κ³Όλ₯Ό μ²λ¦¬νλ μ’μ μμλ‘, ν¬κ΄μ μΈ μμ
κ΄λ¦¬ λ° μλ¦Ό μμ€ν
μ μ΄μμ μ
λλ€. [μμ 보기](https://github.com/crewAIInc/crewAI-examples/tree/main/meeting_assistant_flow)
μ΄ μμ λ€μ ν΅ν΄ λ°λ³΅λλ μμ
μλνλΆν° λμ μμ¬κ²°μ κ³Ό μΈκ° νΌλλ°±μ΄ ν¬ν¨λ 볡μ‘ν λ€λ¨κ³ νλ‘μΈμ€ κ΄λ¦¬μ μ΄λ₯΄κΈ°κΉμ§ λ€μν μ¬μ© μ¬λ‘μμ CrewAI Flowsλ₯Ό μ΄λ»κ² νμ©ν μ μλμ§μ λν ν΅μ°°λ ₯μ μ»μ μ μμ΅λλ€.
λν, μλμ CrewAIμμ flowsλ₯Ό μ¬μ©νλ λ°©λ²μ λν YouTube μμμ νμΈν΄λ³΄μΈμ!
<iframe
className="w-full aspect-video rounded-xl"
src="https://www.youtube.com/embed/MTb5my6VOT8"
title="CrewAI Flows κ°μ"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
></iframe>
## νλ‘μ° μ€ννκΈ°
νλ‘μ°λ₯Ό μ€ννλ λ°©λ²μλ λ κ°μ§κ° μμ΅λλ€:
### Flow API μ¬μ©νκΈ°
νλ‘μ°λ₯Ό νλ‘κ·Έλλ° λ°©μμΌλ‘ μ€ννλ €λ©΄, νλ‘μ° ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό μμ±νκ³ `kickoff()` λ©μλλ₯Ό νΈμΆνλ©΄ λ©λλ€:
```python
flow = ExampleFlow()
result = flow.kickoff()
```
### CLI μ¬μ©νκΈ°
λ²μ 0.103.0λΆν° `crewai run` λͺ
λ Ήμ΄λ₯Ό μ¬μ©νμ¬ flowλ₯Ό μ€νν μ μμ΅λλ€:
```shell
crewai run
```
μ΄ λͺ
λ Ήμ΄λ νλ‘μ νΈκ° pyproject.tomlμ `type = "flow"` μ€μ μ κΈ°λ°μΌλ‘ flowμΈμ§ μλμΌλ‘ κ°μ§νμ¬ ν΄λΉ λ°©μμΌλ‘ μ€νν©λλ€. λͺ
λ Ήμ€μμ flowλ₯Ό μ€ννλ κΆμ₯ λ°©λ²μ
λλ€.
νμ νΈνμ±μ μν΄ λ€μ λͺ
λ Ήμ΄λ μ¬μ©ν μ μμ΅λλ€:
```shell
crewai flow kickoff
```
νμ§λ§ `crewai run` λͺ
λ Ήμ΄κ° μ΄μ crewμ flow λͺ¨λμ μλνλ―λ‘ λμ± μ νΈλλ λ°©λ²μ
λλ€.