세로형
Recent Posts
Recent Comments
Link
01-29 06:19
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

꿈 많은 사람의 이야기

랭그래프(LangGraph)란? LangGraph의 개념과 사용 방법 예제(example) 본문

인공지능(AI)/AI Agent

랭그래프(LangGraph)란? LangGraph의 개념과 사용 방법 예제(example)

이수진의 블로그 2025. 7. 27. 16:29
반응형
728x170

포스팅 개요

이번 포스팅에서는 랭체인(LangChain) 생태계의 라이브러리인 랭그래프(LangGraph)에 대해서 알아봅니다. LangGraph란 무엇인지 알아보고, LangGraph를 사용하여 LLM 애플리케이션의 로직과 흐름을 명확하게 제어하는 방법을 알아봅니다. 특히 LangGraph의 핵심 구성 요소인 상태(State), 노드(Node), 엣지(Edge)에 대해 자세히 살펴보고, LLM을 연동하여 간단한 챗봇 에이전트(Agent)를 만들어보는 예제 코드를 살펴봅니다.

 

본 포스팅은 아래 글들을 참고해서 작성하였습니다.

 

Start with a prebuilt agent

agent LangGraph quickstart This guide shows you how to set up and use LangGraph's prebuilt, reusable components, which are designed to help you construct agentic systems quickly and reliably. Prerequisites Before you start this tutorial, ensure you have th

langchain-ai.github.io

 


포스팅 본문

LLM 애플리케이션을 개발할 때, 단순히 모델을 한 번 호출하는 것을 넘어 여러 단계를 거치거나, 특정 조건에 따라 분기하는 등 복잡한 로직이 필요할 때가 많습니다. LangGraph는 바로 이런 복잡한 흐름을 '그래프(Graph)' 형태로 명확하게 설계하고 제어할 수 있도록 도와주는 라이브러리입니다.

본 포스팅의 순서는 다음과 같습니다.

  1. LangGraph란?
  2. LangGraph의 3가지 핵심 구성 요소
  3. 예제 코드로 LangGraph 작동 방식 이해하기
  4. LangGraph 기본 코드 예제(example)

LangGraph란?

LangGraph는 LLM을 기반으로 상태를 유지하고(Stateful), 여러 단계에 걸쳐 작동하는(multi-step) 에이전트를 구축하기 위한 라이브러리입니다. 기존의 LangChain이 LLM과 외부 도구를 '연쇄적으로(chaining)' 연결하는 데 중점을 두었다면, LangGraph는 이러한 연결 구조를 순환(cycle)을 포함한 그래프 형태로 확장하여 훨씬 더 유연하고 정교한 제어를 가능하게 합니다.

 

단순한 체인 구조로는 구현하기 까다로웠던 '사용자 입력을 다시 받아오는 것', '특정 조건이 만족될 때까지 작업 반복하는 것'과 같은 로직을 손쉽게 구현할 수 있는 것이죠.


LangGraph의 3가지 핵심 구성 요소

LangGraph로 에이전트를 만들 때는 주로 세 가지 핵심 요소를 다루게 됩니다.

  • 상태 (State): 그래프의 '메모리'입니다. 그래프의 각 단계를 거치면서 데이터가 어떻게 변하고 유지되는지를 정의하는 객체입니다. 대화 기록, 중간 결과, 사용자 정보 등 에이전트가 작업을 수행하는 동안 기억해야 할 모든 정보가 이 상태에 담깁니다. 보통 파이썬의 TypedDict를 사용하여 명확한 구조로 정의합니다.
  • 노드 (Nodes): 그래프의 '작업 단위'입니다. 특정 작업을 수행하는 Python 함수라고 생각할 수 있습니다. 노드는 현재의 상태(State)를 입력받아, LLM을 호출하거나 도구를 사용하는 등의 작업을 처리한 뒤, 변경된 상태를 반환합니다.
  • 엣지 (Edges): 노드와 노드를 연결하는 '경로'입니다. 정보와 제어 흐름이 어떤 순서로 이어질지를 결정합니다.

예제 코드로 LangGraph 작동 방식 이해하기

이론적인 설명보다는 코드로 보는 것이 더 이해가 빠를겁니다. 실제 코드를 보며 위에서 설명한 핵심 요소들이 어떻게 작동하는지 알아보겠습니다.

 

 

