재시도만으로는 부족하다: LLM 에이전트의 회복탄력성은 어떻게 설계하는가
9 views
# 재시도의 종말: LLM 에이전트 시대의 회복탄력성은 무엇으로 설계되는가
어떤 에이전트 시스템이 동일한 400 BadRequestError를 11번 반복하고 최종 실패했다. 원인 자체는 단순하다. LLM이 유효하지 않은 arguments JSON을 생성했고, API 게이트웨이가 이를 거부했다. 문제는 거부가 아니라 거부 이후였다. 바뀐 것 하나 없는 입력을 같은 경로로 열한 번 밀어넣은 것은 회복 시도가 아니라 그냥 자원 낭비다.
이 사건이 드러내는 건 단일 버그가 아니라 아키텍처가 깔고 있던 가정이 깨진 지점이다. 분산 시스템에서 재시도(Retry)는 오랫동안 회복력의 기본 어휘였지만, 그 기본은 특정한 종류의 장애를 전제로 한다. 비결정론적 생성 모델이 시스템 구성요소로 들어오는 순간 그 전제가 무너진다.
## 일시 장애의 가정과 결정론적 오류의 충돌
전통적 재시도 패턴은 실패가 시간이 지나면 해소된다는 믿음 위에 서 있다. 네트워크 순단, 일시적 부하, 커넥션 풀 고갈은 모두 시간의 함수다. 잠시 기다렸다가 같은 요청을 다시 보내면 외부 조건이 회복돼 두 번째 시도는 성공할 만하다. 지수 백오프(exponential backoff)와 서킷 브레이커도 이 시간적 자기회복성을 전제로 만들어진 장치다.
LLM의 도구 호출 오류는 이 범주가 아니다. 문법 오류나 스키마 불일치는 외부 환경의 동요가 아니라 모델 내부 상태의 산물이다. Context Window에 담긴 세션 이력, 지시 프롬프트의 구조, 직전 토큰들의 분포가 출력을 결정한다. 입력 상태가 같으면 출력도 같은 방향으로 수렴하는 결정론적 상태성 오류다.
이런 오류에 재시도는 무용한 정도가 아니라 해롭다. 프롬프트와 상태가 그대로인 한 모델은 같은 결함을 같은 자리에서 다시 만들어낸다. 11회 반복은 그 필연의 증거다. 매 시도가 토큰을 쓰고 추론 비용을 청구하고 실패만 쌓는다. 일시 장애용 처방을 결정론적 오류에 투약한 탓에, 회복 장치가 비용 증폭 장치로 뒤집힌 것이다. 시간이 해결할 수 없는 문제에 시간을 들이부은 셈인데, 아키텍처 차원에서 보면 이건 진단의 실패다.
## 엄격한 검증과 유연한 수용 사이의 긴장
오류의 성격을 바로잡았다면 다음 질문은 경계에서 나온다. 잘못된 JSON을 어디서 누가 감당하는가. 여기서 상반된 두 설계 철학이 부딪친다.
첫째는 엄격한 검증(Strict Validation)이다. 백엔드 API 서버는 조금이라도 어긋난 스키마를 400으로 단호히 막아야 한다. 결벽이 아니라 책무다. 데이터 정합성과 보안의 최후 방어선은 입력을 의심하는 데서 출발한다. 관대한 게이트웨이는 오염된 데이터가 시스템 깊숙이 침투하는 통로가 되고, 인젝션과 데이터 변형의 표면을 넓힌다.
둘째는 관용적 수용자(Tolerant Reader)다. 포스텔의 법칙, 즉 "보내는 것은 엄격하게, 받는 것은 관대하게"가 여기 깔려 있다. 에이전트의 클라이언트 파서 단에서 trailing comma나 괄호 불균형 같은 경미한 포맷 오류를 스스로 교정해 정제된 요청만 백엔드로 넘기면 호출 성공률은 분명히 오른다.
트레이드오프는 분명하다. 관용적 설계는 성공률을 얻는 대신 의도치 않은 데이터 변형과 보안 리스크를 떠안는다. 파서가 모델의 의도를 추측해 보정하는 순간, 그 추측이 틀릴 가능성이 시스템에 심긴다. 반대로 엄격한 설계는 안전하지만 모델의 사소한 실수 하나에 전체 흐름이 멈춘다. 11회의 실패는 그 엄격함이 자기회복 기제 없이 홀로 섰을 때 무슨 일이 벌어지는지를 보여준 사례다.
둘 중 하나를 고르는 문제가 아니다. 검증의 엄격함은 백엔드에 두고, 관용은 신뢰 경계 바깥, 즉 에이전트 측에만 둔다. 안전성의 책임과 수용의 책임을 같은 계층에 섞지 않는 것이 경계 설계의 요점이다.
## 자가 치유: 오류를 학습 신호로 전환하는 피드백 루프
엄격함과 관용의 균형만으로는 부족하다. 경미한 포맷 오류는 파서가 정제할 수 있지만, 스키마의 의미론적 불일치는 모델 자신만 바로잡을 수 있다. 여기서 자가 치유 피드백 루프(Feedback-driven Self-Correction)가 필요해진다.
발상은 단순하다. 검증 오류 메시지를 버리지 말고 LLM의 Context에 시스템 피드백으로 다시 넣는다. "당신이 생성한 arguments가 다음 이유로 거부됐다"는 구체적 진단이 새로운 입력 상태를 만들고, 바뀐 상태가 바뀐 출력을 유도한다. 앞서 재시도가 무력했던 이유가 상태의 불변성이었다면, 자가 치유는 그 상태를 일부러 갱신해 결정론의 함정을 빠져나온다. 오류가 반복의 빌미에서 교정의 재료로 바뀐다.
물론 대가가 있다. 매 교정은 1~2회의 추가 추론 홉을 요구하고, 그만큼 레이턴시와 API 비용이 늘어난다. 실시간성이 생명인 경로에서 상한 없는 자가 치유 루프는 또 다른 형태의 자원 소진이다. 그래서 교정 횟수의 상한, 누적 비용의 임계, 최종 실패 시의 우아한 퇴장(graceful degradation)을 함께 설계해야 한다. 자가 치유도 만능이 아니라 비용과 성공률을 저울질하는 트레이드오프다.
그래도 이 패턴의 값어치는 분명하다. 시스템이 외부 개입 없이 모델의 실수를 흡수하고 교정한다는 것, 내결함성의 자기완결성을 한 단계 끌어올린다는 것이다.
## 회복탄력성의 새로운 표준
에이전트 시대의 회복탄력성은 오류를 둘로 나누는 데서 시작한다. 일시 장애(Transient)에는 재시도를, 논리적·구조적 장애(Semantic)에는 자가 치유 피드백을 동적으로 매핑한다. 두 처방은 경쟁하지 않는다. 다른 병에 쓰는 다른 약일 뿐이다. 모든 실패를 재시도로 환원하는 진단 없는 단일 대응, 그것이 11회의 좌초가 남긴 가장 비싼 교훈이다.
여기엔 더 깊은 함의가 있다. 시스템 안정성을 모델 성능 향상에 떠넘기고 싶은 유혹은 강하지만, 그건 책임 전가에 가깝다. 더 똑똑한 모델은 실수의 빈도를 낮출 뿐 가능성을 없애지 못한다. 비결정론은 생성 모델의 결함이 아니라 본성이고, 본성을 다루는 길은 억누르는 게 아니라 견디도록 시스템을 짜는 것이다.
아키텍트가 할 일은 완벽한 부품을 기다리는 게 아니다. 불완전한 부품이 빚는 오류를 분별하고, 분별한 오류를 적절한 계층에서 흡수하고, 흡수의 대가를 의식적으로 따지는 구조를 세우는 것이다. 결국 회복탄력성은 실패가 없는 시스템이 아니라 실패를 읽어낼 줄 아는 시스템을 가리킨다.