[AI] Agent (LangGraph, LangChain)

OpenAPI API / StageGraph(State, Node, Edge)

Posted by Wonyong Jang on February 27, 2026 · 9 mins read

LangGraph는 자연어 처리와 AI 응용 프로그램 개발을 위한 강력한 프레임워크로, 복잡한 언어 모델과의 상호작용을 효율적이고 구조화된 방식으로 구현할 수 있도록 돕는다.
다양한 데이터 소스와 언어 모델을 통합하여 지능형 응답 생성, 정보 검색, 텍스트 분석 등의 고도화된 시스템을 구축할 수 있다.


1. LangGraph 와 LangChain 의 차이점

LangGraph 와 LangChain은 둘다 LLM 어플리케이션 개발을 위한 강력한 도구이지만, 각각의 특징과 장단점이 있다.
이 두 프레임워크의 주요 차이점을 살펴보자.

1-1) 주요 목적

LangGraph는 복잡한 워크플로우와 정교한 의사결정 프로세스를 구현하는 데 특화되어 있다.
여러 단계의 처리 과정이나 조건부 로직이 필요한 고급 AI 시스템에 적합하다.

LangChain은 LLM을 다양한 외부 도구와 쉽게 통합하고, 간단한 체인 구조로 어플리케이션을 구성하는 데 중점을 둔다.
빠른 프로토타이핑과 기본적인 LLM 기반 어플리케이션 개발에 유용하다.

1-2) 구조

LangGraph 는 그래프 기반 구조를 채택하여 노드와 엣지로 구성된 유연한 워크플로우를 만들 수 있다.
이는 복잡한 로직과 다단계 프로세스를 직관적으로 모델링하는 데 도움이 된다.

LangChain은 체인과 에이전트 기반 구조를 사용한다.
이는 선형적인 처리 과정이나 미리 정의된 에이전트 패턴을 구현하기 쉽게 만든다.

1-3) 상태 관리

LangGraph는 명시적이고 세밀한 상태 관리를 제공한다. 개발자가 각 단계에서 상태를 직접 제어하고 수정할 수 있어, 복잡한 상태 변화를 정확하게 추적하고 관리할 수 있다.

LangChain은 상대적으로 암시적이고 자동화된 상태 관리를 제공한다. 이는 개발 과정을 단순화하지만, 세부적인 상태 제어가 필요한 경우 제한적일 수 있다.

1-4) 유연성

LangGraph는 높은 유연성을 제공하여 커스텀 로직을 쉽게 구현할 수 있다. 개발자가 원하는 대로 그래프 구조를 설계하고 각 노드의 동작을 상세하게 정의할 수 있다.

LangChain은 미리 정의된 컴포넌트를 중심으로 구성되어 있어, 기본적인 기능을 빠르게 구현할 수 있지만 고도로 커스터마이즈된 로직을 구현하는 데는 상대적으로 제한이 있을 수 있다.

1-5) 용도

LangGraph 는 복잡한 AI 시스템이나 다중 에이전트 시스템을 구축하는데 적합하다.
여러 AI 모델이 상호작용하거나 복잡한 의사 결정 과정이 필요한 프로젝트에 이상적이다.

LangChain은 간단한 LLM 어플리케이션이나 RAG(Retrieval-Augmented Generation) 시스템을 구축하는데 주로 사용된다.
빠른 개발과 프로토타이핑이 필요한 프로젝트에 적합하다.


2. LangGraph 설치 및 LLM 모델 설정

uv 와 VSCode 를 이용하여 가상환경을 구성해보자.

# 새 프로젝트 생성 (자동으로 가상환경 생성)
uv init langgraph-project
cd langgraph-project

# 또는 기존 폴더에서 가상환경만 생성
uv venv --python 3.11

source .venv/bin/activate

패키지를 아래와 같이 설치해보자. uv add 는 pyproject.toml 에 의존성을 기록하고 설치하며 프로젝트 관리에 권장된다.

# uv로 패키지 추가 (pyproject.toml에 자동 기록)
uv add langgraph langchain langchain-openai

프로젝트 루트 디렉토리에 .env 파일을 생성하고 OpenAI API 키를 추가 후 아래 코드를 실행해보자.
LangChain v1.0 부터 init_chat_model을 사용하면 프로바이더:모델명 형식으로 통일된 방식으로 모델을 초기화할 수 있어서 권장된다.

from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langchain.chat_models import init_chat_model

# .env 파일에서 환경 변수 로드
# OPENAI_API_KEY=your-api-key-here   
load_dotenv()

