Featured Post

CrewAI 멀티에이전트로 개발 리서치 자동화해보니, 혼자 쓰는 LLM과 완전히 달랐던 지점들

CrewAI - 멀티에이전트 관련 이미지

요즘 주변 개발자들이 “LLM은 다 좋은데, 실무에 붙이면 어디까지 믿어야 할지 모르겠다”는 이야기를 참 많이 하더라고요. 저도 비슷했습니다. ChatGPT 창 하나 켜놓고 코드 리뷰도 시키고, 문서 요약도 시키고, 장애 로그도 던져봤는데요. 어느 순간부터는 한 명의 똑똑한 인턴에게 모든 일을 몰아주는 느낌이 들었습니다. 리서치도 하고, 판단도 하고, 글도 쓰고, 검증도 하고. 솔직히 사람한테 그렇게 시키면 사고 나잖아요. 그래서 주말에 시간을 내서 CrewAI 멀티에이전트를 실제 개발 업무에 가까운 형태로 붙여봤습니다. 제가 만든 건 거창한 서비스는 아니고, “이번 주에 우리 팀이 검토할 만한 GitHub 오픈소스와 기술 이슈를 찾아서 보고서로 정리하는 자동화 도구”였습니다.

이 글은 CrewAI 개념 설명서라기보다는, 제가 직접 삽질하면서 얻은 경험담에 가깝습니다. 어디서 막혔는지, 어떤 구조로 폴더를 잡았는지, 에이전트를 몇 개로 나눠야 그나마 덜 헛소리하는지, 그리고 바이브 코딩으로 만들 때 프롬프트를 어떻게 던지면 좋은지까지 같이 적어볼게요. 공식 문서만 보고는 잘 안 보이는 부분들이 꽤 있었습니다.

CrewAI 멀티에이전트를 써본 이유: LLM 하나로는 역할 분리가 너무 흐릿했다

제가 처음에 하려던 일은 단순했습니다. “이번 주 백엔드 팀에서 볼 만한 기술 트렌드를 정리해줘.” 그냥 LLM 하나에 시키면 결과는 빠르게 나옵니다. 그런데 문제는 항상 비슷했습니다.

    • 자료 출처가 흐릿하거나, 실제로는 존재하지 않는 링크를 섞는다.
    • 기술적으로 중요한 내용보다 그럴듯한 마케팅 문장을 우선한다.
    • 요약은 잘하는데, 개발팀에서 바로 액션으로 옮길 수 있는 형태가 아니다.
    • 검증 단계가 없다 보니 “좋아 보이는 말”과 “쓸 수 있는 정보”가 뒤섞인다.

그래서 역할을 나눠봤습니다. 사람 팀처럼요. 한 명은 자료를 찾고, 한 명은 기술적으로 평가하고, 한 명은 보고서로 정리하고, 한 명은 최종 검수만 담당하게 했습니다. 이게 바로 CrewAI 멀티에이전트를 써보고 싶었던 가장 큰 이유였습니다.

방식 장점 제가 겪은 문제 어울리는 작업
단일 LLM 프롬프트 빠르고 단순하다 검증과 작성이 섞이면서 결과가 흐려진다 짧은 요약, 코드 스니펫 생성, 아이디어 초안
CrewAI 멀티에이전트 역할 분리와 단계별 검증이 가능하다 설계가 허술하면 비용과 시간이 늘어난다 리서치, 비교 분석, 보고서 생성, 반복 업무 자동화
직접 파이프라인 구현 제어권이 가장 높다 프롬프트, 상태 관리, 재시도 로직을 다 직접 짜야 한다 운영 서비스, 엄격한 워크플로우, 사내 자동화 플랫폼

제 느낌으로는 CrewAI는 “LLM을 팀처럼 굴려보고 싶은데, 아직 완전한 자체 오케스트레이션 프레임워크를 만들기는 부담스러운 상황”에 딱 맞았습니다. 마치 여행 갈 때 혼자 모든 예약, 동선, 맛집, 교통편을 다 챙기다가 어느 순간 “아, 역할 나누면 훨씬 편하겠는데?” 싶어지는 그런 감각과 비슷했습니다. 다만 여기서 중요한 건 에이전트를 많이 만든다고 똑똑해지는 게 아니라는 점입니다. 오히려 너무 많이 만들면 회의만 길어지는 조직처럼 됩니다.

제가 만든 예제: 개발팀 주간 기술 리서치 보고서 자동화

