
LangGraph AI 에이전트: 그래프, 체크포인트(checkpoint) 및 에이전트 상태
요약
LangGraph를 활용하여 상태(state)와 체크포인트(checkpoint)를 갖춘 신뢰할 수 있는 AI 에이전트를 구축하는 엔지니어링 원칙을 다룹니다. 단순 재시작이 아닌, 장애 발생 시 결정 과정을 설명하고 중단된 지점부터 복구 가능한 제어 가능한 에이전트 설계의 중요성을 강조합니다.
핵심 포인트
- 단순 재시작은 동작 재현일 뿐 결정 과정을 설명하지 못함
- 유료 API 호출 등 부작용이 있는 작업 시 명시적 상태 관리가 필수적임
- 체크포인트를 통한 상태 설정과 전이 지정이 에이전트 제어 가능성의 핵심임
- 복잡한 리듀서와 스키마 설계가 복구 가능한 그래프를 만듦
장애가 발생한 후 에이전트를 재시작하면, 에이전트는 다시 필요한 단계에 도달합니다. 하지만 에이전트는 왜 지난번에 정확히 그 경로를 선택했는지 설명할 수 없습니다. 도구 루프(instrumental cycle)를 다시 실행하는 것은 동작을 재현할 뿐, 결정을 설명하지는 못하기 때문입니다. 에이전트의 단계가 유료 API를 호출하거나 되돌릴 수 없는 동작을 수행할 때마다 이 차이는 확연하게 느껴집니다.
다음으로 저는 구체적인 사례를 분석합니다: 하나의 도구, 명시적인 상태(state), 그리고 체크포인트(checkpoint)를 가진 LangGraph 상의 최소 그래프입니다. 이것은 자율 에이전트에 대한 개요나 프레임워크 비교가 아니라, 하나의 명제를 검증하는 것입니다: 만약 체크포인트 이후에 상태를 설정하고 다음 가능한 전이(transition)를 지정할 수 없다면, 해당 그래프는 주장하는 제어 가능성(controllability)을 제공하지 못한다는 것입니다. 아래 내용은 이미 완료된 실험 보고서가 아니라, 구축 및 검증을 위한 계획입니다.
증명의 범위를 즉시 명시하겠습니다. 그래프, 도구 및 체크포인트의 구성은 2026-07-18 기준 LangGraph의 공식 리포지토리(repository) 및 문서와 대조하여 확인합니다. 특정 API 래퍼(wrapper)가 어떻게 동작하는지, 그리고 귀하의 환경에서 체크포인트가 정확히 어디에 저장되는지는 설치된 패키지를 직접 확인하기 전까지는 알 수 없습니다. 이는 시나리오의 제한 사항이지 LangGraph에 대한 불만 사항이 아닙니다.
재시작이 복구와 같지 않은 이유
langgraph ai agent를 구축하는 사람들은 보통 한 가지를 원합니다: 에이전트가 장애를 극복하는 것입니다. 하지만 "장애를 극복한다"는 것은 두 가지 서로 다른 요구 사항으로 나뉩니다. 첫째: 이미 비용이 지불된 단계를 반복하지 않고 중단된 지점부터 계속하는 것입니다. 둘째: 에이전트가 중단된 순간 어떤 결정에 근거하고 있었는지 설명하는 것입니다. 명시적인 상태(state)가 없는 도구 루프는 기껏해야 첫 번째 요구 사항만을 충족하며, 그마저도 항상 보장되지는 않습니다.
도구 호출 루프를 단순히 처음부터 다시 시작하는 것으로 충분하다는 흔한 가정이 있습니다. 부작용(side effects)이 없는 짧은 작업에서는 이것이 가끔 작동합니다. 하지만 에이전트의 단계가 외부 세계에 무언가를 기록할 때(레코드를 생성하거나, 비용을 지불하거나, 이메일을 보내는 등), 맹목적인 재시작은 효과를 중복시키거나 혹은 조용히 놓쳐버립니다. 명시적인 상태 기술 없이는 이를 추적하는 것이 불가능합니다.
저의 이러한 입장은 LangChain의 문서에서 도출된 것이 아니라 엔지니어링 측면의 선택입니다. 즉, 에이전트의 동작은 명시적인 상태(state) 및 체크포인트(checkpoint)와 함께 그래프에 도입되어야 한다는 것입니다. 이러한 요구사항은 그래프를 복잡하게 만듭니다. 리듀서(reducer), 상태 스키마(state schema), 세이버(saver) 설정 등을 진행 과정에서 임의로 삽입하는 것이 아니라 사전에 설계해야 하기 때문입니다. 하지만 이러한 복잡성은 그래프를 복구 가능하게 만들고, 장애 발생 시 단순히 "다시 실행" 버튼을 누르는 것이 아니라 돌아갈 수 있는 지점을 제공한다는 점에서 충분한 가치가 있습니다.
LangGraph에서 최소 그래프란 무엇인가
LangGraph 공식 리포지토리는 이 프로젝트를 "지속 가능한 상태 유지 에이전트(stateful agents)를 구축, 관리 및 배포하기 위한 저수준 오케스트레이션 프레임워크"라고 설명합니다. 이 프로젝트는 LangChain Inc.에 의해 제작되었으며 MIT 라이선스로 배포됩니다. 실행 모델은 Google의 Pregel과 Apache Beam에서 영감을 받았으며, 공개 인터페이스는 NetworkX 라이브러리를 모델로 구축되었습니다. 이는 프로젝트 페이지에 명시된 사실이며 저의 개인적인 결론이 아닙니다.
실행은 "슈퍼스텝(supersteps)" 단위로 이루어집니다. graph API 문서에 따르면, 슈퍼스텝은 활성 노드들에 대한 하나의 반복(iteration)을 의미합니다. 병렬로 작동하는 노드들은 하나의 슈퍼스텝에 포함되고, 순차적인 노드들은 서로 다른 슈퍼스텝에 포함됩니다. 노드는 입력 엣지(edge) 또는 채널을 통해 상태 업데이트를 받았을 때 활성화됩니다. 여기서 전이 경계(transition boundary)의 관찰 가능성(observability)이 생겨납니다.
상태 자체는 스키마로 정의됩니다. StateGraph는 사용자 정의 State(TypedDict, dataclass 또는 Pydantic 모델)를 기반으로 구축되며, 각 키에는 노드의 업데이트를 상태와 어떻게 병합할지 결정하는 고유한 리듀서(reducer) 함수가 있습니다. 리듀서는 기본적으로 값을 덮어쓰지만, 커스텀 리듀서는 예를 들어 메시지 목록에 내용을 추가하는 방식으로 누적할 수 있습니다. 그래프는 실행 전 반드시 컴파일되어야 합니다.
검증을 위한 최소한의 세트: 하나의 상태 스키마 (state schema), 모델이 포함된 하나의 노드 (node), 하나의 ToolNode, 체크포인터 (checkpointer), 그리고 전이 로그 (transition log)입니다. 논지를 반증하기 위해 이보다 더 많은 것은 필요하지 않습니다. langgraph github 리포지토리 자체에는 이 검증에 필요한 것보다 훨씬 많은 예제가 있지만, 그 양이 무언가를 증명하는 것이 아니라 오직 경계의 구별 가능성만을 증명할 뿐입니다.
체크포인트(checkpoint)가 단순히 실행 사실이 아닌 상태를 저장하는 방법
체크포인터 (Checkpointer)는 그래프 상태의 스냅샷 (snapshot)을 저장합니다. reference-API checkpoint 수준에서 이는 채널 값 (channel values), 채널 버전 (channel versions), 그리고 노드별 버전 추적 (version tracking)을 포함하는 것으로 설명되며, {"configurable": {"thread_id": ...}}를 통해 전달되는 thread_id에 연결됩니다. 각 스레드 (thread)는 자신만의 독립적인 체크포인트 (checkpoint) 시퀀스를 가집니다. 따라서 복구 (restoration)는 주소 지정이 가능해집니다. 즉, 단순히 "처음으로" 돌아가는 것이 아니라, 특정 스레드의 특정 스냅샷으로 돌아가는 것입니다.
서로 다른 세이버 (saver)들은 서로 다른 내구성을 제공하며, 이는 단순한 설정의 차이가 아닙니다. 동일한 문서에 따르면, InMemorySaver는 프로세스 재시작 시 유지되지 않으므로 테스트용으로만 적합합니다. SqliteSaver와 AsyncSqliteSaver는 가벼운 시나리오나 데모 시나리오에 적합하며, PostgresSaver와 AsyncPostgresSaver는 프로덕션 (production) 환경의 지속성을 위해 설계되었습니다. 기본 직렬화 (serialization)는 JsonPlusSerializer (JSON으로 폴백하는 ormsgpack)를 통해 이루어지며, 민감한 상태를 위해서는 EncryptedSerializer를 사용할 수 있습니다.
여기서 논지 검증을 위한 직접적인 결론이 도출됩니다. 만약 인메모리 세이버 (in-memory-saver)를 선택하고 프로세스를 종료하면 상태는 저장되지 않습니다. 이는 메커니즘이 나빠서가 아니라, 해당 세이버가 그렇게 설계되었기 때문입니다. InMemorySaver로 복구를 테스트하는 것은 무의미하며, 이는 단지 살아있는 프로세스 내부에서의 지속성만을 확인해 줄 뿐입니다.

