초당 380회의 토큰 인출, P99 지연 시간 14,200ms 돌파, 그리고 불과 43분 만에 데이터베이스 커넥션 풀(HikariCP) 점유율 100% 도달.
작년 가을, 결제 정산 이상 감지와 자동 보정을 위해 프로덕션 환경에 격리 배포했던 자율 에이전트가 만들어낸 실제 인시던트 지표입니다. 당시 우리 팀은 “LLM에게 명확한 도구(Tool)와 평가 루프(Evaluation Loop)를 쥐여주면 복잡한 예외 상황도 스스로 판단해 해결할 것”이라는 기술적 낭만에 빠져 있었습니다. 하지만 통제되지 않은 자율성은 시스템 관점에서 지능형 워커가 아니라, 비결정적 페이로드를 초고속으로 난사하는 ‘분산 DoS 공격기’에 불과했습니다.
지능이 높아질수록 시스템 장애의 형태는 기괴해집니다. 컴파일 타임 에러나 명확한 500 Internal Server Error 대신, “문법적으로는 완벽하지만 비즈니스 로직을 파괴하는 쿼리”와 “스스로의 실패를 수정하려다 컨텍스트 윈도우 한계까지 토큰을 태우는 자율 루프”가 시스템을 안저 깊숙한 곳부터 잠식해 들어갔습니다.
본 글에서는 24시간 무중단 환경에 자율 에이전트를 방치했을 때 마주했던 처절한 실패의 기록과, 이를 틀어막기 위해 구축한 결정론적 가드레일 아키텍처를 가감 없이 공유합니다.
1. 재귀 호출의 늪과 43분 만에 증발한 월간 토큰 예산
우리가 겪은 가장 뼈아픈 사고는 ‘자기 수정(Self-Correction)’ 루프에서 발생했습니다. 결제 정산 불일치 건을 감지한 에이전트가 분개 원장을 대조하고 보정 트랜잭션을 생성하는 파이프라인이었습니다. 설계 의도는 단순했습니다.
- 정산 불일치 데이터 감지
- LLM이 보정 쿼리 초안 생성
- 정적 밸리데이터가 쿼리 유효성 검증
- 검증 실패 시 에러 메시지를 컨텍스트에 추가하여 재추론(Re-try)
문제는 엣지 케이스에서 터졌습니다. 특정 PG사의 복합 환불 데이터에서 Nullable 필드가 누락되자 밸리데이터가 ConstraintViolationException을 반환했고, 에이전트는 이를 해결하기 위해 새로운 스키마 가설을 세워 쿼리를 재작성했습니다. 그러나 이 재작성된 쿼리는 또 다른 도메인 제약 조건(Foreign Key 무결성)을 건드렸습니다.
에이전트는 실패할 때마다 이전 대화 기록과 스택 트레이스 전체를 프롬프트에 밀어 넣으며 추론을 거듭했습니다.
에러 메시지가 누적될수록 LLM은 환각(Hallucination)에 빠져 존재하지도 않는 가상 테이블을 조회하는 쿼리를 짜기 시작했고, 검증 레이어는 계속해서 거절을 던졌습니다. 에이전트는 포기하지 않는 ‘집요한 일꾼’이었기에 43분 동안 무려 4,200회의 재귀 추론을 감행했습니다.
그 결과, 단일 트랜잭션 건에 대해 배정된 월간 추론 예산 3,500달러가 순식간에 소진되었습니다. 복잡한 시스템 버그를 추적할 때 로깅만으로 한계에 부딪혔던 경험이 있다면, 디버깅 도구 활용법: 복잡한 버그도 한방에! 크롬 개발자 도구 + VSCode 디버거 실전 활용 가이드에서 다룬 것처럼 시스템의 상태 변화를 단계별로 멈춰 세워 검증하는 브레이크포인트 원리가 LLM 런타임에도 동일하게 필요함을 직감할 수 있을 것입니다.
이 실패 이후 우리는 “자율 에이전트의 모든 재귀 루프는 비결정론적 상태 머신이 아니라 엄격히 제한된 유한 상태 머신(FSM) 내부에서만 동작해야 한다”는 제1원칙을 세웠습니다.
2. 비결정성이 유발한 DB 오염과 커넥션 풀 고갈 사태
두 번째 장애는 데이터 무결성과 인프라 리소스 레벨에서 발생했습니다. 에이전트가 “고객 계정의 캐시 잔액과 실제 입금 내역의 불일치를 해소하라”는 태스크를 수행할 때였습니다.
프롬프트 엔지니어링을 통해 아무리 “안전한 트랜잭션 격리 수준을 유지하라”고 지시해도, LLM 본질의 확률론적 특성은 언제든 무너질 수 있습니다. 당시 에이전트는 복잡한 다중 행 락(Row-level Lock)을 유발하는 SELECT ... FOR UPDATE 구문을 포함한 비표준 트랜잭션을 열어두고, 다음 액션을 결정하기 위해 외부 API를 호출하는 짓을 저질렀습니다.
외부 I/O 지연이 LLM의 트랜잭션 내부에서 일어나는 순간, PostgreSQL 커넥션 풀의 Max Active Connection(150개)이 12초 만에 바닥났습니다. 서비스 전체의 정산 API가 먹통이 되었고, 타임아웃 임계치(30,000ms)를 초과한 요청들이 캐스케이딩 다운을 유발했습니다.
더 심각한 것은 데이터 오염이었습니다. 에이전트가 FK 관계를 풀기 위해 임의로 생성한 UPDATE balance = balance - 0.0001 같은 기괴한 보정치가 실제 운영 테이블에 반영되기 직전까지 갔습니다. 코드 변경 사항을 릴리즈할 때 개발 속도 2배, 버그는 절반! ‘세분화된 PR/커밋’ 실전 전략 (세분화된 PR/커밋)에서 강조하듯 영향 범위를 극도로 쪼개어 검증하지 않으면, 에이전트의 한 번의 잘못된 커밋이 전체 DB의 참조 무결성을 완전히 붕괴시킬 수 있음을 뼈저리게 깨달았습니다.
3. 자율 에이전트 가드레일 & 서킷 브레이커 파이프라인
이러한 악몽을 겪은 후, 우리는 에이전트와 데이터베이스 사이에 ‘결정론적 방화벽(Deterministic Firewall)’을 전면 배치했습니다. 에이전트는 결코 프로덕션 데이터베이스의 쓰기(Write) 권한을 직접 갖지 못합니다. 모든 변경 명령은 격리된 샌드박스에서 드라이런을 거치고, 수학적·스키마적 검증을 통과해야만 실행 엔진으로 넘어갑니다.
전체 가드레일 파이프라인 흐름도는 다음과 같이 재설계되었습니다.

토큰 폭탄과 환각 루프의 악몽: 실전 프로덕션에서 건져 올린 가드레일 오답노트 설계, 아키텍처 트레이드오프, 혹은 프로덕션 도입 과정에서 고민이 있으시다면 언제든 편하게 이야기 나눠요. 같은 엔지니어로서 함께 최적의 해법을 고민해 드리겠습니다.
![[자율에이전트 #3] 토큰 폭탄과 환각 루프의 악몽: 실전 프로덕션에서 건져 올린 가드레일 오답노트 - 핵심 인사이트 카드](https://devjun.net/wp-content/uploads/2026/10/post-architecture_card_1299e2-1024x538.webp)