실제로 구성한 예제는 아래 흐름이었습니다. 입력으로 관심 키워드를 넣으면, CrewAI가 GitHub 저장소와 기술 이슈 후보를 조사하고, 기술 평가를 한 뒤, Markdown 보고서를 만들어주는 구조입니다. 저는 “Python”, “LLM API”, “RAG”, “FastAPI”, “observability” 같은 키워드를 넣어서 테스트했습니다.

작업 흐름

    • Researcher Agent: GitHub API와 검색 결과를 바탕으로 후보 프로젝트를 수집한다.
    • Tech Analyst Agent: star 수, 최근 commit, issue 상태, 문서 품질을 보고 실무 도입 가능성을 평가한다.
    • Risk Reviewer Agent: 라이선스, 유지보수 리스크, 과장된 설명을 잡아낸다.
    • Report Writer Agent: 개발팀 회의에서 바로 볼 수 있는 형태로 보고서를 작성한다.

처음에는 에이전트를 7개나 만들었습니다. 트렌드 분석가, 코드 분석가, 보안 분석가, 라이선스 분석가, 문서 작성가, 편집자, 최종 승인자. 그런데 실제로 돌려보니 비용은 늘고, 답변은 장황해졌습니다. 서로 비슷한 말을 반복하는 느낌이 강했어요. 제가 느낀 적정선은 3개에서 4개였습니다. 특히 개인 프로젝트나 작은 팀 자동화라면 4개를 넘기지 않는 편이 좋았습니다.

프로젝트 폴더 구조

저는 CrewAI 프로젝트를 아래처럼 구성했습니다. 설정과 실행 코드를 분리하는 게 나중에 프롬프트 튜닝할 때 훨씬 편했습니다. 특히 agents.yaml과 tasks.yaml을 따로 두면, 개발자가 아닌 팀원도 어느 정도 문구 수정이 가능하더라고요.

crewai-tech-radar/
├── README.md
├── pyproject.toml
├── .env
├── reports/
│   └── weekly_tech_report.md
├── src/
│   └── tech_radar/
│       ├── __init__.py
│       ├── main.py
│       ├── crew.py
│       ├── config/
│       │   ├── agents.yaml
│       │   └── tasks.yaml
│       └── tools/
│           ├── __init__.py
│           └── github_repo_search_tool.py
└── tests/
    └── test_report_flow.py

여기서 핵심은 tools 폴더였습니다. LLM에게 웹 전체를 자유롭게 보게 하는 방식은 편하지만, 재현성이 떨어졌습니다. 그래서 저는 GitHub API처럼 결과 구조가 어느 정도 정해져 있는 도구부터 붙였습니다. “검색은 넓게, 판단은 좁게”가 아니라 “검색부터 어느 정도 통제하고, 판단도 기준을 명확히” 하는 쪽이 실무에서는 훨씬 마음이 편했습니다.

핵심 코드: CrewAI 에이전트와 태스크를 분리해서 관리하기

아래는 제가 테스트한 형태를 조금 정리한 예제입니다. 버전마다 CrewAI 문법이 조금씩 달라질 수 있어서, 실제 프로젝트에서는 설치한 CrewAI 버전에 맞춰 공식 문서와 함께 확인하셔야 합니다. 그래도 구조를 이해하는 데는 충분할 겁니다.

환경 변수 설정

OPENAI_API_KEY=sk-your-key
OPENAI_MODEL_NAME=gpt-4o-mini
GITHUB_API_URL=https://api.github.com/search/repositories

저는 비용 때문에 처음부터 고급 모델을 쓰지 않았습니다. 초안 수집과 정리에는 가벼운 모델을 쓰고, 최종 검수에만 더 좋은 모델을 붙이는 방식이 운영비 면에서 낫습니다. CrewAI에서 모든 에이전트에 같은 모델을 붙이면 편하긴 한데, 비용이 은근히 빨리 올라갑니다.

agents.yaml 예시

researcher:
  role: "오픈소스 기술 리서처"
  goal: "입력된 키워드와 관련된 GitHub 프로젝트 후보를 수집하고, 실무 검토 가치가 있는 항목을 추려낸다."
  backstory: >
    당신은 백엔드 개발팀에서 기술 탐색을 담당하는 시니어 개발자입니다.
    단순히 star 수가 높은 프로젝트보다 최근 활동성, 문서 품질, 실무 적용 가능성을 중요하게 봅니다.
  verbose: true
  allow_delegation: false

