CrewAI

문제를 역할로 본다. 가 그래프라면, 이쪽은 직무 기술서다. 마다 역할·목표·배경을 글로 적고, 를 부여하고, 로 묶는다.


4요소 한눈에

, , , . 이 넷이 거의 전부다.

다이어그램 로딩…
요소책임
Agent역할·목표·백스토리·도구를 가진 LLM 워커
Task한 단위 작업. 설명 + 기대 결과 + 담당 Agent
ProcessTask 실행 흐름 (sequential / hierarchical)
Crew위 셋을 묶은 실행 단위

Agent — 역할 카드

는 시스템 프롬프트 대신 세 가지 자연어 필드로 정의된다. role은 직책, goal은 평가 기준, backstory는 행동 양식을 깐다. 이 셋이 합쳐져 LLM의 페르소나가 된다. 를 자연어로 강제하는 셈이고, 도 같은 필드를 보면 바로 잡힌다. 결과적으로 한 가 한 가지 일만 잘하도록 묶인다.

from crewai import Agent

researcher = Agent(
  role="시니어 데이터 리서처",
  goal="주제에 대한 최신 동향을 신뢰 가능한 출처로 정리한다",
  backstory=(
      "당신은 10년 차 리서처다. 출처 없는 주장은 절대 쓰지 않으며, "
      "발견한 사실을 짧고 단정한 문장으로 옮기는 데 능하다."
  ),
  verbose=True,
)

Task — 일감의 단위

에 붙어 다닌다. description은 무엇을, expected_output은 결과 형태를, agent는 누가를 정한다. 된 Agent가 단일 책임의 Task를 받는 구도다.

expected_output은 단순한 한 줄이 아니라 형식 명세다. “1500자 이내, 단락 3개, 마지막에 출처” 같은 식. 이게 명확하면 후속 의 입력이 안정된다.

from crewai import Task

research = Task(
  description="주제 {topic}에 대해 최근 12개월 동향을 조사한다.",
  expected_output="800~1200자 마크다운. 단락 3개. 끝에 출처 URL 목록.",
  agent=researcher,
)

Process — 실행 흐름

는 두 모드뿐이다. 리스트를 위에서 아래로 줄 세워 실행하고, 앞선 Task 출력이 다음 Task 컨텍스트로 흘러간다.

은 위에 가 생기고, 그 매니저가 워커들을 어느 순서로 부를지 LLM이 직접 정한다. 의 CrewAI 버전이다.

다이어그램 로딩…

sequential Crew

가장 흔한 사용법이다. · 리스트를 만들고 Process.sequential로 묶으면 끝. 앞 의 출력이 그대로 다음 입력에 합쳐진다.

from crewai import Crew, Process

crew = Crew(
  agents=[researcher, writer],
  tasks=[research, write],
  process=Process.sequential,
  verbose=True,
)

result = crew.kickoff(inputs={"topic": "A2A 프로토콜"})
print(result)

hierarchical Crew

모드는 Process.hierarchical을 주고 manager_llm을 같이 넘긴다. CrewAI가 임시 를 자동 생성해 워커들을 디스패치한다.

직접 만든 매니저 를 쓰고 싶으면 manager_agent=...로 주입한다. 11장의 흐름이 그대로 살아 있다.

from crewai import Crew, Process
from crewai.llm import LLM

crew = Crew(
  agents=[researcher, writer, fact_checker],
  tasks=[research, write, verify],
  process=Process.hierarchical,
  manager_llm=LLM(model="claude-sonnet-4-5"),
  verbose=True,
)

result = crew.kickoff(inputs={"topic": "A2A 프로토콜"})

CrewAI Tool

가 호출할 수 있는 함수 단위다. 두 가지 길이 있다. crewai_tools기성품 (SerperDevTool, FileReadTool 등)을 갖다 쓰는 길과, BaseTool을 상속해 커스텀을 짜는 길이다. 결과는 자동으로 다음 LLM 호출에 합쳐진다.

from crewai.tools import BaseTool
from crewai_tools import SerperDevTool

class WordCountTool(BaseTool):
  name: str = "word_count"
  description: str = "텍스트의 단어 수를 센다."

  def _run(self, text: str) -> int:
      return len(text.split())

researcher = Agent(
  role="리서처",
  goal="...",
  backstory="...",
  tools=[SerperDevTool(), WordCountTool()],
)

메모리 — Crew의 기억

단위로 켜는 RAG 보조 메모리다. memory=True 한 줄이면 단기·장기·엔터티 메모리가 자동으로 붙는다. 는 디스크 RAG, 단기는 컨텍스트 윈도 보강용이다. 22장의 주제와 직접 연결된다.

from crewai import Crew, Process

crew = Crew(
  agents=[researcher, writer],
  tasks=[research, write],
  process=Process.sequential,
  memory=True,  # 단기 + 장기 + 엔터티 메모리 일괄 활성화
  embedder={
      "provider": "openai",
      "config": {"model": "text-embedding-3-small"},
  },
)

sequential vs hierarchical 언제 무엇


YAML 구성 — 코드 밖으로

· 정의를 YAML로 빼두면 비개발자도 역할 카피를 수정할 수 있다. CrewBase 데코레이터와 함께 표준 디렉터리 구조(config/agents.yaml, config/tasks.yaml)를 따른다. 정의만 코드에 남는다.

# config/agents.yaml
researcher:
role: 시니어 데이터 리서처
goal: 주제 동향을 출처와 함께 정리
backstory: 10년 차 리서처…
# config/tasks.yaml
research:
description: "주제 {topic}에 대해…"
expected_output: "800~1200자 마크다운…"
agent: researcher

# crew.py — 코드에선 글루만
from crewai.project import CrewBase, agent, task, crew

@CrewBase
class ResearchCrew:
  @agent
  def researcher(self): return Agent(config=self.agents_config["researcher"])
  @task
  def research(self): return Task(config=self.tasks_config["research"])
  @crew
  def crew(self): return Crew(agents=self.agents, tasks=self.tasks)

운영 체크리스트

도입 전 점검:

이 다섯이 통과되면 멀티 운영의 기본은 잡힌다.


다음 장으로

역할 중심 협업의 다른 축, 대화 중심 v0.4. 같은 문제를 메시지 흐름으로 풀어내는 모델로 19장에서 만난다. 의 역할 카드가 그쪽에선 대화 참여자로 모습이 바뀐다.