LangGraph 실전 배포, MemorySaver 쓰다
크래시 맞고 나서야 알게 된 것
인메모리 체크포인터로 시작했다가 프로덕션에서 깨졌다. LangGraph가 제공하는 3단계 체크포인터 구조, 상태 설계 함정, CrewAI 대비 비용·레이턴시까지 정리한 실전 노트.
처음엔 MemorySaver로 충분했다
로컬에서 에이전트 파이프라인 만들 때는 이거면 됐다.
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
graph = builder.compile(checkpointer=checkpointer)
결과도 잘 나오고, 상태도 유지되고. 근데 이게 인메모리라는 게 문제였다. 프로덕션 서버에 배포하고 얼마 지나지 않아 서버가 재시작됐다. 12단계짜리 리서치 에이전트가 8단계까지 진행하다가 그냥 날아갔다. 45분 분량의 LLM 호출이 증발한 거다.
찾아보니까 MemorySaver는 Python 딕셔너리에 상태를 저장한다. 프로세스가 죽으면 그냥 사라진다. AWS Lambda면 콜드스타트 때마다. 컨테이너면 재배포 때마다. 개발용이라고 문서에 명시돼 있는데 그냥 넘겼던 거다.
LangGraph 체크포인터 3단계 구조
LangGraph가 제공하는 체크포인터는 세 가지다. 용도가 확실히 구분된다.
MemorySaver — 개발용, 절대 프로덕션 금지
빠르고 편하다. 세팅 없이 바로 쓴다. 하지만 프로세스 재시작하면 모든 상태 사라진다. 단일 워커 이상은 불가능하다. 테스트용으로만.
SqliteSaver — 단일 서버용 중간 단계
파일에 상태를 저장한다. 재시작해도 상태 유지된다. 단일 서버에서 돌리는 소규모 애플리케이션이나 로컬 앱이면 이걸로 충분하다. 다만 멀티 인스턴스에서는 파일 공유 문제가 생긴다.
from langgraph.checkpoint.sqlite import SqliteSaver
checkpointer = SqliteSaver.from_conn_string("checkpoints.db")
graph = builder.compile(checkpointer=checkpointer)
PostgresSaver — 멀티 인스턴스 프로덕션 기본값
제대로 된 프로덕션이면 이거다. 모든 워커가 같은 Postgres를 바라보니까 어떤 워커가 요청을 받아도 이전 상태에서 이어서 실행할 수 있다.
from psycopg_pool import ConnectionPool
from langgraph.checkpoint.postgres import PostgresSaver
pool = ConnectionPool(
"postgresql://user:pass@host/db",
min_size=2,
max_size=10,
kwargs={
"autocommit": True,
"prepare_threshold": 0, # PgBouncer 쓰면 필수
}
)
checkpointer = PostgresSaver(pool)
checkpointer.setup() # 멱등적 — 매 부팅 시 안전
graph = builder.compile(checkpointer=checkpointer)
autocommit=True 가 중요하다. LLM 호출 중에 트랜잭션이 열려 있으면 Postgres 락이 걸린다. prepare_threshold=0 는 PgBouncer 뒤에서 돌릴 때 필수다.
- TypedDict로 스키마 명시
- 누적 필드엔 Annotated[list, add]
- 대용량 데이터는 S3 URI만 저장
- 직렬화 가능한 타입만 (dict / list / primitive)
- 느슨한 dict로 상태 정의
- reducer 없이 병렬 노드에서 list 업데이트
- PDF·이미지 raw bytes를 상태에 인라인
- 직렬화 불가 객체 (DB 커넥션 / 람다)
상태 설계 실수로 500GB 트래픽 만드는 법
체크포인터만 바꾼다고 끝이 아니다. 상태 스키마를 잘못 설계하면 DB 폭발한다.
TypedDict로 상태 스키마 명시화
프로토타입 때는 느슨한 딕셔너리를 쓰는 경우가 많다. 프로덕션에서는 TypedDict로 명시해야 한다. 이유는 두 가지다. 첫째, 체크포인터에 쓰는 계약서가 된다. 둘째, 필드별로 직렬화 가능한지 확인할 수 있다.
from typing import TypedDict, Annotated
from operator import add
class AgentState(TypedDict):
messages: Annotated[list, add] # 누적
findings: Annotated[list, add] # 누적
current_step: int # 덮어쓰기
approved: bool # 덮어쓰기
Annotated[list, add] reducer — 덮어쓰기 방지
이게 핵심이다. Annotated[list, add]를 붙이지 않으면 노드가 반환하는 새 리스트가 이전 리스트를 덮어쓴다. 병렬 브랜치에서 두 노드가 동시에 findings를 업데이트하면 하나가 날아간다. reducer를 달면 LangGraph가 자동으로 병합해준다.
그리고 상태 크기 문제. 조사 결과를 정리하면 이게 제일 충격적인 함정인데, 상태에 PDF나 이미지를 통째로 넣으면 안 된다. 10MB짜리 상태가 50 스텝 파이프라인에서 1,000개 동시 실행되면 500GB 체크포인트 트래픽이 나온다. 대용량 데이터는 S3에 올리고 URI만 상태에 저장해야 한다.
(에이전트당 ≈ 450 토큰 오버헤드)
CrewAI vs LangGraph, 비용으로 보면 답이 나온다
처음에 CrewAI로 시작하는 팀이 많다. 빠르게 프로토타입 만들 수 있고, 역할 기반 에이전트 정의가 직관적이다. 근데 트래픽이 쌓이면 비용 차이가 보이기 시작한다.
일 10,000건 처리 기준으로 비교하면, LangGraph는 하루 약 $32, CrewAI는 약 $50이 나온다. 56% 차이다. CrewAI가 에이전트마다 역할 정의를 시스템 프롬프트로 주입하는 방식이라 요청당 약 450토큰 오버헤드가 붙는다. LangGraph는 프롬프트를 직접 제어하니까 이런 낭비가 없다. [출처: 여러 프로덕션 사례 보고 종합]
레이턴시도 차이난다. 3노드 병렬 작업 기준으로 LangGraph는 약 4.2초, CrewAI hierarchical 모드는 약 7.8초다. CrewAI가 매 위임마다 매니저 에이전트 LLM 호출을 추가로 한다.
그래서 현장에서 자주 채택하는 패턴은 이렇다. 아이디어 검증은 CrewAI로 빠르게. 검증된 파이프라인은 LangGraph로 마이그레이션해서 프로덕션 올리기. 둘이 경쟁 관계가 아니라 단계별 도구다.
프로토타입 속도는 CrewAI가 빠르지만,
상태 관리와 크래시 복구가 필요해지는 순간
결국 LangGraph로 오게 된다.
학습 곡선은 가파르다, 그래도 갈 길이다
솔직하게 말하면, LangGraph 학습 곡선은 가파르다. 그래프 개념에 익숙하지 않으면 첫 며칠이 고통이다. CrewAI 대비 보일러플레이트도 확실히 많다. 프로토타입 속도는 CrewAI가 훨씬 빠르다.
하지만 프로덕션에서 상태 관리와 크래시 복구가 필요한 순간이 오면, 결국 LangGraph로 오게 된다. MemorySaver가 날린 45분, 잘못 짠 상태 스키마가 만든 500GB. 이런 경험을 한 번 겪고 나면 선택지가 좁아진다.
체크포인터를 PostgresSaver로 바꾸고, 상태를 TypedDict + reducer로 명시하고, 대용량은 S3 URI로 빼는 것. 이 세 가지만 지켜도 프로덕션 사고의 절반은 막힌다. 나머지 절반은 — 그건 또 다른 글에서.
- LangGraph Persistence Concepts — langchain-ai.github.io/langgraph/concepts/persistence
- PostgresSaver Reference — langgraph.checkpoint.postgres 공식 API 문서
- psycopg ConnectionPool — autocommit · prepare_threshold 동작 가이드
- CrewAI vs LangGraph 비교 분석 — 토큰 오버헤드 및 hierarchical 모드 레이턴시 보고 [출처 필요: 다수 프로덕션 사례]
📌 함께 보면 좋은 글
'AI.IT' 카테고리의 다른 글
| CrewAI 실전 구성하다 막혔던 3가지, 공식 예제엔 없던 문제들 (0) | 2026.05.13 |
|---|---|
| Dify 워크플로우를 n8n 옆에 뒀더니, 어디에 쓰는 건지 비로소 알았다 (0) | 2026.05.12 |
| Claude Code 토큰 65% 절감 케이브맨 스킬, 진짜 쓸 만한 건 따로 있다 (0) | 2026.05.12 |
| Zapier AI Agents 써봤는데, 쉽다는 말은 반만 맞았다 (0) | 2026.05.12 |
| Claude Code Agent View 정리 — IDE에서 에이전트 OS로 넘어가는 신호 (0) | 2026.05.12 |