CrewAI 크루 (Crews)¶
에이전트 하나만으로는 복잡한 일을 끝내기 어려워요. 조사하고, 분석하고, 보고서로 정리하는 이런 일들은 사실상 서로 다른 능력을 가진 팀원들이 협력해야 끝나거든요. CrewAI에서는 각자 역할을 가진 에이전트들을 모아 크루(crew) 라는 단위로 묶고, 에이전트들이 함께 일하면서 작업을 끝내도록 해요. '팀' 대신 '크루'라는 단어를 쓰는 이유는, 승무원들이 각자 맡은 일을 하면서 한 임무를 완수하는 구조를 그대로 닮았기 때문이에요.
크루가 하는 일이 뭐예요¶
CrewAI 공식 문서에 따르면, 크루는 함께 일하는 에이전트들의 협력 그룹이에요. 각 크루는 작업을 어떻게 실행할지, 에이전트들이 서로 어떻게 협력할지, 전체 작업 흐름이 어떤지에 대한 전략을 정의해요. 쉽게 말해 에이전트가 '개인'이라면, 크루는 '그 개인들이 모인 조직'이고, 그 조직의 운영 방식까지 정해주는 거예요.
크루를 만드는 두 가지 방법¶
크루를 만드는 방법은 크게 두 가지예요. 공식 문서는 JSONC 설정 방식을 새 크루에 권장하고, 또 하나는 코드로 직접 정의하는 방식이에요.
JSONC 설정 (권장)¶
crewai create crew <name>으로 새 프로젝트를 만들면 크루 단위 설정은 crew.jsonc에, 에이전트마다 하나씩 agents/ 폴더 안에 파일로 저장돼요. 그리고 crewai run을 실행하면 crew.jsonc나 crew.json을 자동으로 감지해, 참조된 에이전트를 불러오고, 없는 자리 표시자(placeholder)를 물어본 뒤 크루를 시작해요.
{
"name": "Market Research Crew",
"agents": ["researcher", "analyst"],
"tasks": [
{
"name": "research",
"description": "Research {topic} and collect the most relevant facts.",
"expected_output": "Structured research notes about {topic}.",
"agent": "researcher"
},
{
"name": "analysis",
"description": "Analyze the research and write a concise report.",
"expected_output": "A markdown report with findings and recommendations.",
"agent": "analyst",
"context": ["research"],
"output_file": "output/report.md"
}
],
"process": "sequential",
"verbose": true,
"memory": true,
"inputs": {
"topic": "AI Agents"
}
}
agents 배열에 적힌 문자열은 먼저 agents/<name>.jsonc를 찾고, 없으면 agents/<name>.json을 참조해요.
{
"role": "{topic} Senior Researcher",
"goal": "Find accurate and current information about {topic}.",
"backstory": "You are a careful researcher who cites clear evidence.",
"llm": "openai/gpt-4o",
"tools": ["SerperDevTool"]
}
여기서 process가 "sequential"이면 작업(tasks)은 배열에 적힌 순서대로 실행돼요. 계층형(hierarchical) 크루를 쓰려면 "process": "hierarchical"로 두고 manager_llm이나 manager_agent를 넣어줘야 해요.
코드로 직접 정의¶
파이썬 코드 안에서 바로 에이전트, 작업, 크루를 정의하는 방식도 있어요. 데코레이터 없이 클래스 안에서 직접 만들고, 목록을 손으로 관리해요. 더 세밀하게 제어할 수 있지만, 프로젝트가 커지면 관리하기 어려워질 수 있어요.
from crewai import Agent, Crew, Task, Process
from crewai_tools import YourCustomTool
class YourCrewName:
def agent_one(self) -> Agent:
return Agent(
role="Data Analyst",
goal="Analyze data trends in the market",
backstory="An experienced data analyst with a background in economics",
verbose=True,
tools=[YourCustomTool()]
)
def agent_two(self) -> Agent:
return Agent(
role="Market Researcher",
goal="Gather information on market dynamics",
backstory="A diligent researcher with a keen eye for detail",
verbose=True
)
def task_one(self) -> Task:
return Task(
description="Analyze the market data and identify key trends",
expected_output="A clear summary of the market trends",
agent=self.agent_one()
)
def task_two(self) -> Task:
return Task(
description="Gather latest market information",
expected_output="A set of facts about the current market",
agent=self.agent_two()
)
def crew(self) -> Crew:
return Crew(
agents=[self.agent_one(), self.agent_two()],
tasks=[self.task_one(), self.task_two()],
process=Process.sequential,
verbose=True
)
크루의 핵심 속성들¶
크루를 만들 때 쓸 수 있는 속성이 꽤 많아요. 처음부터 다 외울 필요는 없고, agents와 tasks가 기본이라는 것만 잡으면 돼요.
agents— 크루에 속한 에이전트 목록tasks— 크루에 할당된 작업 목록process— 작업 실행 방식. 순차(sequential) 또는 계층(hierarchical)verbose(선택) — 실행 중 로그 상세 수준. 기본값은Falsemanager_llm(선택) — 계층형 프로세스에서 매니저 에이전트가 쓰는 언어 모델. 계층형 프로세스를 쓸 땐 필수memory(선택) — 실행 메모리(단기·장기·엔티티 메모리) 저장에 사용cache(선택) — 도구 실행 결과를 캐시에 저장할지. 기본값은Truemax_rpm(선택) — 크루가 지키는 분당 최대 요청 수. 기본값은Noneplanning(선택) — 실행 전에 AgentPlanner가 작업을 계획하도록 함stream(선택) — 실시간 출력을 받도록 함. 기본값은False
max_rpm을 설정하면 분당 요청 한도를 걸어 속도 제한(rate limit)을 피할 수 있고, 개별 에이전트의 max_rpm 설정을 덮어쓰기(override)도 해요.
크루 실행과 결과 받기¶
크루를 시작하는 메서드(kickoff)는 동기와 비동기로 나뉘어요.
- 동기:
kickoff()는 정의된 프로세스대로 실행을 시작하고,kickoff_for_each()는 입력 이벤트나 컬렉션의 각 항목에 대해 작업을 순차 실행해요. - 비동기:
akickoff()는 실행 전 과정이 진짜 async/await로 동작하고,akickoff_for_each()는 리스트의 각 입력을 네이티브 비동기로 실행해요.kickoff_for_each_async()는 스레드 기반이에요.
높은 동시성 작업이 필요하다면 akickoff()와 akickoff_for_each()를 쓰는 게 좋아요. 작업 실행·메모리·지식 검색이 모두 네이티브 비동기로 돌기 때문이에요.
실행이 끝나면 결과가 CrewOutput 객체에 담겨요. raw(기본 포맷, 문자열), json_dict(JSON 딕셔너리), tasks_output(각 작업의 TaskOutput 목록), token_usage(토큰 사용량 요약) 같은 속성으로 결과에 접근할 수 있어요. 또 usage_metrics 속성으로 실행된 모든 작업의 LLM 사용량을 확인할 수도 있어요.
체크포인트 (Checkpointing)¶
긴 작업이나 중간에 끊길 수 있는 실행에서, 크루가 작업 완료 같은 주요 이벤트 뒤에 상태를 자동으로 저장하게 할 수 있어요. 이렇게 하면 완료된 작업을 다시 실행하지 않고도 끊긴 지점부터 정확히 이어서 재개할 수 있어요. checkpoint에 True를 주면 기본값으로 동작하고, CheckpointConfig로 위치·트리거 이벤트·저장 백엔드·보관 개수를 세밀하게 제어할 수 있어요.
from crewai import Crew, Process
from crewai.state.checkpoint_config import CheckpointConfig
crew = Crew(
agents=[researcher, writer],
tasks=[research_task, write_task],
process=Process.sequential,
checkpoint=CheckpointConfig(
location="./.checkpoints", # JSON 파일 저장 폴더 (기본값)
on_events=["task_completed"], # 각 작업 완료 후 트리거 (기본값)
max_checkpoints=5, # 최근 5개만 보관
),
)
CheckpointConfig의 provider 기본값은 JsonProvider()(일반 JSON 파일)이고, max_checkpoints를 None으로 두면 모든 체크포인트를 다 보관해요.
데이터스케쳐스 실무 관점¶
가장 자주 쓰는 조합은 에이전트를 역할별로 나누고, 크루에서 process="sequential"로 순서를 고정한 다음, 조사 결과가 다음 리포트 작업의 context로 들어가게 하는 형태예요. 데이터 파이프라인처럼 '조사 → 분석 → 보고'가 자연스럽게 이어지는 흐름에 잘 맞아요. 다만 계층형 프로세스를 쓸 땐 manager_llm이나 manager_agent가 반드시 필요하다는 점을 꼭 기억하세요 — 이것이 없으면 계층형은 정의 자체가 성립하지 않아요. 또 실무에서는 crewai run이 비대화형 환경(CI 등)에서 placeholder를 물어볼 수 있으니, inputs를 미리 채워두거나 프롬프트 입력을 처리할 방안을 확인해야 해요. 크루 단위로 max_rpm을 걸어 비용과 속도 제한을 관리하는 것과, 장기 실행이면 checkpoint를 켜서 끊겨도 이어서 재개되게 하는 것도 챙기면 좋아요.
더 알아보기¶
- 원문 공식 문서를 직접 보려면: CrewAI Crews 공식 문서