tech_analyst:
  role: "기술 도입 분석가"
  goal: "후보 프로젝트의 장점, 약점, 도입 난이도, 팀 적용 가능성을 평가한다."
  backstory: >
    당신은 실제 운영 환경에서 라이브러리를 도입해본 경험이 많은 개발자입니다.
    과장된 장점보다 유지보수 리스크와 장애 가능성을 더 신중하게 봅니다.
  verbose: true
  allow_delegation: false

risk_reviewer:
  role: "리스크 검토자"
  goal: "라이선스, 유지보수 중단 가능성, 보안 리스크, 근거 부족한 주장을 찾아낸다."
  backstory: >
    당신은 기술 검토 회의에서 늘 불편한 질문을 던지는 리뷰어입니다.
    보고서에 출처가 없거나 검증이 약한 문장이 있으면 반드시 지적합니다.
  verbose: true
  allow_delegation: false

report_writer:
  role: "개발팀 보고서 작성자"
  goal: "리서치와 분석 내용을 바탕으로 회의에서 바로 읽을 수 있는 보고서를 작성한다."
  backstory: >
    당신은 개발팀 리드에게 전달할 주간 기술 보고서를 작성합니다.
    짧고 명확하게 쓰되, 도입 판단에 필요한 근거는 빠뜨리지 않습니다.
  verbose: true
  allow_delegation: false

tasks.yaml 예시

research_task:
  description: >
    키워드 "{topic}"와 관련된 GitHub 오픈소스 프로젝트를 조사하세요.
    최소 5개 후보를 찾고, 각 후보에 대해 저장소 이름, 설명, star 수, 최근 업데이트 여부,
    주요 사용 사례를 정리하세요.
  expected_output: >
    후보 프로젝트 목록.
    각 항목은 name, url, stars, last_updated, why_it_matters 필드를 포함해야 합니다.
  agent: researcher

analysis_task:
  description: >
    research_task 결과를 바탕으로 실무 도입 가능성을 평가하세요.
    평가 기준은 문서 품질, API 안정성, 커뮤니티 활동성, 운영 환경 적용 난이도입니다.
  expected_output: >
    프로젝트별 점수와 도입 추천 여부.
    추천, 보류, 제외 중 하나로 분류하고 이유를 작성하세요.
  agent: tech_analyst

risk_review_task:
  description: >
    analysis_task 결과에서 근거가 부족한 주장, 라이선스 확인 필요 항목,
    유지보수 리스크, 보안 리스크를 찾아 지적하세요.
  expected_output: >
    리스크 체크리스트와 수정 권고안.
  agent: risk_reviewer

report_task:
  description: >
    앞선 결과를 바탕으로 개발팀 주간 기술 리서치 보고서를 작성하세요.
    보고서는 한글로 작성하고, 회의에서 5분 안에 읽을 수 있게 구성하세요.
  expected_output: >
    Markdown 형식의 주간 기술 리서치 보고서.
    추천 프로젝트 3개, 보류 프로젝트, 리스크 메모, 다음 액션을 포함하세요.
  agent: report_writer

여기서 제가 꽤 중요하게 본 부분은 expected_output입니다. 대충 “잘 정리해줘”라고 하면 정말 대충 잘 정리합니다. 사람이 보기엔 그럴듯하지만, 다음 단계 에이전트가 받기에는 애매한 결과가 나옵니다. 필드명을 정해주고, 분류 기준을 정해주고, 최종 보고서에서 필요한 항목을 미리 박아두면 품질이 확 올라갑니다.

GitHub 검색 도구 예시

import os
import requests
from crewai.tools import BaseTool
from pydantic import BaseModel, Field


class GitHubRepoSearchInput(BaseModel):
    query: str = Field(..., description="검색할 GitHub 저장소 키워드")
    limit: int = Field(default=5, description="가져올 저장소 개수")


class GitHubRepoSearchTool(BaseTool):
    name: str = "GitHub Repository Search Tool"
    description: str = "GitHub 저장소를 검색하고 star 수, 설명, 업데이트 날짜를 반환합니다."
    args_schema: type[BaseModel] = GitHubRepoSearchInput

    def _run(self, query: str, limit: int = 5) -> str:
        api_url = os.getenv("GITHUB_API_URL", "https://api.github.com/search/repositories")

        params = {
            "q": query,
            "sort": "stars",
            "order": "desc",
            "per_page": limit
        }

        response = requests.get(api_url, params=params, timeout=10)
        response.raise_for_status()

        items = response.json().get("items", [])

        results = []
        for item in items:
            results.append({
                "name": item.get("full_name"),
                "url": item.get("html_url"),
                "description": item.get("description"),
                "stars": item.get("stargazers_count"),
                "last_updated": item.get("updated_at"),
                "language": item.get("language"),
                "open_issues": item.get("open_issues_count")
            })

        return str(results)

