본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2026. 4. 13. · 1 Views
프레임워크 선택 LangGraph vs CrewAI vs AutoGen 완벽 가이드
AI 에이전트 개발을 위한 세 가지 핵심 프레임워크를 비교 분석합니다. 각 프레임워크의 특징, 장단점, 실무 선택 기준을 초급 개발자도 이해할 수 있도록 설명합니다.
목차
- LangGraph_vs_CrewAI_vs_AutoGen_비교_분석
- LangGraph가_프로덕션에_권장되는_이유
- 프레임워크_채택_시_안티패턴_피하기
- 공급업체_종속성_문제_해결_전략
- 에이전트_그래프에서_상태_State의_개념
- 도구_선택_라우터_구현_방법
- 노트북_데모에서_프로덕션_마이그레이션_경로
1. LangGraph vs CrewAI vs AutoGen 비교 분석
어느 날 김개발 씨가 사내 스터디에서 발표를 준비하다가 고민에 빠졌습니다. "에이전트 프레임워크가 이렇게 많은데, 도대체 어떤 걸 써야 할까요?" 팀원들마다 각기 다른 프레임워크를 추천하고 있었습니다.
에이전트 프레임워크 비교는 프로젝트의 성패를 가르는 첫 번째 결정입니다. 마치 자동차를 살 때 용도에 맞는 차를 선택하는 것처럼, 에이전트의 목적에 맞는 프레임워크를 골라야 합니다.
세 가지 대표 프레임워크의 특징을 비교해 봅시다.
다음 코드를 살펴봅시다.
# 세 가지 에이전트 프레임워크 핵심 비교
frameworks = {
"LangGraph": {
"특징": "상태 기반 그래프 워크플로우",
"적합한_용도": "복잡한 다단계 에이전트",
"학습난이도": "중간",
"커뮤니티": "가장 큼"
},
"CrewAI": {
"특징": "역할 기반 팀 협업 모델",
"적합한_용도": "협업 에이전트 시스템",
"학습난이도": "쉬움",
"커뮤니티": "빠르게 성장 중"
},
"AutoGen": {
"특징": "대화 기반 다중 에이전트",
"적합한_용도": "연구 및 프로토타이핑",
"학습난이도": "쉬움~중간",
"커뮤니티": "Microsoft 기반"
}
}
"AI 에이전트 AI 엔지니어 되기 위한 로드맵" 코스의 6번째 시간입니다. 지난 시간까지 우리는 LLM의 함수 호출, 환각 문제, 임베딩까지 핵심을 배웠습니다.
이제 본격적으로 에이전트를 구축할 프레임워크를 선택할 차례입니다. 김개발 씨는 입사 3개월 차 주니어 개발자입니다.
오늘도 열심히 코드를 작성하던 중, 팀장님께서 새로운 에이전트 프로젝트를 맡겼습니다. "이번에 고객 응대 에이전트를 만들어야 하는데, 프레임워크부터 선정해 봐요." 김개발 씨가 검색을 시작하자 수많은 프레임워크가 쏟아졌습니다.
LangGraph, CrewAI, AutoGen, Semantic Kernel, Camel... 너무 많아 어디서부터 시작해야 할지 막막했습니다.
그때 박시니어 씨가 커피를 들고 다가왔습니다. "처음부터 모든 프레임워크를 다 알 필요는 없어요.
세 가지만 제대로 이해하면 돼요." 박시니어 씨가 화이트보드에 세 개의 프레임워크를 적기 시작했습니다. 먼저 LangGraph입니다.
LangGraph는 상태(State)를 중심에 두고 에이전트의 동작을 그래프 형태로 정의합니다. 마치 지하철 노선도처럼, 어디서 출발해서 어떤 역을 거쳐 최종 목적지에 도달하는지 명확하게 그릴 수 있습니다.
다음은 CrewAI입니다. 이 프레임워크는 팀 프로젝트를 모델링합니다.
각 에이전트에게 역할을 부여하고, 팀원들처럼 협업하게 만듭니다. "연구원 에이전트가 조사한 내용을 작가 에이전트가 정리하고, 편집자 에이전트가 검수하는" 식의 구조를 쉽게 만들 수 있습니다.
마지막으로 AutoGen입니다. Microsoft가 개발한 이 프레임워크는 에이전트 간의 대화를 핵심 메커니즘으로 삼습니다.
에이전트들이 서로 메시지를 주고받으며 문제를 해결합니다. 연구 목적으로 많이 사용되며, 빠른 프로토타이핑에 강점이 있습니다.
세 프레임워크를 한눈에 비교해 볼까요? LangGraph는 제어력이 가장 뛰어납니다.
복잡한 조건 분기, 반복, 병렬 처리를 세밀하게 제어할 수 있습니다. 대신 학습 곡선이 조금 가파릅니다.
CrewAI는 직관성이 강점입니다. 역할을 정의하고 팀을 구성하는 방식이 매우 자연스러워서 초보자도 빠르게 시작할 수 있습니다.
다만 복잡한 워크플로우를 구현하면 제어력의 한계를 느낄 수 있습니다. AutoGen은 유연성이 돋보입니다.
에이전트 간 대화 패턴을 자유롭게 설계할 수 있어 연구和新しい 아이디어 실험에 적합합니다. 하지만 프로덕션 환경에서의 안정성 검증은 아직 진행 중인 부분도 있습니다.
김개발 씨가 물었습니다. "그럼 우리 프로젝트에는 어떤 게 맞을까요?" 박시니어 씨가 미소를 지었습니다.
"고객 응대는 단계별로 처리해야 하는 복잡한 흐름이 있으니 LangGraph를 추천해요. 물론, 처음에는 CrewAI로 프로토타입을 만들어보고 LangGraph로 마이그레이션하는 방법도 있어요." 이처럼 프레임워크 선택은 정답이 하나가 아닙니다.
프로젝트의 복잡도, 팀의 경험 수준, 장기적인 유지보수 계획을 종합적으로 고려해야 합니다. 가장 중요한 것은 하나를 깊이 이해하는 것입니다.
실전 팁
💡 - LangGraph는 복잡한 워크플로우와 세밀한 제어가 필요할 때 선택하세요
- CrewAI로 빠르게 프로토타이핑한 후 필요에 따라 LangGraph로 전환하는 전략도 좋습니다
- 이 카드뉴스는 "AI 에이전트 AI 엔지니어 되기 위한 로드맵" 코스의 6/16편입니다
2. LangGraph가 프로덕션에 권장되는 이유
김개발 씨가 회사의 기존 에이전트 서비스를 점검하다가 한 가지 사실을 발견했습니다. 대부분의 프로덕션 서비스가 LangGraph를 사용하고 있었습니다.
"왜 모두들 LangGraph를 선택한 걸까요?"
LangGraph의 프로덕션 적합성은 상태 관리와 제어 흐름의 정교함에서 비롯됩니다. 마치 스마트폰의 운영체제처럼, 모든 동작을 예측 가능하게 관리할 수 있습니다.
이것이 기업들이 LangGraph를 선택하는 핵심 이유입니다.
다음 코드를 살펴봅시다.
from langgraph.graph import StateGraph, START, END
from typing import TypedDict, Annotated
# 에이전트 상태 정의 - 모든 노드가 공유하는 데이터 구조
class AgentState(TypedDict):
user_query: str
intent: str
response: str
retry_count: int
# 상태 기반 그래프 빌더 생성
builder = StateGraph(AgentState)
# 노드와 엣지를 추가하여 워크플로우 구성
builder.add_node("classify", classify_intent)
builder.add_node("respond", generate_response)
builder.add_edge(START, "classify")
builder.add_edge("classify", "respond")
builder.add_edge("respond", END)
graph = builder.compile()
박시니어 씨가 김개발 씨의 질문에 답하려 화이트보드 앞에 섰습니다. "LangGraph가 프로덕션에서 강력한 이유를 세 가지로 설명해 드릴게요." 첫 번째 이유는 상태의 일관성입니다.
에이전트가 동작하는 동안 모든 중간 결과를 하나의 상태 객체로 관리합니다. 마치 은행 거래 내역이 장부에 순서대로 기록되는 것처럼, 에이전트의 모든 결정과 결과가 추적 가능합니다.
만약 에이전트가 중간에 오류를 내면 어떻게 될까요? 상태를 확인하면 어느 단계에서 문제가 발생했는지 정확히 알 수 있습니다.
디버깅이 훨씬 쉬워지는 것이죠. 두 번째 이유는 제어 흐름의 정교함입니다.
LangGraph는 조건부 분기, 반복 루프, 병렬 실행을 모두 지원합니다. 단순히 A에서 B로 가는 1차선 도로가 아니라, 상황에 따라 여러 경로를 선택할 수 있는 고속도로 인터체인지를 만들 수 있습니다.
실제 코드를 살펴볼까요? 위 코드에서 StateGraph가 바로 LangGraph의 핵심입니다.
TypedDict로 상태 구조를 정의하고, 각 노드가 이 상태를 읽고 수정합니다. START에서 시작해 classify 노드를 거쳐 respond 노드로 이동하는 직선적인 흐름입니다.
세 번째 이유는 검증된 생태계입니다. LangGraph는 LangChain 위에 구축되어 있어, 방대한 통합 커넥터와 도구를 그대로 활용할 수 있습니다.
이미 수많은 기업이 LangGraph로 프로덕션 서비스를 운영하고 있으며, 그 경험과 해결책이 커뮤니티에 공유되고 있습니다. 하지만 무조건 LangGraph를 선택해야 하는 것은 아닙니다.
박시니어 씨가 덧붙였습니다. "간단한 PoC를 3일 안에 만들어야 한다면 CrewAI가 더 빠를 수 있어요.
중요한 건 용도에 맞는 도구를 선택하는 거예요." 김개발 씨는 고개를 끄덕였습니다. "상태 관리, 제어 흐름, 생태계...
이 세 가지를 기준으로 판단하면 되겠군요." 맞습니다. 프로덕션에서는 예측 가능성과 디버깅 가능성이 곧 서비스의 신뢰성으로 이어집니다.
LangGraph는 이 두 가지를 가장 잘 제공하는 프레임워크입니다.
실전 팁
💡 - 프로덕션 배포를 염두에 둔다면 처음부터 LangGraph로 시작하는 것이 마이그레이션 비용을 줄입니다
- 상태 구조를 설계할 때는 필드를 최소화하고 필요한 데이터만 포함하세요
- 이 카드뉴스는 "AI 에이전트 AI 엔지니어 되기 위한 로드맵" 코스의 6/16편입니다
3. 프레임워크 채택 시 안티패턴 피하기
김개발 씨의 동기 이신입 씨가 뜬금없이 이렇게 말했습니다. "프레임워크를 세 개 다 쓰면 더 강력한 에이전트를 만들 수 있지 않을까요?" 김개발 씨는 순간 큰일 났다는 생각이 들었습니다.
프레임워크 안티패턴은 초보자들이 가장 흔히 겪는 실수입니다. 마치 한 요리에 모든 향신료를 넣으면 맛이 이상해지듯, 여러 프레임워크를 섞어 쓰면 코드가 복잡해지고 유지보수가 불가능해집니다.
다음 코드를 살펴봅시다.
# 안티패턴: 프레임워크 혼합 사용 (절대 하지 마세요!)
from langgraph.graph import StateGraph # LangGraph
from crewai import Agent, Task # CrewAI
from autogen import AssistantAgent # AutoGen
# 이렇게 섞어 쓰면 상태 관리가 엉망이 됩니다
# 각 프레임워크의 상태 모델이 서로 충돌합니다
# 디버깅이 거의 불가능해집니다
# 올바른 방법: 하나의 프레임워크로 통일
from langgraph.graph import StateGraph, START, END
# LangGraph 하나로 모든 워크플로우를 구성하세요
김개발 씨는 동기의 말에 깜짝 놀라 박시니어 씨에게 달려갔습니다. "선배님, 이신입 씨가 세 프레임워크를 다 쓰겠다고 하던데요..." 박시니어 씨도 표정이 굳었습니다.
"오, 그건 정말 위험한 발상이에요. 당장 설명해 드릴게요." 가장 흔한 안티패턴은 프레임워크 과도한 혼합입니다.
각 프레임워크는 자체적인 상태 관리 모델과 실행 엔진을 가지고 있습니다. LangGraph는 그래프 기반 상태, CrewAI는 역할 기반 컨텍스트, AutoGen은 메시지 기반 대화 상태를 사용합니다.
이것들을 섞어 쓰면 어떻게 될까요? 마치 세 명의 지휘자가 각기 다른 악보를 들고 하나의 오케스트라를 지휘하는 것과 같습니다.
혼란만 가중될 뿐입니다. 두 번째 안티패턴은 프레임워크를 만능 해결사로 맹신하는 것입니다.
"LangGraph를 쓰면 어떤 에이전트든 만들 수 있어요"라는 생각은 위험합니다. 때로는 순수 Python 코드로 작은 스크립트를 만드는 것이 더 효율적일 수 있습니다.
세 번째는 초기에 과도한 추상화입니다. 처음부터 복잡한 노드 구조와 상태 계층을 설계하는 경우가 있는데, 이는 변경이 매우 어려워집니다.
마치 집을 지을 때 기초 공사도 안 끝났는데 지붕부터 올리려는 것과 같습니다. 박시니어 씨가 화이트보드에 올바른 접근법을 적기 시작했습니다.
"먼저 문제를 명확히 정의하세요. 그 다음 가장 단순한 구조로 시작하고, 필요할 때만 복잡도를 추가하세요.
이것이 프레임워크 채택의 기본 원칙입니다." 김개발 씨가 물었습니다. "그럼 프레임워크를 바꿔야 할 때는 어떻게 하나요?" "좋은 질문이에요.
프레임워크 마이그레이션은 비용이 크니 처음부터 신중하게 선택해야 합니다. 하지만 핵심 비즈니스 로직을 프레임워크에 종속시키지 않으면, 나중에 교체도 가능해요.
이 부분은 다음 카드에서 자세히 다룰게요." 프레임워크는 도구일 뿐입니다. 망치가 모든 문제를 해결하지 못하듯, 하나의 프레임워크가 모든 에이전트 시나리오에 완벽하게 들어맞지는 않습니다.
상황에 맞게 선택하고, 선택한 후에는 깊이 파고들어야 합니다.
실전 팁
💡 - 하나의 프로젝트에서는 반드시 하나의 프레임워크만 사용하세요
- 비즈니스 로직을 프레임워크 계층과 분리하면 나중에 교체가 가능합니다
- 이 카드뉴스는 "AI 에이전트 AI 엔지니어 되기 위한 로드맵" 코스의 6/16편입니다
4. 공급업체 종속성 문제 해결 전략
김개발 씨가 사내 에이전트 프로젝트를 리뷰하다가 불길한 징후를 발견했습니다. 코드 곳곳에 특정 프레임워크의 전용 클래스가 하드코딩되어 있었습니다.
"이거 프레임워크를 바꾸려면 전체를 다시 써야 하는 거 아닌가요?"
**공급업체 종속성(Vendor Lock-in)**은 프레임워크를 변경할 수 없게 만드는 가장 큰 위험입니다. 마치 특정 브랜드의 전용 부품만 사용하는 가전제품처럼, 한 번 종속되면 벗어나기 매우 어렵습니다.
이 문제를 해결하는 전략을 알아봅시다.
다음 코드를 살펴봅시다.
# 안티패턴: 프레임워크에 강하게 결합된 코드
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o") # OpenAI에 종속
# 올바른 패턴: 추상화 계층을 통한 종속성 분리
from langchain_core.language_models import BaseChatModel
from typing import Protocol
class LLMProvider(Protocol):
def invoke(self, prompt: str) -> str: ...
class MyAgent:
def __init__(self, llm: LLMProvider):
self.llm = llm # 어떤 LLM이든 주입 가능
# 사용 시: 필요에 따라 OpenAI, Anthropic, 로컬 모델 교체 가능
박시니어 씨가 김개발 씨가 발견한 코드를 살펴보더니 한숨을 쉬었습니다. "이건 전형적인 벤더 락인(Vendor Lock-in) 사례네요." 공급업체 종속성 문제는 왜 위험할까요?
쉽게 비유하자면, 특정 통신사의 전용 폰을 사면 다른 통신사로 갈아탈 수 없는 것과 같습니다. 프레임워크도 마찬가지입니다.
코드가 특정 프레임워크의 API에 깊이 결합되어 있으면, 나중에 더 나은 대안이 나와도 바꿀 수 없습니다. "지난해에 이 회사는 다른 프레임워크로 전체 시스템을 재작성한 적이 있어요.
3개월이 걸렸죠." 박시니어 씨의 말에 김개발 씨가 눈을 크게 떴습니다. 해결책은 추상화 계층을 두는 것입니다.
비즈니스 로직과 프레임워크 의존성 사이에 벽을 세우는 것이죠. 위 코드에서 Protocol을 사용한 방식이 바로 그것입니다.
MyAgent는 구체적인 LLM 구현을 알 필요 없이, invoke 메서드만 있으면 어떤 모델이든 사용할 수 있습니다. 이 패턴의 핵심은 **의존성 역전 원칙(Dependency Inversion Principle)**입니다.
상위 모듈이 하위 모듈에 의존하지 않고, 둘 다 추상화에 의존하게 만듭니다. 이것은 소프트웨어 공학의 기본 원칙이지만, AI 에이전트 개발에서는 특히 중요합니다.
왜냐하면 AI 분야는 변화가 매우 빠르기 때문입니다. 오늘 최고의 모델이 내일 구식이 될 수 있습니다.
프레임워크도 마찬가지입니다. 작년에 인기 있던 프레임워크가 올해 업데이트를 멈출 수도 있습니다.
박시니어 씨가 실전 팁을 알려주었습니다. "코드를 작성할 때마다 스스로에게 질문하세요.
'이 코드를 다른 프레임워크로 옮기려면 몇 줄을 바꿔야 할까?' 대답이 '전체를 다시 써야 함'이라면 리팩토링이 필요해요." 김개발 씨는 노트에 적으며 고개를 끄덕였습니다. "핵심 로직은 프레임워크와 분리하고, 인터페이스로 연결하라...
기본이지만 정말 중요하네요." 맞습니다. 프레임워크는 도구입니다.
언제든 교체할 수 있다는 마음가짐으로 코드를 작성하는 것이 장기적으로 훨씬 안전합니다.
실전 팁
💡 - 비즈니스 로직은 순수 Python 함수로 작성하고 프레임워크 코드와 분리하세요
- LLM 호출은 별도의 어댑터 클래스로 래핑하여 모델 교체를 쉽게 만드세요
- 이 카드뉴스는 "AI 에이전트 AI 엔지니어 되기 위한 로드맵" 코스의 6/16편입니다
5. 에이전트 그래프에서 상태 State의 개념
김개발 씨가 첫 LangGraph 프로젝트를 시작했습니다. 하지만 State라는 개념이 잘 이해되지 않았습니다.
"그냥 변수에 값을 저장하면 되는 거 아닌가요?" 박시니어 씨가 다가와 설명을 시작했습니다.
**상태(State)**는 에이전트 워크플로우에서 모든 노드가 공유하는 단일 진실 공급원입니다. 마치 여러 사람이 하나의 구글 문서를 함께 편집하는 것처럼, 각 노드가 상태를 읽고 업데이트합니다.
이것이 LangGraph의 핵심 아키텍처입니다.
다음 코드를 살펴봅시다.
from typing import TypedDict, Annotated
from operator import add
class AgentState(TypedDict):
# 기본 필드 - 덮어쓰기 방식
query: str
current_step: str
# 리스트 필드 - 누적 방식 (Annotated + add)
messages: Annotated[list, add]
errors: Annotated[list, add]
def researcher_node(state: AgentState) -> dict:
return {
"current_step": "research",
"messages": ["사용자 질문을 분석했습니다"]
}
def writer_node(state: AgentState) -> dict:
# 이전 메시지가 그대로 유지됩니다
return {
"current_step": "writing",
"messages": ["답변을 작성했습니다"]
}
박시니어 씨가 화이트보드에 원을 하나 그렸습니다. "이 원이 바로 **상태(State)**예요.
모든 노드가 이 원 안의 데이터를 공유합니다." 상태의 핵심은 **단일 진실 공급원(Single Source of Truth)**이라는 개념에 있습니다. 여러 노드가 독립적으로 데이터를 관리하는 대신, 하나의 상태 객체가 모든 정보를 담습니다.
마치 회사에서 모든 부서가 하나의 ERP 시스템을 사용하는 것과 같습니다. 왜 이 방식이 좋을까요?
첫째, 일관성이 보장됩니다. 모든 노드가 동일한 데이터를 보기 때문에 정보가 엇갈릴 일이 없습니다.
둘째, 추적 가능성이 생깁니다. 상태의 변화 이력을 보면 에이전트가 어떤 결정을 내렸는지 알 수 있습니다.
코드를 자세히 살펴볼까요? TypedDict는 Python의 타입 힌팅 기능으로, 상태가 어떤 필드를 가지는지 명확하게 정의합니다.
이것은 문서 역할도 하고, IDE의 자동완성도 지원합니다. 가장 흥미로운 부분은 Annotated[list, add]입니다.
이것은 리스트 필드를 누적 모드로 설정합니다. 노드가 messages를 반환하면 기존 리스트에 새 메시지가 추가됩니다.
반면 query나 current_step 같은 필드는 새 값이 이전 값을 덮어씁니다. 실제로 researcher_node가 messages: ["사용자 질문을 분석했습니다"]를 반환하면 상태에 이 메시지가 추가됩니다.
그 다음 writer_node가 messages: ["답변을 작성했습니다"]를 반환하면, 이전 메시지는 유지된 채 새 메시지가 누적됩니다. "이게 진짜 마법 같은 부분이에요." 박시니어 씨가 설명했습니다.
"각 노드는 자신이 변경할 부분만 반환하면 됩니다. 나머지는 LangGraph가 알아서 유지해 줍니다." 김개발 씨가 물었습니다.
"상태에 너무 많은 필드를 넣어도 괜찮을까요?" "좋은 질문이에요. 상태는 최대한 가볍게 유지하는 것이 좋아요.
불필요한 필드가 많아지면 메모리 사용량이 늘어나고, 상태를 파악하기도 어려워져요. 정말 필요한 데이터만 포함하세요." 상태 설계는 에이전트 아키텍처의 기초입니다.
처음에는 최소한의 필드로 시작하고, 워크플로우가 복잡해지면서 필요한 필드를 하나씩 추가하는 것이 좋습니다.
실전 팁
💡 - 상태 필드는 변경 가능성이 있는 데이터만 포함하고, 파생 데이터는 노드 내부에서 계산하세요
- Annotated와 add를 사용하면 여러 노드의 결과를 하나의 리스트로 누적할 수 있습니다
- 이 카드뉴스는 "AI 에이전트 AI 엔지니어 되기 위한 로드맵" 코스의 6/16편입니다
6. 도구 선택 라우터 구현 방법
김개발 씨가 에이전트에게 여러 도구를 연결하려다가 막혔습니다. "에이전트가 사용자 질문을 보고 어떤 도구를 써야 할지 어떻게 알 수 있을까요?" 박시니어 씨가 라우터 패턴을 소개했습니다.
**도구 라우터(Tool Router)**는 사용자의 요청을 분석하여 가장 적합한 도구로 전달하는 결정 노드입니다. 마치 우체국의 분류 담당자가 편지를 목적지별로 나누는 것처럼, 라우터가 각 요청을 올바른 처리기로 안내합니다.
다음 코드를 살펴봅시다.
from langgraph.graph import StateGraph, START, END
def route_by_intent(state: AgentState) -> str:
"""의도에 따라 다음 노드를 결정하는 라우터"""
query = state["query"].lower()
if any(w in query for w in ["날씨", "기온", "비"]):
return "weather_tool"
elif any(w in query for w in ["검색", "찾아", "조회"]):
return "search_tool"
elif any(w in query for w in ["계산", "얼마", "수학"]):
return "calculator_tool"
return "general_response"
# 조건부 엣지로 라우터 연결
builder.add_conditional_edges(
"classifier", # 출발 노드
route_by_intent, # 라우터 함수
{ # 가능한 경로
"weather_tool": "weather_tool",
"search_tool": "search_tool",
"calculator_tool": "calculator_tool",
"general_response": "general_response",
}
)
"도구 선택은 에이전트의 핵심 능력 중 하나예요." 박시니어 씨가 설명을 시작했습니다. "에이전트가 스스로 판단해서 적절한 도구를 사용할 수 있어야 진정한 에이전트라고 할 수 있어요." 도구 라우터의 기본 원리는 간단합니다.
사용자의 입력을 분석하고, 그 의도에 따라 다음에 실행할 노드를 결정하는 것입니다. 마치 건물의 로비 안내 데스크가 방문객의 목적에 따라 적절한 층으로 안내하는 것과 같습니다.
위 코드의 route_by_intent 함수가 바로 라우터입니다. 사용자 질문에 포함된 키워드를 확인하여, 날씨 관련이면 weather_tool로, 검색 관련이면 search_tool로, 계산 관련이면 calculator_tool로 분기합니다.
add_conditional_edges는 LangGraph의 강력한 기능입니다. 고정된 엣지 대신, 함수의 반환값에 따라 동적으로 다음 노드를 결정합니다.
이것이 바로 LangGraph가 제어 흐름에서 강력한 이유입니다. "초보자들이 흔히 하는 실수가 있어요." 박시니어 씨가 말했습니다.
"라우터 함수 내부에서 직접 처리 로직을 넣는 거예요. 라우터는 오직 '어디로 보낼지'만 결정해야 합니다.
실제 처리는 각 도구 노드가 담당해야 해요." 김개발 씨가 고개를 끄덕였습니다. "라우터는 안내 데스크, 도구 노드는 실제 부서...
역할 분리가 중요하군요." 맞습니다. 라우터는 가볍고 빨라야 합니다.
복잡한 처리는 라우터가 아니라 각 노드에 맡겨야 합니다. 이 원칙을 지키면 전체 워크플로우가 훨씬 깔끔해집니다.
더 발전된 형태의 라우터는 LLM을 사용하여 의도를 분류합니다. 단순 키워드 매칭 대신, LLM이 문맥을 이해하고 더 정확한 분류를 내릴 수 있습니다.
하지만 이 경우 응답 시간이 늘어나니, 실시간성이 중요한 서비스에서는 키워드 기반 라우터와 LLM 기반 라우터를 적절히 조합하는 것이 좋습니다.
실전 팁
💡 - 라우터 함수는 분류 로직만 담고, 실제 처리는 각 노드에 위임하세요
- 키워드 기반 라우터는 빠르지만 정확도가 낮고, LLM 기반 라우터는 정확하지만 느립니다
- 이 카드뉴스는 "AI 에이전트 AI 엔지니어 되기 위한 로드맵" 코스의 6/16편입니다
7. 노트북 데모에서 프로덕션 마이그레이션 경로
김개발 씨가 주피터 노트북으로 멋진 에이전트 데모를 완성했습니다. "이제 이걸 서비스에 배포하면 되겠죠?" 박시니어 씨가 조용히 머리를 저었습니다.
"노트북 코드를 그대로 배포하면 안 돼요."
노트북에서 프로덕션으로의 마이그레이션은 데모와 실제 서비스 사이의 간극을 메우는 과정입니다. 마치 시험 주행용 프로토타입 자동차를 양산 모델로 바꾸는 것처럼, 안정성과 확장성을 갖추는 구조적 변화가 필요합니다.
다음 코드를 살펴봅시다.
# 노트북 코드 (데모용 - 배포 금지!)
llm = ChatOpenAI(api_key="sk-xxx", model="gpt-4o")
result = llm.invoke("안녕하세요")
# 프로덕션 코드 (배포용)
import os
from langchain_openai import ChatOpenAI
class AgentConfig:
MODEL = os.getenv("LLM_MODEL", "gpt-4o")
TEMPERATURE = float(os.getenv("LLM_TEMPERATURE", "0"))
def create_llm() -> ChatOpenAI:
return ChatOpenAI(
model=AgentConfig.MODEL,
temperature=AgentConfig.TEMPERATURE,
max_retries=3,
timeout=30,
)
# 사용 시
llm = create_llm()
김개발 씨의 얼굴이 당황으로 가득 찼습니다. "노트북에서 잘 되는데 왜 배포하면 안 되는 거예요?" 박시니어 씨가 차근차근 설명했습니다.
"노트북은 탐색과 실험을 위한 도구예요. 프로덕션은 안정성과 확장성이 필수죠.
두 환경의 요구사항이 완전히 달라요." 노트북 코드의 전형적인 문제점을 살펴볼까요? 첫 번째, API 키 하드코딩입니다.
코드에 시크릿이 직접 들어가 있으면 보안 사고로 이어집니다. 반드시 환경 변수로 관리해야 합니다.
두 번째, 에러 처리 부재입니다. 노트북에서는 LLM 호출이 실패하면 셀을 다시 실행하면 그만입니다.
하지만 프로덕션에서는 네트워크 오류, API 한도 초과, 모델 과부하 등 다양한 실패 상황에 대응해야 합니다. 세 번째, 재시도 로직이 없습니다.
LLM API는 가끔 일시적인 오류를 반환합니다. 프로덕션에서는 max_retries=3처럼 자동 재시도 설정이 필수입니다.
네 번째, 타임아웃 설정이 없습니다. 노트북에서는 응답이 늦어도 기다리면 되지만, 프로덕션에서는 무한 대기가 서비스 전체를 멈출 수 있습니다.
박시니어 씨가 마이그레이션 체크리스트를 적어주었습니다. "환경 변수로 설정 관리, 에러 처리와 로깅 추가, 재시도와 타임아웃 설정, 상태 관리 도입, 모니터링 연동...
이 다섯 가지는 필수예요." 김개발 씨가 노트에 적으며 말했습니다. "노트북은 아이디어 검증용, 프로덕션은 안정적인 서비스용...
개발 단계를 명확히 구분해야겠군요." 마이그레이션의 핵심은 점진적 전환입니다. 노트북에서 핵심 로직을 검증한 후, 모듈 파일로 분리하고, 설정 관리와 에러 처리를 추가하는 순서로 진행하세요.
한 번에 모든 것을 바꾸려 하지 마세요. 다음 시간에는 이러한 프레임워크의 고급 개념인 LCEL, 워크플로우, 구조화된 출력에 대해 더 깊이 알아볼 것입니다.
오늘 배운 기초가 그때 큰 도움이 될 것입니다.
실전 팁
💡 - 노트북에서 검증한 핵심 로직을 Python 모듈로 분리하는 것이 첫 번째 마이그레이션 단계입니다
- 모든 외부 API 호출에 재시도 로직과 타임아웃을 반드시 설정하세요
- 다음 카드뉴스에서는 고급 프레임워크 개념인 LCEL, 워크플로우, 구조화된 출력을 다룹니다
- 이 카드뉴스는 "AI 에이전트 AI 엔지니어 되기 위한 로드맵" 코스의 6/16편입니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Day 6 학습 루프 이해하기
LLM이 실제로 어떻게 학습하는지 학습 루프의 핵심 원리를 단계별로 살펴봅니다. Forward Pass, Loss 계산, Backward Pass, 파라미터 업데이트까지 한 사이클의 전 과정을 이해합니다.
Day 5 Baseline 모델 만들기
복잡한 모델에 앞서 가장 단순한 Baseline 모델을 직접 만들어봅니다. 아무런 기교 없이 순수하게 다음 토큰을 예측하는 모델을 구현하면서, 언어모델의 가장 기본 구조를 이해합니다.
Day 4 학습용 샘플 데이터 만들기
LLM을 학습시키기 위한 샘플 데이터를 직접 만들어봅니다. 작은 텍스트 말뭉치를 준비하고, 토크나이저로 변환한 뒤 PyTorch 텐서로 만드는 전체 과정을 단계별로 배웁니다.
Day 2 PyTorch 기본기 정리
LLM을 직접 만들기 위해 꼭 알아야 할 PyTorch의 핵심 개념을 정리합니다. 텐서, 자동 미분, 옵티마이저까지 모델 학습의 기초를 다집니다.
LLM 핵심 원리 함수 호출 환각 임베딩 완벽 가이드
LLM의 세 가지 핵심 개념인 함수 호출(Function Calling), 환각(Hallucination), 임베딩(Embedding)을 중급 개발자 관점에서 실무 중심으로 설명합니다. 에이전트 AI 엔지니어가 반드시 알아야 할 원리와 실전 팁을 담았습니다.