테마
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. 실무 선택 가이드
어떤 상황에서 어떤 타입을 선택할까?
컨텍스트 타입을 선택할 때는 아래 두 가지 질문을 던지면 된다.
- 이 데이터는 실행 중에 변하는가?
- 변하지 않으면 Static Runtime Context
- 변하면 다음 질문으로 넘어간다
- 이 데이터는 현재 대화가 끝나도 유지되어야 하는가?
- 현재 대화에서만 필요하면 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로 영구 저장한다. 사용자 선호도처럼 세션을 넘어 유지해야 하는 데이터에 적합하다.컨텍스트 타입 선택은 "변하는가?" 그리고 "유지되어야 하는가?"라는 두 질문으로 결정된다. 올바른 타입을 선택해야 에이전트가 필요한 정보를 적절한 방식으로 관리할 수 있다.