이 도구를 붙이고 나서 결과가 꽤 안정됐습니다. LLM이 “아마 이런 저장소가 있을 것”이라고 상상하는 게 아니라, 실제 API 응답을 기반으로 말하게 되니까요. 다만 GitHub API는 인증 없이 쓰면 rate limit이 낮습니다. 팀에서 자주 돌릴 거라면 GitHub token을 붙이는 쪽이 좋습니다.

Crew 구성 코드

from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task

from tech_radar.tools.github_repo_search_tool import GitHubRepoSearchTool


@CrewBase
class TechRadarCrew:
    agents_config = "config/agents.yaml"
    tasks_config = "config/tasks.yaml"

    @agent
    def researcher(self) -> Agent:
        return Agent(
            config=self.agents_config["researcher"],
            tools=[GitHubRepoSearchTool()]
        )

    @agent
    def tech_analyst(self) -> Agent:
        return Agent(
            config=self.agents_config["tech_analyst"]
        )

    @agent
    def risk_reviewer(self) -> Agent:
        return Agent(
            config=self.agents_config["risk_reviewer"]
        )

    @agent
    def report_writer(self) -> Agent:
        return Agent(
            config=self.agents_config["report_writer"]
        )

    @task
    def research_task(self) -> Task:
        return Task(
            config=self.tasks_config["research_task"]
        )

    @task
    def analysis_task(self) -> Task:
        return Task(
            config=self.tasks_config["analysis_task"]
        )

    @task
    def risk_review_task(self) -> Task:
        return Task(
            config=self.tasks_config["risk_review_task"]
        )

    @task
    def report_task(self) -> Task:
        return Task(
            config=self.tasks_config["report_task"],
            output_file="reports/weekly_tech_report.md"
        )

    @crew
    def crew(self) -> Crew:
        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential,
            verbose=True
        )

실행 코드

from tech_radar.crew import TechRadarCrew


def run():
    inputs = {
        "topic": "LLM observability Python"
    }

    result = TechRadarCrew().crew().kickoff(inputs=inputs)
    print(result)


if __name__ == "__main__":
    run()

저는 처음에 Process를 hierarchical로 두고 매니저 에이전트를 붙여봤는데, 작은 작업에서는 오히려 과했습니다. 순서가 명확한 리서치 자동화는 Process.sequential이 훨씬 예측 가능했습니다. CrewAI 멀티에이전트라고 해서 꼭 복잡한 조직도를 만들 필요는 없습니다. 단순한 파이프라인부터 시작하는 게 좋습니다.

실제로 돌려보며 만난 에러와 해결 방법

공식 예제만 보면 금방 될 것 같지만, 막상 붙이면 자잘한 에러가 꽤 나옵니다. 특히 CrewAI는 LLM, tool, 환경 변수, 외부 API가 같이 움직이다 보니 에러 원인이 한 군데가 아닐 때가 많았습니다.

도구 타입 오류: BaseTool 형태가 맞지 않을 때

ValidationError: 1 validation error for Agent
tools.0
  Input should be a valid dictionary or instance of BaseTool

이 에러는 제가 LangChain에서 쓰던 tool 스타일을 그대로 가져오면서 만났습니다. CrewAI에서 기대하는 BaseTool 형태와 맞지 않았던 거죠. 해결은 단순했습니다. CrewAI의 BaseTool을 상속하고, args_schema와 _run 메서드를 명확히 정의했습니다.

문제 상황 원인 해결
Agent 생성 시 tools validation 실패 CrewAI BaseTool 형식이 아님 crewai.tools.BaseTool 상속 구조로 변경
tool input이 엉뚱하게 들어감 args_schema 설명이 모호함 Pydantic Field description을 구체적으로 작성
검색 결과가 너무 많거나 없음 query를 LLM이 과하게 확장함 query 생성 규칙을 task description에 제한

API 키 오류: 모델 설정은 늘 먼저 확인하기

litellm.AuthenticationError: AuthenticationError: OpenAIException - The api_key client option must be set

