본문 바로가기
최신 AI

LangGraph 사용법

by 구라100단 2026. 2. 10.

LangGraph란? (간단 개념)

LangGraph는 복잡한 AI 에이전트를 만들 때 유용한 도구입니다. 기존의 LangChain이 A→B→C처럼 한 방향으로 흐르는 파이프라인에 강점이 있었다면, LangGraph는 상황에 따라 B에서 다시 A로 돌아가거나, C 대신 D로 가는 등의 순환과 분기가 가능한, 더 유연한 '그래프' 형태의 워크플로우를 만들 수 있게 해줍니다.

쉽게 말해, '상태'를 가진 에이전트를 만들 때 사용합니다. 에이전트가 어떤 행동을 하고(Node), 그 결과에 따라 다음 행동을 결정하는(Edge) 과정을 시각적으로 구성할 수 있습니다.


LangGraph 사용법: 설치부터 실행까지

1단계: 설치하기

가장 먼저 필요한 패키지들을 설치해야 합니다. LangGraph는 LangChain 생태계의 일부이므로 langchain과 함께 설치하며, 보통 OpenAI의 모델을 많이 사용하므로 langchain-openai도 같이 설치하는 것이 일반적입니다.

터미널에 다음 명령어를 입력하여 설치합니다.

pip install langgraph langchain langchain-openai

2단계: 핵심 개념 이해하기 (상태, 노드, 엣지)

LangGraph를 사용하려면 세 가지 핵심 요소를 이해해야 합니다.

  1. 상태 (State): 그래프의 모든 단계(노드)가 공유하는 '메모리' 또는 데이터 저장소입니다. 각 노드는 이 상태를 읽고, 자신의 작업을 수행한 뒤, 상태를 업데이트하여 다음 노드로 전달합니다. 보통 파이썬의 TypedDict를 사용하여 구조를 정의합니다.
  2. 노드 (Node): 그래프에서 실제 작업을 수행하는 단위입니다. LLM을 호출하거나, 특정 도구를 사용하거나, 데이터를 처리하는 하나의 '함수'라고 생각하면 쉽습니다. 각 노드는 현재 '상태'를 입력받아 작업을 처리하고, 변경된 '상태' 정보를 반환합니다.
  3. 엣지 (Edge): 노드와 노드를 연결하는 **'경로'**입니다. 이 엣지가 워크플로우의 흐름을 결정합니다.
    • 일반 엣지: A 노드가 끝나면 항상 B 노드로 이동합니다.
    • 조건부 엣지: A 노드의 결과에 따라 B로 갈지, C로 갈지를 결정합니다. 이것이 LangGraph의 핵심 기능입니다.

3단계: 간단한 AI 에이전트 만들어보기

이제 간단한 'AI 연구 비서' 에이전트를 만들어 보겠습니다. 이 에이전트는 사용자의 질문에 대해 웹 검색이 필요한지 스스로 판단하고, 필요하면 검색을 수행한 후 답변을 생성합니다.

1. 상태(State) 정의하기

먼저, 에이전트가 작업하는 동안 유지해야 할 정보들을 '상태'로 정의합니다. 여기서는 사용자의 질문과 생성된 답변들을 리스트로 관리하겠습니다.

from typing import List, TypedDict
from langchain_core.messages import BaseMessage

class AgentState(TypedDict):
    # BaseMessage는 LangChain에서 사용하는 메시지 형식 (HumanMessage, AIMessage 등)
    messages: List[BaseMessage]

2. 노드(Node) 정의하기

이제 에이전트가 수행할 작업들을 함수(노드)로 만듭니다.

  • call_model: LLM을 호출하여 사용자의 질문에 답변하거나, 다음 할 일을 결정하는 핵심 노드입니다.
  • call_tool: call_model이 웹 검색이 필요하다고 판단했을 때, 실제 검색을 수행하는 노드입니다.
import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage
from langchain_community.tools.tavily_search import TavilySearchResults

# .env 파일 등에 OPENAI_API_KEY, TAVILY_API_KEY를 설정해야 합니다.
# os.environ["OPENAI_API_KEY"] = "sk-..."
# os.environ["TAVILY_API_KEY"] = "tvly-..."

# 도구 정의: 웹 검색 도구
tool = TavilySearchResults(max_results=2)
tools = [tool]

# 모델 정의
model = ChatOpenAI(temperature=0).bind_tools(tools)

