도구 호출 실패, 재시도인가 보상인가

「도구 호출 10개 중 9개가 성공하고 마지막 하나가 실패하면 어떻게 할 것인가」가 묻는 것은 예외 처리가 아니라 **부작용 모델링(side-effect modeling)**이다.

워크플로를 상태 머신으로 쪼개고, 각 도구 동작에 읽기 전용 / 멱등 쓰기 / 롤백 가능 쓰기 / 불가역 쓰기라는 리스크 등급을 매긴다. 실행 시 상태와 멱등 키를 기록하고, 실패 후에는 먼저 실제 업무 상태를 조회한 다음 재시도, 스킵, 롤백, 보상, 사람 전환 중 무엇을 할지 결정한다.

핵심 결론: 실패 복구의 관건은 Agent를 더 용감하게 재시도시키는 것이 아니라, 어떤 동작이 이미 발생했는지 알게 하는 것이다.

왜 「재시도」가 틀린 답인가

실제 워크플로에서 많은 동작은 한 번 실행되면 간단히 취소할 수 없다.

동작의 롤백 가능성 분류

어떤 것은 취소 가능롤백
어떤 것은 보상만 가능새로운 업무 동작으로 상쇄
어떤 것은 사람이 처리해야 함사람 전환

3단 판단 + 4종 동작의 복구 전략

  1. 먼저 실패가 어느 단계에서 발생했는지 판단
  2. 그다음 앞서 성공한 동작에 부작용이 있는지 판단
  3. 마지막으로 롤백 가능한지 / 보상이 필요한지 판단
읽기 전용 조작바로 재시도
멱등 쓰기 조작상태 조회 후 재시도
불가역 쓰기 조작맹목적 재시도 금지. 보상 또는 사람 확인으로

1단계: 워크플로를 상태 머신으로 쪼개기

사용자 검증(S1) → 자격 잠금(S2) → 쿠폰 생성(S3) → 알림 발송(S4) → 감사 기록(S5)

인터페이스의 성공/실패만 봐서는 안 된다. 겉보기에는 둘 다 "부분 실패"지만 실제로는 완전히 다른 두 상황을 예로 들면:

상황의미복구 전략
쿠폰 생성 성공 + 알림 실패쿠폰은 나갔는데 사용자가 모름알림만 재발송하면 됨
쿠폰 생성 실패 + 알림 미발송아무 일도 일어나지 않음안전하게 재실행 가능
결제 타임아웃즉시 한 번 더 차감하면 안 됨먼저 결제 상태 조회
SMS 발송 실패네트워크나 게이트웨이 이상안전한 재시도 허용
쿠폰 발급 성공레코드를 간단히 삭제하면 안 됨알림 재발송 / 고객센터 후속 기록

결론: Agent는 작업이 어느 상태에 멈춰 있는지 반드시 알아야 한다.

2단계: 도구에 복구 의미론 정의하기 (tool schema 확장)

도구 schema에는 파라미터만이 아니라 네 가지 메타 정보를 더 써야 한다:

  1. 멱등한가
  2. 롤백 가능한가
  3. 현재 상태를 어떻게 조회하는가
  4. 실패 코드의 의미는 무엇인가

3단계: 보상 동작과 사람의 경계 설정

보상 ≠ 롤백. 보상은 새로운 업무 동작으로 영향을 상쇄하는 것이지 원래 동작을 취소하는 것이 아니다. 예:

  • 쿠폰을 잘못 발급함 → 올바른 쿠폰 발급 + 잘못된 쿠폰 동결
  • 메일을 잘못 보냄 → 회수 불가, 정정 안내를 보낼 수밖에 없음

「고위험 동작 통제」: Agent가 「보상 전략 제안」 → 확인 대기 → 「사람/사용자가 확인 후 실행」. 하단 경고문: 「Agent가 모든 부작용을 독단적으로 처리하는 것 금지」

어떻게 테스트하나? — 장애 주입 4장면

#주입할 장애
1어떤 단계가 타임아웃했지만 실제로는 성공(가장 위험한 유형)
2어떤 단계가 부분 성공
3보상 도구 자체도 실패
4상태 조회 응답이 지연

진단 요점: 많은 시스템이 평소에 문제없어 보이는 것은 성공 경로만 테스트했기 때문이다. 진짜 상용 사고는 대개 반쯤 성공, 반쯤 실패, 중복 제출 사이에서 발생한다.