이건 민망하지만 자주 납니다. .env 파일은 만들었는데 로딩이 안 됐거나, 실행 위치가 달라서 환경 변수를 못 읽는 경우였습니다. 저는 main.py 시작 지점에서 dotenv를 명시적으로 불러오게 했습니다.

from dotenv import load_dotenv

load_dotenv()

그리고 운영 환경에서는 .env 파일에 의존하지 않고 GitHub Actions Secrets나 서버 환경 변수로 주입하는 게 안전합니다. 특히 CrewAI 로그를 verbose로 켜두면 프롬프트와 중간 출력이 많이 남기 때문에, 민감 정보가 프롬프트에 섞이지 않도록 조심해야 합니다.

환각 문제: “출처가 있는 척”하는 문장을 잡아내기

제가 가장 신경 쓴 건 환각이었습니다. 리서치 보고서에서 없는 사실을 있는 것처럼 쓰면, 자동화 안 하느니만 못합니다. 그래서 Risk Reviewer Agent에게 아래 같은 문장을 강하게 넣었습니다.

출처 URL이 없는 구체적 수치나 사실은 보고서에 확정적으로 쓰지 마세요.
GitHub API 결과에 없는 내용은 "추정" 또는 "추가 확인 필요"로 표시하세요.
프로젝트가 production-ready라고 주장하려면 최근 업데이트, issue 상태, 문서 품질 중 최소 2개 근거를 함께 제시하세요.

이 한 줄 차이가 꽤 컸습니다. LLM은 자신감 있게 말하는 경향이 있기 때문에, “모르면 모른다고 표시하라”는 규칙을 역할에 심어줘야 합니다. 그냥 “정확하게 작성해줘”는 약합니다. “어떤 경우에 확정적으로 말하면 안 되는지”를 써줘야 실제 결과가 좋아졌습니다.

적용 전후 비교: 단일 프롬프트보다 나아진 점과 여전히 불편한 점

같은 키워드로 단일 LLM 프롬프트와 CrewAI 멀티에이전트를 비교해봤습니다. 물론 모델, 프롬프트, 도구에 따라 결과는 달라집니다. 그래도 제 테스트에서는 차이가 꽤 분명했습니다.

항목 단일 LLM CrewAI 멀티에이전트
속도 빠름. 10~30초 내 결과 느림. 태스크 수에 따라 1~3분 이상
비용 낮음 에이전트와 태스크 수만큼 증가
결과 구조 프롬프트 품질에 크게 의존 태스크별 출력 형식을 고정하기 쉬움
검증 한 번에 같이 시키면 흐려짐 Reviewer 역할을 따로 두면 개선됨
디버깅 어디서 틀렸는지 추적이 어려움 어느 task에서 품질이 깨졌는지 보기 쉬움
실무 적합성 개인 보조 도구에 적합 반복 리포트, 검토 파이프라인에 적합

좋았던 점은 “중간 결과를 볼 수 있다”는 겁니다. 단일 프롬프트에서는 최종 답변이 이상하면 전체를 다시 고쳐야 했습니다. CrewAI는 Researcher 결과는 괜찮은데 Analyst가 과하게 판단한다든지, Report Writer가 너무 미사여구를 넣는다든지, 문제가 생긴 위치가 보입니다. 이건 개발자 입장에서 꽤 큰 장점입니다. 로그 보고 병목 찾는 느낌이랑 비슷합니다.

불편했던 점도 있습니다. 에이전트가 많아지면 토큰 비용이 늘고, 속도도 느려집니다. 또 각 에이전트가 이전 결과를 잘못 해석하면 뒤 단계까지 오류가 전파됩니다. 멀티에이전트라고 해서 자동으로 더 정확해지는 건 아니었습니다. 역할, 입력, 출력, 검증 기준이 명확할 때만 좋아집니다.

비용과 운영 감각: 작은 자동화도 토큰 예산을 잡아야 한다

개인 테스트에서는 비용이 크게 부담되지 않았지만, 팀 단위로 매일 돌리면 이야기가 달라집니다. 특히 리서치형 작업은 입력보다 출력이 길어지는 경우가 많고, 에이전트가 여러 명이면 중간 결과도 계속 토큰으로 소비됩니다.

운영 방식 대략적인 특징 추천 상황
저비용 모델만 사용 빠르고 싸지만 분석 깊이가 얕을 수 있음 초안 생성, 후보 수집
고급 모델만 사용 품질은 좋지만 비용 증가가 빠름 중요한 의사결정 보고서
역할별 모델 분리 수집은 저비용, 검토는 고품질 모델로 분리 실무 자동화에 가장 현실적
캐시 사용 동일 키워드 반복 실행 비용 감소 주간 리포트, 정기 분석

제 기준에서는 아래처럼 나누는 게 좋았습니다.

    • Researcher: 저비용 모델 사용. 어차피 tool 결과를 정리하는 역할이 큼.
    • Tech Analyst: 중간급 이상 모델 사용. 판단 기준이 중요함.
    • Risk Reviewer: 가능하면 더 좋은 모델 사용. 환각과 과장 표현을 잡아야 함.
    • Report Writer: 저비용 또는 중간급 모델 사용. 형식이 정해져 있으면 크게 어렵지 않음.

실제 가격은 모델 제공사 정책에 따라 자주 바뀌니, 운영 전에 반드시 최신 요금표를 확인해야 합니다. 다만 개발팀 내부 자동화라면 “한 번 실행에 얼마인가”보다 “하루에 몇 번 자동 실행되는가”를 먼저 계산하는 게 더 현실적입니다. 크론으로 매시간 돌려놓으면 작은 비용도 금방 쌓입니다.

바이브 코딩으로 CrewAI 만들 때 잘 먹혔던 프롬프트 꿀팁

요즘 바이브 코딩으로 빠르게 프로토타입 만드는 분들 많죠. 저도 처음 뼈대는 AI에게 시켰습니다. 그런데 “CrewAI로 멀티에이전트 만들어줘”라고만 하면 너무 일반적인 예제 코드가 나옵니다. 실제로 돌아가게 만들려면 프롬프트를 훨씬 구체적으로 던져야 했습니다.

제가 실제로 쓴 프롬프트 형태

나는 Python 개발자이고 CrewAI로 개발팀 주간 기술 리서치 자동화 도구를 만들고 싶다.

요구사항:
1. GitHub Repository Search Tool을 직접 구현한다.
2. 에이전트는 researcher, tech_analyst, risk_reviewer, report_writer 4개만 둔다.
3. agents.yaml과 tasks.yaml을 분리한다.
4. 최종 결과는 reports/weekly_tech_report.md로 저장한다.
5. 모든 task의 expected_output을 구조화한다.
6. Process는 sequential로 둔다.
7. 실행 가능한 폴더 구조와 전체 코드를 제시한다.

주의사항:
  • 가짜 import를 만들지 마라.
  • CrewAI 버전 차이로 의심되는 부분은 주석으로 표시해라.
  • API 키는 코드에 하드코딩하지 말고 .env를 사용해라.
  • tool input은 Pydantic schema로 정의해라.
  • 결과가 없을 때의 예외 처리도 넣어라.

여기서 핵심은 “가짜 import를 만들지 마라”였습니다. AI 코딩 도구들이 종종 그럴듯한 패키지명이나 클래스를 만들어냅니다. 특히 LLM 프레임워크는 버전 변화가 빠르다 보니, 예전 문법과 최신 문법이 섞이는 일이 잦았습니다. 저는 아예 프롬프트에 “불확실한 부분은 확정적으로 쓰지 말고 주석으로 표시해라”라고 넣었습니다.

바이브 코딩 체크리스트

    • 처음부터 에이전트를 5개 이상 만들지 않는다.
    • 각 에이전트의 역할을 한 문장으로 설명할 수 있어야 한다.
    • 각 task의 expected_output에 필드명이나 형식을 넣는다.
    • 외부 API tool은 먼저 단독 테스트하고 CrewAI에 붙인다.
    • verbose 로그를 켜고, 어느 단계에서 결과가 깨지는지 확인한다.
    • 프롬프트에는 “하지 말아야 할 것”을 꼭 넣는다.
    • 최종 보고서에 출처 없는 수치가 들어가면 실패로 본다.

뭐랄까, CrewAI 바이브 코딩은 “코드를 대신 짜줘”보다 “작은 팀의 업무 프로세스를 설계해줘”에 가깝습니다. 프롬프트를 코드 중심으로만 던지면 껍데기는 빨리 나오는데, 결과 품질은 애매합니다. 반대로 역할, 책임, 실패 기준, 출력 형식을 같이 주면 훨씬 실무적인 코드가 나옵니다.

실무 적용 시 주의할 부작용: 멀티에이전트는 만능이 아니다