다음은 테스트할 그래프의 뼈대입니다. 이것은 개념을 설명하기 위한 예시일 뿐 표준은 아닙니다. StateSnapshot의 필드 이름과 개별 파라미터의 의미론(semantics)은 설치된 패키지 버전과 대조해야 합니다. 2026년 당시 문서가 docs.langchain.com과 reference.langchain.com으로 활발히 이전되고 있었기 때문입니다.
from typing import Annotated, TypedDict
from operator import add
from langgraph.graph import StateGraph, START, END
...
도구가 상태(state)에 정확히 반영되는 방식
LangGraph에서 도구(tool)를 통합하는 과정은 두 단계로 이루어지며 노드(node) 단위로 작동합니다. bind_tools()를 통해 도구가 연결된 모델은 AIMessage 내부에 tool_calls를 반환하지만, 모델 스스로가 아무것도 실행하지는 않습니다. 별도의 ToolNode가 마지막 AIMessage에서 tool_calls를 읽어와 적절한 Python 함수를 호출하고, 그 결과를 기본적으로 messages 키 아래에 ToolMessage로서 상태(state)에 다시 기록합니다. 도구의 실행 결과는 상태의 일부가 되며, 따라서 체크포인트(checkpoint)에 저장됩니다.
도구의 오류 처리(error handling)는 기대치가 어긋나기 쉬운 부분입니다. 기본적으로 ToolNode는 잘못된 인자 전달과 같은 호출 오류를 포착하여, 예외(exception)를 던지는 대신 설명이 포함된 ToolMessage를 반환합니다. 하지만 이 동작은 handle_tool_errors 파라미터(불리언, 문자열, 예외 타입 또는 콜백)를 통해 설정할 수 있습니다. 즉, 무엇을 '복구 가능한' 도구 실패로 간주하고 무엇을 치명적인 실패로 간주할지는 LangGraph의 기본 설정이 아니라 특정 그래프의 설정에 의해 결정됩니다.
만약 이미 완성된 추론 및 행동(reasoning and action) 루프가 필요하다면, 생태계에는 미리 조립된 langgraph react agent (ReAct 패턴의 구현체)가 있습니다. 이는 코드를 절약해주지만, 우리가 여기서 수동으로 파헤치고 있는 바로 그 지점, 즉 모델의 결정과 도구(tool) 실행 사이의 경계를 숨겨버립니다. 제어 가능성을 증명하기 위해서는 눈에 보이는 이음새가 필요하므로, 최소한의 그래프에서는 노드(node)들을 명시적으로 구성합니다.
별도의 메커니즘이 부분적인 작업을 보호합니다. "Pending writes"는 동일한 슈퍼스텝(superstep) 내의 인접 노드가 실패하더라도 성공적으로 완료된 노드의 기록을 보존합니다. 바로 이 기능 덕분에 재개된 실행 시 그래프 전체를 다시 시작하는 대신 이미 완료된 노드들을 건너뛸 수 있습니다. 이것이 없다면 어떤 장애라도 전체 실행을 시작 시점으로 되돌릴 것입니다.
체크포인트(checkpoint)가 해결하지 못하는 것
문서화된 복구 패턴은 다음과 같습니다: 장애 발생 시 LangGraph는 thread_id에 연결된 마지막 저장된 체크포인트(checkpoint)를 사용하며, 처음부터가 아니라 해당 지점부터 실행을 계속합니다. update_state() 메서드는 저장된 상태를 변경하고 새로운 체크포인트를 생성할 수 있으며, 이후 해당 스레드(thread)로 그래프를 다시 호출하면 실행이 계속되거나 분기됩니다. 이것은 하나의 메커니즘일 뿐입니다. 프로세스의 모든 충돌에 대해 자동으로 복구를 보장하는 장치로 변하는 것은 아닙니다.
공식적인 주의 사항은 그 경계를 명확히 규정합니다: 인메모리 체크포인트(in-memory-checkpoint)는 재시작 시 유지되지 않으며, 긴 스레드에 체크포인트를 축적하는 것은 지연 시간(latency)과 저장 비용을 증가시키기 때문에, 체크포인팅(checkpointing)은 스레드에 종속된 재개 가능한 상태를 위한 메커니즘으로 남을 뿐 보편적인 결함 허용(fault-tolerance)을 제공하지는 않습니다.
도구(tool)의 효과가 되돌릴 수 없는 경우에는 별도의 주의가 필요합니다. 어떤 공식 문서도 체크포인팅(checkpointing)이 노드 중간에서의 충돌, 외부 도구 측의 장애, 또는 도구가 충돌 전 이미 기록해 버린 비멱등적(non-idempotent) 부작용(side effect)으로부터 구해줄 것이라고 주장하지 않습니다. 만약 도구가 돈을 인출했는데 다음 줄에서 프로세스가 중단되었다면, 체크포인트(checkpoint)는 상태를 복구할 수는 있지만 인출된 금액을 취소하지는 못합니다.
이미 장애가 발생했을 때 이를 해석하는 방법은 다음과 같습니다.
| 발생한 상황 | 체크포인트를 통한 복구 가능 여부 | 조치 방법 |
|---|---|---|
| 슈퍼스텝(superstep)의 인접 노드가 충돌했으나, 자신의 작업은 완료됨 | 예, pending writes를 통해 가능 | 스레드(thread)를 통해 실행 재개 |
| ... |
이 표는 단순히 장식용이 아닙니다. 이것은 상태 전이 로그(transition log)를 작성하는 목적이 되는 회귀 테스트 고정 요소(regression fixture)입니다. 각 행은 그래프가 반드시 구분해내야 하는 시나리오를 설명하며, 그렇지 못하다면 제어 가능성은 허상에 불과합니다. langgraph api 도움말에서 이 모든 시나리오는 단 세 가지 메서드로 요약됩니다: get_state, update_state, 그리고 스레드 설정이 포함된 invoke입니다. 만약 표에 있는 시나리오를 로그를 통해 이 메서드들로 처리할 수 없다면, 해당 시나리오는 커버되지 않은 상태로 남게 됩니다.

여기서 호환 가능한 API란 무엇이며, 왜 상태와 별도로 존재하는가
상태(state)는 그래프에 모델 호출이 추가되기 전에 설계되어야 하므로, 이 주제는 이러한 순서로 전개됩니다. 그래프가 검증되고 복구 경계가 증명되면, 상태 로직이나 체크포인트(checkpoint)를 건드리지 않고도 모델이 포함된 노드를 어떤 호환 가능한 엔드포인트(endpoint)로든 보낼 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