핵심 통찰

  1. 실패 복구의 제1원리적 질문은 "세상이 바뀌었는가"이지 "호출이 무엇을 반환했는가"가 아니다 — 인터페이스가 실패를 반환했다고 동작이 발생하지 않은 것은 아니다(타임아웃했지만 실제로는 성공한 경우가 가장 전형적인 반례다). 따라서 상태 조회는 어떤 복구 결정보다도 우선해야 한다.
  2. 부작용은 타입 시스템으로 모델링할 수 있다 — 읽기 전용 / 멱등 쓰기 / 롤백 가능 쓰기 / 불가역 쓰기 이 네 등급은 본질적으로 「리스크」를 도구 정의에 인코딩해, 복구 전략을 사람이 현장에서 판단하는 대신 자동으로 추론할 수 있게 한다.
  3. 보상과 롤백은 서로 다른 두 패러다임이다 — 롤백은 「없던 일로 만드는 것」이고 보상은 「한 가지 일을 더 해서 영향을 상쇄하는 것」이다. 현실 세계의 불가역 동작(이미 발송된 메일, 이미 통지한 사용자)에는 보상이라는 길밖에 없으며, 이것이 분산 트랜잭션에서 Saga 패턴의 핵심 사상이다.
  4. 멱등 키는 재시도 능력의 전제 조건이다 — 멱등 키가 없으면 어떤 재시도도 도박이다. 멱등 키가 있어야 재시도가 「위험한 조작」에서 「안전한 조작」으로 바뀐다.
  5. Agent의 자율권은 리스크에 따라 수렴시켜야 한다 — 저위험 동작은 완전 자동, 고위험 보상 동작은 사람 확인을 강제. 「Agent가 제안하고 사람이 결정한다」는 것은 고위험 장면의 기본 협업 형태이지 능력 부족에 따른 타협이 아니다.
  6. 테스트의 가치는 이상 경로를 덮는 데 있고, 성공 경로 테스트는 거의 무효다 — 장애 주입으로 「반쯤 성공」 상태를 일부러 만들어야 한다. 상용 사고는 거의 전부 이 구간에 집중되기 때문이다.
  7. 평가는 동종 작업의 전체적 안정성을 봐야지 단일 답변의 인상을 보면 안 된다 — 「답이 듣기 좋다」는 사람을 속이기 가장 쉬운 지표다. 고정된 회귀 샘플 + 다차원 지표(정확률/경로 안전/인용 품질/비용·지연)만이 진짜 변화를 반영한다.

엔지니어링 실전 Tips

  • 타임아웃 ≠ 실패: 결제 타임아웃 시 첫 동작은 언제나 「결제 상태 조회」이지 「한 번 더 차감」이 아니다. 이것이 가장 전형적인 금전 손실 사고의 원인이다.
  • 멱등 키는 호출을 발기하기 전에 생성해 영속화해야 한다. 그렇지 않으면 재시도할 때 쓸 키가 없다.
  • 상태 머신의 입도는 「부작용이 있는 모든 동작」까지 세밀해야 한다. 굵은 입도의 상태로는 「쿠폰 생성 성공, 알림 실패」 같은 중간 상태를 구분할 수 없다.
  • 실패 코드는 error 하나만 두지 말고 분류할 것: 최소한 「확실히 미실행」, 「확실히 실행됨」, 「상태 불명」 세 종류로 구분하고, 세 번째만 상태 조회로 보낼 것.
  • 보상 동작 자체도 실패할 수 있으므로 일급 객체로 테스트에 포함할 것(장애 주입 3항).
  • 고위험 보상은 반드시 사람 확인 채널을 거쳐야 하며 Agent에게 직접 실행 권한을 주지 말 것.
  • 회귀 샘플셋은 고정해야 한다. 그렇지 않으면 Prompt 변경 후의 지표 변화를 귀인할 수 없다.
  • 상용 trace 샘플링 → 실패 샘플을 평가셋에 환류시키는 것이, 평가셋을 실제 분포에 계속 근접시키는 데이터 플라이휠이다.

용어

멱등(Idempotent)MDN 문서

같은 요청을 한 번 실행하든 연속해서 여러 번 실행하든 서버에 대한 기대 효과가 동일하다면, 그 HTTP 메서드는 멱등하다고 한다.