CrewAI 멀티에이전트를 써보며 가장 크게 느낀 건, 이 방식이 꽤 매력적이지만 동시에 관리 포인트도 많다는 겁니다. 자동화가 잘 되면 정말 편합니다. 그런데 설계가 어설프면 “LLM 여러 명이 돌아가며 애매한 말을 하는 시스템”이 됩니다.

에이전트가 서로의 실수를 증폭할 수 있다

Researcher가 잘못된 후보를 가져오면 Analyst는 그 후보를 진지하게 분석합니다. Risk Reviewer가 강하게 잡아주지 않으면 Report Writer는 예쁘게 포장합니다. 그래서 저는 최종 보고서 앞에 항상 “검증 상태”를 넣었습니다.

검증 상태:
  • GitHub API로 확인된 정보: 저장소명, URL, star 수, 최근 업데이트 날짜
  • 추가 확인이 필요한 정보: 실제 production 사용 사례, 보안 이슈, 라이선스 세부 조건
  • 보고서에서 제외한 정보: 출처 없는 성능 수치, 확인되지 않은 기업 도입 사례

이걸 넣으면 보고서를 읽는 사람도 어느 정도 안전장치를 갖고 볼 수 있습니다. 자동화 결과를 사람이 최종 판단하는 구조로 둬야 합니다. 저는 아직 LLM 리서치 결과를 바로 의사결정에 쓰는 건 위험하다고 봅니다.

프롬프트가 길어지면 유지보수가 어려워진다

처음엔 agents.yaml에 이것저것 다 넣고 싶어집니다. “정확하게 해라”, “간결하게 해라”, “실무적으로 해라”, “출처를 확인해라”, “리스크를 봐라” 같은 문장이 계속 붙습니다. 그런데 프롬프트가 길어질수록 나중에 어떤 문장이 효과가 있었는지 알기 어려워집니다.

저는 프롬프트도 코드처럼 관리하기로 했습니다. 한 번에 여러 문장을 바꾸지 않고, 변경 전후 보고서를 비교했습니다. 특히 아래 세 가지는 별도로 기록해두면 좋았습니다.

    • 변경한 프롬프트 문장
    • 바뀐 출력 품질
    • 나빠진 부작용

예를 들어 “비판적으로 검토하라”는 문장을 강하게 넣었더니, 추천할 만한 프로젝트까지 전부 보류로 분류하는 문제가 생겼습니다. 그래서 “명확한 근거가 있는 경우 추천을 유지하되, 리스크를 함께 적어라”로 바꿨습니다. 작은 문장 하나가 결과 톤을 많이 바꿉니다.

도구 호출 비용과 속도를 무시하면 안 된다

LLM 호출만 비용이 아닙니다. 외부 API가 느리거나 rate limit에 걸리면 전체 Crew 실행이 지연됩니다. 저는 GitHub API 호출에 timeout을 꼭 넣었고, 실패 시 빈 결과를 반환하지 않고 에러 메시지를 명확히 남기게 했습니다.

try:
    response = requests.get(api_url, params=params, timeout=10)
    response.raise_for_status()
except requests.Timeout:
    return "GitHub API 요청 시간이 초과되었습니다. 검색 키워드를 줄이거나 나중에 다시 시도하세요."
except requests.HTTPError as error:
    return f"GitHub API HTTP 오류가 발생했습니다: {str(error)}"
except requests.RequestException as error:
    return f"GitHub API 요청 중 알 수 없는 오류가 발생했습니다: {str(error)}"

이 처리를 안 해두면 에이전트가 빈 결과를 보고도 뭔가를 상상해서 써버릴 수 있습니다. 실패는 실패라고 알려줘야 합니다. 사람에게도 그렇고, LLM에게도 그렇습니다.

CrewAI 멀티에이전트를 어디에 쓰면 좋을까

제가 써본 느낌으로는 CrewAI는 “한 번 물어보고 끝나는 질문”보다는 “여러 단계를 거쳐야 하는 지식 작업”에 잘 맞았습니다. 개발자 입장에서 쓸 만한 예시는 꽤 많습니다.

