Claude Code, Codex 등 Agent CLI의 자동 재시도 구현 방법





Claude Code, Codex 등 Agent CLI의 자동 재시도 구현 방법
자동 재시도라는 말은 작은 스위치처럼 보이지만, 실제 엔지니어링 현장에서는 전혀 그렇지 않습니다. 전국 제작자 여러분 안녕하세요, HagiCode 제작자 유쿤입니다. 오늘은 공허한 이야기 없이 Claude Code, Codex 같은 Agent CLI의 자동 재시도가 실제로 어떻게 해야 예외를 처리하면서도 시스템을 무한 반복 실행으로 빠뜨리지 않는지 이야기하겠습니다.
배경
최근 AI 프로그래밍에도 관심이 있으시다면 이런 문제를 이미 겪으셨을 것입니다: 작업이 처음부터 실패하는 것이 아니라 중간에 끊어집니다.
이것은 일반적인 HTTP 요청에서는 재전송하면 되고 기껏해야 지수 백오프를 추가하면 되지만, Agent CLI는 다릅니다. Claude Code, Codex 같은 도구는 일반적으로 스트리밍으로 실행되고 출력이 한 줄씩 나오며, 프로세스 중에 thread, session 또는 resume token이 바인딩됩니다. 즉, “이 요청이 실패했는가”가 아니라:
- 앞서 이미 출력된 내용이 유효한지
- 현재 컨텍스트를 계속 실행할 수 있는지
- 이번 실패를 자동 복구해야 하는지
- 복구한다면 얼마나 후에 재시도하고, 재시도 시 무엇을 보내며, 기존 컨텍스트를 재사용할지
많은 팀이 처음 이 부분을 구현할 때 무의식적으로 가장 단순한 버전을 작성합니다: 오류가 나면 다시 시도합니다. 이 생각은 매우 자연스럽지만, 실제 프로젝트에 넣으면 문제가 하나씩 나타납니다.
- 일부 오류는 명백히 일시적 장애인데 최종 실패로 간주됩니다
- 일부 오류는 재시도할 가치가 없는데 시스템이 반복 재생합니다
- thread가 있는 요청과 없는 요청이 동일하게 취급됩니다
- 백오프 전략에 경계가 없어 백엔드 요청이 스스로를 과부하시킵니다
HagiCode도 여러 Agent CLI를 연동하는 과정에서 이러한 함정을 겪었습니다. 특히 Codex 측에서 처음 드러난 문제는 특정 reconnect 메시지가 재시도 가능한 종료 상태로 인식되지 않아 기존 복구 메커니즘이 작동하지 않았다는 것입니다. 즉, 시스템에 자동 재시도가 없는 것이 아니라 “이번에 재시도할 가치가 있는지”를 인식하지 못한 것입니다.
따라서 이 글의 핵심 포인트는 명확합니다: 자동 재시도는 버튼이 아니라 계층화된 설계입니다.
HagiCode에 대하여
이 글에서 공유하는 솔루션은 HagiCode 프로젝트의 실제 실천에서 왔습니다. HagiCode가 하려는 것은 특정 모델을 연결하는 것으로 끝나는 것이 아니라, 여러 Agent CLI의 스트리밍 메시지, 도구 호출, 실패 복구, 세션 컨텍스트를 장기 유지보수 가능한 실행 모델로 통합하는 것입니다.
제가 항상 가장 관심을 갖는 것 중 하나는 AI 프로그래밍을 실제 엔지니어링 현장에 정착시키는 방법입니다. Demo를 작성하는 것은 어렵지 않지만, Demo를 팀이 정말로 장기적으로 사용하려는 것으로 만드는 것이 어렵습니다. HagiCode가 자동 재시도를 진지하게 하는 이유는 이 기능이 고급스러워 보여서가 아니라, 긴 체인, 스트리밍, 재개 가능한 CLI 실행이 안정적이지 않으면 사용자가 보는 것은 스마트 어시스턴트가 아니라 중간에 자주 끊기는 명령 래퍼이기 때문입니다.
프로젝트 진입점을 먼저 보고 싶으시다면 두 링크를 먼저 올려놓겠습니다:
- GitHub: github.com/HagiCode-org/site
- 공식 웹사이트: hagicode.com
한 걸음 더 나아가, HagiCode는 이미 Steam에 출시되었습니다. Steam이 있는 분들은 먼저 위시리스트에 추가해 주세요:
왜 Agent CLI의 자동 재시도가 일반 재시도보다 더 어려울까요
이 질문은 매우 현실적입니다. 결론부터 말씀드리겠습니다: Agent CLI의 자동 재시도는 어려움이 “몇 초 후에 다시 시도”가 아니라 “원래 컨텍스트에서 계속할 수 있는지”에 있습니다.
이것을 긴 대화로 이해할 수 있습니다. 일반적인 API 재시도는 전화가 통화 중일 때 다시 거는 것과 비슷하고, Agent CLI 재시도는 상대방이 중간에 신호가 끊겼을 때 다시 거는지, 다시 거면 처음부터 말해야 하는지, 상대방이 아까 어디까지 말했는지 기억하는지 판단해야 하는 것과 비슷합니다. 이 둘이 같은 문제라고 할 수 있겠습니까? 전혀 다른 엔지니어링 문제입니다.
구체적으로 보면 네 가지 어려운 점이 가장 전형적입니다.
1. 스트리밍 방식입니다
출력이 이미 사용자에게 전송되면 일반 요청처럼 실패를 몰래 삼키고 조용히 재시도할 수 없습니다. 앞부분 콘텐츠가 이미 보였기 때문에 재생 전략이 잘못되면 프론트엔드에서 중복 텍스트, 혼란스러운 상태를 보게 되고 도구 호출 수명 주기도 함께 꼬입니다. 이것은 신비로운 것이 아니라 엔지니어링입니다.
2. 일반적으로 세션 컨텍스트에 바인딩됩니다
Codex 같은 provider는 thread에 바인딩하고, Claude Code 같은 구현에는 continuation target 또는 동등한 재개 컨텍스트가 있습니다. 진정한 자동 재시도의 전제는 “이 오류가 일시적 장애처럼 보인다”뿐만 아니라 “이번 실행에 계속할 수 있는 매개체가 있는지”도 포함합니다.
3. 모든 오류가 재시도할 가치가 있는 것은 아닙니다
네트워크 흔들림, SSE idle timeout, 업스트림 일시적 장애는 일반적으로 시도해 볼 가치가 있습니다. 하지만 인증 실패, 컨텍스트 상실, 또는 provider가 resume 능력이 없다면 계속 재시도하는 것은 복구가 아니라 노이즈 생성입니다.
4. 경계가 필요합니다
무한 자동 재시도는 거의 항상 잘못입니다. 기술 트렌드는 한동안 뜨거울 수 있지만, 엔지니어링 법칙은 종종 수년간 안정적이며, 그중 하나는 실패 복구에는 반드시 경계가 있어야 한다는 것입니다. 시스템은 최대 몇 번 시도할지, 각 시도 사이에 얼마나 기다릴지, 언제 손을 들고 이번에는 정말 안 된다고 인정해야 하는지 알아야 합니다.
바로 이러한 특징 때문에 HagiCode는 자동 재시도를 특정 provider의 몇 줄 try/catch로 작성하지 않고 공유 레이어로 추출했습니다. 결국 엔지니어링 문제는 엔지니어링 방법으로 돌아가 해결해야 합니다.
HagiCode의 방법: 재시도를 Provider에서 꺼내기
HagiCode의 현재 실제 구현은 한 문장으로 압축할 수 있습니다:
공유 레이어가 재시도 프로세스를 통합 관리하고, 구체적인 Provider는 두 가지 질문에만 답합니다: 이 종료 상태는 재시도할 가치가 있는가? 현재 컨텍스트를 계속할 수 있는가?
이것은 복잡하지 않지만 매우 중요합니다. 책임을 분리하면 Claude Code, Codex, 심지어 다른 Agent CLI도 동일한 골격을 재사용할 수 있습니다. 모델은 바뀌고, 도구는 변하고, 워크플로우는 업그레이드되지만 엔지니어링의 기반은 항상 그곳에 있습니다.
첫 번째 레이어: 통합 조정자로 재시도 루프 관리
프로젝트의 핵심 구현 부분은 대략 다음과 같습니다:
internal static class ProviderErrorAutoRetryCoordinator{ public static async IAsyncEnumerable<CliMessage> ExecuteAsync( string prompt, ProviderErrorAutoRetrySettings? settings, Func<string, IAsyncEnumerable<CliMessage>> executeAttemptAsync, Func<bool> canRetryInSameContext, Func<TimeSpan, CancellationToken, Task> delayAsync, Func<CliMessage, bool> isRetryableTerminalMessage, [EnumeratorCancellation] CancellationToken cancellationToken) { var normalizedSettings = ProviderErrorAutoRetrySettings.Normalize(settings); var retrySchedule = normalizedSettings.Enabled ? normalizedSettings.GetRetrySchedule() : [];
for (var attempt = 0; ; attempt++) { var attemptPrompt = attempt == 0 ? prompt : ProviderErrorAutoRetrySettings.ContinuationPrompt;
CliMessage? terminalFailure = null;
await foreach (var message in executeAttemptAsync(attemptPrompt) .WithCancellation(cancellationToken)) { if (isRetryableTerminalMessage(message)) { terminalFailure = message; break; }
yield return message; }
if (terminalFailure is null) { yield break; }
if (attempt >= retrySchedule.Count || !canRetryInSameContext()) { yield return terminalFailure; yield break; }
await delayAsync(retrySchedule[attempt], cancellationToken); } }}이 코드가 하는 일은 매우 소박하지만 강력합니다.
- 중간 실패를 먼저 직접 전달하지 않고 조정자가 먼저 복구 가능한지 판단합니다
- 재시도 예산이 소진되면 최종 실패만 상위로 반환됩니다
- 두 번째 라운드부터는 원래 prompt를 보내지 않고 통합된 continuation prompt를 보냅니다
이것이 제가 앞서 계속 강조한 이유입니다. 자동 재시도는 단순한 “다시 요청하기”가 아닙니다. 예외 분기를 추가하는 것이 아니라 실행 수명 주기를 관리하는 것입니다. 제품 관리자 같이 들리지만 엔지니어링적으로는 실제 그렇습니다.
두 번째 레이어: 재시도 전략 스냅샷화
또 하나 쉽게 간과되는 문제가 있습니다: 이 요청에 자동 재시도를 활성화할지 결정하는 것은 누구인가요?
HagiCode의 답은 “현재의 글로벌 구성”에 의존하지 않고 전략을 스냅샷으로 만들어 이 요청과 함께 전달하는 것입니다. 이렇게 하면 세션 큐잉, 메시지 지속화, 실행 전달, provider 적응 중 어느 것도 전략을 잃지 않습니다. 한 번의 성공은 체계가 아니고, 지속적인 성공만이 체계입니다.
핵심 구조는 다음과 같이 단순화할 수 있습니다:
public sealed record ProviderErrorAutoRetrySnapshot{ public const string DefaultStrategy = "default";
public bool Enabled { get; init; }
public string Strategy { get; init; } = DefaultStrategy;
public static ProviderErrorAutoRetrySnapshot Normalize(bool? enabled, string? strategy) { return new ProviderErrorAutoRetrySnapshot { Enabled = enabled ?? true, Strategy = string.IsNullOrWhiteSpace(strategy) ? DefaultStrategy : strategy.Trim() }; }}그런 다음 실행 측에서 provider가 실제로 소비하는 설정 객체로 매핑합니다. 이 방법의 가치는 매우 직접적입니다:
- 비즈니스 레이어가 “재시도해야 하는지”를 결정합니다
- 런타임이 “어떻게 재시도할지”를 결정합니다
양쪽이 각자 관할하여 충돌하지 않습니다. 많은 문제가 불가능한 것이 아니라 비용을 명확히 계산하지 않은 것입니다. 전략을 스냅샷화하는 것은 본질적으로 비용을 미리 계산하는 것입니다.
세 번째 레이어: Provider는 종료 상태 판정과 컨텍스트 판정만 수행
구체적인 Claude Code 또는 Codex provider에 오면 여기서의 책임은 오히려 매우 얇습니다. 이것을 대체가 아닌 강화로 이해하시기 바랍니다.
Codex를 예로 들면, 공유 조정자에 연결할 때 본질적으로 세 가지만 제공하면 됩니다:
await foreach (var message in ProviderErrorAutoRetryCoordinator.ExecuteAsync( prompt, options.ProviderErrorAutoRetry, retryPrompt => ExecuteCodexAttemptAsync(...), () => !string.IsNullOrWhiteSpace(resolvedThreadId), DelayAsync, IsRetryableTerminalFailure, cancellationToken)){ yield return message;}Provider 자체의 판단은 두 가지뿐이라는 것을 알 수 있습니다:
IsRetryableTerminalFailurecanRetryInSameContext
Codex는 thread를 계속할 수 있는지 보고, Claude Code는 continuation target이 있는지 봅니다. 백오프 전략, 재시도 횟수, 후속 prompt는 모두 Provider가 다시 발명할 필요가 없는 것들입니다.
이 레이어를 분리한 후 HagiCode가 더 많은 CLI를 연결하는 비용이 훨씬 낮아졌습니다. 재시도 상태 머신 전체를 복사할 필요 없이 “이 provider의 경계 조건”만 연결하면 됩니다. 빠르게 작성하는 것이 안정적으로 작성하는 것을 의미하지 않고, 연결하는 것이 잘 연결하는 것을 의미하지 않으며, 실행되는 것이 장기 유지보수 가능한 것을 의미하지 않습니다.
쉽게 틀리기 쉬운 점: 모든 오류를 재시도 가능으로 간주하지 마세요
이번 분석에서 가장 단독으로 이야기할 가치가 있다고 생각하는 것은 “재시도를 구현하는 방법”이 아니라 “잘못된 재시도를 피하는 방법”입니다.
초기 문제의 접근점은 Codex가 reconnect 메시지 하나를 인식하지 못한 것이었습니다. 직감적으로 많은 분이 최소 수정법을 선택할 것입니다: 화이트리스트에 문자열 접두사 하나를 더 추가합니다. 이 접근이 틀렸다고 할 수는 없지만, 장기 유지보수의 해결책이라기보다는 Demo 시기의 해결책에 더 가깝습니다.
현재 HagiCode의 실제 구현을 보면 시스템은 이미 더 안정적인 방향으로 나아갔습니다. 더 이상 특정 문자열만 보지 않고 복구 가능한 종료 상태를 통합 조정자에 통합 처리합니다. 이렇게 하면 다음과 같은 명확한 이점이 있습니다:
- 특정 문구의 작은 변경으로 완전히 실패하지 않습니다
- 테스트 커버리지를 “종료 상태 envelope” 중심으로 전개할 수 있고, 단일 하드코딩된 텍스트가 아닙니다
- 동일한 provider의 재시도 로직이 더 일관됩니다
물론 여기에 경계를 세워야 합니다: 더 범용적인 것이 더 느슨한 것을 의미하지는 않습니다. 현재 컨텍스트를 계속할 수 없다면, 오류가 일시적 장애처럼 보이더라도 맹목적으로 재생하지 않아야 합니다.
이 점이 매우 중요합니다. 진정으로 안심시키는 것은 가끔 한 번 성공하는 것이 아니라 대부분의 경우에 신뢰할 수 있는 것입니다. 프로세스가 고수준 사용자만 유지할 수 있다면 대중화에는 아직 멀었습니다.
실천에서 가장 보존할 가치가 있는 세 가지 경험
글이 여기까지 왔으니 실천 층으로 정리할 수 있습니다. 자신의 프로젝트에서 유사한 기능을 구현하려면 다음 세 가지를 먼저 지키는 것을 가장 권장합니다.
1. 재시도 예산에는 반드시 경계가 있어야 합니다
HagiCode의 현재 기본 백오프 리듬은 다음과 같습니다:
- 10초
- 20초
- 60초
이 리듬이 모든 시스템에 적합한 것은 아니지만 “경계가 있다”는 것은 반드시 유지해야 합니다. 그렇지 않으면 자동 재시도는 빠르게 복구 메커니즘에서 사고 증폭기로 변합니다. 이름을 너무 크게 짓기 전에 이것이 팀에서 두 번의 반복을 버틸 수 있는지 먼저 확인하세요.
2. continuation prompt를 통합하세요
프로젝트에서는 고정 continuation prompt를 사용하여 후속 attempt이 “현재 컨텍스트 계속” 경로를 명확히 따르고 완전한 새 요청을 다시 시작하지 않도록 합니다. 이 능력은 화려하지 않지만 실제 프로젝트에서는 필수적입니다. 많은 능력이 마법처럼 보이지만 분해하면 잘 다듬어진 엔지니어링 프로세스일 뿐입니다.
3. 공유 라이브러리와 적응 레이어 모두 미러 테스트가 있어야 합니다
이 점에 대해 더 말하고 싶습니다. 많은 팀이 공유 런타임에 테스트 레이어를 작성하고 대충 끝납니다. 하지만 충분하지 않습니다.
HagiCode가 신뢰할 수 있는 이유는 두 레이어 모두 테스트를 보완했기 때문입니다:
- 공유 Provider는 “진정한 자동 재개가 발생했는지”를 테스트합니다
- 적응 레이어는 “최종 오류와 스트리밍 메시지가 손상되지 않았는지”를 테스트합니다
이번에도 관련 테스트 두 그룹을 추가로 실행했고, 결과는 31개 테스트 케이스 모두 통과였습니다. 이 결과 자체가 설계가 완벽하다는 것을 증명할 수는 없지만, 적어도 한 가지는 증명할 수 있습니다: 현재 이 자동 재시도는 문서상의 계획이 아니라 코드와 테스트에 의해 공동으로 제약된 능력입니다. Talk is cheap. Show me the code. 여기에 놓기에 딱 맞습니다.
요약
이 글을 한 문장으로 압축하면 다음과 같습니다:
Claude Code, Codex 등 Agent CLI의 자동 재시도는 특정 Provider 내부의 국소적인 기술로 만들지 말고, 공유 조정자 + 전략 스냅샷 + 컨텍스트 판정 + 미러 테스트의 조합으로 만드는 것이 좋습니다.
이렇게 하면 다음과 같은 매우 실질적인 이점이 있습니다:
- 로직을 한 번만 작성하면 여러 Provider가 재사용할 수 있습니다
- 요청이 재시도를 허용하는지 실행 체인을 따라 안정적으로 전달될 수 있습니다
- 컨텍스트가 있으면 계속 실행하고, 없으면 적시에 멈춥니다
- 프론트엔드가 보는 것은 안정적인 완료 상태 또는 실패 상태이며, 중도 포기된 중간 노이즈가 아닙니다
이 솔루션은 HagiCode가 실제로 여러 Agent CLI를 연동하는 과정에서 조금씩 다듬어진 것입니다. AI 보조 프로그래밍이 새 시대의 페어 프로그래밍이 아니라고 누가 말했습니까? 모델이 시작, 완성, 발산을 도와주지만, 경험의 상한을 결정하는 것은 종종 컨텍스트, 프로세스 및 제약입니다.
이 글이 도움이 되셨다면 HagiCode의 공개 진입점도 함께 살펴보세요:
- GitHub: github.com/HagiCode-org/site
- 공식 웹사이트: hagicode.com
- 30분 실전 데모: www.bilibili.com/video/BV1pirZBuEzq/
- Desktop 설치 진입점: hagicode.com/desktop/
- Steam: Steam 스토어 페이지 (위시리스트 추가 / 상세 보기)
HagiCode는 이미 Steam에 출시되었습니다. 이것은 허풍이 아니라 링크도 여기에 올려놓았습니다. Steam이 있는 분들은 먼저 위시리스트에 추가하고 직접 들어가보세요. 제가 여기서 열 마디를 더 하는 것보다 훨씬 직접적입니다.
일단 여기까지 이야기하고, 나머지는 실제 프로젝트에서 계속 만나겠습니다.
참고 자료
- HagiCode 프로젝트 홈페이지: https://www.hagicode.com
- HagiCode GitHub 저장소: https://github.com/HagiCode-org/site
- 공식 데모 비디오: https://www.bilibili.com/video/BV1pirZBuEzq/
- Desktop 설치 안내: https://www.hagicode.com/desktop/
저작권 안내
읽어주셔서 감사합니다. 이 글이 유용하시다면 좋아요, 북마크, 공유로 지원해 주세요. 이 콘텐츠는 인공지능 보조 협력으로 작성되었으며, 최종 내용은 저자가 검토하고 확인했습니다.
- 이 글의 저자: newbe36524
- 원문 링크: https://docs.hagicode.com/blog/2026-02-11-agent-cli-automatic-retry/
- 저작권 선언: 이 블로그의 모든 글은 특별한 선언이 없는 한 BY-NC-SA 라이선스 계약을 채택합니다. 출처를 명시해 주세요!
开始使用 HagiCode
一次安装,几分钟上手
HagiCode for Windows 在 Microsoft Store 免费提供。打开商店即可安装并保持更新;也可以先对比各版本与定价,再决定从哪个渠道开始。
아이디어를 실제로 배포되는 소프트웨어로.
HagiCode는 에이전트 코딩 작업 공간입니다. OpenSpec 워크플로로 변경을 계획하고, 다중 에이전트 실행으로 진행하며, Hero Scenario로 긴 작업의 진행 상황을 한눈에 보여 아이디어를 실제로 배포되는 소프트웨어로 만듭니다.
- 스마트
- OpenSpec 워크플로는 의도를 제안부터 배포까지 이어지는 실행 가능한 경로로 바꿉니다.
- 효율적
- 다중 에이전트 실행으로 조사, 구현, 검토를 병렬로 진행합니다.
- 즐거운
- 편리한 UI 상호작용으로 계획, 에이전트 실행, 프로젝트 작업을 쉽게 따라갈 수 있습니다.
© 2026 HagiCode | Powered By hagilight-starlight@0.21.0 | Branch: main | Commit: 951128b | Built:

