[LangChain] LangGraph로 Multi-Agent 구현하기 — Supervisor, Planner, Researcher, Writer, Reviewer
by 우와한개발자
1. Multi-Agent
1) 개념
- Multi-Agent는 여러 개의 자율적인 AI Agent가 역할을 나누어 협력하는 아키텍처이다.
- 하나의 Agent가 모든 작업을 처리하는 것이 아니라, Planner, Researcher, Writer, Reviewer처럼 역할별 Agent가 각자 맡은 작업을 수행한다.
- 복잡한 작업을 분해하고, 각 단계의 결과를 연결하여 최종 결과물을 만든다.
2) 사용하는 이유
- 복잡한 작업을 역할별로 나누어 처리할 수 있다.
- 각 Agent의 책임이 명확해져 프롬프트와 로직을 설계하기 쉽다.
- 중간 결과를 검토하고 수정하는 피드백 루프를 만들 수 있다.
- 조사, 작성, 검토처럼 성격이 다른 작업을 각각의 Agent에 최적화할 수 있다.
2. Supervisor Pattern
1) 개념
- Supervisor Pattern은 상위 Agent가 여러 하위 Agent를 조정하고 제어하는 구조이다.
- Supervisor는 사용자 요청을 분석하고, 어떤 Agent에게 어떤 작업을 맡길지 결정한다.
- 각 Agent의 실행 결과를 모아 전체 프로세스를 관리하고 최종 결과를 통합한다.
2) 역할
- 사용자 요청 분석
- 작업 분배
- Agent 실행 순서 제어
- 중간 결과 수집
- 결과 통합
- 필요 시 재작업 요청
사용자 요청 → Supervisor → Planner / Researcher / Writer / Reviewer → 최종 결과
3. 주요 Agent 역할
1) Planner Agent
- 사용자의 요청을 분석하고 전체 작업의 목표와 범위를 명확히 정의한다.
- 복잡한 작업을 작은 하위 작업으로 분해한다.
- 작업 순서와 의존관계를 설계한다.
- 실행 중 상황이 바뀌면 계획을 수정하거나 작업을 재분배한다.
2) Research Agent
- Planner가 설계한 단계에 따라 필요한 정보를 수집하고 분석한다.
- 외부 검색, 문서 조회, DB 조회, RAG 검색 등을 수행할 수 있다.
- 수집한 정보를 요약하고, Writer Agent가 사용할 수 있는 형태로 정리한다.
3) Writer Agent
- Planner와 Research Agent의 결과를 바탕으로 최종 산출물을 작성한다.
- 보고서, 요약문, 기획서, 답변 초안 등 구조화된 글을 생성한다.
- Writer Agent는 결과물을 짧게 생성하는 경향이 있을 수 있으므로, 프롬프트에서 분량, 구조, 포함할 항목을 구체적으로 지시하는 것이 중요하다.
4) Reviewer Agent
- 생성된 결과물의 품질과 정확성을 검증하는 최종 관문 역할을 한다.
- 내용의 사실성, 출처 일치 여부, 논리적 일관성, 누락된 요구사항을 점검한다.
- 문제가 발견되면 Writer Agent 또는 Research Agent에게 수정 요청을 보낸다.
4. Multi-Agent Graph
1) 개념
- Multi-Agent Graph는 여러 Agent의 실행 흐름을 그래프 구조로 표현한 것이다.
- 각 Agent는 하나의 노드로 구성될 수 있고, Agent 간 결과 전달은 엣지로 표현할 수 있다.
- LangGraph를 사용하면 Multi-Agent 흐름을 State, Node, Edge 기반으로 명확하게 설계할 수 있다.
2) 기본 흐름
START
→ Planner Agent
→ Research Agent
→ Writer Agent
→ Reviewer Agent
→ END
3) 피드백 루프가 있는 흐름
START
→ Planner Agent
→ Research Agent
→ Writer Agent
→ Reviewer Agent
→ 통과 시 END
→ 수정 필요 시 Writer Agent 또는 Research Agent로 재요청
4) 예시 구조
사용자 요청
→ Planner Agent: 작업 분해
→ Research Agent: 정보 수집
→ Writer Agent: 결과물 작성
→ Reviewer Agent: 품질 검토
→ Supervisor: 최종 결과 통합
→ 사용자 응답
5. LangGraph로 Multi-Agent 구현 예시
1) 예제 개요
- 각 역할별 Agent를 별도로 생성한다.
- Planner Agent, Researcher Agent, Writer Agent, Reviewer Agent마다 서로 다른 system prompt를 설정한다.
- LangGraph의 각 Node에서는 직접 LLM을 호출하지 않고, 미리 생성한 Agent를 invoke한다.
- 각 Agent의 결과를 State에 저장하고 다음 노드로 전달한다.
START
→ planner_node
→ researcher_node
→ writer_node
→ reviewer_node
→ END
2) 전체 코드
from typing import TypedDict
from dotenv import load_dotenv
from langgraph.graph import StateGraph, START, END
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
load_dotenv()
class ReportState(TypedDict):
topic: str
plan: str
research: str
draft: str
review: str
model = ChatOpenAI(
model="gpt-4o-mini",
temperature=0
)
planner_agent = create_agent(
model=model,
tools=[],
system_prompt="""
당신은 보고서 기획 전문 Planner Agent입니다.
역할:
- 사용자의 주제를 분석합니다.
- 보고서의 목표와 범위를 정의합니다.
- 목차를 구조적으로 작성합니다.
- 각 목차에서 다룰 핵심 내용을 간단히 제안합니다.
출력 형식:
1. 보고서 목적
2. 목차
3. 각 장별 핵심 내용
"""
)
researcher_agent = create_agent(
model=model,
tools=[],
system_prompt="""
당신은 조사와 분석을 담당하는 Research Agent입니다.
역할:
- Planner Agent가 만든 목차를 기반으로 조사 내용을 작성합니다.
- 각 목차에 들어갈 핵심 개념, 배경, 고려사항을 정리합니다.
- Writer Agent가 보고서를 작성할 수 있도록 충분한 근거와 내용을 제공합니다.
출력 형식:
1. 조사 요약
2. 장별 조사 내용
3. 보고서에 포함하면 좋은 핵심 포인트
"""
)
writer_agent = create_agent(
model=model,
tools=[],
system_prompt="""
당신은 보고서 작성 전문 Writer Agent입니다.
역할:
- Research Agent가 정리한 조사 내용을 바탕으로 보고서를 작성합니다.
- 문장을 자연스럽게 연결하고, 보고서 형식에 맞게 구조화합니다.
- 내용이 너무 짧아지지 않도록 각 장을 충분히 설명합니다.
출력 형식:
1. 제목
2. 서론
3. 본론
4. 결론
"""
)
reviewer_agent = create_agent(
model=model,
tools=[],
system_prompt="""
당신은 결과물 검토를 담당하는 Reviewer Agent입니다.
역할:
- Writer Agent가 작성한 보고서를 검토합니다.
- 내용의 정확성, 논리적 흐름, 누락된 항목, 개선할 표현을 점검합니다.
- 최종 개선사항을 구체적으로 제안합니다.
출력 형식:
1. 전체 평가
2. 잘된 점
3. 개선이 필요한 점
4. 수정 제안
"""
)
def get_agent_answer(result: dict) -> str:
"""Agent 실행 결과에서 마지막 메시지 content를 추출한다."""
return result["messages"][-1].content
def planner_node(state: ReportState) -> ReportState:
result = planner_agent.invoke({
"messages": [
{
"role": "user",
"content": f"다음 주제로 보고서 목차를 작성하시오.\n\n주제: {state['topic']}"
}
]
})
return {
"plan": get_agent_answer(result)
}
def researcher_node(state: ReportState) -> ReportState:
result = researcher_agent.invoke({
"messages": [
{
"role": "user",
"content": f"다음 목차를 기반으로 조사 내용을 작성하시오.\n\n{state['plan']}"
}
]
})
return {
"research": get_agent_answer(result)
}
def writer_node(state: ReportState) -> ReportState:
result = writer_agent.invoke({
"messages": [
{
"role": "user",
"content": f"아래 조사 내용을 바탕으로 보고서를 작성하시오.\n\n{state['research']}"
}
]
})
return {
"draft": get_agent_answer(result)
}
def reviewer_node(state: ReportState) -> ReportState:
result = reviewer_agent.invoke({
"messages": [
{
"role": "user",
"content": f"아래 보고서를 검토하고 개선사항을 제안하시오.\n\n{state['draft']}"
}
]
})
return {
"review": get_agent_answer(result)
}
builder = StateGraph(ReportState)
builder.add_node("planner", planner_node)
builder.add_node("researcher", researcher_node)
builder.add_node("writer", writer_node)
builder.add_node("reviewer", reviewer_node)
builder.add_edge(START, "planner")
builder.add_edge("planner", "researcher")
builder.add_edge("researcher", "writer")
builder.add_edge("writer", "reviewer")
builder.add_edge("reviewer", END)
graph = builder.compile()
result = graph.invoke({
"topic": "공공기관 생성형 AI 활용 전략",
"plan": "",
"research": "",
"draft": "",
"review": ""
})
print("===== 목차 =====")
print(result["plan"])
print("===== 조사 내용 =====")
print(result["research"])
print("===== 보고서 초안 =====")
print(result["draft"])
print("===== 검토 결과 =====")
print(result["review"])
3) 코드 설명
- planner_agent, researcher_agent, writer_agent, reviewer_agent를 각각 따로 생성한다.
- 각 Agent는 같은 모델을 사용할 수 있지만, 서로 다른 system prompt를 가진다.
- system prompt가 다르기 때문에 각 Agent는 서로 다른 역할처럼 동작한다.
- 노드 함수에서는 직접 llm.invoke()를 호출하지 않고, 해당 역할의 Agent를 invoke()한다.
- 각 노드는 Agent 실행 결과를 State의 특정 필드에 저장한다.
planner_node → plan 저장
researcher_node → research 저장
writer_node → draft 저장
reviewer_node → review 저장
4) 기존 코드와의 차이
| 구분 | 기존 코드 | Agent 분리 코드 |
| 호출 방식 | 노드에서 직접 llm.invoke() 호출 | 노드에서 역할별 Agent 호출 |
| 역할 분리 | prompt만 다름 | Agent 단위로 역할 분리 |
| system prompt | 각 노드의 prompt에 포함 | Agent 생성 시 system_prompt로 고정 |
| 확장성 | 단순한 순차 워크플로우에 적합 | Multi-Agent 구조 설명에 적합 |
| 도구 사용 | 각 노드에서 직접 처리 | Agent별로 tools를 다르게 줄 수 있음 |
5) 이 구조의 장점
- 각 Agent의 역할이 명확해진다.
- Agent별 system prompt를 따로 관리할 수 있다.
- Research Agent에는 검색 Tool, Writer Agent에는 문서 작성 Tool처럼 역할별 도구를 다르게 줄 수 있다.
- LangGraph는 전체 실행 흐름을 관리하고, 각 Agent는 자신의 역할에 집중한다.
LangGraph = 전체 워크플로우 제어
각 Agent = 역할별 작업 수행
'AI > LangChain' 카테고리의 다른 글
| [LangGraph] A2A 멀티에이전트 구현하기 — 오케스트레이터, RAG, 멀티쿼리 (0) | 2026.06.27 |
|---|---|
| [LangGraph] A2A 멀티에이전트란? — Agent-to-Agent 프로토콜과 오케스트레이터 패턴 (0) | 2026.06.27 |
| [LangChain] LangGraph로 Agent 워크플로우 구현하기 — State, Node, Edge, Router (0) | 2026.06.23 |
| [LangChain] Tool Calling과 Agent 구현하기 — @tool, ReAct, Memory, LangGraph (0) | 2026.06.23 |
| [LangChain] RAG 검색 품질 높이기 — Hybrid Search, Reranking (0) | 2026.06.22 |
블로그의 정보
우와한개발자 님의 블로그
우와한개발자