사용 사례 에이전트 구성 주의할 점
PR 리뷰 초안 생성 Code Reader, Risk Reviewer, Comment Writer 실제 merge 판단은 사람이 해야 함
장애 로그 분석 Log Parser, Cause Analyst, Action Planner 운영 명령어 자동 실행은 금지하는 게 안전
기술 리서치 보고서 Researcher, Analyst, Reviewer, Writer 출처 검증과 환각 방지 규칙 필수
API 문서 초안 작성 Code Scanner, Spec Writer, Example Generator 실제 코드와 문서 불일치 테스트 필요
테스트 케이스 생성 Requirement Reader, Test Designer, Edge Case Reviewer 생성된 테스트가 의미 있는지 검토해야 함

개인적으로 가장 추천하고 싶은 시작점은 리서치 보고서 자동화입니다. 운영 시스템을 건드리지 않고도 효과를 체감할 수 있고, 실패해도 위험이 낮습니다. 반대로 DB 수정, 배포, 인프라 변경처럼 실제 시스템에 영향을 주는 작업은 바로 자동화하지 않는 게 좋습니다. 읽기 전용 작업부터 시작하세요. 그게 마음도 편하고, 팀 설득도 쉽습니다.

제가 정한 CrewAI 설계 원칙

몇 번 돌려보고 나서 제 나름대로 원칙이 생겼습니다. 이건 정답이라기보다, 40대 개발자로 이런저런 자동화 도구를 만져보며 생긴 방어적인 습관에 가깝습니다.

    • 에이전트 수는 적게 시작한다. 3개로 부족할 때만 늘린다.
    • 역할 이름보다 책임이 중요하다. 멋진 직함보다 입력과 출력이 명확해야 한다.
    • Tool 결과와 LLM 추론을 구분한다. 확인된 사실과 추정은 보고서에서 분리한다.
    • 최종 판단은 사람이 한다. CrewAI는 판단 보조 도구이지 책임자가 아니다.
    • 로그를 남긴다. 결과가 이상할 때 어느 태스크에서 틀어졌는지 봐야 한다.
    • 비용 한도를 정한다. 자동 실행 주기와 모델 비용을 같이 본다.
    • 프롬프트도 버전 관리한다. 품질 개선은 감이 아니라 비교로 해야 한다.

특히 “Tool 결과와 LLM 추론을 구분한다”는 원칙은 정말 중요했습니다. 예를 들어 GitHub API에서 확인된 star 수는 사실에 가깝지만, “이 프로젝트는 대기업에서도 많이 쓴다”는 말은 별도 근거가 필요합니다. 이 둘을 같은 톤으로 쓰면 보고서 신뢰도가 확 떨어집니다.

짧은 후기: CrewAI는 LLM을 팀처럼 다루는 연습에 좋다

CrewAI 멀티에이전트를 써보면서 느낀 건, 이제 개발자의 일이 “프롬프트 하나 잘 쓰기”에서 “LLM이 일하는 구조를 설계하기”로 조금씩 옮겨가고 있다는 점입니다. 예전에는 함수를 어떻게 나눌지, 클래스를 어떻게 분리할지 고민했다면, 이제는 에이전트의 책임과 태스크의 경계를 어떻게 나눌지도 고민하게 됩니다.

이 글은 이런 분들이 읽으면 특히 도움이 될 것 같습니다.

    • ChatGPT나 Claude를 개발 업무에 쓰고 있지만 결과 품질이 들쭉날쭉해서 고민인 개발자
    • LLM을 단순 챗봇이 아니라 반복 업무 자동화에 붙여보고 싶은 분
    • CrewAI 멀티에이전트를 실제 코드 구조로 어떻게 시작할지 감이 안 오는 분
    • 기술 리서치, 보고서 작성, PR 리뷰, 장애 분석 같은 지식 작업을 자동화하고 싶은 팀

솔직히 CrewAI가 모든 걸 해결해주진 않습니다. 그래도 “LLM 하나에게 다 시키는 방식”에서 벗어나, 역할을 나누고 검증 단계를 넣는 감각을 익히기에는 꽤 좋은 도구였습니다. 처음부터 큰 시스템에 붙이기보다, 주간 기술 리포트나 읽기 전용 분석 작업부터 작게 시작해보세요. 잘 설계된 멀티에이전트는 생각보다 든든합니다. 물론, 아직은 옆에서 커피 마시며 지켜보는 사람이 필요하고요.


👨‍💻

작성자: 20년 경력 IT 전문 아키텍트

실무 개발과 아키텍처 설계를 거쳐 현재는 AI 바이브 코딩과 개발 자동화를 연구하고 있습니다. 직접 삽질하며 깨달은 실전 꿀팁과 에러 극복 사례만 투명하게 공유합니다.

댓글