LangGraph
LangGraph Supervisor 예제
오예에
2025. 6. 19. 15:04
https://langchain-ai.github.io/langgraph/tutorials/multi_agent/agent_supervisor/
Agent Supervisor
Multi-agent supervisor Supervisor is a multi-agent architecture where specialized agents are coordinated by a central supervisor agent. The supervisor agent controls all communication flow and task delegation, making decisions about which agent to invoke b
langchain-ai.github.io
자세한 내용은 위 공식문서 확인
해당 예제에는 아래 표와 같이 3가지 방식으로 supervisor를 구현하고 있음
구분 | langgraph-supervisor | Supervisor from scratch | Delegation tasks |
구현 방식 | 함수 호출으로 구성 | Graph API + primitives 직접 구현 | handoff tool 커스터마이징, Send/forward 도입 |
설정/커스터마이징 난이도 | 낮음, 기본 구성 제공 | 높음, 모든 로직 직접 정의 | 중간, tool 정의만 잘 하면 됨 |
제어 수준 | 보통 수준 | 매우 세밀한 제어 가능 | transfer granularity 높이며 메시지 흐름 직접 정의 가능 |
추천 대상 | 빠르게 supervisor 구현하고 싶은 경우 | 복잡한 흐름이나 유연한 라우팅이 필요한 경우 | task delegation이나 handoff 조정이 필요한 경우 |
정리
간편하게 multi-agent supervisor가 필요하면 → langgraph-supervisor 활용 (방법 2)
보다 정교한 agent 흐름 제어가 필요하면 → Graph API로 직접 구현 (방법 3)
특정 단계에 delegate나 forward 메시지가 중요하면 → delegation 로직 추가 (방법 4)
내용 설명
langgraph-supervisor 이용: 미리 준비된 Supervisor
- create_supervisor라는 함수 하나로 구현 가능 → 코드 간결
- 내부에서 handoff tool과 supervisor agent 생성/관리 모두 처리
- 장점: 빠르고 직관적, 기본 레벨 multi-agent 구축에 적합
- 주요 설정 옵션:
- output_mode: 메시지 기록 방식 선택 (full_history, last_message)
- handoff_tool_prefix, add_handoff_messages 등으로 handoff 동작 커스터마이징 가능
- 확장성: supervisor 계층화 가능 (multi-level hierarchical)
Supervisor from scratch: 직접 손수 구현
- StateGraph + Command/Send 같은 primitives로 명시적으로 구성
- agent 간 graf node, message 흐름, routing logic 직접 설정
- 장점: handoff 과정, 메시지 구조, 상태 전달 등을 훨씬 세밀하게 제어 가능
- 필요 작업:
- 각 agent 노드 정의 → MessagesState 사용
- Command로 어떤 agent에게 handoff할지 지정
- Send로 payload 직접 추가
- 적합 대상: 복잡하거나 정교한 흐름이 필요한 커스텀 multi-agent 시스템
Delegation tasks: 위임(task delegation) 기법
- supervisor나 agent가 하위 agent에게 task 요청, 결과 수집하는 고급 패턴
- 예시: create_handoff_tool를 Send 포함해서 task 설명 직접 작성하게 유도
- 또는 create_forward_message_tool로 하위 agent의 답변을 supervisor 없이 바로 최종 출력까지 전달
- 장점: task granularity를 조절하거나 요약/전달 방식 정의 가능
- 특히 도메인 특정 handoff나 역할 분리된 비즈니스 로직에 유리
예제 코드
1. Create worker agents
Research agen
웹서치를 위한 도구 생성
from langchain_tavily import TavilySearch
web_search = TavilySearch(max_results=3)
web_search_results = web_search.invoke("who is the mayor of NYC?")
print(web_search_results["results"][0]["content"])
웹서치 도구를 사용하는 agent생성
from langgraph.prebuilt import create_react_agent
research_agent = create_react_agent(
model="openai:gpt-4.1",
tools=[web_search],
prompt=(
"You are a research agent.\n\n"
"INSTRUCTIONS:\n"
"- Assist ONLY with research-related tasks, DO NOT do any math\n"
"- After you're done with your tasks, respond to the supervisor directly\n"
"- Respond ONLY with the results of your work, do NOT include ANY other text."
),
name="research_agent",
)
agent 실행
for chunk in research_agent.stream(
{"messages": [{"role": "user", "content": "who is the mayor of NYC?"}]}
):
pretty_print_messages(chunk)
Math agent
수학 작업을 하는 tool과 agent생성
def add(a: float, b: float):
"""Add two numbers."""
return a + b
def multiply(a: float, b: float):
"""Multiply two numbers."""
return a * b
def divide(a: float, b: float):
"""Divide two numbers."""
return a / b
math_agent = create_react_agent(
model="openai:gpt-4.1",
tools=[add, multiply, divide],
prompt=(
"You are a math agent.\n\n"
"INSTRUCTIONS:\n"
"- Assist ONLY with math-related tasks\n"
"- After you're done with your tasks, respond to the supervisor directly\n"
"- Respond ONLY with the results of your work, do NOT include ANY other text."
),
name="math_agent",
)
Math agent실행
for chunk in math_agent.stream(
{"messages": [{"role": "user", "content": "what's (3 + 5) x 7"}]}
):
pretty_print_messages(chunk)
2. Create supervisor with langgraph-supervisor
prebuilt를 사용하여 supervisor생성
from langgraph_supervisor import create_supervisor
from langchain.chat_models import init_chat_model
supervisor = create_supervisor(
model=init_chat_model("openai:gpt-4.1"),
agents=[research_agent, math_agent],
prompt=(
"You are a supervisor managing two agents:\n"
"- a research agent. Assign research-related tasks to this agent\n"
"- a math agent. Assign math-related tasks to this agent\n"
"Assign work to one agent at a time, do not call agents in parallel.\n"
"Do not do any work yourself."
),
add_handoff_back_messages=True,
output_mode="full_history",
).compile()
두 에이전트(검색 수학)가 모두 필요한 쿼리로 실행
for chunk in supervisor.stream(
{
"messages": [
{
"role": "user",
"content": "find US and New York state GDP in 2024. what % of US GDP was New York state?",
}
]
},
):
pretty_print_messages(chunk, last_message=True)
final_message_history = chunk["supervisor"]["messages"]
3. Create supervisor from scratch
에이전트 커뮤니케이션 설정
from typing import Annotated
from langchain_core.tools import tool, InjectedToolCallId
from langgraph.prebuilt import InjectedState
from langgraph.graph import StateGraph, START, MessagesState
from langgraph.types import Command
def create_handoff_tool(*, agent_name: str, description: str | None = None):
name = f"transfer_to_{agent_name}"
description = description or f"Ask {agent_name} for help."
@tool(name, description=description)
def handoff_tool(
state: Annotated[MessagesState, InjectedState],
tool_call_id: Annotated[str, InjectedToolCallId],
) -> Command:
tool_message = {
"role": "tool",
"content": f"Successfully transferred to {agent_name}",
"name": name,
"tool_call_id": tool_call_id,
}
return Command(
goto=agent_name,
update={**state, "messages": state["messages"] + [tool_message]},
graph=Command.PARENT,
)
return handoff_tool
# Handoffs
assign_to_research_agent = create_handoff_tool(
agent_name="research_agent",
description="Assign task to a researcher agent.",
)
assign_to_math_agent = create_handoff_tool(
agent_name="math_agent",
description="Assign task to a math agent.",
)
supervisor 에이전트 생성
supervisor_agent = create_react_agent(
model="openai:gpt-4.1",
tools=[assign_to_research_agent, assign_to_math_agent],
prompt=(
"You are a supervisor managing two agents:\n"
"- a research agent. Assign research-related tasks to this agent\n"
"- a math agent. Assign math-related tasks to this agent\n"
"Assign work to one agent at a time, do not call agents in parallel.\n"
"Do not do any work yourself."
),
name="supervisor",
)
multi-agent graph 생성
from langgraph.graph import END
# Define the multi-agent supervisor graph
supervisor = (
StateGraph(MessagesState)
# NOTE: `destinations` is only needed for visualization and doesn't affect runtime behavior
.add_node(supervisor_agent, destinations=("research_agent", "math_agent", END))
.add_node(research_agent)
.add_node(math_agent)
.add_edge(START, "supervisor")
# always return back to the supervisor
.add_edge("research_agent", "supervisor")
.add_edge("math_agent", "supervisor")
.compile()
)
실행
for chunk in supervisor.stream(
{
"messages": [
{
"role": "user",
"content": "find US and New York state GDP in 2024. what % of US GDP was New York state?",
}
]
},
):
pretty_print_messages(chunk, last_message=True)
final_message_history = chunk["supervisor"]["messages"]
4. Create delegation tasks
from langgraph.types import Send
def create_task_description_handoff_tool(
*, agent_name: str, description: str | None = None
):
name = f"transfer_to_{agent_name}"
description = description or f"Ask {agent_name} for help."
@tool(name, description=description)
def handoff_tool(
# this is populated by the supervisor LLM
task_description: Annotated[
str,
"Description of what the next agent should do, including all of the relevant context.",
],
# these parameters are ignored by the LLM
state: Annotated[MessagesState, InjectedState],
) -> Command:
task_description_message = {"role": "user", "content": task_description}
agent_input = {**state, "messages": [task_description_message]}
return Command(
goto=[Send(agent_name, agent_input)],
graph=Command.PARENT,
)
return handoff_tool
assign_to_research_agent_with_description = create_task_description_handoff_tool(
agent_name="research_agent",
description="Assign task to a researcher agent.",
)
assign_to_math_agent_with_description = create_task_description_handoff_tool(
agent_name="math_agent",
description="Assign task to a math agent.",
)
supervisor_agent_with_description = create_react_agent(
model="openai:gpt-4.1",
tools=[
assign_to_research_agent_with_description,
assign_to_math_agent_with_description,
],
prompt=(
"You are a supervisor managing two agents:\n"
"- a research agent. Assign research-related tasks to this assistant\n"
"- a math agent. Assign math-related tasks to this assistant\n"
"Assign work to one agent at a time, do not call agents in parallel.\n"
"Do not do any work yourself."
),
name="supervisor",
)
supervisor_with_description = (
StateGraph(MessagesState)
.add_node(
supervisor_agent_with_description, destinations=("research_agent", "math_agent")
)
.add_node(research_agent)
.add_node(math_agent)
.add_edge(START, "supervisor")
.add_edge("research_agent", "supervisor")
.add_edge("math_agent", "supervisor")
.compile()
)
for chunk in supervisor.stream(
{
"messages": [
{
"role": "user",
"content": "find US and New York state GDP in 2024. what % of US GDP was New York state?",
}
]
},
subgraphs=True,
):
pretty_print_messages(chunk, last_message=True)