본 게시글은 LLM을 통해 작성된 게시글입니다.
LangChain과 LangGraph는 LLM 기반 애플리케이션을 개발할 때 자주 사용되는 프레임워크입니다. 특히 Agent를 구현하는 방식에 있어서 각각의 접근법과 특징이 있습니다. 이번 포스트에서는 initialize_agent
, create_react_agent
, 그리고 create_supervisor_agent
의 세 가지 함수를 비교 분석해 보겠습니다.
from langchain.agents.initialize import initialize_agent
initialize_agent
는 LangChain의 초기 버전에서 도입된 에이전트 생성 방식으로, 데코레이터를 통해 이미 deprecated 되었음을 알 수 있습니다. 다양한 유형의 에이전트를 생성할 수 있으며, AgentExecutor
객체를 반환합니다.
해당 링크에서 확인해보니, 레거시임메서드임을 확인할 수 있었다. LCEL기반의
create_react_agent
를 권장하는 문구가 있다.
from langgraph.prebuilt import create_react_agent
create_react_agent
는 ReAct(Reasoning and Acting) 패턴을 구현한 에이전트를 생성합니다. 이는 initialize_agent
보다 더 현대적인 접근법으로, Runnable 인터페이스를 기반으로 합니다. 코드 주석에서도 언급했듯이, 프로덕션 환경에서는 LangGraph의 구현을 사용하는 것이 권장됩니다. LangGraph의 create_react_agent
는 CompiledGraph를 반환하는데, 이는 실행 가능한 그래프 인스턴스입니다.
create_react_agent
를 통해 생성된 Graph를 mermaid로 통해 보면 위와 같은 구조를 갖는다.
from langgraph_supervisor import create_supervisor
create_supervisor_agent
는 LangGraph에서 제공하는 함수로, 여러 에이전트를 관리하고 조율하는 슈퍼바이저를 생성합니다. 이는 가장 최신의 접근법으로, StateGraph를 반환합니다. 이는 아직 컴파일되지 않은 그래프 정의로, 사용하기 전에 .compile()
메서드를 호출하여 CompiledGraph로 변환해야 합니다.
그림에서 Supervisor 아래의 Agent들은 create_react_agent로 생성된 하위 에이전트들로, 각자 독립적인 SubGraph를 형성합니다. 또는 더 단순한 구현에서는 Tool로 대체될 수도 있습니다.
langgraph-supervisor github에서 소스코드를 확인할 수 있으며, 2025년 2월쯤 Release된, LangGraph 0.3버전에서 추가된 메서드입니다.
create_supervisor_agent
를 이해하기 위해서는 먼저 다중 에이전트 시스템의 개념을 명확히 해야 합니다. 다중 에이전트 시스템이란 단순히 여러 도구(tools)를 하나의 에이전트가 사용하는 것이 아니라, 서로 다른 역할과 전문성을 가진 여러 독립적인 에이전트가 협업하여 복잡한 작업을 수행하는 시스템을 의미합니다.
역할 및 책임의 분리:
독립적인 개발 및 확장:
상태(State) 관리:
SubGraph 구조:
특성 | 단일 에이전트 (create_react_agent ) | 다중 에이전트 (create_supervisor_agent ) |
---|---|---|
구조 | 하나의 에이전트가 모든 도구 사용 | 여러 전문 에이전트가 각자의 도구 사용 |
상태 관리 | 단일 상태 흐름 | 복잡한 상태 전이 및 에이전트 간 전환 |
확장성 | 도구를 추가하여 확장 | 새로운 에이전트를 추가하여 확장 |
모듈성 | 제한적 | 높음 (각 에이전트는 독립적인 모듈) |
개발 방식 | 중앙집중식 | 분산식 (여러 개발자가 각 에이전트 개발 가능) |
각 함수는 서로 다른 파라미터와 반환 값을 가지고 있습니다. 아래에서 주요 차이점을 살펴보겠습니다.
initialize_agent
와 create_react_agent
는 llm
이라는 이름으로, create_supervisor_agent
는 model
이라는 이름으로 받습니다.initialize_agent
는 agent
파라미터를 통해 다양한 에이전트 타입(AgentType)을 지정할 수 있습니다.create_react_agent
와 create_supervisor_agent
는 명시적으로 프롬프트를 받습니다.create_supervisor_agent
는 여러 에이전트(agents
)를 입력으로 받습니다. 이는 다중 에이전트 구조를 반영합니다.create_supervisor_agent
는 parallel_tool_calls
파라미터를 통해 병렬 도구 호출을 지원합니다. 이를 통해 여러 에이전트에 동시에 작업을 할당할 수 있습니다.create_supervisor_agent
는 output_mode
파라미터를 통해 메시지 히스토리에 에이전트 출력을 추가하는 방식을 지정할 수 있습니다.initialize_agent
: AgentExecutor 반환 (바로 사용 가능)create_react_agent
: CompiledGraph 반환 (바로 사용 가능)create_supervisor_agent
: StateGraph 반환 (사용 전 .compile() 필요)각 함수는 서로 다른 방식으로 에이전트를 구현합니다. 이제 그 차이점을 자세히 살펴보겠습니다.
앞서 언급했듯이, 이제 LangChain에서는 Legacy 메서드입니다.
initialize_agent
는 가장 전통적인 방식으로 에이전트를 생성합니다:
from_llm_and_tools
메서드를 호출하여 에이전트 객체를 생성합니다.AgentExecutor.from_agent_and_tools
메서드를 통해 최종 에이전트 실행기를 반환합니다.이 접근법은 직관적이지만, 확장성과 유연성이 제한되어 있습니다.
# 에이전트 타입 또는 경로 결정
if agent is None and agent_path is None:
agent = AgentType.ZERO_SHOT_REACT_DESCRIPTION
# 에이전트 객체 생성
agent_obj = agent_cls.from_llm_and_tools(
llm, tools, callback_manager=callback_manager, **agent_kwargs
)
# AgentExecutor 반환
return AgentExecutor.from_agent_and_tools(
agent=agent_obj,
tools=tools,
callback_manager=callback_manager,
tags=tags_,
**kwargs,
)
create_react_agent
는 Runnable 인터페이스를 기반으로 한 더 현대적인 접근법을 사용합니다:
이 접근법은 함수형 프로그래밍 스타일을 사용하며, 파이프라인 방식으로 데이터를 처리합니다.
# 프롬프트 변수 확인
missing_vars = {"tools", "tool_names", "agent_scratchpad"}.difference(
prompt.input_variables + list(prompt.partial_variables)
)
# 프롬프트 준비
prompt = prompt.partial(
tools=tools_renderer(list(tools)),
tool_names=", ".join([t.name for t in tools]),
)
# Runnable 파이프라인 구성
agent = (
RunnablePassthrough.assign(
agent_scratchpad=lambda x: format_log_to_str(x["intermediate_steps"]),
)
| prompt
| llm_with_stop
| output_parser
)
create_supervisor_agent
는 LangGraph의 StateGraph를 사용하여 여러 에이전트를 관리하는 더 복잡한 시스템을 구현합니다:
이 접근법은 그래프 기반 워크플로우를 사용하여 여러 에이전트 간의 복잡한 상호작용을 가능하게 합니다. 각 에이전트는 SubGraph로 구현되며, 이러한 SubGraph들이 슈퍼바이저에 의해 조율됩니다.
# 에이전트 이름 검증
agent_names = set()
for agent in agents:
if agent.name is None or agent.name == "LangGraph":
raise ValueError(...)
if agent.name in agent_names:
raise ValueError(...)
agent_names.add(agent.name)
# Handoff 도구 설정 (에이전트 간 작업 전환용)
handoff_destinations = [create_handoff_tool(agent_name=agent.name) for agent in agents]
# StateGraph 구성
builder = StateGraph(state_schema, config_schema=config_schema)
builder.add_node(supervisor_agent, destinations=tuple(agent_names) + (END,))
builder.add_edge(START, supervisor_agent.name)
for agent in agents:
builder.add_node(...)
builder.add_edge(agent.name, supervisor_agent.name)
create_supervisor_agent
와 ReAct 패턴의 관계는 다음과 같습니다:
create_supervisor_agent
는 내부적으로 ReAct 패턴을 활용합니다. 코드를 자세히 살펴보면:
supervisor_agent = create_react_agent(
name=supervisor_name,
model=model,
tools=all_tools,
prompt=prompt,
state_schema=state_schema,
response_format=response_format,
)
여기서 주목할 점은 슈퍼바이저 자체가 create_react_agent
함수를 통해 생성된다는 것입니다. 이는 슈퍼바이저도 ReAct 패턴을 기반으로 작동함을 의미합니다.
또한, 슈퍼바이저가 관리하는 개별 에이전트들도 일반적으로 ReAct 패턴을 사용합니다:
# 전문 에이전트 생성 예시
researcher = create_react_agent(
name="researcher",
model=model,
tools=[...], # 리서치 도구
)
ReAct 패턴은 "Reasoning and Acting"의 약자로, LLM이 다음과 같은 단계를 통해 문제를 해결하는 방식입니다:
create_supervisor_agent
는 다음과 같이 ReAct 패턴을 확장하여 다중 에이전트 시스템에 적용합니다:
슈퍼바이저 ReAct: 슈퍼바이저 자체가 ReAct 패턴을 사용하여 문제를 분석하고, 어떤 하위 에이전트에게 작업을 위임할지 결정합니다.
하위 에이전트 ReAct: 각 하위 에이전트도 ReAct 패턴을 사용하여 자신에게 할당된 특정 작업을 처리합니다.
다단계 ReAct: 슈퍼바이저는 하위 에이전트의 결과를 관찰하고, 추가 작업이 필요한지 결정하여 전체 워크플로우를 조율합니다.
이 과정을 통해 슈퍼바이저는 문제를 분석(Reasoning)하고, 적절한 하위 에이전트에게 작업을 위임(Acting)한 후, 결과를 수집(Observation)하는 확장된 ReAct 패턴을 구현합니다.
슈퍼바이저가 ReAct 패턴을 사용하지만, 일반적인 ReAct 에이전트와는 다음과 같은 차이점이 있습니다:
parallel_tool_calls
파라미터를 통해 여러 하위 에이전트에 병렬로 작업을 할당할 수 있습니다.각 함수는 서로 다른 사용 사례와 상황에 적합합니다. 이제 언제 어떤 함수를 사용해야 하는지 살펴보겠습니다.
from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0)
tools = [...] # 도구 목록
agent = initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True
)
agent.run("주식 시장 동향을 분석해줘")
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate
# ReAct 패턴을 구현하는 프롬프트 템플릿
prompt = PromptTemplate.from_template("""다음 질문에 답변해주세요. 당신은 도구를 사용할 수 있습니다:
{tools}
질문에 답하기 위해 다음 형식을 사용하세요:
질문: 사용자의 질문
생각: 다음에 무엇을 해야 할지 생각합니다
행동: 사용할 도구 이름, 다음 중 하나여야 합니다 - [{tool_names}]
행동 입력: 도구에 전달할 입력
관찰: 도구의 결과
... (이 생각/행동/행동 입력/관찰 단계를 여러 번 반복할 수 있습니다)
생각: 이제 최종 답변을 알고 있습니다
최종 답변: 질문에 대한 최종 답변
질문: {input}""")
model = ChatOpenAI(model_name="gpt-4o-mini")
tools = [...] # 도구 목록
agent = create_react_agent(model, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools)
result = agent_executor.invoke({"input": "오늘 날씨 어때?"})
from langgraph_supervisor import create_supervisor
from langgraph.prebuilt.chat_agent_executor import create_react_agent
from langchain_community.chat_models import ChatOpenAI
model = ChatOpenAI()
# 전문 에이전트 생성 (각각이 독립적인 SubGraph)
researcher = create_react_agent(
name="researcher",
model=model,
tools=[web_search], # 리서치 도구
)
math_agent = create_react_agent(
name="math_expert",
model=model,
tools=[add, multiply], # 수학 도구
)
# 슈퍼바이저 생성 (여러 SubGraph를 조율)
supervisor = create_supervisor(
agents=[researcher, math_agent],
model=model,
prompt=(
"You are a team supervisor managing a research expert and a math expert. "
"For current events, use researcher. "
"For math problems, use math_expert."
),
parallel_tool_calls=True, # 병렬 처리 활성화
output_mode="last_message", # 메시지 관리 방식 지정
)
# StateGraph를 CompiledGraph로 변환
graph = supervisor.compile()
result = graph.invoke({
"messages": [{"content": "FAANG 회사들의 2024년 총 직원 수는?"}]
})
세 함수를 비교 분석한 결과, 다음과 같은 결론을 내릴 수 있습니다:
initialize_agent:
create_react_agent:
create_supervisor_agent:
.compile()
을 호출해야 합니다. 이는 추가 구성 옵션(메모리, 체크포인터 등)을 제공하는 장점이 있습니다.현재 각 프로젝트의 복잡성, 필요한 기능, 그리고 개발 팀의 친숙도를 고려하여 적절한 함수를 선택하는 것이 중요합니다. 일반적으로, 새로운 프로젝트라면 다음과 같이 선택하는 것을 추천합니다:
create_react_agent
create_supervisor_agent
각 함수는 LangChain과 LangGraph의 발전 과정을 보여주며, 더 복잡한 AI 시스템을 구현하기 위한 프레임워크의 진화를 반영합니다. 이러한 이해를 바탕으로 프로젝트에 가장 적합한 도구를 선택할 수 있을 것입니다.