AI 에이전트를 14번 죽였는데, 계속 작동했다는 경험
요약
본 글은 에이전트 프레임워크의 가장 큰 문제점인 '내구성' 문제를 다룹니다. 기존 프레임워크들은 작업자 강제 종료 시 재개 기능이 없어 전체 작업을 처음부터 다시 시작해야 합니다. 필자는 DHP(Durable Handoff Protocol)라는 내구성 계층을 구축하여, 체크포인팅, 페일오버 등을 통해 중단된 에이전트 작업을 손실 없이 완벽하게 재개하는 방법을 제시합니다.
핵심 포인트
- 에이전트 작업의 강제 종료 시 데이터 및 진행 상황 손실 문제가 발생함.
- DHP는 내구성 실행 상태를 처리하며, 체크포인팅과 페일오버 기능을 제공함.
- 강력한 프로토콜 설계로 인해 재시작 과정에서 재작업(rework)이 전혀 발생하지 않음.
- 리스, 하트비트 등 검증된 분산 시스템 개념을 에이전트에 적용함.
모든 종료(kill)는 실제였다. 경고 없이, 실행 도중에 kill -9를 사용했다. 이것이 지루하게 만든 내구성 계층이다.
아무도 데모하지 않는 문제점
어떤 에이전트 프레임워크 데모를 보든: 에이전트가 실행되고, 완료되며, 모두 박수를 친다. 이제 무대에서 아무도 묻지 않는 질문을 해보자:
작업자가 90% 지점에서 죽으면 어떻게 될까?
OOM-killed(메모리 부족으로 종료). Spot instance 회수됨. 누군가 kill -9를 사용하다 손가락이 미끄러진다. 컨테이너가 강제 퇴거된다.
내가 이 분야의 환경을 조사했다 — LangGraph, CrewAI, AutoGen, OpenAI Agents SDK. 답은 어디서나 같다: 아무것도 아니다. 죽음 감지 기능도 없고, 예약된 재개(resume) 기능도 없다. 3시간 동안 실행되는 작업이 2시간 59분에 죽으면, 처음부터 다시 시작해야 한다.
이것은 예외적인 경우(corner case)가 아니다. 만약 프로덕션 환경에서 에이전트를 운영한다면 — 장기간의 연구 작업, 다단계 코딩, 데이터 파이프라인 — 작업자 사망은 '만약'이 아니라 '언제' 일어날지(when)에 대한 문제이다.
내가 구축한 것
DHP (Durable Handoff Protocol). 이것은 에이전트 프레임워크 아래에 놓이는 내구성 계층이다:
- MCP: 에이전트 ↔ 도구(tool)를 처리한다.
- A2A: 에이전트 ↔ 에이전트를 처리한다.
- DHP: 내구성 실행 상태(durable execution state)를 처리한다: 체크포인팅(checkpointing), 펜싱(fencing), 페일오버(failover), 휴대 가능한 일시 중지 작업(portable suspended work).
다섯 가지 보장 사항: 결과 손실 없음, 입력 교차 없음, 비타입화된 결과 없음, 조용한 예산 초과 없음, 러너 종속성 없음.
핵심 아이디어들은 오래되었고 검증되었다 — 리스(leases), 하트비트(heartbeats), 원자적 비교-교환 소유권(atomic compare-and-swap ownership), 단조 펜싱 토큰(monotonic fencing tokens) — 이들을 에이전트 세계가 아직 해결하지 못한 문제에 적용한 것이다.
종료 #1: 나를 설득한 경험
60개의 실제 Wikipedia 페이지를 가져와야 했다. Worker A가 시작했다. 20페이지에서 나는 kill -9로 이를 종료시켰다. 경고도, 우아한 종료(graceful shutdown)도 없었다.
무슨 일이 일어났는가:
- 작업자의 하트비트가 멈췄다.
- 감독자(Supervisor)는 약 6.5초 후에 누락된 리스를 감지했다.
- 감독자는 핸드오프를 고아 상태(orphaned)로 표시했다.
- 대기 작업자(standby worker)가 이를 주장하고, 마지막 체크포인트(20페이지, 종료되기 전에 TCP를 통해 전송됨)를 읽었다.
- 대기 작업자가 21페이지부터 재개했다.
결과: 60/60 페이지 가져오기 완료. 재가져온 것 없음. 이 종료는 출력에서 눈에 띄지 않았다 — 단지 6.5초의 일시 정지일 뿐이었다.
종료 #2–4: 네트워크 혼란 실행
저는 한 번의 종료로는 만족하지 않았습니다. 다음 테스트에서는 네 번의 실행 라운드 동안, TCP 전송 도중(mid-TCP-shipment)에 세 번의 실제 SIGKILL이 발생했습니다. 체크포인트가 와이어를 가로질러 절반쯤 이동했을 때라 가장 최악의 순간이었죠.
- 고아 시간(Orphan times): 7.0초, 6.5초, 6.0초.
- 피어는 24/24개의 체크포인트를 수신했습니다.
- 재작업 없음(Zero rework).
전송 프로토콜은 수신 시 엔벨로프 식별자와 체크포인트별 해시를 검증하므로, 손상된 쓰기 작업이 재개 지점을 오염시킬 수 없습니다.
종료 #5–18: 무작위 혼란(randomized chaos)
다음은 결함 주입 하네스(fault-injection harness)입니다. 워커와 슈퍼바이저 모두에 대해 무작위 SIGKILL을 발생시켰습니다. 14번의 워커 종료, 4번의 슈퍼바이저 종료, 무작위 타이밍이었습니다.
가장 흥미로웠던 것은 제가 워커 및 리드 슈퍼바이저를 같은 순간에 종료시킨 경우입니다. 리더 선출(leader election)을 통해 승격된 팔로워 슈퍼바이저가 6.6초 만에 고아 상태를 감지했고, 대기 시스템은 마지막 체크포인트로부터 원자적 CAS(atomic CAS)를 통해 복구했습니다. 1,600개의 체크포인트, 재작업 없음, 결과는 정확함을 검증받았습니다.
모든 불변성(invariant)이 유지되었습니다: 손실된 결과가 없고, 교차된 입력도 없으며, 항상 단 하나의 소유자만 존재했습니다 (동시 복구 스레드 10개 → 정확히 한 명의 승자가 확인됨).
제가 솔직하게 밝힌 것
서브-초(Sub-second) 페일오버는 불가능합니다. 저는 이를 진지하게 조사했습니다. LLM 워크로드를 위해, 추론 계층은 오탐지 없이 서브-초 사망 감지를 하기에 너무 느리고 예측 불가능합니다. 솔직한 수치는 밀리초가 아니라 **초(seconds)**입니다: 약 7초의 종료부터 재개까지 걸립니다. 이는 제가 찾을 수 있었던 최고 기록(Temporal의 상태 저장 페일오버에 대한 약 12초)보다 여전히 2배 빠르며, 예측이 아닌 실제 측정값입니다.
작동 방식 (30초 버전)
import dhp
tore = dhp.Store("/var/lib/dhp")
...
만약 worker-1이 해당 with 블록 내에서 죽으면, 슈퍼바이저는 핸드오프를 고아 상태로 만들고, 대기 시스템은 마지막 checkpoint()부터 이를 가져갑니다. complete() 함수는 스키마와 결과를 검증하여 타입이 지정되지 않은 결과가 새어 나오는 것을 막습니다.
MCP 사용자를 위해 8가지 도구 서버가 있습니다:
claude mcp add dhp -- dhp-mcp --root ~/.dhp
그리고 A2A 브릿지(bridge) — A2A 태스크 ID가 안정적인 식별자(identity)가 되고, DHP 핸드오프(handoff)는 그 아래의 실행 시도들입니다. A2A 클라이언트는 WORKING → COMPLETED를 보게 되며, 워커 스왑은 눈에 띄지 않습니다.
아키텍처
주요 설계 결정 사항:
- 콘텐츠 주소 지정 봉투(Content-addressed envelopes): 식별자가 변경 가능한 상태가 아닌 의도(intent)를 담습니다. 변조된 체크포인트는 유효한 것으로 오인될 수 없습니다.
- 펜싱 토큰(Fencing tokens): 단조 증가 카운터(monotonic counters)가 오래된 워커들을 거부합니다. 죽었다고 선언된 워커가 돌아와 커밋할 수 없습니다.
- 원자적 CAS 소유권(Atomic CAS ownership): 경쟁 상황에서도 오직 한 명의 복구자(recoverer)만이 승리합니다.
- 공유 데이터베이스 불필요: 전송 로그(transport log, append-only JSON-lines)만 있으면 피어(peer)가 전송된 체크포인트만으로 상태를 재구성할 수 있습니다. 저는 실행 도중에 전체 호스트 — 디스크까지도 — 를 파괴함으로써 이를 증명했습니다.
직접 사용해보기
pip install dhp-protocol
# 또는 한 줄로:
curl -fsSL https://raw.githubusercontent.com/SIDDARTHAREDDY8/dhp/main/install.sh | bash
이 저장소에는 실행 가능한 종료 데모(demo/run_mad_demo.py)가 있습니다. 이 데모는 실제 페이지를 가져오고, 실제 워커를 종료하며, 복구 과정을 보여줍니다. 직접 실행해 보세요. 제 말만 믿지 마세요.
링크:
DHP는 MIT 라이선스를 따릅니다. 45개 테스트가 성공했고, 10/10의 적합성을 보이며, 실제 종료를 통해 카오스 테스트를 거쳤습니다. 만약 프로덕션 환경에서 에이전트를 실행한다면, 이 레이어가 빠져있을 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기