작년 10월, 우리 팀에서 코드 리뷰 자동화 파이프라인을 구축하는 프로젝트를 맡았다. 아이디어는 단순했다 — PR이 열리면 에이전트가 코드를 분석하고, 버그 패턴을 찾고, 문서까지 자동으로 업데이트하는 것. 막상 구현에 들어가니 “어떤 프레임워크를 쓸 것인가”가 예상보다 훨씬 중요한 결정이었다.
그래서 2주 동안 AutoGen 0.4, LangGraph 0.2, CrewAI 0.86을 실제 코드베이스에 순서대로 적용해봤다. 같은 태스크를 세 가지 방식으로 구현하면서 비교한 내용을 여기 정리한다.
AutoGen 0.4: 대화형 멀티에이전트의 강자, 단 마이그레이션 주의
AutoGen은 Microsoft가 만든 프레임워크인데, 0.4 버전에서 아키텍처가 통째로 바뀌었다. 이게 좋은 소식이기도 하고 나쁜 소식이기도 하다.
좋은 소식은: 새 API가 훨씬 깔끔해졌다. 기존 0.2.x에서는 UserProxyAgent와 AssistantAgent 사이의 대화 루프 관리가 약간 마법처럼 돌아가는 느낌이었다. 0.4에서는 AgentRuntime이라는 개념이 도입되면서 에이전트들이 메시지를 주고받는 방식이 훨씬 명시적이 됐다.
나쁜 소식은: 0.2.x로 작성된 코드가 거의 다 안 돌아간다. GitHub에 autogen-core 관련 이슈들을 보면 마이그레이션 때문에 고생한 사람들 이야기가 즐비하다. 나도 처음에 0.2.x 기준 튜토리얼을 따라가다가 30분을 날렸다. 검색해서 나오는 예제 코드의 절반은 이미 구버전이라고 보면 된다.
AutoGen이 진짜 빛나는 순간은 에이전트들 간의 대화가 핵심인 태스크다. 코드 리뷰 에이전트가 버그를 발견하고, 다른 에이전트가 수정 제안을 하고, 또 다른 에이전트가 그 수정이 기존 로직을 깨지 않는지 검증하는 — 이런 멀티턴 대화 패턴에서 AutoGen은 여전히 가장 자연스럽다.
다만, 워크플로우가 “에이전트 간 대화”보다 “순차적 파이프라인”에 가까울수록 AutoGen은 어색해진다. 내 케이스에서 “PR 분석 → 버그 탐지 → 문서 생성” 같은 흐름을 AutoGen으로 구현하니 억지스러운 느낌이 났다. 에이전트들이 대화하는 척 하면서 실제로는 순서대로 처리하는 구조가 됐는데, 굳이 이렇게 써야 하나 싶었다.
LangGraph: 복잡한 워크플로우의 현실적인 선택지
LangGraph는 LangChain 팀이 만든 그래프 기반 워크플로우 프레임워크다. 에이전트 로직을 노드(node)와 엣지(edge)로 표현하는 방식인데, 처음엔 “굳이 이렇게 복잡하게 만들어야 하나?” 싶었다. 두 번째 날부터 생각이 바뀌기 시작했다.
특히 조건부 분기가 필요한 경우 — 버그의 심각도에 따라 에이전트가 다른 경로를 타야 할 때 — LangGraph의 conditional_edges는 다른 프레임워크들보다 훨씬 직관적이다.
실제로 내가 구현한 코드 일부:
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
import operator
class ReviewState(TypedDict):
pr_diff: str
bugs_found: list[str]
severity: str # "critical", "warning", "info"
doc_updated: bool
messages: Annotated[list, operator.add] # 메시지는 누적 방식으로 병합
def analyze_code(state: ReviewState):
bugs = run_bug_detector(state["pr_diff"])
# 실제로는 여기서 LLM 호출이 들어간다
severity = "critical" if any(b.is_critical for b in bugs) else "warning"
return {"bugs_found": bugs, "severity": severity}
def route_by_severity(state: ReviewState) -> str:
# 반환값이 엣지 이름이 된다 — 이 패턴이 처음엔 낯설지만 강력하다
if state["severity"] == "critical":
return "block_pr"
return "suggest_changes"
graph = StateGraph(ReviewState)
graph.add_node("analyze", analyze_code)
graph.add_node("block_pr", block_and_notify)
graph.add_node("suggest_changes", suggest_and_update_docs)
graph.set_entry_point("analyze")
graph.add_conditional_edges(
"analyze",
route_by_severity,
{"block_pr": "block_pr", "suggest_changes": "suggest_changes"}
)
graph.add_edge("block_pr", END)
graph.add_edge("suggest_changes", END)
app = graph.compile()
이 패턴의 진짜 장점은 워크플로우가 코드에 명시적으로 드러난다는 점이다. 팀원이 코드를 봤을 때 “에이전트가 어떻게 동작하는지”를 그래프 정의만 보고 파악할 수 있다. 3개월 뒤에 내가 다시 봐도 마찬가지고.
근데 솔직히 말하면, 처음 이틀은 Annotated 타입 시스템이랑 싸웠다. 문서가 버전마다 미묘하게 달라서 혼란스러운 부분이 있다. 특히 checkpointer를 이용한 상태 영속성(persistence) 부분에서 삽질을 좀 했다 — SQLite 체크포인터가 멀티스레드 환경에서 락 문제를 일으키는데, 이게 공식 문서에 잘 안 나와 있다. 프로덕션에 Postgres 체크포인터를 쓸 계획이라면, 로컬에서도 처음부터 Postgres로 테스트하길 추천한다. SQLite로 개발하고 Postgres로 바꾸면 동작이 미묘하게 달라지는 경우가 있었다.
One thing I noticed: LangGraph Studio(시각적 디버깅 도구)가 0.2 이후로 많이 좋아졌다. 그래프를 시각적으로 보면서 각 노드의 상태를 실시간으로 확인할 수 있는데, 복잡한 에이전트 디버깅할 때 정말 유용하다. 이 도구가 있었으면 첫 이틀을 아꼈을 것 같다.
실전 기준: 에이전트가 조건부로 다른 경로를 타야 하거나, 중간 상태를 저장하고 실패 시 재개해야 하는 워크플로우라면 LangGraph다. 초기 설정 비용이 있지만 장기적으로 남는 장사다.
CrewAI: 빠르게 시작하고 싶다면 — 단 함정을 알고 써야 한다
CrewAI는 세 프레임워크 중 가장 빠르게 뭔가 돌아가는 걸 볼 수 있다. 에이전트에게 역할(role)을 부여하는 방식이 직관적이어서, LLM을 처음 다루는 팀원한테 코드를 보여줬더니 설명 없이도 “아, 이게 뭘 하는 건지 알겠어”라고 했다. 이건 진짜 장점이다.
from crewai import Agent, Task, Crew, Process
code_reviewer = Agent(
role="Senior Code Reviewer",
goal="PR에서 잠재적인 버그와 보안 취약점을 찾아내라",
backstory="""
10년 경력의 백엔드 엔지니어. Python 비동기 코드와
SQL 인젝션 패턴에 특히 예민하다.
""",
verbose=True,
allow_delegation=False, # 이걸 True로 두면 아래에서 설명할 문제가 생긴다
llm="claude-sonnet-4-6"
)
doc_writer = Agent(
role="Technical Writer",
goal="코드 변경사항을 반영해서 문서를 업데이트하라",
backstory="개발자가 쓴 기술 내용을 인간이 읽을 수 있게 바꾸는 것이 전문",
verbose=True,
)
review_task = Task(
description="다음 PR diff를 분석하고 문제점을 정리하라: {pr_diff}",
expected_output="버그 목록, 심각도 등급, 수정 제안",
agent=code_reviewer,
)
doc_task = Task(
description="코드 리뷰 결과를 바탕으로 CHANGELOG를 업데이트하라",
expected_output="업데이트된 CHANGELOG 섹션 (Keep a Changelog 형식)",
agent=doc_writer,
context=[review_task], # 이전 태스크 출력을 컨텍스트로 사용
)
crew = Crew(
agents=[code_reviewer, doc_writer],
tasks=[review_task, doc_task],
process=Process.sequential,
)
result = crew.kickoff(inputs={"pr_diff": diff_content})
여기서 내가 제대로 삽질한 부분: 처음에 allow_delegation=True를 켜놨더니, 에이전트가 스스로 판단해서 다른 에이전트한테 서브태스크를 위임하기 시작했다. 때로는 괜찮은 동작이지만, 내 케이스에서는 예상치 못한 LLM 호출이 늘어나면서 비용이 눈에 띄게 불어났다. 하루 테스트 비용이 평소 3배가 나왔다. 프로덕션에서 쓸 거라면 allow_delegation=False를 기본값으로 시작하고, 필요한 에이전트에만 명시적으로 켜는 걸 권장한다.
또 하나: CrewAI의 메모리 시스템(short-term, long-term, entity memory)이 0.80 이후로 많이 개선됐지만, 커스터마이즈하려고 파고들면 문서보다 소스코드를 직접 보는 게 빠를 때가 있다. 내부적으로 Chroma를 쓰는데, 이미 다른 벡터 DB가 인프라에 있다면 교체 작업이 생각보다 번거롭다.
같은 태스크를 세 가지로 구현하고 나서 보이는 것들
디버깅 경험: LangGraph가 단연 좋았다. 상태(State)가 명시적으로 정의돼 있어서 “지금 이 에이전트가 뭘 알고 있는가”를 언제든 확인할 수 있다. AutoGen과 CrewAI는 에이전트 내부 상태가 프레임워크 뒤에 숨어 있어서, 뭔가 잘못됐을 때 원인 추적에 시간이 더 걸렸다.
토큰 비용: CrewAI가 프롬프트를 가장 많이 쓴다. 역할(role), 목표(goal), 배경(backstory)을 모든 LLM 호출에 포함하기 때문이다. AutoGen 0.4는 메시지 관리를 세밀하게 할 수 있어서, 긴 대화에서 컨텍스트 윈도우를 아끼는 전략을 쓰기가 수월하다. 비용 민감한 프로덕션 환경이라면 이 차이가 쌓인다.
에러 복구: LangGraph의 체크포인터 기능이 여기서 빛난다. 에이전트 실행 중간에 실패하면 처음부터 다시 시작하지 않고 마지막 체크포인트에서 재개할 수 있다. 수십 분 돌아가는 워크플로우에서 이건 치명적으로 중요하다. CrewAI도 태스크 단위 재실행을 지원하지만 LangGraph만큼 세밀하지 않다.
팀 온보딩: CrewAI가 압도적으로 쉬웠다. LangGraph는 그래프 사고방식에 익숙해지는 데 시간이 필요하고, AutoGen 0.4는 새 아키텍처 개념(AgentRuntime, MessageContext 등)을 이해해야 제대로 쓸 수 있다.
솔직히 100% 확신할 수 없는 부분도 있다 — 에이전트 수가 10개, 20개로 늘어났을 때 세 프레임워크가 어떻게 다르게 동작하는지는 내가 테스트한 범위를 벗어난다. 대규모 멀티에이전트 시스템을 운영 중이라면 내 결론이 다르게 읽힐 수 있다.
나라면 무엇을 쓸까
“상황에 따라 다르다”는 말은 하지 않겠다. 그건 도움이 안 된다.
처음으로 에이전트 시스템을 만드는 경우: CrewAI로 시작해라. 빠르게 프로토타입 만들고 개념 검증하기에 최적이다. 나중에 더 세밀한 제어가 필요해지면 그때 마이그레이션을 고려하면 된다. 첫 삽부터 LangGraph 배우는 데 시간 쓰지 마라.
프로덕션 레벨의 복잡한 워크플로우, 상태 관리와 에러 복구가 중요한 경우: LangGraph. 초기 설정 비용이 있지만 장기적으로 유지보수와 디버깅이 훨씬 쉽다. 내가 코드 리뷰 파이프라인 최종 구현을 LangGraph로 선택한 이유가 바로 이것이다.
에이전트들이 자유롭게 대화하며 문제를 해결하는 시스템, 특히 연구나 실험 목적: AutoGen. 에이전트 간 대화 패턴이 핵심인 시스템에서 여전히 강점이 있다. 다만 0.4 API는 0.2.x와 완전히 다르니 검색으로 나오는 예제 코드를 무작정 믿지 마라.
마지막으로 하나 더 — 세 프레임워크 모두 아직 빠르게 개발 중이다. 이 글은 2026년 3월 기준이고 몇 달 후면 상황이 또 달라질 수 있다. 프레임워크 선택 전에 GitHub의 최근 커밋과 이슈 트래커를 한 번 훑어보는 습관이 필요하다. 그리고 어떤 프레임워크를 쓰든, 에이전트 동작의 80%는 프롬프트와 도구(tool) 설계가 결정한다. 프레임워크는 그걸 연결하는 파이프일 뿐이다.