AI Agent 중복 실행 방지, 재시도에도 안전한 멱등성 설계 기준
메일 발송·CRM 등록·결제 요청 같은 AI 자동화가 네트워크 재시도 중 두 번 실행되지 않도록 요청 키, 상태 저장, 잠금, 결과 재사용 기준을 정리합니다.
AI Agent가 고객 문의를 읽고 CRM에 상담 건을 만든 뒤 접수 메일까지 보냈다고 가정해보겠습니다. 메일 API 응답이 늦어 자동화가 시간 초과로 끝나면, 운영자는 같은 업무를 다시 실행하고 싶어집니다.
하지만 외부 시스템에서는 이미 처리가 끝났을 수 있습니다. 아무 기준 없이 재시도하면 CRM 상담 건과 고객 메일이 두 개씩 생깁니다. 장애를 복구하려던 재시도가 새로운 운영 사고가 되는 이유입니다.

핵심 요약
- 멱등성은 코드를 정확히 한 번만 실행한다는 약속이 아니라, 같은 업무 요청이 반복돼도 추가 부수 효과가 늘지 않게 만드는 성질입니다.
- 하나의 업무 의도에 멱등성 키를 한 번 발급하고, 네트워크·큐·스케줄러가 재시도할 때도 같은 키를 재사용합니다.
- 같은 키와 같은 요청이면 저장된 상태·결과를 돌려주고, 같은 키에 다른 대상·금액·수신자가 들어오면 충돌로 멈춥니다.
- 처리 중·성공·재시도 가능 실패·최종 실패·상태 불명을 영속 저장하고, 외부 시스템의 메시지·거래·레코드 ID를 함께 남깁니다.
- 메일·결제·예약·삭제처럼 되돌리기 어려운 단계는 응답이 없다고 바로 다시 실행하지 말고 실제 상태 조회와 사람 확인을 먼저 둡니다.
재시도 횟수를 줄이는 것보다, 같은 재시도가 들어와도 업무 결과가 하나로 수렴하게 만드는 것이 먼저입니다.
멱등성은 부분 실패 복구와 무엇이 다를까
멱등성(idempotency)은 같은 입력의 작업을 여러 번 요청해도 관찰 가능한 업무 결과가 더 늘지 않는 성질입니다. 실행 시도는 여러 번일 수 있지만 고객 메일, 결제, 티켓, 파일 같은 부수 효과는 한 번의 의도에 대응해야 합니다.
부분 실패 복구가 ‘어디까지 성공했고 어느 단계부터 이어갈지’를 정한다면, 멱등성은 ‘그 단계를 다시 호출해도 결과가 중복되지 않게’ 합니다. 여러 도구를 잇는 AI Agent에는 단계 상태 기록과 멱등성 설계가 함께 필요합니다.
Amazon Builders’ Library도 재시도의 이점을 살리려면 호출을 다시 보내도 추가 부수 효과가 생기지 않는 멱등 API가 필요하다고 설명합니다. 단순히 요청 파라미터가 비슷한지를 보는 대신, 호출자가 전달한 요청 식별자로 같은 의도를 구분하는 방식도 강조합니다.
어떤 자동화 단계에 먼저 적용해야 할까
- 고객·직원에게 이메일, 문자, 메신저 알림을 보내는 단계
- CRM 상담 건, ERP 전표, 헬프데스크 티켓, 업무 태스크를 새로 만드는 단계
- 결제·환불·포인트·쿠폰·예약처럼 금전 또는 약속 상태를 바꾸는 단계
- 파일 게시·이동·삭제, 권한 변경, 외부 승인처럼 되돌리기 어렵거나 감사 이력이 필요한 단계
반대로 검색·조회처럼 상태를 바꾸지 않는 작업은 원래 멱등적인 경우가 많습니다. 먼저 ‘성공할 때 외부에 무엇이 새로 생기거나 바뀌는가’를 표시하면 중복 방지 우선순위를 빠르게 정할 수 있습니다.
요청 키·입력 지문·결과 기록을 한 세트로 설계합니다
1. 멱등성 키는 기술 시도가 아니라 업무 의도를 식별합니다
키는 AI 모델이 만든 문장이나 매 실행 시각이 아니라 ‘어느 조직의 어떤 업무 객체에 어떤 행동을 하려는가’를 가리켜야 합니다. 예를 들어 상담 접수 메일이라면 조직 ID, 고객 문의 ID, 행동 이름, 규칙 버전을 조합하거나 최초 요청에서 발급한 UUID를 사용할 수 있습니다.
- 같은 의도를 다시 보내는 기술 재시도에는 같은 키를 사용합니다.
- 같은 고객에게 다음 달 새 안내를 보내는 것처럼 새로운 업무 의도에는 새 키를 발급합니다.
- 조직·테넌트와 행동 범위를 키에 포함해 서로 다른 고객사의 같은 번호가 충돌하지 않게 합니다.
2. 입력 지문은 같은 키의 내용이 바뀌는 사고를 막습니다
멱등성 키만 같다고 무조건 이전 결과를 돌려주면 위험합니다. 대상 고객, 수신자, 금액, 템플릿 버전, 승인 ID처럼 결과를 바꾸는 필드를 정규화해 지문으로 저장하고, 재시도 요청의 지문이 다르면 새 실행이 아니라 충돌로 처리해야 합니다. Stripe도 같은 키가 재사용될 때 원래 요청과 파라미터를 비교해 오용을 막는 방식을 안내합니다.
3. 상태와 결과를 영속 저장해야 재시작 뒤에도 안전합니다
프로세스 메모리의 플래그만으로는 서버 재시작, 여러 인스턴스, 동시 웹훅을 막을 수 없습니다. 공유 데이터베이스나 영속 저장소에 키, 입력 지문, 상태, 결과 요약, 외부 결과 ID, 시도 시각과 만료 시각을 남겨야 합니다.
- RECEIVED: 요청을 받았지만 외부 부수 효과를 시작하지 않은 상태
- IN_PROGRESS: 한 실행자가 작업을 맡았고 임대 만료 시각까지 처리 중인 상태
- SUCCEEDED: 외부 결과 ID와 재사용할 응답이 저장된 완료 상태
- FAILED_RETRYABLE / FAILED_FINAL: 일시 오류와 입력·권한·업무 규칙 오류를 분리한 상태
- UNKNOWN: 외부 처리는 됐을 수 있지만 응답을 받지 못해 조회·대조가 필요한 상태
IN_PROGRESS에는 잠금만 두지 말고 임대(lease) 만료 시각과 복구 규칙을 둡니다. 다만 임대가 끝났다고 결제·삭제를 곧바로 재실행하지 말고, 먼저 외부 결과 ID나 업무 키로 실제 반영 여부를 확인해야 합니다.
AI Agent 멱등성 흐름을 만드는 7단계
아래 순서를 자동화 정의서와 구현 작업에 함께 적으면 개발자와 현업 운영자가 같은 ‘한 건’의 경계를 공유하기 쉽습니다.
- 부수 효과의 경계를 정합니다. 메일 한 통, CRM 레코드 한 건, 결제 승인 한 건처럼 중복되면 안 되는 결과를 구체적으로 적습니다.
- AI가 도구를 호출하기 전에 멱등성 키를 발급합니다. 모델 출력이 달라질 때마다 키가 바뀌지 않도록 업무 요청 계층에서 만듭니다.
- 공유 저장소에 키와 입력 지문을 원자적으로 등록합니다. 고유 제약이나 조건부 쓰기로 동시에 들어온 두 요청 중 하나만 최초 실행자가 되게 합니다.
- 이미 키가 있으면 입력 지문을 비교합니다. 같으면 현재 상태나 저장된 결과를 반환하고, 다르면 사람이 확인할 수 있는 충돌 오류로 멈춥니다.
- 외부 API가 자체 멱등성 키를 지원하면 같은 키를 전달합니다. 지원하지 않으면 원 시스템의 업무 키·외부 결과 ID로 생성 전 조회와 사후 대조를 설계합니다.
- 성공 응답을 보내기 전에 SUCCEEDED 상태와 메시지·거래·레코드 ID를 저장합니다. 민감한 원문 대신 재사용과 감사에 필요한 최소 결과만 남깁니다.
- 시간 초과와 상태 불명은 실제 시스템을 먼저 조회합니다. 재시도 가능 오류만 제한·백오프해 다시 실행하고, 불일치와 고위험 작업은 예외 큐로 보냅니다.
완성 후에는 같은 요청 10개를 동시에 보내기, 성공 응답 직전 프로세스 종료, 늦게 도착한 웹훅, 만료 직전 재시도 같은 시험을 해보세요. 호출 횟수가 아니라 최종 메일·티켓·거래·파일이 정말 한 건인지 확인해야 합니다.
실무에서 자주 만나는 중복 실행 시나리오
고객 메일과 CRM 상담 건을 함께 만드는 경우
고객 문의 ID 하나를 워크플로우 기준으로 삼고, CRM 생성과 접수 메일 발송에는 단계별 멱등성 키를 파생합니다. CRM이 성공하고 메일 응답만 유실돼도 CRM 단계를 다시 만들지 않고 메일 메시지 ID나 발송 기록부터 확인할 수 있습니다.
- 같은 문의의 재수신은 기존 workflow ID와 단계 상태를 조회합니다.
- CRM 레코드 ID와 메일 메시지 ID를 단계 결과로 각각 저장합니다.
- 같은 키의 완료 요청에는 기존 결과를 돌려주고, 수신자나 템플릿이 달라졌다면 새 업무 승인 또는 충돌 처리로 분리합니다.
결제·환불·삭제처럼 되돌리기 어려운 경우
금액이나 삭제 대상은 AI가 생성한 자연어 설명만으로 식별하지 않습니다. 승인된 주문·환불·삭제 요청 ID를 키의 근거로 사용하고, 응답이 없으면 공급자의 거래 조회 API나 원장부터 확인합니다.
- 같은 승인 요청 ID로 새 거래를 만들지 않고 기존 거래 상태를 조회합니다.
- 외부 시스템이 상태를 확정하지 못하면 UNKNOWN으로 멈추고 금전·삭제 권한을 가진 담당자에게 넘깁니다.
- 새로운 결제나 재삭제가 실제로 필요한 경우에는 기존 키를 재사용하지 말고 별도 승인과 새 업무 키를 발급합니다.
멱등성 설계가 무너지는 흔한 이유
재시도할 때마다 새 UUID를 만든다
키가 매번 달라지면 서버는 모든 요청을 새로운 업무로 봅니다. 최초 요청에서 만든 키를 큐 메시지, 스케줄러 재시도, 하위 도구 호출까지 전달해야 합니다.
입력 전체를 해시하면 업무 의도까지 구분된다고 생각한다
똑같은 상품 두 개를 각각 주문하는 것처럼 입력이 같아도 별개의 의도일 수 있고, 생성 시각 한 필드가 달라져 같은 재시도가 다른 해시가 될 수도 있습니다. 명시적인 업무 요청 ID와 결과를 바꾸는 필드의 지문을 분리하는 편이 안전합니다.
한 서버의 메모리 잠금만 사용한다
서버가 여러 대이거나 프로세스가 재시작되면 메모리 잠금은 사라집니다. 공유 저장소의 고유 제약, 조건부 쓰기, 트랜잭션처럼 동시 요청 중 최초 실행자를 원자적으로 정하는 장치가 필요합니다.
처리 중 상태를 영원히 잠그거나, 만료 즉시 무조건 재실행한다
영구 잠금은 정상 업무를 막고, 무조건 재실행은 이미 성공한 외부 작업을 중복시킵니다. 임대 만료 뒤에는 상태 조회와 사후 대조를 거쳐 재개·완료·사람 확인 중 하나를 선택합니다. Google Cloud 문서처럼 재시도 가능 응답인지와 작업의 멱등성을 함께 판단하고, 백오프만으로 중복 방지를 대신하지 않습니다.
AI Agent 중복 실행 방지 체크리스트
- 중복되면 안 되는 부수 효과를 메일·레코드·거래·파일 단위로 정의했다.
- 멱등성 키를 AI 도구 호출 전에 만들고 모든 재시도 계층에서 재사용한다.
- 키의 범위에 조직·업무 행동·원 업무 객체가 포함돼 다른 고객사와 충돌하지 않는다.
- 같은 키와 같은 입력은 저장된 상태·결과를 반환하고 외부 작업을 다시 만들지 않는다.
- 같은 키와 다른 대상·금액·수신자·템플릿은 충돌로 중단한다.
- 동시 요청 중 한 실행자만 부수 효과를 시작하도록 원자적 고유 제약이나 조건부 쓰기가 있다.
- 외부 메시지·거래·레코드·파일 ID를 성공 결과와 함께 영속 저장한다.
- 시간 초과를 실패로 단정하지 않고 UNKNOWN 상태, 원 시스템 조회, 사람 예외 큐를 운영한다.
- 키 보관기간이 큐·웹훅의 최대 재전송, 수동 재처리, 장애 조사 기간보다 짧지 않다.
- 동시 중복, 지연 중복, 서버 종료, 잠금 만료, 다른 입력의 키 재사용을 테스트했다.
자주 묻는 질문
Q. workflow ID와 멱등성 키는 같은가요?
같게 쓸 수도 있지만 범위가 다를 수 있습니다. workflow ID는 고객 문의 접수 전체를 식별하고, 멱등성 키는 그 안의 CRM 생성·메일 발송·결제 요청처럼 한 부수 효과를 식별합니다. 여러 단계라면 workflow ID에서 단계별 키를 파생하되 각 키의 범위를 문서화하세요.
Q. 멱등성 키는 얼마나 오래 보관해야 하나요?
하나의 고정 숫자를 모든 시스템에 적용하면 안 됩니다. 큐와 웹훅의 최대 재전송 기간, 운영자의 수동 재처리 시점, 외부 시스템의 조회 가능 기간, 사고 조사 기간을 합쳐 정합니다. Stripe의 24시간 같은 값은 특정 서비스의 정책 예시일 뿐, 우리 업무의 공통 정답은 아닙니다.
Q. 메시지 큐가 정확히 한 번 전달을 지원하면 멱등성이 필요 없나요?
전달 계층의 보장은 외부 API, 데이터베이스, 이메일, 결제까지 한 번에 묶어주지 않습니다. 소비자 재시작이나 응답 유실도 남습니다. ‘정확히 한 번 실행’을 가정하기보다 중복 전달을 받아도 하나의 업무 결과로 수렴하도록 상태 저장과 대조 절차를 두는 편이 안전합니다.
HeyRatty와 재시도에 안전한 자동화를 설계하려면
HeyRatty는 AI Agent가 도구를 호출하는 데서 자동화 설계를 끝내지 않습니다. 업무 ID, 단계별 멱등성 키, 상태 저장, 외부 결과 대조, 사람 예외 큐까지 연결해 장애가 나도 같은 고객과 거래에 부수 효과가 겹치지 않게 설계합니다.
처음부터 모든 흐름을 바꿀 필요는 없습니다. 중복 발송이나 중복 등록이 가장 치명적인 자동화 하나를 골라 ‘같은 업무를 어떻게 알아볼 것인가’와 ‘응답이 없을 때 무엇을 확인할 것인가’를 먼저 정리해보세요. 현재 구조가 복잡하다면 HeyRatty가 작은 파일럿 범위부터 함께 설계할 수 있습니다.
참고 및 이미지 출처
- Amazon Builders’ Library — Making retries safe with idempotent APIs
- Stripe API Reference — Idempotent requests
- Google Cloud Storage — Retry strategy
- Powertools for AWS Lambda — Idempotency utility
- 이미지 원본: Wikimedia Commons 「Packages on UPS conveyor belt.jpg」 · U.S. Department of Agriculture(USDA), 사진 Lance Cheung · 원본 Flickr · Public domain(미국 연방정부·USDA 저작물) · Commons API가 제공한 1920×1280 JPEG 썸네일을 외부 URL로 직접 사용했습니다. 로컬 생성 이미지 0장.