CrewAI ์ต์ ๊ธฐ์ค ์ด๋ณด์ ์๋ฒฝ ๊ฐ์ด๋: ํ์ ์ฌ์ ์ค์น ์๊ฑด, ์์ด์ ํธ(Agent)ยท์์
(Task)ยทํฌ๋ฃจ(Crew) 3๋ ํต์ฌ ๊ฐ๋
, ์ญํ ๊ธฐ๋ฐ ๋ฉํฐ ์์ด์ ํธ ํ์
, ์์ฐจ ๋ฐ ๊ณ์ธต์ (Hierarchical) ํ๋ก์ธ์ค, ์ปค์คํ
๋๊ตฌ ์ ์, ๋ฉ๋ชจ๋ฆฌ ์์คํ
๋ฐ ๋ก์ปฌ Ollama ์ฐ๋ ์ค์ ๊ฐ์ด๋
## 1. ํ์ ์ฌ์ ์ค์น ์๊ฑด & ๊ฐ๋ฐ ํ๊ฒฝ ๊ตฌ์ฑ (Prerequisites)
CrewAI๋ ์ฌ๋ฌ ์ ๋ฌธ AI ์์ด์ ํธ๋ค์ด ์ฌ๋์ฒ๋ผ ์ญํ ์ ๋ถ๋ดํ๊ณ ํ์
ํ๋ ๋ฉํฐ ์์ด์ ํธ ํ๋ ์์ํฌ์
๋๋ค. ์ด๋ณด์๋ ๋ฌธ์ ์์ด ๋ฐ๋ผ ํ ์ ์๋๋ก ํ์ ์ฌ์ ํ๊ฒฝ ๊ตฌ์ฑ๋ถํฐ ์์ํฉ๋๋ค.
### ๐ 1. Python ๋ฒ์ & ๊ฐ์ํ๊ฒฝ (Virtual Environment)
CrewAI๋ **Python 3.10 ~ 3.13 (๊ถ์ฅ: Python 3.11 ๋๋ 3.12)** ํ๊ฒฝ์ ์ง์ํฉ๋๋ค. ํจํค์ง ๋ฒ์ ์ถฉ๋์ ๋ฐฉ์งํ๊ธฐ ์ํด ๊ฐ์ํ๊ฒฝ ์์ฑ์ด **ํ์**์
๋๋ค.
```bash
# 1. ํ์ค venv ๊ฐ์ํ๊ฒฝ ์์ฑ
python -m venv .venv
# 2. ๊ฐ์ํ๊ฒฝ ํ์ฑํ (Windows PowerShell)
# โป ๊ถํ ์ค๋ฅ ๋ฐ์ ์ ๊ด๋ฆฌ์ ๋ชจ๋ ๋๋: Set-ExecutionPolicy Unrestricted -Scope Process
.venv\Scripts\Activate.ps1
# ๊ฐ์ํ๊ฒฝ ํ์ฑํ (macOS / Linux / WSL)
source .venv/bin/activate
# 3. ๋๋ ์ฐจ์ธ๋ ์ด๊ณ ์ ํจํค์ง ๊ด๋ฆฌ์ uv ์ฌ์ฉ ์ (๊ฐ๋ ฅ ์ถ์ฒ)
pip install uv
uv venv
# Windows: .venv\Scripts\activate / macOS: source .venv/bin/activate
uv pip install crewai crewai-tools
```
### ๐ ๏ธ 2. OS๋ณ C/C++ ๋ค์ดํฐ๋ธ ๋น๋ ๋๊ตฌ (์ปดํ์ผ๋ฌ)
CrewAI์ ๋ด๋ถ ์๋ฒ ๋ฉ ๋ฐ ๋ฒกํฐ ์ ์ฅ์(ChromaDB), ํ ํฌ๋์ด์ ๋ฐ์ธ๋ฉ ์ค์น ์๋ฌ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ค์ดํฐ๋ธ ์ปดํ์ผ๋ฌ๊ฐ ํ์ํฉ๋๋ค.
- **Windows**: [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) ("C++๋ฅผ ์ฌ์ฉํ ๋ฐ์คํฌํฑ ๊ฐ๋ฐ" ์ํฌ๋ก๋ ์ฒดํฌ)
- **macOS**: `xcode-select --install`
- **Linux (Ubuntu/Debian)**: `sudo apt update && sudo apt install -y build-essential python3-dev`
### ๐ฆ 3. ํจํค์ง ์ค์น
```bash
# CrewAI ํต์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ๊ณต์ ๋๊ตฌ ๋ชจ์(crewai-tools) ์ค์น
pip install crewai crewai-tools
# ํ๊ฒฝ๋ณ์ ๋ก๋ ๋ฐ Pydantic ๋ฐ์ดํฐ ๊ฒ์ฆ
pip install python-dotenv pydantic
```
### ๐ 4. ํ๊ฒฝ ๋ณ์ ์ค์ (`.env`)
ํ๋ก์ ํธ ํด๋ ๋ฃจํธ์ `.env` ํ์ผ์ ๋ง๋ค๊ณ API ํค๋ฅผ ์ค์ ํฉ๋๋ค:
```bash
# OpenAI API ํค (๊ธฐ๋ณธ ๋ชจ๋ธ: gpt-4o ๋๋ gpt-4o-mini)
OPENAI_API_KEY="sk-proj-xxxxxxxxxxxxxxxxxxxx"
# Serper API ํค (์ธํฐ๋ท ์ค์๊ฐ ๊ตฌ๊ธ ๊ฒ์ ๋๊ตฌ ์ฌ์ฉ ์ ๋ฌด๋ฃ ๋ฐ๊ธ: serper.dev)
SERPER_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```
ํ์ด์ฌ ์ฝ๋ ์ฒซ ์ค์์ ํ๊ฒฝ๋ณ์๋ฅผ ๋ก๋ํฉ๋๋ค:
```python
from dotenv import load_dotenv
load_dotenv()
```
---
## 2. CrewAI ํต์ฌ ๊ฐ๋
& ๋ฉํ ๋ชจ๋ธ (Mental Model)
CrewAI๋ ์ค์ ๊ธฐ์
์ **ํ๋ก์ ํธ ํ**๊ณผ ๋์ผํ ๊ตฌ์กฐ๋ก ๋์ํฉ๋๋ค.
```text
[CrewAI ์ํคํ
์ฒ ๋ฉํ ๋ชจ๋ธ]
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Crew (ํ ์ ์ฒด) โ
โ - Process.sequential (์์ฐจ ์งํ) ๋๋ hierarchical (๊ณ์ธต) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Agent (์ ๋ฌธ๊ฐ ์ญํ ) โ Task (๋ด๋น ์
๋ฌด) โ
โ - Role (์ง์ฑ
/์ญํ ) โ - Description (์์
์ค๋ช
) โ
โ - Goal (๋ฌ์ฑ ๋ชฉํ) โ - Expected Output (๊ฒฐ๊ณผ๋ฌผ) โ
โ - Backstory (๋ฐฐ๊ฒฝ ์คํ ๋ฆฌ)โ - Agent (๋ด๋น์ ๋ฐฐ์ ) โ
โ - Tools (๋ณด์ ๋๊ตฌ) โ - Output Pydantic (๊ตฌ์กฐํ) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
### ๐ 3๋ ํต์ฌ ๊ฐ์ฒด
1. **Agent (์์ด์ ํธ)**: "๋๊ฐ ํ๋๊ฐ?" ์ง์ฑ
(Role), ๋ชฉํ(Goal), ํ๋ฅด์๋(Backstory), ๋ณด์ ๋๊ตฌ(Tools)๋ฅผ ๊ฐ์ง ์ ๋ฌธ๊ฐ.
2. **Task (์์
)**: "๋ฌด์์ ํ๋๊ฐ?" ๊ตฌ์ฒด์ ์ธ ์์
์ง์นจ(Description)๊ณผ ๊ธฐ๋ํ๋ ๊ฒฐ๊ณผ๋ฌผ(Expected Output).
3. **Crew (ํฌ๋ฃจ)**: ์์ด์ ํธ์ ์์
์ ๋ชจ์ ์ํฌํ๋ก์ฐ(Process)์ ๋ฐ๋ผ ์คํ์ ์งํํ๋ ๊ด๋ฆฌ์.
---
## 3. [์ด๋ณด์ 1๋จ๊ณ] ํฌ๋ก์๋: ๋จ์ผ ์์ด์ ํธ & ๋จ์ผ ์์
๊ฐ์ฅ ๋จ์ํ 1์ธ ์์ด์ ํธ๋ก ์์ํ์ฌ ๋์ ์๋ฆฌ๋ฅผ ์ตํ๋๋ค.
```python
from crewai import Agent, Task, Crew
from dotenv import load_dotenv
# 1. ํ๊ฒฝ๋ณ์(.env) ๋ก๋
load_dotenv()
# 2. ์์ด์ ํธ ์ ์ (๊ธฐ์ ๋ธ๋ก๊ทธ ์ ๋ฌธ ์๊ฐ)
tech_writer = Agent(
role="์๋์ด ํ
ํฌ ๋ผ์ดํฐ",
goal="๋ณต์กํ ์ต์ IT ๊ธฐ์ ์ ๋น์ ๊ณต์๋ ์ดํดํ๊ธฐ ์ฌ์ด ๋น์ ๋ก ์ค๋ช
ํ๊ธฐ",
backstory="๋น์ ์ 10๋
๊ฐ ๊ธฐ์ ๋ธ๋ก๊ทธ๋ฅผ ์ด์ํ ๋ฒ ํ
๋ ๊ฐ๋ฐ์์ด์ ์๊ฐ์
๋๋ค. ๋ช
์พํ๊ณ ์น์ ํ ๊ธ์์จ๋ก ์ ๋ช
ํฉ๋๋ค.",
verbose=True # ์์ด์ ํธ์ ์ค์๊ฐ ์๊ฐ๊ณผ ์ถ๋ก ๊ณผ์ ์ ์ฝ์์ ์ถ๋ ฅ
)
# 3. ์์
์ ์
writing_task = Task(
description="{topic} ๊ธฐ์ ์ด ๋ฌด์์ธ์ง ์ด๋ฑํ์๋ ์ดํดํ ์ ์๋ ์ผ์์ํ ๋น์ 1๊ฐ์ง๋ฅผ ๋ค์ด 3๋ฌธ์ฅ์ผ๋ก ์ค๋ช
ํด์ฃผ์ธ์.",
expected_output="๋น์ ๊ฐ ํฌํจ๋ ์น์ ํ 3๋ฌธ์ฅ ํ๊ตญ์ด ์ค๋ช
๋ฌธ",
agent=tech_writer
)
# 4. ํฌ๋ฃจ ๊ฒฐ์ฑ ๋ฐ ์คํ
crew = Crew(
agents=[tech_writer],
tasks=[writing_task],
verbose=True
)
# 5. kickoff()๋ก ์์
์์ (๋์ ๋ณ์ {topic} ์ ๋ฌ)
result = crew.kickoff(inputs={"topic": "ํด๋ผ์ฐ๋ ์ปดํจํ
(Cloud Computing)"})
print("\n" + "="*50)
print("๐ฏ [์ต์ข
๊ฒฐ๊ณผ๋ฌผ]:\n", result)
print("="*50)
```
---
## 4. [์ด๋ณด์ 2๋จ๊ณ] 2์ธ ํ์
: ๋ฆฌ์์ฒ + ๋ผ์ดํฐ ์์ฐจ ํ์ดํ๋ผ์ธ
ํ ์์ด์ ํธ์ ์์
๊ฒฐ๊ณผ๋ฌผ์ด ๋ค์ ์์ด์ ํธ์ ์
๋ ฅ์ผ๋ก ์๋ ์ ๋ฌ๋๋ `Process.sequential` ๊ธฐ๋ณธ ํ์
ํจํด์
๋๋ค.
```text
[์์ฐจ ํ์
์ํฌํ๋ก์ฐ]
[์ฌ์ฉ์ ์ฃผ์ ์
๋ ฅ]
โ
โผ
[1. ์๋์ด ๋ฆฌ์์ฒ] โโโบ [์ต์ ํธ๋ ๋ & ํต์ฌ ํฉํธ ์กฐ์ฌ]
โ
โผ (๊ฒฐ๊ณผ๋ฌผ ์๋ ์ ๋ฌ)
[2. ์ฝํ
์ธ ์๋ํฐ] โโโบ [๋งค๋ ฅ์ ์ธ ๋ธ๋ก๊ทธ ์ํฐํด ์ต์ข
์์ฑ]
โ
โผ
[์ต์ข
๋งํฌ๋ค์ด ๊ธ]
```
```python
from crewai import Agent, Task, Crew, Process
from dotenv import load_dotenv
load_dotenv()
# 1. ์ฒซ ๋ฒ์งธ ์์ด์ ํธ: IT ์์ฅ ์กฐ์ฌ ์ ๋ฌธ๊ฐ
researcher = Agent(
role="์ธ๊ณต์ง๋ฅ ํธ๋ ๋ ๋ฆฌ์์ฒ",
goal="{topic} ๋ถ์ผ์ 2026๋
์ต์ ๊ธฐ์ ๋ํฅ๊ณผ ํต์ฌ ์ด์ 3๊ฐ์ง๋ฅผ ๋ฐ๊ตดํ๊ธฐ",
backstory="๋ฐฉ๋ํ ๊ธ๋ก๋ฒ IT ๋ด์ค์ ์ฐ๊ตฌ ๋
ผ๋ฌธ์์ ์์ง๋ฐฐ๊ธฐ ํธ๋ ๋๋ง ์ ํํ๊ฒ ์ง์ด๋ด๋ ๋ฐ์ดํฐ ๋ถ์ ์ ๋ฌธ๊ฐ์
๋๋ค.",
verbose=True,
memory=True
)
# 2. ๋ ๋ฒ์งธ ์์ด์ ํธ: ํ
ํฌ ์ ๋ฌธ ๋ธ๋ก๊ฑฐ
writer = Agent(
role="ํ
ํฌ ์ํฐํด ์๋ํฐ",
goal="๋ฆฌ์์ฒ๊ฐ ์กฐ์ฌํ ๋ด์ฉ์ ๋ฐํ์ผ๋ก ๊ฐ๋ฐ์ ๋
์๋ค์ ์์ ์ ์ฌ๋ก์ก๋ ๋งํฌ๋ค์ด ๊ธ ์์ฑํ๊ธฐ",
backstory="๋ณต์กํ ํธ๋ ๋ ์๋ฃ๋ฅผ ์ฝ๊ธฐ ํธํ ํค๋๋ผ์ธ๊ณผ ๋ถ๋ฆฟ ํฌ์ธํธ๋ก ๊ฐ๊ณตํ๋ ๋ฐ ํ์ํ ๋ฅ๋ ฅ์ ๊ฐ์ถ ์ ๋ฌธ ์๋ํฐ์
๋๋ค.",
verbose=True,
memory=True
)
# 3. ์์
1: ๋ฆฌ์์น ์์
task_research = Task(
description="{topic} ๊ธฐ์ ์ ํต์ฌ ๊ฐ๋
๊ณผ 2026๋
ํ์ฌ ๊ฐ์ฅ ์ฃผ๋ชฉ๋ฐ๋ ์ค๋ฌด ํ์ฉ ์ฌ๋ก 3๊ฐ์ง๋ฅผ ์ ๋ฆฌํ์ธ์.",
expected_output="ํต์ฌ ๊ฐ๋
์์ฝ ๋ฐ 3๊ฐ์ง ์ค๋ฌด ์ฌ๋ก๊ฐ ์ ๋ฆฌ๋ ๋ถ๋ฆฟ ํฌ์ธํธ ๋ฆฌํฌํธ",
agent=researcher
)
# 4. ์์
2: ๊ธ ์์ฑ ์์
(์ด์ task_research์ ๊ฒฐ๊ณผ๋ฅผ ์๋์ผ๋ก ์ฐธ๊ณ ํจ)
task_write = Task(
description="๋ฆฌ์์ฒ๊ฐ ์์ฑํ ๋ฆฌํฌํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ ๋ชฉ, ๋์
๋ถ, ๋ณธ๋ฌธ 3๊ฐ ๋จ๋ฝ, ๊ฒฐ๋ก ์ด ํฌํจ๋ ์์ฑ๋ ๋งํฌ๋ค์ด ์ํฐํด์ ์์ฑํ์ธ์.",
expected_output="์ ๋ชฉ(#)๊ณผ ์์ ๋ชฉ(##)์ด ๊ฐ์ถ์ด์ง ์์ฑ๋ ํ๊ตญ์ด ๋งํฌ๋ค์ด ๊ธฐ์ ๊ธ",
agent=writer
)
# 5. ํฌ๋ฃจ ๊ตฌ์ฑ ๋ฐ ์คํ (์์ฐจ ํ๋ก์ธ์ค)
editorial_crew = Crew(
agents=[researcher, writer],
tasks=[task_research, task_write],
process=Process.sequential, # ์ ์์
์ด ๋๋๋ฉด ๋ค์ ์์
์ผ๋ก ์ ๋ฌ
verbose=True
)
# 6. ์คํ
final_article = editorial_crew.kickoff(inputs={"topic": "LangChain๊ณผ CrewAI์ ๋ฉํฐ ์์ด์ ํธ ์ํ๊ณ"})
print("\n" + "#"*50)
print(final_article)
```
---
## 5. [์ด๋ณด์ 3๋จ๊ณ] ์ปค์คํ
๋๊ตฌ(Tool) ๊ฐ๋ฐ & ์ฐ๋
์์ด์ ํธ๊ฐ ๊ณ์ฐ๊ธฐ, ์น ๊ฒ์, ์ฌ๋ด DB ์กฐํ๋ฅผ ์ง์ ์ํํ ์ ์๋๋ก ํ์ด์ฌ ํจ์๋ฅผ ๋๊ตฌ๋ก ๋ง๋๋ ๋ฐฉ๋ฒ์
๋๋ค.
### ๐งฐ `@tool` ๋ฐ์ฝ๋ ์ดํฐ๋ก ์์ฝ๊ฒ ๋๊ตฌ ์ ์ํ๊ธฐ
```python
from crewai.tools import tool
from crewai import Agent, Task, Crew
# 1. ํ์ด์ฌ ํจ์์ @tool ๋ถ์ด๊ธฐ (๋
์คํธ๋ง์ด LLM์ ๋๊ตฌ ์ฌ์ฉ ์ค๋ช
์๊ฐ ๋จ)
@tool("ํ์จ ๊ณ์ฐ ๋๊ตฌ")
def currency_converter(usd_amount: float) -> str:
"""๋ฏธ๊ตญ ๋ฌ๋ฌ(USD) ๊ธ์ก์ ์
๋ ฅ๋ฐ์ ํ๊ตญ ์ํ(KRW, ํ์จ 1,380์ ๊ธฐ์ค)๋ก ํ์ฐํฉ๋๋ค."""
krw = usd_amount * 1380
return f"{usd_amount:,.2f} USD๋ ์ฝ {krw:,.0f} KRW ์
๋๋ค."
@tool("ํ ์ธ์จ ์ ์ฉ ๊ณ์ฐ๊ธฐ")
def apply_discount(price: float, discount_percent: float) -> str:
"""์๊ฐ์ ํ ์ธ์จ(์: 20์ 20%)์ ๋ฐ์ ํ ์ธ๋ ์ต์ข
๊ฐ๊ฒฉ์ ๊ณ์ฐํฉ๋๋ค."""
discounted = price * (1 - discount_percent / 100)
return f"์ ๊ฐ {price:,.0f}์์์ {discount_percent}% ํ ์ธ๋ ๊ฐ๊ฒฉ์ {discounted:,.0f}์ ์
๋๋ค."
# 2. ๋๊ตฌ๋ฅผ ์ฅ์ฐฉํ ์์ด์ ํธ
finance_agent = Agent(
role="์ ์์๊ฑฐ๋ ๊ฐ๊ฒฉ ์ ์ฐ ์ ๋ฌธ๊ฐ",
goal="ํด์ธ ์ง๊ตฌ ์ํ์ ๊ด์ธ ๋ฐ ์ํ ํ์ฐ ๊ฐ๊ฒฉ์ ์ ํํ ๊ณ์ฐํ๊ธฐ",
backstory="์ซ์์ ์ค์ฐจ๊ฐ ์๋๋ก ๋๊ตฌ๋ฅผ ์ ๊ทน์ ์ผ๋ก ํ์ฉํ์ฌ ์ ํํ ์ต์ข
์ฒญ๊ตฌ ๊ธ์ก์ ์ฐ์ถํ๋ ํ๊ณ ์ ๋ฌธ๊ฐ์
๋๋ค.",
tools=[currency_converter, apply_discount], # ๋๊ตฌ ๋ชฉ๋ก ๋ฐ์ธ๋ฉ
verbose=True
)
# 3. ์์
์์ฑ
calc_task = Task(
description="๋ฏธํ $250๋ฌ๋ฌ์ง๋ฆฌ ์ค๋งํธ์์น๊ฐ 15% ๋ธ๋ํ๋ผ์ด๋ฐ์ด ์ธ์ผ ์ค์
๋๋ค. ํ ์ธ๋ ์ต์ข
์ํ(KRW) ๊ธ์ก์ด ์ผ๋ง์ธ์ง ๊ณ์ฐ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ฐ์ถํ์ธ์.",
expected_output="ํ ์ธ ์ ํ ๋ฌ๋ฌ ๊ฐ๊ฒฉ๊ณผ ์ต์ข
๊ณ์ฐ๋ ์ํ(KRW) ๊ธ์ก ๋ช
์",
agent=finance_agent
)
# 4. ์คํ
crew = Crew(agents=[finance_agent], tasks=[calc_task], verbose=True)
result = crew.kickoff()
print("\n๊ฒฐ๊ณผ:", result)
```
---
## 6. ๊ณ์ธต์ ํ๋ก์ธ์ค (Hierarchical Process & Manager Agent)
์์
์์๋ฅผ ํ๋์ฝ๋ฉํ์ง ์๊ณ , **์ด๊ด ๋งค๋์ (Manager LLM)**๊ฐ ํ์ ์์ด์ ํธ๋ค์๊ฒ ์ผ์ ์ค์ค๋ก ์์(Delegation)ํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ทจํฉํ์ฌ ์ต์ข
๋ฉํํ๋ ์ํฐํ๋ผ์ด์ฆ ํจํด์
๋๋ค.
```python
from crewai import Agent, Task, Crew, Process
from langchain_openai import ChatOpenAI
# 1. ์ค๋ฌด ์์
์ ์์ด์ ํธ๋ค
market_analyst = Agent(
role="์์ฅ ์ ์ ์จ ๋ถ์๊ฐ",
goal="๊ฒฝ์์ฌ ์ ํ์ ์ฅ๋จ์ ๋ฐ ์์ฅ ๋ฐ์ ์กฐ์ฌ",
backstory="์ ๋์ ๋ฐ์ดํฐ ๋ถ์์ ์ ๋ฌธ์ผ๋ก ํ๋ ์์ฅ ๋ถ์๊ฐ์
๋๋ค.",
verbose=True
)
marketing_strategist = Agent(
role="๋ง์ผํ
์ ๋ต ์๋ฆฝ๊ฐ",
goal="์ ์ ํ ๋ฐ์นญ์ ์ํ ํจ๊ณผ์ ์ธ ๋ฐ์ด๋ด ์บ ํ์ธ ์ ๋ต ์๋ฆฝ",
backstory="์๋น์์ ์ฌ๋ฆฌ๋ฅผ ๊ฟฐ๋ซ์ด ๋ณด๋ ์ฐฝ์์ ์ธ ๋ง์ผํ
๋๋ ํฐ์
๋๋ค.",
verbose=True
)
# 2. ๋งค๋์ ์์ด์ ํธ์ฉ LLM ์ง์
manager_llm = ChatOpenAI(model="gpt-4o", temperature=0.2)
# 3. ์ต์ข
๋ชฉํ ์์
launch_task = Task(
description="{product_name} ์ ์ ํ ์ถ์๋ฅผ ์ํ 1) ๊ฒฝ์์ฌ ๋ถ์๊ณผ 2) ์ฐจ๋ณํ ๋ง์ผํ
์ก์
ํ๋์ ์ข
ํฉ ์๋ฆฝํ์ธ์.",
expected_output="๊ฒฝ์ ๋ถ์ ๋ฐ ๊ตฌ์ฒด์ ๋ง์ผํ
์คํ ๋ฐฉ์์ด ํฌํจ๋ 1ํ์ด์ง ์ข
ํฉ ๊ธฐํ์"
)
# 4. ๊ณ์ธต์ ํฌ๋ฃจ (manager_llm์ด ์์์ ๋ ์์ด์ ํธ์๊ฒ ์ผ์ ์ชผ๊ฐ์ด ๋ถ๋ฐฐํจ)
project_crew = Crew(
agents=[market_analyst, marketing_strategist],
tasks=[launch_task],
process=Process.hierarchical, # ๐ ๊ณ์ธต์ ์์จ ์์ ๋ชจ๋
manager_llm=manager_llm,
verbose=True
)
result = project_crew.kickoff(inputs={"product_name": "AI ๊ธฐ๋ฐ ์๋ ๋ถ๋ฆฌ์๊ฑฐ ๋ก๋ด"})
print(result)
```
---
## 7. ๊ตฌ์กฐํ๋ ์ถ๋ ฅ (Pydantic Output)
์์ด์ ํธ์ ๊ฒฐ๊ณผ๋ฌผ์ ํ์ฑํ๊ธฐ ํ๋ ์ค๊ธ ๋์ **Pydantic ์คํค๋ง**๋ฅผ ํตํด 100% ์ ํํ๋ JSON ๋ฐ์ดํฐ๋ก ์์ ํ๊ฒ ์ถ์ถํฉ๋๋ค.
```python
from pydantic import BaseModel, Field
from typing import List
from crewai import Agent, Task, Crew
# 1. Pydantic ์ถ๋ ฅ ์คํค๋ง ์ ์
class JobOpening(BaseModel):
title: str = Field(description="์ฑ์ฉ ๊ณต๊ณ ์ ๋ชฉ")
required_skills: List[str] = Field(description="ํ์ ์๊ตฌ ๊ธฐ์ ์คํ 3๊ฐ์ง ์ด์")
experience_years: int = Field(description="์ต์ ์๊ตฌ ๊ฒฝ๋ ฅ ์ฐ์")
summary: str = Field(description="์ง๋ฌด ํต์ฌ ์์ฝ 1๋ฌธ์ฅ")
# 2. ์ธ์ฌ ๋ด๋น ์์ด์ ํธ
recruiter = Agent(
role="HR ์ฑ์ฉ ์ ๋ฌธ๊ฐ",
goal="์ง๋ฌด ๊ธฐ์ ์๋ฅผ ๋ถ์ํ์ฌ ํ์ค ์ฑ์ฉ ๊ท๊ฒฉ์ผ๋ก ์ ํํํ๊ธฐ",
backstory="์์ฒ ๊ฑด์ ์ด๋ ฅ์์ ์ง๋ฌด ๊ธฐ์ ์๋ฅผ ๋ถ์ํด์จ ์ธ์ฌ ๋ฒ ํ
๋์
๋๋ค.",
verbose=True
)
# 3. output_pydantic ํ๋ผ๋ฏธํฐ ์ ์ฉ
struct_task = Task(
description="์๋์ด ํ์คํ ๊ฐ๋ฐ์(React, Python FastAPI, Docker ๊ฒฝํ 5๋
์ด์) ์ฑ์ฉ ๊ณต๊ณ ๋ฅผ ๋ถ์ํ์ฌ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๋ง๊ฒ ์ถ์ถํ์ธ์.",
expected_output="JobOpening Pydantic ๊ท๊ฒฉ์ ๋ถํฉํ๋ ์ ํ ๋ฐ์ดํฐ",
agent=recruiter,
output_pydantic=JobOpening # ๐ ์๋ Pydantic ์ธ์คํด์คํ
)
crew = Crew(agents=[recruiter], tasks=[struct_task], verbose=True)
result = crew.kickoff()
# 4. Pydantic ๊ฐ์ฒด๋ก ๋ฐ๋ก ์ ๊ทผ ๊ฐ๋ฅ
parsed: JobOpening = result.pydantic
print(f"์ง๋ฌด๋ช
: {parsed.title}")
print(f"๊ฒฝ๋ ฅ ์๊ตฌ: {parsed.experience_years}๋
")
print(f"ํ์ ์คํฌ: {', '.join(parsed.required_skills)}")
print(f"์์ฝ: {parsed.summary}")
```
---
## 8. ๋ก์ปฌ ๋ฌด๋ฃ ์คํ๋ผ์ธ LLM (Ollama) ์ฐ๋
OpenAI API ๋น์ฉ ์ง์ถ ์์ด ๋ด PC์ GPU/CPU์์ ์์ ๋ฌด๋ฃ๋ก ๋์ํ๋๋ก Ollama๋ฅผ ์ฐ๊ฒฐํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
```python
from crewai import Agent, Task, Crew, LLM
# 1. Ollama ๋ก์ปฌ LLM ๊ฐ์ฒด ์์ฑ (CrewAI ์ ์ฉ LLM ํด๋์ค ์ฌ์ฉ)
local_llm = LLM(
model="ollama/llama3.2:latest",
base_url="http://localhost:11434"
)
# 2. ๋ก์ปฌ ๋ชจ๋ธ์ ํ์ฌํ ์์ด์ ํธ
local_coder = Agent(
role="ํ์ด์ฌ ๋ฐฑ์๋ ๊ฐ๋ฐ์",
goal="์ต์ ํ๋ ํ์ด์ฌ ํจ์์ ์ ๋ํ
์คํธ ์ฝ๋ ์์ฑ",
backstory="์คํ๋ผ์ธ ๋ณด์ ํ๊ฒฝ์์๋ ์ต๊ณ ์ ์ฝ๋๋ฅผ ์์ฐํ๋ ํด๋ฆฐ ์ฝ๋ ์ ๋ฌธ๊ฐ์
๋๋ค.",
llm=local_llm, # ๐ ๋ก์ปฌ LLM ์ง์
verbose=True
)
# 3. ์์
code_task = Task(
description="์ด๋ฉ์ผ ์ฃผ์ ์ ํจ์ฑ์ ๊ฒ์ฌํ๋ ์ ๊ท์ ํจ์ `validate_email(email: str) -> bool`์ ์์ฑํ์ธ์.",
expected_output="์ค๋ช
์ฃผ์์ด ํฌํจ๋ ํ์ด์ฌ ํจ์ ์ฝ๋ ๋ธ๋ก",
agent=local_coder
)
crew = Crew(agents=[local_coder], tasks=[code_task], verbose=True)
print(crew.kickoff())
```
---
## 9. ์ค๋ฌด ๊ฐ๋ฐ์ ์ฒดํฌ๋ฆฌ์คํธ & ํธ๋ฌ๋ธ์ํ
| ๋ฌธ์ ์ํฉ | ์์ธ | ํด๊ฒฐ ๋ฐฉ๋ฒ (Best Practice) |
| :--- | :--- | :--- |
| **์์ด์ ํธ๊ฐ ๋ฌดํ ๋ฃจํ์ ๋น ์ง** | ๋๊ตฌ ํธ์ถ ์คํจ๋ฅผ ๋ฐ๋ณตํ๊ฑฐ๋ ๋ชฉํ๊ฐ ๋ชจํธํจ | Agent์ `max_iter=5` ์ค์ ๋ฐ Task description์ ๋ช
ํํ ์ข
๋ฃ ์กฐ๊ฑด ๋ช
์ |
| **๋ค๋ฅธ ์์ด์ ํธ์๊ฒ ์๋ฑํ ์ง๋ฌธ ๋ฐ๋ณต** | ์์ด์ ํธ ๊ฐ ์์ ๊ถํ์ด ๊ณผ๋ํ๊ฒ ์ผ์ ธ ์์ | ๋ถํ์ํ ์์์ ๋ง์ผ๋ ค๋ฉด Agent์ `allow_delegation=False` ๋ช
์ |
| **OpenAI Rate Limit ์ด๊ณผ (429 ์๋ฌ)** | ์์ด์ ํธ๋ค์ด ๋จ์๊ฐ์ ๋๋ฌด ๋ง์ ์์ฒญ ๋ฐ์ | Crew ์์ฑ ์ `max_rpm=20` (๋ถ๋น ์ต๋ ์์ฒญ ์) ์ค์ |
| **๋ฉ๋ชจ๋ฆฌ(Memory) ํ์ฑํ ์ค๋ฅ** | ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ฏธ์ค์ ๋๋ chromadb ๋๋ฝ | `pip install chromadb` ์ค์น ํ์ธ ๋ฐ OpenAI ์๋ฒ ๋ฉ ํค ์ค์ |
| **๋น์ฉ ์ ๊ฐ ์ต์ ํ** | ๋ชจ๋ ์์ด์ ํธ์ ์ต๊ณ ๊ธ ๋ชจ๋ธ(GPT-4o) ๋ฐฐ์ | ๋จ์ ์์ฑ/์กฐ์ฌ ์์ด์ ํธ๋ `gpt-4o-mini`, ์ต์ข
๋งค๋์ ๋ง `gpt-4o`๋ก ๋ถ๋ฆฌ |
์๊ฒฌ ๋ฐ ์ง๋ฌธ
0์์ง ๋ฑ๋ก๋ ์๊ฒฌ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋๊ธ์ ๋จ๊ฒจ๋ณด์ธ์!
๋๊ธ ์์
๋๊ธ ์ญ์