화요일 오후, 에이전트가 $153을 태웠다
데모는 완벽했다. 5개 프롬프트를 직접 테스트했고, 이해관계자들은 고개를 끄덕였다. 그렇게 배포됐다. 그리고 30분 만에 $153이 사라졌다. 에이전트가 애매한 쿼리를 만나 추론 루프에 빠졌고, 세 번 만에 에스컬레이션해야 할 질문을 해결하려 GPT-4를 47번 호출했다. dev.to에 공개된 이 실제 사례는 '가장 흔한 프로덕션 AI 에이전트 실패 패턴'의 전형이다.
문제는 테스트를 건너뛴 게 아니다. 전통적인 테스트 방식을 설계 상 그 방식을 깨도록 만들어진 시스템에 그대로 적용한 것이다.
원칙 1: LLM이 아닌 '뼈대'를 테스트하라
AI 에이전트는 비결정론적이다. 같은 입력에 매번 다른 출력이 나온다. 두 출력 모두 맞을 수 있지만 assertEqual은 여전히 실패한다. 전통적 단위 테스트가 깨지는 지점이다.
dev.to의 에이전트 테스트 가이드가 제시하는 첫 번째 해법은 'Deterministic Skeleton Test'다. 핵심 통찰은 단순하다. LLM은 테스트할 필요가 없다. OpenAI와 Anthropic이 알아서 한다. 당신이 테스트해야 할 건 LLM을 감싸는 코드—라우팅 로직, 툴 선택, 상태 관리, 오케스트레이션이다.
LLM을 Mock으로 대체하고 뼈대만 테스트하면 밀리초 단위로 실행된다. API 호출이 없으니 비용도 없다. 잘못된 툴로 쿼리를 보내는 라우팅 버그, 파괴적 작업의 누락된 안전장치, 스텝 간 컨텍스트 유실 같은 가장 치명적인 버그들을 커밋마다 잡아낼 수 있다.
두 번째 패턴은 Property-Based Assertion이다. '에이전트가 무엇을 출력해야 하는가'를 단언하는 대신, '에이전트가 절대 해선 안 되는 것'을 단언한다. 확인 없이 DB를 삭제하지 않는다, 요청당 비용이 $0.50을 넘지 않는다, 추론 스텝이 10회를 초과하지 않는다—이런 불변 조건(invariants)을 코드로 강제하는 것이다. 신뢰를 갉아먹고 실제 돈이 나가는 실패는 바로 이 불변 조건이 깨질 때 발생한다.
원칙 2: 태스크 크기가 완료율을 결정한다
454개 자율 태스크를 3개월간 실행한 실측 데이터가 있다. 결론은 명확하다. 태스크 성공률을 결정하는 단일 최강 지표는 복잡도도, 우선순위도 아닌 '소요 시간'이다.
| 태스크 소요 시간 | 완료율 |
|---|---|
| 15~45분 | 92% |
| 45~90분 | 71% |
| 90~120분 | 54% |
| 2시간 이상 | 33% |
2시간 벽은 가파르다. 실패 원인을 추적해보면 컨텍스트 윈도우 고갈이 34%, 외부 의존성 타임아웃이 28%, 중단 및 컨텍스트 스위칭이 19%였다. 긴 태스크는 더 많은 토큰을 생성하고, 더 많은 API 호출을 하고, 더 긴 인터럽션 창을 열어둔다. 모든 리스크가 시간과 함께 누적된다.
이 데이터가 제안하는 설계 원칙은 실용적이다: 45분 하드캡. 태스크 설명에 'and then'이 들어가면 그건 이미 두 개의 태스크다. '코드베이스 리팩토링' 하나가 67% 실패하던 것이, 구조 감사(20분) → 디렉터리 레이아웃 생성(15분) → 모듈 이동(30분) → 임포트 업데이트(15분) → 테스트 검증(15분)으로 쪼개지면 각 92% 완료율로 바뀐다. 작업이 실제로 완료된다.
검증 기준도 미리 써야 한다. '작동하는지 확인'은 검증이 아니다. 'pytest 실행 후 47개 테스트 통과 확인'이 검증이다. 구체적이고, 자동화되고, 부인 불가능해야 한다.
원칙 3: 예산은 사후 청구서가 아닌 사전 예약으로 통제하라
LangChain은 에이전트를 만들기 쉽게 해준다. 에이전트가 얼마나 쓸 수 있는지 제한하는 기능은 없다. 이 공백이 프로덕션에서 리스크가 된다. 특히 멀티테넌트 환경에서는 한 명의 사용자가 수백 달러를 날리기 전까지 아무도 모를 수 있다.
dev.to에 공개된 Cycles 기반 예산 통제 패턴은 데이터베이스 트랜잭션 방식을 차용한다. 실행 전에 예산을 예약하고, 실행 후에 실제 사용량만 커밋하고, 실패하면 전액 반환한다. 청구서로 사후 발견하는 게 아니라, 지출이 일어나기 전에 하드 리밋이 강제된다.
더 정교한 건 ALLOW_WITH_CAPS 패턴이다. 예산이 빡빡할 때 단순 거부 대신 '제한 조건부 허용' 신호를 보낸다. 에이전트는 이 신호를 받아 GPT-4o 대신 GPT-4o-mini로 다운그레이드하거나 툴 접근을 제한한다. 완전 차단 대신 성능을 조절해 서비스를 유지한다. 멀티테넌트 환경이라면 Subject(tenant="acme") 같은 방식으로 고객별 독립 예산 풀을 운영할 수 있다.
에이전트를 배포하기 전에 팀이 물어야 할 것
세 데이터 소스가 공통적으로 가리키는 지점이 있다. 에이전트는 코드가 잘 작동해도 망가질 수 있다. LLM 자체가 아닌 그 주변 구조—라우팅, 태스크 크기, 예산 경계—에서 프로덕션 실패의 대부분이 발생한다.
AI-First 팀이 에이전트를 배포하기 전에 실제로 점검해야 할 체크리스트는 생각보다 단순하다.
- 뼈대 테스트가 CI에 들어가 있는가? LLM Mock으로 라우팅·안전장치·상태 관리를 커밋마다 검증하고 있는가.
- 태스크가 45분 안에 끝나는가? 그렇지 않다면 쪼개는 것이 먼저다. 에이전트가 더 열심히 일하게 만드는 건 해법이 아니다.
- 예산 트립와이어가 코드 안에 있는가? 청구서 알림은 너무 늦다. 실행 전 예약, 실행 후 커밋 패턴이 코드 레벨에서 강제돼야 한다.
지금 당장 하나만 한다면
프로퍼티 기반 단언 세 개를 먼저 작성하라. 확인 없이 파괴적 작업을 수행하지 않는다, 요청당 비용 상한, 최대 추론 스텝 수. 이 세 가지만 코드로 강제해도 가장 비싼 프로덕션 실패의 대부분을 막는다. 나머지는 그 다음이다.
에이전트를 안전하게 프로덕션에 올리는 것은 운의 문제가 아니다. 기본값이 완료로 향하도록 시스템을 설계하는 엔지니어링의 문제다.