Skip to content

LangGraph 컨텍스트 분류

변경 가능성과 생존 기간에 따른 3가지 컨텍스트 타입


학습 목표

  • 컨텍스트를 분류하는 두 가지 축(변경 가능성, 생존 기간)을 이해한다.
  • LangGraph가 제공하는 3가지 컨텍스트 타입의 특성과 차이를 구분할 수 있다.
  • 각 컨텍스트 타입에 대응하는 LangGraph 구현체를 파악하고, 실무 상황에 맞는 타입을 선택할 수 있다.

1. 컨텍스트 분류의 두 가지 축

AI 에이전트가 다루는 컨텍스트는 모두 같은 성격이 아니다. LangGraph는 컨텍스트를 변경 가능성(Mutability)생존 기간(Lifetime) 이라는 두 가지 축으로 분류한다. 이 두 축의 조합으로 컨텍스트의 성격이 결정되고, 그에 맞는 구현 방식이 달라진다.

변경 가능성 (Mutability)

구분설명예시
Static (정적)한번 설정하면 실행 중 변하지 않는 불변 데이터DB 연결 정보, 사용자 이름, API 키
Dynamic (동적)실행 도중 계속 변하는 가변 데이터대화 내역, 중간 계산 결과, 검색 결과

생존 기간 (Lifetime)

구분설명예시
Runtime한 번의 실행(invoke) 동안만 존재하는 일회성 데이터현재 요청의 파라미터, 단일 대화 내 메시지
Cross-conversational여러 대화(세션)에 걸쳐 계속 유지되는 데이터사용자 선호도, 과거 대화 기록, 학습된 패턴

분류 축 다이어그램

이 두 축을 조합하면 이론적으로 4가지 유형이 나오지만, LangGraph에서는 실질적으로 의미 있는 3가지 타입을 정의한다. "Static + Cross-conversational"은 실무에서 거의 발생하지 않기 때문에 별도 타입으로 다루지 않는다.


2. LangGraph의 3가지 컨텍스트 타입


Type 1: Static Runtime Context (고정값 + 일회성)

정의: 그래프 실행 시 한 번 전달되며, 실행 도중 변하지 않는 읽기 전용 데이터다. graph.invoke() 호출 시 context 인자로 넘기면, 그래프 내 모든 노드에서 해당 값을 참조할 수 있다.

사용 시점: 실행 전에 이미 확정된 값을 그래프 전체에 전달할 때 사용한다.

예시: 사용자 이름, 시스템 설정값, 외부 서비스 엔드포인트

구현 방식 --- @dataclass + context 인자:

python
from dataclasses import dataclass
from langgraph.graph import StateGraph

@dataclass
class ContextSchema:
    user_name: str
    system_language: str = "ko"

# 그래프 정의 시 context_schema 지정
graph_builder = StateGraph(State, context_schema=ContextSchema)

# 실행 시 context 인자로 고정값 전달
result = graph.invoke(
    {"messages": [{"role": "user", "content": "안녕하세요"}]},
    context=ContextSchema(user_name="John Smith", system_language="ko")
)

핵심 특징:

  • @dataclass로 스키마를 정의하여 타입 안전성을 확보한다.
  • 실행 중에 값이 변하지 않으므로, 노드 간 데이터 충돌 걱정이 없다.
  • 그래프 내부 노드에서 context.user_name처럼 직접 접근한다.

Type 2: Dynamic Runtime Context (가변값 + 일회성)

정의: 하나의 그래프 실행(싱글턴 대화) 안에서 노드가 실행될 때마다 변할 수 있는 데이터다. LangGraph의 State 객체가 이 역할을 담당한다.

사용 시점: 대화 중 메시지가 쌓이거나, 노드 실행 결과가 다음 노드에 영향을 줄 때 사용한다.

예시: 대화 메시지 목록, 검색 결과, 중간 처리 상태

구현 방식 --- State 객체:

python
from typing import Annotated
from langgraph.graph import MessagesState
from langgraph.graph.message import add_messages

class State(MessagesState):
    """동적 런타임 컨텍스트: 실행 중 계속 변하는 상태"""
    messages: Annotated[list, add_messages]  # 대화 내역 (자동 누적)
    search_results: list[str] = []           # 검색 결과 (노드마다 갱신 가능)
    current_step: str = "init"               # 현재 처리 단계

대안 --- InMemorySaver (단기 메모리):

단일 대화 내에서 체크포인트를 저장하여, 같은 thread_id 내에서 상태를 유지할 수도 있다.

python
from langgraph.checkpoint.memory import InMemorySaver

checkpointer = InMemorySaver()
graph = graph_builder.compile(checkpointer=checkpointer)

# 같은 thread_id로 호출하면 이전 상태를 이어받는다
config = {"configurable": {"thread_id": "conversation-1"}}
result = graph.invoke({"messages": [...]}, config=config)

핵심 특징:

  • State 객체는 노드가 실행될 때마다 갱신된다.
  • add_messages 같은 리듀서를 통해 메시지가 자동으로 누적된다.
  • 그래프 실행이 끝나면 State는 사라진다(InMemorySaver를 쓰면 체크포인트로 유지 가능).