# 1) 모델 호출 노드
def call_model(state: AgentState):
    messages = state['messages']
    response = model.invoke(messages)
    # AIMessage 형태로 응답을 messages 리스트에 추가
    return {"messages": [response]}

# 2) 도구 호출 노드
def call_tool(state: AgentState):
    last_message = state['messages'][-1] # 모델이 생성한 메시지
    # tool_calls에서 도구 이름과 인자를 추출하여 실행
    tool_call = last_message.tool_calls[0]
    result = tool.invoke(tool_call['args'])
    # 도구 실행 결과를 ToolMessage 형태로 messages 리스트에 추가
    return {"messages": [AIMessage(content=str(result), tool_call_id=tool_call['id'])]}

3. 엣지(Edge)와 그래프 연결하기

이제 정의한 상태와 노드들을 그래프로 엮어줍니다. 여기서 조건부 엣지가 사용됩니다.

  • 모델을 호출(call_model)한 뒤, 그 결과에 tool_calls가 있으면 웹 검색(call_tool) 노드로 이동합니다.
  • tool_calls가 없으면(단순 답변이면) 워크플로우를 종료(END)합니다.
  • 웹 검색(call_tool)이 끝나면, 검색 결과를 가지고 다시 모델을 호출(call_model)하여 최종 답변을 생성합니다.
from langgraph.graph import StateGraph, END

# 조건부 엣지를 위한 라우팅 함수
def should_continue(state: AgentState):
    last_message = state['messages'][-1]
    if last_message.tool_calls:
        return "call_tool" # tool_calls가 있으면 call_tool 노드로
    else:
        return END # 없으면 종료

# 그래프 생성
graph = StateGraph(AgentState)

# 노드 추가
graph.add_node("call_model", call_model)
graph.add_node("call_tool", call_tool)

# 진입점(Entry Point) 설정
graph.set_entry_point("call_model")

# 조건부 엣지 추가
graph.add_conditional_edges(
    "call_model",       # call_model 노드 실행 후
    should_continue,    # should_continue 함수 결과에 따라
    {
        "call_tool": "call_tool", # "call_tool"이 반환되면 call_tool 노드로
        END: END                  # END가 반환되면 종료
    }
)

# 일반 엣지 추가 (도구 사용 후 다시 모델 호출)
graph.add_edge("call_tool", "call_model")

# 그래프 컴파일
app = graph.compile()

4. 실행하기

컴파일된 appinvoke 메소드로 실행하면 됩니다. 첫 질문을 messages에 담아 전달합니다.

inputs = {"messages": [HumanMessage(content="What is the weather in Seoul?")]}
result = app.invoke(inputs)

# 최종 결과 출력
print(result['messages'][-1].content)

위 코드를 실행하면, 에이전트는 다음과 같은 순서로 동작합니다.

  1. "서울 날씨가 어때?"라는 질문을 받고 call_model 노드가 실행됩니다.
  2. 모델은 이 질문에 답하려면 웹 검색이 필요하다고 판단하고, tool_calls가 포함된 응답을 생성합니다.
  3. should_continue 함수가 tool_calls를 감지하고, 워크플로우를 call_tool 노드로 보냅니다.
  4. call_tool 노드가 실제 웹 검색을 수행하고, 그 결과를 상태에 추가합니다.
  5. call_tool 노드에서 call_model 노드로 엣지가 연결되어 있으므로, 검색 결과를 가지고 다시 call_model이 실행됩니다.
  6. 모델은 검색 결과를 바탕으로 "서울의 현재 날씨는..."과 같은 최종 답변을 생성합니다.
  7. 이 최종 답변에는 tool_calls가 없으므로, should_continue 함수가 END를 반환하고 워크플로우가 종료됩니다.

요약

LangGraph 사용법을 정리하면 다음과 같습니다.

  1. 설치: pip install langgraph langchain langchain-openai
  2. 상태 정의: 에이전트의 메모리 역할을 할 TypedDict를 만든다.
  3. 노드 정의: 실제 작업을 수행할 함수들을 만든다. (LLM 호출, 도구 사용 등)
  4. 그래프 구성: StateGraph를 만들고, 노드와 엣지(특히 조건부 엣지)를 추가하여 워크플로우를 설계한다.
  5. 컴파일 및 실행: 그래프를 compile()하고, invoke()로 실행한다.

처음에는 조금 복잡해 보일 수 있지만, 이 구조 덕분에 여러 단계를 거치며 스스로 판단하고 행동하는 복잡한 AI 에이전트를 훨씬 체계적으로 만들 수 있습니다.