에이전트가 길어질수록 체크포인트 크기는 어떻게 변하는가
LLM 에이전트를 단순한 request/response가 아니라 장기 실행 워크플로로 운영할 때 가장 먼저 나타나는 문제는 checkpoint 크기 폭증이다.
LangGraph는 상태를 그래프 실행 경계마다 직렬화해 checkpoint store에 저장한다. 에이전트가 대화를 이어가면 messages 채널처럼 누적되는 값은 스텝마다 전체를 다시 직렬화한다. 500 턴 대화라면 1 턴의 delta가 아니라 500 턴 전체가 담긴 blob이 매 스텝 저장된다.
| 상황 | 저장 방식 | 500 턴 시점 blob 크기 |
|---|---|---|
기존 add_messages 채널 | 전체 메시지 목록 재직렬화 | 약 219 MB |
DeltaChannel (snapshot_frequency 없음) | delta만 기록 | 약 3 KB |
DeltaChannel (snapshot_frequency=10) | 10 스텝마다 full snapshot | 약 5배 절감, 읽기 지연 실용적 수준 |
2026년 5월 12일 출시된 LangGraph 1.2.0은 이 문제를 DeltaChannel로 구조적으로 해결했다. 같은 릴리스에서 TimeoutPolicy와 streaming v2 API도 함께 출시됐다.
이 장은 2026년 7월 15일 기준으로 작성했다. LangGraph 1.2.0은 2026-05-12에 출시됐고 최신 패치는 1.2.9(2026-07-10)다. DeltaChannel과 TimeoutPolicy는 1.2.0에서 beta로 표시됐으며 streaming v2는 opt-in이다. API 고정보다 검증 가능한 운영 계약에 초점을 맞춘다.
LangGraph 상태 관리와 채널 구조
LangGraph의 상태는 그래프 전역 TypedDict(또는 dataclass)로 선언한다. 각 필드는 채널(channel)에 대응하며, 채널은 스텝 사이 값을 저장하고 reducer를 통해 값을 합친다.
기존 add_messages 어노테이션은 BinaryOperatorAggregate 채널로 연결된다. 이 채널은 reducer가 반환한 값 전체를 매 스텝 직렬화한다. 메시지가 100개면 100개짜리 리스트, 500개면 500개짜리 리스트가 checkpoint에 들어간다.
DeltaChannel은 이 직렬화 경계를 바꾼다. 노드가 쓴 값만 delta로 기록하고, restore 시 sentinel 값부터 delta를 순서대로 replay해 원래 값을 재구성한다.
DeltaChannel: delta를 checkpoint에 저장하는 fold-reducer 패턴
DeltaChannel을 쓰면 필드 어노테이션이 바뀐다.
from langgraph.channels.delta import DeltaChannel
from typing import Annotated
class State(TypedDict):
messages: Annotated[list[BaseMessage], DeltaChannel(snapshot_frequency=10)]DeltaChannel은 snapshot_frequency 파라미터 하나로 저장 공간과 읽기 지연을 조정한다.
snapshot_frequency | 동작 | 저장 공간 | restore 지연 |
|---|---|---|---|
None (기본) | delta만 기록, snapshot 없음 | 최소 | 전체 history replay (history 비례) |
| 정수 K | K 스텝마다 full snapshot 삽입 | 중간 | 최근 snapshot부터 replay |
1 | 매 스텝 full snapshot | 기존과 동일 | 최소 |
snapshot_frequency=None은 저장 공간은 가장 작지만 history가 길수록 restore 지연이 늘어난다. snapshot_frequency=10은 약 5배 절감 효과를 유지하면서 실용적인 읽기 지연을 확보한다.
내부 동작을 이해하면 적합한 채널을 고를 수 있다.
- 노드가 새 메시지를 쓰면 DeltaChannel은 그 delta 값만 checkpoint row에 직렬화한다.
- 저장 크기는 turn 수와 무관하게 마지막 write 크기에 비례한다.
- thread를 복원할 때 가장 최근 full snapshot부터 이후 delta를 순서대로 적용해 현재 값을 재구성한다.
snapshot_frequency=K는 K 스텝마다 그 시점의 전체 값을 snapshot row로 저장해 replay 길이에 상한을 둔다.
중요한 제약: DeltaChannel은 1.2.0에서 beta API다. reducer가 pure function이 아닌 채널에는 적합하지 않다. 예를 들어 timestamp를 자동으로 붙이거나 random 값을 사용하는 reducer는 replay 시 일관된 결과를 보장하지 않는다. 채택 전에 reducer가 동일 입력에 대해 항상 동일 출력을 내는지 확인한다.
TimeoutPolicy: async 노드에 하드 시간 경계를 추가하는 방법
장기 실행 에이전트가 외부 API를 호출하거나 LLM 응답을 기다릴 때 특정 노드가 무기한 실행될 수 있다. 이를 제어하려면 TimeoutPolicy를 add_node()에 전달한다.
from langgraph.types import TimeoutPolicy
async def tool_node(state: State) -> dict:
result = await some_slow_api_call(state)
return {"messages": [result]}
graph.add_node(
"tool",
tool_node,
timeout=TimeoutPolicy(run_timeout=60.0, idle_timeout=10.0)
)run_timeout과 idle_timeout은 독립적으로 작동하며 먼저 도달하는 쪽이 발동한다.
run_timeout: 노드 시작부터 hard wall-clock을 센다. 진행 상황과 무관하게 60초가 지나면 즉시 NodeTimeoutError를 발생시킨다. 대용량 파일 처리처럼 실행 총시간에 상한이 필요한 경우에 적합하다.
idle_timeout: 마지막 진행 신호 이후 경과 시간을 센다. LangChain LLM 모델의 스트리밍 청크, 채널 write, 자식 태스크 이벤트가 모두 진행 신호다. 스트리밍 LLM 응답은 청크마다 타이머를 리셋하므로 total 응답 시간이 길더라도 idle_timeout에 걸리지 않는다. 진짜로 멈춘 호출만 잡아낸다.
TimeoutPolicy(
run_timeout=300.0, # 5분 초과 실행 금지
idle_timeout=30.0 # 30초 이상 진행 없으면 종료
)NodeTimeoutError는 기본적으로 retryable이다. RetryPolicy와 함께 쓰면 타임아웃 후 자동 재시도가 가능하다. 단 run_timeout에 걸렸다면 재시도해도 같은 시간이 걸릴 가능성이 높으므로 retry budget과 함께 설계한다.
핵심 제약: TimeoutPolicy는 async 노드만 지원한다. sync 함수에 timeout을 붙이면 compile-time에 오류가 발생한다. 기존 sync 노드를 마이그레이션할 때는 반드시 async def로 바꿔야 한다. 이때 event loop 안에서 blocking I/O를 수행하는 코드는 asyncio.to_thread()나 loop.run_in_executor()로 감싸야 한다.
표준 LangChain 콜백 없이 자체 루프를 도는 노드에서 idle_timeout이 너무 공격적으로 발동한다면 refresh_on="heartbeat" 모드와 runtime.heartbeat() 명시 호출을 사용한다.
Streaming v2: 타입 안전한 통합 스트리밍 API
기존 stream()과 astream()은 mode 파라미터(values, updates, messages, custom 등)에 따라 반환 타입이 달라 타입 체킹이 어려웠다. 1.2의 streaming v2는 모든 청크를 StreamPart로 통일한다.
async for chunk in agent.astream(
{"messages": [("user", "안녕하세요")]},
version="v2"
):
chunk_type = chunk["type"] # "values" | "updates" | "messages" | ...
namespace = chunk["ns"] # 이벤트 발생 노드/서브그래프
data = chunk["data"] # mode별 TypedDict payloadStreamPart의 구조는 세 키로 고정된다.
| 키 | 역할 | 예시 |
|---|---|---|
type | 청크 종류 | "values", "updates", "messages" |
ns | 이벤트 발생 namespace | ["agent", "tools"] |
data | 실제 payload | mode별 TypedDict |
각 mode별 TypedDict는 langgraph.types에서 직접 import할 수 있어 IDE 자동완성과 mypy 검사가 쉬워진다. 서브그래프가 중첩된 경우에도 ns 필드로 이벤트 출처를 구분할 수 있어 디버깅이 편해진다.
v2는 opt-in이다. version 파라미터를 명시하지 않으면 기존 v1 동작을 그대로 유지한다. 기존 스트리밍 코드를 즉시 마이그레이션하지 않아도 된다.
운영 고려사항
DeltaChannel 도입 시 확인할 세 가지
저장소 row 수: DeltaChannel을 켜면 단일 row 크기는 줄지만 스텝 수만큼 row 수가 늘어난다. snapshot_frequency=10이면 10 스텝마다 full snapshot row도 추가된다. checkpoint store의 row 수 상한이나 쿼리 scan 비용이 있다면 함께 확인한다.
restore 지연: 현재 스레드를 복원할 때 store에서 여러 row를 순서대로 읽어야 한다. store latency가 높은 환경에서는 snapshot_frequency를 낮춰 read 횟수를 제한한다.
beta API 안정성: DeltaChannel은 1.2.0에서 beta다. minor version update에서 API가 변경될 수 있다. 프로덕션 적용 전 SDK 버전을 lockfile에 고정하고 변경사항을 추적한다.
TimeoutPolicy와 외부 서비스
idle_timeout의 진행 신호 인식은 LangChain LLM 모델에 최적화되어 있다. 자체 HTTP 클라이언트나 다른 스트리밍 프로토콜을 쓴다면 refresh_on="heartbeat" 모드로 전환하고 명시적으로 runtime.heartbeat()를 호출해야 신호가 전달된다.
run_timeout을 너무 짧게 설정하면 RetryPolicy와 결합했을 때 (run_timeout × max_attempts) 만큼의 wall-clock 시간이 소모된다. 총 실행 시간 예산과 함께 설정한다.
streaming v2와 Platform 호환성
v2는 opt-in이므로 기존 consumer를 즉시 바꿀 필요는 없다. 그러나 LangGraph Platform이나 LangGraph Cloud를 사용한다면 서버 SDK 버전도 v2를 지원하는지 확인한다. 로컬 SDK와 플랫폼 서버 SDK 버전이 다르면 StreamPart 구조가 달라질 수 있다.
채택 판단표
정리
LangGraph 1.2의 핵심 변화는 세 축으로 정리된다.
DeltaChannel: 장기 실행 에이전트의 checkpoint 크기 폭증을 구조적으로 해결한다. 500 턴 기준 219 MB → 3 KB는 저장 비용, 직렬화 시간, restore 지연 모두에 영향을 준다. snapshot_frequency로 공간과 지연의 트레이드오프를 조정한다. reducer가 pure function이어야 한다는 제약을 먼저 확인한다.
TimeoutPolicy: async 노드에 run_timeout(하드 wall-clock)과 idle_timeout(진행 신호 기반)을 붙여 hung call과 무한 대기를 차단한다. NodeTimeoutError는 retryable이므로 RetryPolicy와 조합해 장애 복구 루프를 설계할 수 있다.
Streaming v2: 모든 청크를 StreamPart(type, ns, data)로 통일해 타입 안전한 스트림 소비를 가능하게 한다. opt-in이므로 기존 코드는 즉시 바꿀 필요 없다.
세 기능 모두 1.2.0에서 beta 표시가 있다. 운영 환경 적용 전 restore 일관성, timeout-retry 비용 조합, Platform SDK 호환성을 먼저 검증한다.
References
- LangGraph 1.2.0 릴리스 — 2026-05-12
- LangGraph 1.2.9 릴리스 — 2026-07-10
- Delta Channels: How We're Evolving our Runtime for Long-Running Agents
- Fault Tolerance in LangGraph: Retries, Timeouts and Error Handlers
- LangGraph Fault Tolerance Docs
- DeltaChannel API Reference
- LangGraph 1.0 and 1.2 in 2026: Why Durable State Has Changed Everything
- LangGraph Review 2026: The Graph-Based Agent Framework Powering Enterprise AI