Type 3: Dynamic Cross-conversational Context (가변값 + 멀티턴 지속)

정의: 여러 대화(세션)에 걸쳐 유지되며, 새로운 정보가 들어올 때마다 갱신될 수 있는 데이터다. LangGraph의 Long-term Memory 시스템(InMemoryStore)이 이 역할을 담당한다.

사용 시점: 사용자의 선호도, 과거 대화 요약, 학습된 패턴 등 세션을 넘어서 기억해야 할 정보가 있을 때 사용한다.

예시: 사용자 선호도("한국어로 답변해 주세요"), 이전 대화 요약, 자주 묻는 질문 패턴

구현 방식 --- InMemoryStore + Namespace:

python
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()
graph = graph_builder.compile(store=store)

# 네임스페이스로 사용자별 데이터를 구분한다
namespace = ("user_preferences", "user-123")

# 장기 메모리에 저장
store.put(namespace, key="language", value={"preference": "ko"})
store.put(namespace, key="style", value={"preference": "formal"})

# 장기 메모리에서 조회
items = store.search(namespace)
# [Item(key="language", value={"preference": "ko"}),
#  Item(key="style", value={"preference": "formal"})]

핵심 특징:

  • Namespace 기반 구분: ("user_preferences", "user-123")처럼 계층적 네임스페이스로 데이터를 정리한다.
  • 세션 독립적: 어떤 대화에서 저장하든, 다른 대화에서 꺼내 쓸 수 있다.
  • 능동적 갱신: 에이전트가 대화 중 새로운 선호도를 발견하면, 기존 메모리를 갱신할 수 있다.
  • 검색 가능: store.search()로 관련 메모리를 검색하여 컨텍스트에 주입한다.

3. 구현체 매핑 다이어그램

아래 다이어그램은 각 컨텍스트 타입이 LangGraph에서 어떤 구현체에 대응하고, 데이터가 어떤 흐름으로 사용되는지를 보여준다.


4. 실무 선택 가이드

어떤 상황에서 어떤 타입을 선택할까?

컨텍스트 타입을 선택할 때는 아래 두 가지 질문을 던지면 된다.

  1. 이 데이터는 실행 중에 변하는가?
    • 변하지 않으면 Static Runtime Context
    • 변하면 다음 질문으로 넘어간다
  2. 이 데이터는 현재 대화가 끝나도 유지되어야 하는가?
    • 현재 대화에서만 필요하면 Dynamic Runtime Context
    • 다음 대화에서도 필요하면 Dynamic Cross-conversational Context

비교 테이블

타입변경 가능성유지 기간구현체사용 사례
Static Runtime불변 (Static)invoke 1회context 인자 + @dataclass사용자 이름, 시스템 설정, API 엔드포인트
Dynamic Runtime가변 (Dynamic)단일 대화 (thread)State 객체 / InMemorySaver대화 메시지, 검색 결과, 중간 처리 상태
Dynamic Cross-conv.가변 (Dynamic)여러 세션 (영구)InMemoryStore / Long-term Memory사용자 선호도, 대화 요약, 학습된 패턴

실무 시나리오별 선택 예시

시나리오권장 타입이유
챗봇에 사용자 이름을 전달하고 싶다Static Runtime이름은 대화 중 변하지 않으므로 고정값으로 전달
대화 중 이전 메시지를 참조해야 한다Dynamic Runtime메시지는 계속 쌓이는 가변 데이터이지만, 현재 대화에서만 필요
사용자가 "항상 한국어로 답변해 줘"라고 한 설정을 기억해야 한다Dynamic Cross-conv.다음 세션에서도 유지되어야 하는 선호도 정보
검색 에이전트의 중간 검색 결과를 다음 노드에 전달해야 한다Dynamic Runtime실행 중 변하지만, 현재 실행에서만 의미 있는 데이터
고객 지원 봇이 과거 문의 이력을 참조해야 한다Dynamic Cross-conv.이전 대화의 정보를 현재 대화에서 활용

5. 핵심 정리

LangGraph는 컨텍스트를 변경 가능성(Static/Dynamic)과 생존 기간(Runtime/Cross-conversational)이라는 두 축으로 분류한다.

  • Static Runtime Context: 고정값을 @dataclass + context 인자로 전달한다. 설정값처럼 변하지 않는 데이터에 적합하다.
  • Dynamic Runtime Context: 가변값을 State 객체로 관리한다. 대화 메시지처럼 실행 중 변하지만 현재 세션에서만 필요한 데이터에 적합하다.
  • Dynamic Cross-conversational Context: 가변값을 InMemoryStore로 영구 저장한다. 사용자 선호도처럼 세션을 넘어 유지해야 하는 데이터에 적합하다.

컨텍스트 타입 선택은 "변하는가?" 그리고 "유지되어야 하는가?"라는 두 질문으로 결정된다. 올바른 타입을 선택해야 에이전트가 필요한 정보를 적절한 방식으로 관리할 수 있다.