상시 구동 AI 에이전트의 장시간 작업 체크포인트 설계 및 재개 방법
요약
장시간 AI 에이전트 작업의 안정성을 확보하기 위해 체크포인트 및 재개 설계 방식을 제시합니다. 프로세스 다운 시 비용 낭비와 데이터 오류를 막기 위해, 작업을 단계별로 외부 스토리지에 영속화하고 부작용 호출에는 반드시 멱등 키(idempotency key)를 부여해야 합니다.
핵심 포인트
- 장시간 작업은 중간 실패 시 재실행이 불가능하므로 복구 설계가 필수입니다.
- 작업 진행 상태는 메모리가 아닌 외부 스토리지에 단계별로 영속화해야 합니다.
- 부작용을 수반하는 호출에는 중복 실행 방지를 위해 멱등 키를 반드시 사용해야 합니다.
- 재개 시에는 위치 기반이 아닌, 각 단계의 상태(status) 기반으로 판단하여 진행해야 안전합니다.
채팅에 상주하는 AI 에이전트에게 '이 자료들을 모아서 요약해 줘', '모든 고객의 청구 상황을 확인해 줘'와 같이 도구 호출(tool calling)을 수십 번 반복해야 하는 장시간 작업을 시키기 시작하면, 반드시 부딪히는 문제가 있습니다. 바로 프로세스가 중간에 다운되었을 때 어디까지 진행했는지 알 수 없게 되는 문제입니다. 배포나 충돌은 짧은 응답이라면 '다시 한번 말씀해 주시겠어요?'로 해결되지만, 15분 동안 걸려 80%까지 진행된 작업이 재실행으로 처음부터 돌아가면, 사용자 신뢰뿐만 아니라 API 비용도 낭비됩니다. 이 글에서는 장시간 작업의 진행 상태를 '다운되어도 복구할 수 있게' 하는 체크포인트 및 재개 설계 방식을 정리합니다.
왜 '처음부터 다시 하기'가 허용되지 않는가
단순한 질의응답 응답이라면, 프로세스 재시작 후 사용자에게 '죄송하지만 다시 한번 부탁드립니다'라고 해도 실질적인 피해는 작습니다. 하지만 장시간 작업에서는 이 전제가 무너집니다.
- 도구 호출 1회마다 외부 API에 실제 비용(LLM 추론·검색·타 시스템 쓰기)이 발생하므로, 재실행은 그대로 두 배의 비용이 됩니다.
- '청구 상황을 확인해 줘'와 같이 부작용을 수반하는 호출(메일 전송·상태 업데이트)을 포함하는 작업은, 재실행할 경우 이중 전송·이중 업데이트라는 실질적인 피해를 발생시킵니다. - 작업이 길수록 '어디까지 진행했는지 알 수 없다'는 상태로 재실행되면 사용자 불신감이 커집니다. 진행 상황이 보이지 않는 블랙박스 처리일수록, 실패 시 설명 가능성(explainability)이 중요해집니다.
이는 앞서 언급된 제로 다운타임 배포 설계가 '처리 중에 끊기지 않게 하는 것'을 목표로 한다면, 이번 주제는 '그래도 끊기는 것은 전제하고, 끊긴 후에 어떻게 복구할 것인가'라는 한 단계 뒤의 방어선입니다.
패턴 1: 작업을 '단계 배열(array of steps)'로 외부 영속화하기
먼저, 작업 진행 상태를 프로세스의 메모리(변수·클로저)에만 두지 않고, 각 단계가 완료되는 시점에 외부 스토리지에 기록합니다.
type TaskStep = {
stepId: string;
kind: "search" | "tool_call" | "write";
...
}
핵심은 단계 단위로 영속화하는 것입니다. 작업 전체를 1회 처리로 간주하고 마지막에 한 번에 저장하는 구현 방식으로는, 중간에 다운되었을 때 결국 어디까지 진행했는지 알 수 없게 되어 체크포인트의 의미가 사라집니다.
패턴 2: 부작용이 있는 호출에는 반드시 **멱등 키(idempotency key)**를 부여하기
재개 시 가장 사고가 나기 쉬운 경우는 '이미 완료했다고 생각되는 단계를 다시 실행해 버리는' 경우입니다. 이를 방지하려면, 부작용을 수반하는 모든 호출에 멱등 키를 부여하고, 호출 받는 쪽에서도 같은 키로의 중복 실행을 거부하도록 해야 합니다.
| 단계 유형 | 재실행 시 동작 | 대책 |
|---|---|
| 검색·읽기 전용 도구 호출 | 몇 번 실행해도 안전 | 멱등 키 불필요. 재개 시에는 단순히 재실행하면 됨 |
| ... |
외부 서비스 측에서 멱등 키를 지원하지 않는 경우, 호출하기 전에 '이 키로 이미 실행되었는지'를 우리 쪽 기록으로 확인하는 가드 처리를 삽입해야 합니다.
패턴 3: 재개 시에는 '어디부터'보다 '무엇이 미완료인지'로 판단하기
체크포인트 구현에서 흔히 하는 실수는 'cursor의 위치로부터 다시 시작한다'는 위치 기반(position-based) 재개입니다. 이는 단계가 완료되었는데 persist 쓰기가 완료되기 전에 프로세스가 다운된 경우, 완료된 단계가 미완료로 처리되어 패턴 2의 대책이 있어도 판단이 복잡해집니다.
더 안전한 것은, 재개 시 각 단계의 status를 개별적으로 확인하고, done인 것은 건너뛰고, pending 또는 failed인 것만 실행하는 상태 기반(state-based) 재개입니다.
async function resumeTask(taskId: string) {
const state = await loadState(taskId);
for (const step of state.steps) {
...
}
위치(커서)는 어디까지 '다음으로 착수해야 할 곳의 참고 지점'으로만 사용하고, 실행 가능 여부의 최종 판단은 각 단계의 상태로 진행하는 이중 체크를 하면, 영속화 타이밍 차이에 대해서도 사고가 적습니다.
패턴 4: 사용자에게는 '진행 상황'으로 보여주기
지금까지의 메커니즘은 단순한 장애 대비책이지만, 같은 데이터를 사용자에게 진행 상황 보고에 그대로 활용할 수 있습니다. '8단계 중 5단계 완료, 남은 시간 추정 2분'과 같은 표시는 장시간 작업에서는 여러 건의 업무를 병행하는 PM(Project Manager)이 진행 상황을 파악하기 어려운 문제와 동일한 구조의 불안감을 해소합니다. 인간 PM이 진행 상황을 기억에 의존하여 관리하면 사일로화(属人化, 지식 종속성)되는 것과 마찬가지로, 에이전트의 작업 진행 상황 역시 기계적으로 영구화된 상태를 유일한 정답으로 함으로써, 도중에 담당자(프로세스)가 바뀌어도 진행 상황 설명에 오류가 생기지 않습니다.
요약
- 장시간 작업은 프로세스가 다운되는 것을 전제로 설계하여 '처음부터 다시 하기'라는 선택지를 배제한다.
- 작업의 진행 상태는 단계(step) 단위로 외부에 영구화해야 하며, 작업 전체 완료 시점에 일괄 저장하는 것은 의미가 없다.
- 부작용이 있는 호출에는 멱등 키(Idempotency Key)를 필수적으로 적용하여 재실행 시 이중 실행을 호출 받는 쪽에서도 방지한다.
- 재개 판정은 위치(커서)에만 의존하지 않고, 각 단계의 상태(done/pending/failed)를 개별적으로 확인해야 한다.
- 영구화된 진행 상태는 장애 대비책인 동시에, 사용자에게 보고하는 진행 상황에도 그대로 활용할 수 있는 자산이 된다.
상주 에이전트가 다루는 작업이 길고 복잡해질수록, '다운되어도 되찾을 수 있다'라는 설계를 미룬다면 재실행 비용은 증가하게 됩니다. 짧은 응답 위주의 작업에서부터 단계 단위의 영구화만은 먼저 구성해 두는 것이 결국 안전합니다.
저는 Slack / Teams / Chatwork에 상주하며 자료 수집, 요약, 여러 시스템 확인 작업과 같은 장시간 작업을 백그라운드에서 실행하는 AI 에이전트 HACH를 개발하고 있으며, 처리가 길어질수록 '도중에 다운되어도 진행 상황을 잃지 않는' 설계는 피할 수 없는 과제라고 생각합니다.
논의

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기