# ChatOpenAI 직접 사용
# gpt4_mini = ChatOpenAI(
#     model="gpt-4.1-mini",
#     temperature=0.7,
#     max_tokens=150,
# )

# init_chat_model 사용 (권장)
gpt4_mini = init_chat_model(
    "openai:gpt-4.1-mini",
    temperature=0.7,
    max_tokens=150,
)

# OpenAI → Anthropic 전환이 간단
# llm = init_chat_model("openai:gpt-4.1-mini")
# llm = init_chat_model("anthropic:claude-sonnet-4-6")
# llm = init_chat_model("google-genai:gemini-2.5-flash")

모델의 파라미터를 아래와 같이 설정할 수 있다.

temperature: 0 ~ 1 사이 값이며 낮을 수록 일관된 응답, 높을 수록 창의적인 응답을 생성한다.

max_tokens: 생성할 최대 토큰 수, 모델과 사용 사례에 따라 적절히 조정해야 한다.


3. LangChain 의 개요

먼저 LangChain ToolCalling(도구 호출) 에 대해서 살펴보자.

Tool Calling 이란 LLM이 외부 기능이나 데이터에 접근할 수 있게 해주는 메커니즘이다.
LLM의 한계인 최신 정보가 부족하거나 특정 작업 수행(코드를 실행하거나 전문지식이 필요할 때)이 불가능한 경우가 있었다.
이러한 한계를 극복하게 해주는 것이 Tool Calling 이다.


4. LangGraph 의 개요

4-1) StateGraph

StateGraph는 상태(state)를 기반으로 작동하는 그래프 구조이다.

  • State: 모든 노드가 공유하는 데이터 저장소이며, 시스템의 전체 컨텍스트를 포함한다.
# 주로 TypedDict나 Pydantic BaseModel을 사용한다.  
# 그래프의 전체 상태(이것은 노드 간 공유되는 공용 상태)
cass OverallState(BaseModel):
    text: str
  • Node: 실제 작업을 수행하는 Python 함수이며, 입력과 출력이 존재한다. 즉, 현재 State를 입력받아 계산을 한 후 업데이트 된 State를 반환하게 된다.
# 위에서 정의한 전체 상태가 그대로 전달됨.   
def node(state: OverallState):
    return {"text": "반갑습니다"} # 상태를 변경해서 출력
  • Edge: 노드들 사이의 연결을 정의하며, “이 작업 다음에 저 작업을 하자”라고 알려주는 역할을 한다.
# 그래프 구축(엣지로 연결)
builder = StateGraph(OverallState) # StateGraph 객체로 연결 
builder.add_node(node) # 첫번째 노드 
builder.add_edge(STARTT, "node") # START 는 그래프의 시작점을 나타냄
builder.add_edge("node", END) # END 는 그래프의 종료를 추상화하여 나타냄    
graph = builder.compile()

# Initial State 값을 전달
graph.invoke({"text": "안녕하세요"})

추가적으로 조건부 Edge를 활용하여 분기(Branching)처리를 할 수도 있다.
즉, 현재 상태나 입력에 따라 다음 노드를 동적으로 결정하기 때문에 시스템의 흐름을 더 유연하고 상황에 맞게 제어가 가능하다.

def decide_next_step(state: MenuState):
    if state['is_menu_related']:
        return "search_menu_info"
    else:
        return "generate_general_response" # 리턴값은 노드의 이름을 사용   
# 조건부 엣지 추가 
builder.add_conditional_edges(
        "analyze_input" # 해당 노드에서 조건에 따라 분기 
        decide_next_step,
        {
            "search_menu_info": "search_menu_info", # 리턴값에 매칭되면 해당 노드 실행
            "generate_general_response": "generate_general_response"
        }

4-2) State Reducer

Reducer 는 상태를 업데이트를 관리하는 함수이며, 각 노드의 반환값은 해당 상태 키의 이전 값을 덮어쓰기 저장을 한다.(기본 리듀서)

또한, 메시지 리스트 등에서 이전 상태에 새로운 값을 추가할때도 사용 가능하며 이를 add 리듀서라고 부른다.

그 외에 중복 제거, 정렬 등 특수한 상태 관리를 하고 싶을 경우는 이를 custom 리듀서를 정의하여 사용이 가능하다.

class CustomReducerState(TypedDict):
    query: str
    documents: Annotated[List[str], reduce_unique_documents] # Custom Reducer 적용   

Referrence

https://wikidocs.net/261585
https://platform.openai.com/