이 글은 시리즈 3편입니다.
- 1편: 왜 Python이 2026년에도 압도적 1위인가
- 2편: 나만의 AI 챗봇 만들기 — RAG 시스템 처음부터 배포까지
- 3편: 혼자 일하는 AI는 이제 옛날 — LangGraph로 멀티 에이전트 시스템 만들기 ← 지금 여기
📌 난이도: 중·고급 (2편까지 따라왔다면 충분합니다) ⏱️ 읽는 시간: 약 13분 / 실습 시간: 약 3~4시간 🛠️ 완성물: 리서치 → 초안 작성 → 팩트체크를 자동으로 수행하는 3인조 AI 에이전트 팀
“AI한테 복잡한 일을 시키면 왜 이렇게 멍청할까?”
라는 생각을 해본 적 있으신가요?
GPT든 Claude든, 단일 AI에게 복잡한 업무를 통째로 던져주면 결과가 들쑥날쑥합니다. 조사도 하고, 글도 쓰고, 검증까지 한 번에 하라고 하면 어딘가 허점이 생깁니다.
사람도 마찬가지입니다. 기자가 취재도 하고, 기사도 쓰고, 팩트체크까지 혼자 다 하면 품질이 떨어집니다. 그래서 팀이 있습니다.
2026년, AI도 팀으로 일하기 시작했습니다.
📊 목차
- 멀티 에이전트가 뭔지 — “AI 팀원” 개념으로 이해하기
- LangGraph를 써야 하는 이유
- 오늘 만들 것: 3인조 리서치 팀
- 환경 세팅
- 핵심 개념 3가지 — State, Node, Edge
- 단계별 구현: 에이전트 3개 만들기
- 슈퍼바이저로 팀 조율하기
- 전체 파이프라인 실행
- 실전 활용 패턴 & 확장 아이디어
1. 멀티 에이전트가 뭔지 — “AI 팀원” 개념으로 이해하기
지금까지 우리가 만든 AI는 혼자 일하는 프리랜서였습니다. 질문을 받으면 혼자 생각해서 혼자 답변합니다.
멀티 에이전트 시스템은 분업하는 팀입니다.
[단일 AI]사용자 → AI (혼자 다 함) → 결과 └ 조사도, 작성도, 검증도 전부 혼자[멀티 에이전트]사용자 → 슈퍼바이저 (팀장) ├→ 리서처 에이전트 (조사 전문) ├→ 라이터 에이전트 (작성 전문) └→ 팩트체커 에이전트 (검증 전문) ↓ 최종 결과물
각 에이전트는 자기 역할만 잘하면 됩니다. 그리고 팀장(슈퍼바이저)이 순서를 조율합니다.
실제로 2026년 현재 대부분의 개발자들이 단일 체인 파이프라인에 머물러 있지만, 복잡한 작업에 부딪히면 바로 한계가 드러납니다. LangGraph는 에이전트들이 서로 협력하고, 결과를 검토하며, 작업이 완료될 때까지 반복하는 상태 기반의 순환 AI 워크플로우를 구축할 수 있게 해줍니다.
2. LangGraph를 써야 하는 이유
에이전트 프레임워크는 여러 개 있습니다. 왜 LangGraph인가요?
| 프레임워크 | 특징 | 적합한 상황 |
|---|---|---|
| LangChain (단순 체인) | A→B→C 선형 흐름 | 간단한 파이프라인 |
| CrewAI | 빠른 프로토타이핑 | 아이디어 검증 단계 |
| AutoGen | 에이전트 대화 중심 | 대화형 협업 |
| LangGraph | 그래프 기반, 정밀 제어 | 프로덕션 배포 |
2026년 AI 에이전트 프레임워크 시장은 정리됐습니다. Microsoft는 AutoGen을 유지보수 모드로 전환했고, CrewAI는 빠른 프로토타이핑에는 여전히 쓰이지만, 세밀한 제어와 안정적인 실행, Human-in-the-Loop가 필요한 프로덕션 워크로드에서는 LangGraph가 기본 선택입니다.
LangGraph는 2026년 4월 기준 GitHub 스타 126,000개를 돌파했으며, Klarna, Uber, Replit, Elastic 같은 기업들이 실제 프로덕션에서 사용하고 있습니다.
LangGraph가 특별한 이유 세 가지:
- 순환 가능 — 결과가 마음에 안 들면 루프를 돌아서 재시도할 수 있습니다
- 상태 영속 — 에이전트가 중간에 실패해도 거기서부터 재개됩니다
- 조건 분기 — “결과가 충분하면 종료, 부족하면 다시 조사” 같은 로직이 자연스럽습니다
3. 오늘 만들 것: 3인조 리서치 팀
시나리오: “특정 주제를 입력하면, 자동으로 리서치하고 블로그 초안을 작성한 뒤 팩트를 검증해주는 AI 팀”
[사용자 입력: "Python 2026 트렌드"] ↓[슈퍼바이저 에이전트] ← 팀장. 전체 흐름 결정 ↓[리서처 에이전트] ← 웹 검색, 정보 수집 ↓[라이터 에이전트] ← 수집된 정보로 블로그 초안 작성 ↓[팩트체커 에이전트] ← 주요 주장을 검증, 수정 요청 or 승인 ↓ [최종 결과물] ← 검증된 블로그 초안
각 에이전트는 이전 에이전트의 결과물을 받아서 자기 역할을 수행합니다. 팩트체커가 통과시켜야 최종 결과물이 나옵니다. 통과 못 하면 라이터에게 다시 보내 수정을 요청합니다.
4. 환경 세팅
bash
pip install langgraph langchain langchain-anthropic \ langchain-community python-dotenv
.env 파일
bash
ANTHROPIC_API_KEY=your-api-key-here
폴더 구조
multi-agent/├── .env├── main.py # 실행 진입점├── state.py # 공유 상태 정의├── agents.py # 에이전트 3개├── supervisor.py # 슈퍼바이저 로직└── graph.py # 그래프 조립
5. 핵심 개념 3가지 — State, Node, Edge
코드 보기 전에 LangGraph의 핵심 3가지를 먼저 이해하고 가야 합니다. 이걸 알면 나머지 코드가 전부 이해됩니다.
① State (상태) — 팀의 공유 메모장
모든 에이전트가 공유하는 하나의 딕셔너리입니다. 에이전트들은 이 메모장을 읽고, 자기 결과를 여기에 씁니다.
python
# 팀 공유 메모장state = { "topic": "Python 2026 트렌드", # 입력 "research": "", # 리서처가 채움 "draft": "", # 라이터가 채움 "fact_check": "", # 팩트체커가 채움 "approved": False, # 최종 승인 여부 "iteration": 0 # 수정 횟수}
② Node (노드) — 각 팀원
그래프에서 하나의 작업 단위입니다. 각 에이전트가 하나의 노드입니다. State를 받아서 State를 돌려주는 함수라고 생각하면 됩니다.
python
def researcher_node(state): # state에서 topic 읽기 # 리서치 수행 # state의 research 필드 업데이트 return {"research": "...리서치 결과..."}
③ Edge (엣지) — 팀원 간 연결
노드와 노드를 연결하는 선입니다. 조건부 엣지(Conditional Edge) 를 쓰면 “이 경우엔 A로, 저 경우엔 B로” 분기가 가능합니다.
python
# 팩트체크 결과에 따라 분기def should_continue(state): if state["approved"]: return "END" # 승인됐으면 종료 elif state["iteration"] >= 3: return "END" # 3번 이상 수정됐으면 그냥 종료 else: return "writer" # 승인 안 됐으면 라이터에게 다시
이 세 가지가 LangGraph의 전부입니다. 나머지는 조립입니다.
6. 단계별 구현: 에이전트 3개 만들기
state.py — 공유 상태 정의
python
# state.pyfrom typing import TypedDict, Annotatedfrom langgraph.graph.message import add_messagesclass ResearchState(TypedDict): """팀 전체가 공유하는 상태""" topic: str # 리서치 주제 research_notes: str # 리서처의 조사 결과 draft: str # 라이터의 초안 fact_check_result: str # 팩트체커의 검토 의견 approved: bool # 최종 승인 여부 revision_notes: str # 수정 요청 사항 iteration: int # 현재 수정 횟수 (무한루프 방지) final_output: str # 최종 결과물
agents.py — 에이전트 3개
python
# agents.pyimport osfrom dotenv import load_dotenvfrom langchain_anthropic import ChatAnthropicfrom langchain.prompts import ChatPromptTemplatefrom state import ResearchStateload_dotenv()# 공통 LLM (모든 에이전트가 같은 모델 사용, 역할은 프롬프트로 구분)llm = ChatAnthropic( model="claude-sonnet-4-20250514", api_key=os.getenv("ANTHROPIC_API_KEY"), temperature=0.3, max_tokens=2000)# ────────────────────────────────────────# 에이전트 1: 리서처# ────────────────────────────────────────def researcher_agent(state: ResearchState) -> dict: """ 주제를 받아 핵심 정보를 조사합니다. 실제 프로덕션에서는 Tavily, SerpAPI 등 검색 툴을 연결하세요. 여기서는 LLM의 사전 지식을 활용합니다. """ print("🔍 [리서처] 조사 시작...") prompt = ChatPromptTemplate.from_template("""당신은 전문 리서처입니다. 주어진 주제에 대해 핵심 정보를 조사하세요.주제: {topic}다음 형식으로 조사 결과를 작성하세요:## 핵심 사실 (5~7가지)- 사실 1: ...- 사실 2: ...## 주요 통계 & 데이터- ...## 최신 트렌드- ...## 참고할 만한 사례- ...정확하고 구체적인 정보만 포함하세요. 불확실한 정보는 "(추정)" 표시를 붙이세요.""") chain = prompt | llm result = chain.invoke({"topic": state["topic"]}) print(f"✅ [리서처] 조사 완료 — {len(result.content)}자") return {"research_notes": result.content}# ────────────────────────────────────────# 에이전트 2: 라이터# ────────────────────────────────────────def writer_agent(state: ResearchState) -> dict: """ 리서처의 조사 결과를 바탕으로 블로그 초안을 작성합니다. 팩트체커의 수정 요청이 있으면 그것도 반영합니다. """ print("✍️ [라이터] 초안 작성 시작...") # 첫 번째 작성인지, 수정 요청이 온 건지 구분 revision_context = "" if state.get("revision_notes"): revision_context = f"""⚠️ 팩트체커의 수정 요청:{state['revision_notes']}위 피드백을 반드시 반영해서 수정해주세요.""" prompt = ChatPromptTemplate.from_template("""당신은 기술 블로그 전문 작가입니다. 리서처의 조사 자료를 바탕으로 독자가 읽기 쉬운 블로그 글을 작성하세요.주제: {topic}리서처 조사 자료:{research_notes}{revision_context}작성 기준:- 제목 포함- 소개 → 본문 (3~4 섹션) → 마무리 구조- 전문 용어는 쉽게 설명- 구체적인 수치와 예시 활용- 약 800~1000자 분량""") chain = prompt | llm result = chain.invoke({ "topic": state["topic"], "research_notes": state["research_notes"], "revision_context": revision_context }) print(f"✅ [라이터] 초안 완성 — {len(result.content)}자") return { "draft": result.content, "revision_notes": "" # 수정 후 노트 초기화 }# ────────────────────────────────────────# 에이전트 3: 팩트체커# ────────────────────────────────────────def fact_checker_agent(state: ResearchState) -> dict: """ 라이터의 초안을 검토합니다. 조사 자료와 대조해 사실 오류나 과장을 찾아냅니다. 통과 or 수정 요청 둘 중 하나를 결정합니다. """ print("🔎 [팩트체커] 검토 시작...") prompt = ChatPromptTemplate.from_template("""당신은 엄격한 팩트체커입니다. 블로그 초안을 검토하세요.원본 리서치 자료:{research_notes}검토할 초안:{draft}다음 기준으로 검토하세요:1. 리서치 자료에 없는 내용을 지어냈는가?2. 통계/수치가 정확한가?3. 과장된 표현이 있는가?4. 논리적 모순이 있는가?반드시 아래 형식으로만 응답하세요:판정: [APPROVED 또는 NEEDS_REVISION]검토 의견:(승인 시: 품질이 양호한 이유 1~2줄)(수정 요청 시: 구체적인 수정 항목과 이유)""") chain = prompt | llm result = chain.invoke({ "research_notes": state["research_notes"], "draft": state["draft"] }) content = result.content approved = "APPROVED" in content.upper() if approved: print("✅ [팩트체커] 승인!") return { "fact_check_result": content, "approved": True, "final_output": state["draft"], # 승인된 초안이 최종 결과물 "iteration": state.get("iteration", 0) + 1 } else: print(f"⚠️ [팩트체커] 수정 요청 (시도 {state.get('iteration', 0) + 1}회)") return { "fact_check_result": content, "approved": False, "revision_notes": content, "iteration": state.get("iteration", 0) + 1 }
supervisor.py — 슈퍼바이저 (팀장)
python
# supervisor.pyfrom state import ResearchStatedef should_continue(state: ResearchState) -> str: """ 팩트체크 결과를 보고 다음 단계를 결정하는 팀장 로직. 반환값: - "writer" → 라이터에게 수정 요청 - "end" → 작업 완료 """ MAX_ITERATIONS = 3 # 무한루프 방지: 최대 3번까지만 수정 current_iter = state.get("iteration", 0) if state.get("approved", False): print(f"\n🎉 [슈퍼바이저] 최종 승인! (총 {current_iter}회 시도)") return "end" if current_iter >= MAX_ITERATIONS: print(f"\n⏱️ [슈퍼바이저] 최대 수정 횟수 도달. 마지막 버전으로 마무리.") return "end" print(f"\n🔄 [슈퍼바이저] 수정 요청 → 라이터에게 전달 (시도 {current_iter + 1}/{MAX_ITERATIONS})") return "writer"
graph.py — 그래프 조립 (핵심!)
python
# graph.pyfrom langgraph.graph import StateGraph, ENDfrom state import ResearchStatefrom agents import researcher_agent, writer_agent, fact_checker_agentfrom supervisor import should_continuedef build_research_graph(): """ 3인조 에이전트 팀을 그래프로 조립합니다. 흐름: researcher → writer → fact_checker ↑ ↓ └── (수정 요청 시 루프) ──┘ ↓ (승인 or 최대 횟수) END """ # 1. 그래프 초기화 workflow = StateGraph(ResearchState) # 2. 노드 등록 (에이전트 연결) workflow.add_node("researcher", researcher_agent) workflow.add_node("writer", writer_agent) workflow.add_node("fact_checker", fact_checker_agent) # 3. 시작점 설정 workflow.set_entry_point("researcher") # 4. 일반 엣지 (순서대로 진행) workflow.add_edge("researcher", "writer") # 리서처 → 라이터 workflow.add_edge("writer", "fact_checker") # 라이터 → 팩트체커 # 5. 조건부 엣지 (팩트체커 결과에 따라 분기) workflow.add_conditional_edges( "fact_checker", # 이 노드의 출력을 기준으로 should_continue, # 이 함수가 다음 노드를 결정 { "writer": "writer", # "writer" 반환 시 → 라이터로 "end": END # "end" 반환 시 → 종료 } ) # 6. 컴파일 (실행 가능한 앱으로 변환) return workflow.compile()# 그래프 시각화 (선택사항, graphviz 설치 필요)# pip install grandalfdef print_graph_structure(graph): try: print(graph.get_graph().draw_ascii()) except Exception: print("그래프 시각화 라이브러리가 없습니다. pip install grandalf")
7. 전체 파이프라인 실행
python
# main.pyfrom dotenv import load_dotenvfrom graph import build_research_graph, print_graph_structureload_dotenv()def run_research_team(topic: str) -> dict: """ 3인조 에이전트 팀을 실행합니다. """ print(f"\n{'='*60}") print(f"🚀 리서치 팀 가동 — 주제: '{topic}'") print(f"{'='*60}\n") # 그래프 생성 app = build_research_graph() # 초기 상태 initial_state = { "topic": topic, "research_notes": "", "draft": "", "fact_check_result": "", "approved": False, "revision_notes": "", "iteration": 0, "final_output": "" } # 실행 result = app.invoke(initial_state) print(f"\n{'='*60}") print("📄 최종 결과물") print(f"{'='*60}") final = result.get("final_output") or result.get("draft", "결과물 없음") print(final) print(f"\n{'='*60}") print(f"📊 실행 요약") print(f" - 총 수정 횟수: {result.get('iteration', 0)}회") print(f" - 최종 승인: {'✅ 승인' if result.get('approved') else '⏱️ 시간 초과'}") print(f"{'='*60}\n") return resultif __name__ == "__main__": # 테스트 실행 result = run_research_team("Python과 AI 개발 2026년 트렌드")
실행 결과 예시:
============================================================🚀 리서치 팀 가동 — 주제: 'Python과 AI 개발 2026년 트렌드'============================================================🔍 [리서처] 조사 시작...✅ [리서처] 조사 완료 — 1243자✍️ [라이터] 초안 작성 시작...✅ [라이터] 초안 완성 — 987자🔎 [팩트체커] 검토 시작...⚠️ [팩트체커] 수정 요청 (시도 1회)🔄 [슈퍼바이저] 수정 요청 → 라이터에게 전달 (시도 1/3)✍️ [라이터] 초안 작성 시작...✅ [라이터] 초안 완성 — 1054자🔎 [팩트체커] 검토 시작...✅ [팩트체커] 승인!🎉 [슈퍼바이저] 최종 승인! (총 2회 시도)============================================================
8. 실전 활용 패턴 & 확장 아이디어
여기서 소개한 패턴은 수많은 실제 업무에 바로 적용할 수 있습니다.
패턴 1: 병렬 처리 (속도 향상)
python
# 리서처가 여러 소스를 동시에 조사from langgraph.graph import StateGraph# 여러 리서처를 병렬로 실행하고 결과를 합치는 패턴workflow.add_node("researcher_news", news_researcher)workflow.add_node("researcher_data", data_researcher)workflow.add_node("aggregator", combine_results)# 두 리서처가 동시에 실행되고 aggregator에서 합쳐짐workflow.add_edge("researcher_news", "aggregator")workflow.add_edge("researcher_data", "aggregator")
패턴 2: Human-in-the-Loop (사람이 개입)
python
# 민감한 결정 전에 사람의 승인을 기다리는 패턴from langgraph.types import interruptdef sensitive_action_node(state): # 실행 전 사람에게 확인 요청 approval = interrupt({ "message": "이 내용을 발행하시겠습니까?", "draft": state["draft"] }) if approval.get("approved"): return {"final_output": state["draft"]} else: return {"revision_notes": approval.get("feedback", "")}
확장 아이디어
업무 자동화에 바로 적용할 수 있는 아이디어들입니다.
| 유즈케이스 | 에이전트 구성 |
|---|---|
| 주간 보고서 자동화 | 데이터 수집 → 분석 → 작성 → 검토 |
| 코드 리뷰 봇 | 정적 분석 → 보안 검사 → 성능 검토 → 피드백 |
| 고객 이메일 대응 | 분류 → 정보 검색(RAG) → 초안 작성 → 톤 검토 |
| 경쟁사 모니터링 | 크롤링 → 요약 → 비교 분석 → 리포트 |
마치며 — 에이전트는 도구가 아니라 팀원입니다
오늘 만든 3인조 AI 팀을 돌아봅시다.
리서처는 정보를 모읍니다. 라이터는 그걸 글로 씁니다. 팩트체커는 틀린 걸 잡아냅니다. 그리고 팀장이 전체를 조율합니다.
이게 바로 좋은 팀의 작동 방식입니다. AI든 사람이든.
멀티 에이전트 시스템의 핵심은 기술이 아닙니다. 어떤 역할 분담이 이 문제를 가장 잘 해결하는가를 설계하는 것입니다. 코드는 그 설계를 구현하는 수단입니다.
다음 4편에서는 이 에이전트 팀에 메모리(장기 기억) 를 붙여봅니다. 지금은 대화가 끝나면 다 잊어버리지만, 메모리를 연결하면 지난주에 작성한 글을 기억하고, 반복 주제를 알아서 피하고, 사용자의 스타일을 학습하는 AI 팀이 됩니다.
🔖 이 시리즈의 다른 글
- 1편: 왜 Python이 2026년에도 압도적 1위인가
- 2편: 나만의 AI 챗봇 만들기 — RAG 처음부터 배포까지
- 3편: 혼자 일하는 AI는 이제 옛날 — LangGraph 멀티 에이전트 ← 지금 여기
- 4편: AI 팀에 장기 기억 달기 — LangGraph Memory 완벽 가이드 (예정)
태그: #Python #LangGraph #멀티에이전트 #AI에이전트 #LangChain #AI자동화 #개발튜토리얼 #2026 #AgenticAI #프로덕션AI
데이터 출처: LangGraph GitHub · LangChain Docs · Dev.to LangGraph Guide 2026 · Tech-Insider LangGraph Tutorial