참고사항

 

이 예제는 colab 환경에서 vLLM으로 배포된 모델을 사용하여 간단한 챗봇을 만드는 코드입니다.

여러분들이 만약 Ollama를 사용하고 계시다면, Ollama를 활용하시면 됩니다. OpenAI 등을 사용하시면 그 환경에 맞게 LLM을 바꾸시면 됩니다.

제가 활용한 방법인 Colab 환경에서 vLLM을 서버로 사용하는 방법이 궁금하신 분들은 블로그( https://lsjsj92.tistory.com/693 ) 내용을 참고해주세요!

 

Google Colab과 ngrok으로 나만의 LLM API 서버 구축하기 (feat. Ollama, vLLM)

포스팅 개요이번 포스팅은 로컬 개발 환경에 고사양의 GPU가 없더라도 구글 코랩(Google Colab)의 무료 GPU 자원을 활용해 자신만의 LLM(거대 언어 모델) API 서버를 구축하는 방법에 대해 정리합니다. n

lsjsj92.tistory.com

 

반응형

1. LLM 객체 생성 및 vLLM 서버 연동

먼저 LLM 객체를 설정합니다. 주목할 점은 ChatOpenAI 클래스를 사용하지만, openai_api_base에 vLLM으로 배포한 서버의 주소를 지정했다는 것입니다.

또한, 저는 Qwen3 모델을 사용했습니다. Qwen 모델은 알리바바에서 제공한 모델인데요. 뛰어난 한국어 성능을 제공할 뿐만 아니라, thinking 모드와 tool을 사용할 수 있는 방법을 지원해주는 매우 유용한 모델입니다.

# vLLM 서버와 통신할 LLM 객체를 생성합니다.
# OpenAI의 API와 호환되므로 ChatOpenAI를 사용합니다.
# api_key는 vLLM에서 사용되지 않으므로 아무 값이나 넣어도 됩니다.
llm = ChatOpenAI(
    model="Qwen/Qwen3-14B",
    openai_api_key="EMPTY",
    openai_api_base="{YOUR_ADDRESS}/v1", # vLLM 서버 주소
    temperature=0.2,
    max_tokens=512,
    ...
)

 

이렇게 하면 OpenAI 라이브러리의 편리한 인터페이스를 그대로 사용하면서, 실제 모델은 우리가 직접 배포한 로컬 LLM을 사용하게 됩니다.

 

2. 에이전트 상태(State) 정의

다음으로 그래프의 '메모리' 역할을 할 AgentState를 정의합니다.

from typing import List, Annotated
from typing_extensions import TypedDict
from langchain_core.messages import AnyMessage

class AgentState(TypedDict):
    # 'messages'는 대화 기록을 저장하는 리스트입니다.
    messages: Annotated[List[AnyMessage], lambda x, y: x + y]
    turn_count: int
  • messages: 사용자와 AI의 대화 기록을 list 형태로 계속 축적해 나갑니다. Annotated와 lambda 함수 lambda x, y: x + y는 LangGraph가 새로운 메시지를 기존 리스트에 자동으로 더해주도록 하는 편리한 기능입니다.
  • turn_count: 대화 턴 수를 기록하는 정수 값입니다.

 

3. 에이전트 노드(Node) 정의

그래프의 '작업 단위'인 chatbot_node 함수입니다. 이 함수는 AgentState를 입력으로 받아, 그 안의 messages를 LLM에 전달합니다.

 

def chatbot_node(state: AgentState):
    """
    현재 상태(대화 기록)를 기반으로 LLM을 호출하여 응답을 생성하는 노드입니다.
    """
    print("--- 챗봇 노드 실행 ---")
    # 현재 상태에서 메시지들을 가져옵니다.
    messages = state['messages']
    turn_count = state['turn_count']
    
    # vLLM 서버에 메시지를 보내고 응답을 받습니다.
    response = llm.invoke(messages)
    
    # 받은 응답(AIMessage)을 상태의 messages 리스트에 추가하여 반환합니다.
    return {
        "messages": [response],
        "turn_count": turn_count
    }

 

그리고 LLM으로부터 받은 응답(response)을 다시 messages 키에 담아 딕셔너리 형태로 반환합니다. 또한, 카운트 값도 반환하구요.

LangGraph는 이 반환값을 받아 기존 AgentState에 자동으로 업데이트해 줍니다.

 

4. 그래프 생성 및 조립

이제 위에서 만든 상태와 노드를 조립하여 실제 워크플로우를 만듭니다.

from langgraph.graph import StateGraph, END

# StateGraph에 위에서 정의한 상태(AgentState)를 연결하여 그래프 빌더를 생성합니다.
graph_builder = StateGraph(AgentState)

# 그래프에 노드를 추가합니다. "chatbot"이라는 이름으로 chatbot_node 함수를 등록합니다.
graph_builder.add_node("chatbot", chatbot_node)

# 그래프의 진입점(Entry Point)과 종료점(End Point)을 설정합니다.
# "chatbot" 노드에서 시작합니다.
graph_builder.set_entry_point("chatbot")
# "chatbot" 노드가 끝나면, 워크플로우를 종료(END)합니다.
graph_builder.add_edge("chatbot", END)
# 정의된 내용으로 그래프를 컴파일하여 실행 가능한 앱을 만듭니다.
agent_app = graph_builder.compile()
  1. StateGraph(AgentState): 우리가 정의한 AgentState를 사용하는 그래프를 만들겠다고 선언합니다.
  2. graph_builder.add_node("chatbot", chatbot_node): "chatbot"이라는 이름으로 chatbot_node 함수를 그래프에 작업 단위로 추가합니다.
  3. graph_builder.set_entry_point("chatbot"): 이 그래프는 "chatbot" 노드에서 실행을 시작한다고 지정합니다.
  4. graph_builder.add_edge("chatbot", END): "chatbot" 노드의 작업이 끝나면, 더 이상 다른 노드로 가지 않고 그래프 실행을 종료(END)하라고 엣지를 연결합니다. (이 예제는 노드가 하나뿐이라 간단하지만, 여러 노드를 연결할 때 이 add_edge가 핵심 역할을 합니다.)
  5. agent_app = graph_builder.compile(): 정의된 구조를 바탕으로 실행 가능한 애플리케이션을 생성합니다.

 

5. 에이전트 실행 및 결과 확인

이제 모든 준비가 끝났습니다. 생성된 agent_app을 직접 실행하여 vLLM 서버와 통신하는 것을 확인해 보겠습니다.

agent_app.invoke()에 첫 사용자 메시지가 담긴 initial_input을 전달하면, 우리가 설계한 그래프가 실행됩니다.

from langchain_core.messages import HumanMessage, AIMessage

# 에이전트와 상호작용을 시작합니다.
# 초기 메시지를 HumanMessage로 설정합니다.
initial_input = {
    "messages": [HumanMessage(content="안녕하세요? 이수진이라고 합니다.")],
    "turn_count": 0
}

# agent_app.invoke()를 사용하여 그래프를 실행합니다.
final_state = agent_app.invoke(initial_input)

# 최종 상태에 담긴 모든 메시지를 출력합니다.
print("\n--- 최종 대화 기록 ---")
for message in final_state['messages']:
    if isinstance(message, HumanMessage):
        print(f"사용자: {message.content}")
    elif isinstance(message, AIMessage):
        print(f"AI 응답: {message.content}")
  1. initial_inputchatbot 노드에 전달됩니다.
  2. chatbot_nodellm.invoke()를 통해 vLLM 서버에 요청을 보내고 응답을 받습니다.
  3. 받은 AI 응답 메시지가 messages 리스트에 추가되어 final_state가 반환됩니다.

 

최종 출력된 final_state를 보면, 초기 HumanMessage와 LLM이 생성한 AIMessage가 모두 messages 리스트에 담겨 있는 것을 확인할 수 있습니다. 저는 예제로 "안녕하세요? 이수진이라고 합니다"라는 메세지를 전달했는데요. 모델이 잘 응답하는 것을 확인할 수 있습니다.


마무리

이번 포스팅에서는 LangGraph의 핵심 개념과 간단한 예제를 통해 복잡한 LLM 에이전트를 어떻게 제어할 수 있는지 알아보았습니다. 다음번에는 조건부 엣지(Conditional Edge)를 활용하여 여러 도구(Tool)를 사용하고, 그 결과에 따라 동적으로 판단하고 행동하는 한층 더 발전된 에이전트를 만들어 보겠습니다.

반응형
그리드형
Comments