버그가 CPU를 태우던 시절과 달리, 이제는 돈을 태운다
요약
AI 시스템의 비용 관리는 전통적인 소프트웨어 버그와 달리 '청구 이벤트'가 되어 재정적 위험을 초래합니다. 특히 에이전트나 복잡한 LLM 기능은 자체 수정 루프, 비선형적 비용 증가 등 통제 불능 상태에 빠지기 쉽습니다. 따라서 모든 반복 과정에 하드 상한선을 설정하고, 요청당 예산 및 사용자별/테넌트별 속도 제한을 구현하는 것이 필수적입니다.
핵심 포인트
- LLM 시스템의 오류는 CPU 과부하가 아닌 비용 청구로 나타난다.
- 자체 수정 루프에는 반드시 시도 횟수와 토큰 수에 대한 하드 상한선을 설정해야 한다.
- 요청당 지연 시간처럼 요청당 비용을 파악하고 예산을 설정하는 것이 중요하다.
- 글로벌 속도 제한 외에 사용자별, API 키별 등 세분화된 제한이 필요하다.
전통적인 소프트웨어에서는 잘못 작성된 루프가 CPU 급증(CPU spike)을 일으킵니다. 누군가가 호출되어 그래프가 다시 내려가고, 그 비용은 느린 오후의 시간이 됩니다.
하지만 AI 시스템에서 같은 실수는 청구 이벤트(billing event)가 됩니다. 모든 반복(iteration)이 유료 API 호출이며, 계량기는 해당 호출이 유용했는지 여부에 전혀 신경 쓰지 않습니다. 아무도 알아차리기 전에 10분 동안 실행되는 루프는 한 달 동안 기능이 벌어들이는 수익보다 더 많은 비용을 초래할 수 있습니다.
LLM(대규모 언어 모델) 기능의 튜토리얼 버전은 호출 한 번, 응답 한 번으로 끝납니다. 하지만 프로덕션 버전에는 재시도(retries), 자체 수정 단계(self-correction steps), 도구를 호출하는 에이전트가 모델을 호출하고, 수천 명의 사용자가 이 모든 것을 동시에 수행합니다. 이러한 각 배수(multipliers)는 비용이 통제 불능 상태로 벗어날 수 있는 지점입니다.
제가 가장 자주 보는 세 가지 실패 모드를 소개합니다.
실패 모드 1: 수렴하지 않는 자체 수정 루프
예시 시나리오: 에이전트가 JSON을 생성하고, 유효성을 검사하며, 유효성 검사에 실패하면 오류를 모델에 다시 보내 출력을 수정하도록 요청합니다. 합리적인 패턴입니다. 그러다가 스키마 변경 사항이 배포되면서 하나의 필드를 만족시키기 불가능하게 됩니다. 모델은 계속해서 출력을 '수정'하고, 검증기는 계속 거부하며, 루프는 계속 돌아갑니다.
아무것도 충돌하지 않습니다. 오류 추적기에 예외(exception)가 도달하지도 않습니다. 유일한 신호는 청구서입니다.
해결책: 모든 재시도 및 수정 루프에는 시도 횟수와 토큰 수에 대한 하드 상한선(hard ceiling)을 설정하고, 이 상한선에 도달하는 것은 조용한 폴백(fallback)이 아니라 기록되는 실패로 간주해야 합니다.
async function generateValid<T>(prompt: string, validate: (x: unknown) => T) {
const MAX_ATTEMPTS = 3;
const MAX_TOKENS_TOTAL = 20_000;
...
이 원칙은 에이전트에도 적용됩니다. 작업당(per task), 요청당(per request)뿐만 아니라 도구 호출 수와 모델 호출 수를 제한해야 합니다.
실패 모드 2: 트래픽은 선형적으로 증가하지만, 비용은 그렇지 않다
실패 모드 2: 트래픽은 선형적으로 증가하지만, 비용은 그렇지 않다
만약 하나의 사용자 액션이 요약(summarization) 호출, 분류(classification) 호출, 임베딩(embedding) 호출을 모두 유발한다면, 요청당 비용은 측정되는 세 가지 API의 합계가 됩니다. 사용자를 두 배로 늘리면 재시도 횟수와 관계없이 이 세 가지 모두가 두 배가 됩니다.
해결책: 요청당 지연 시간(latency)을 아는 것처럼 요청당 비용도 파악해야 합니다. 기능에 예산(budget)을 설정하고, 예산이 초과되었을 때 어떤 것이 저하될지 미리 결정해야 합니다. 예를 들어, 더 저렴한 모델을 사용하거나, 컨텍스트 길이를 줄이거나, 캐시된 답변을 제공하거나, 아예 AI 출력을 하지 않는 방식입니다.
실패 모드 3: 사용자당 제한 없음
글로벌 속도 제한(Global rate limits)은 서비스 제공업체의 할당량(quota)을 보호합니다. 하지만 이는 한 명의 사용자(또는 하나의 스크립트, 또는 매 렌더링마다 요청을 재발행하는 자체 프론트엔드의 버그)가 그 할당량을 불균형하게 소모하는 것으로부터는 당신을 보호해 주지 못합니다.
예시 시나리오: 사용자별 제한이 없는 채팅 기능. 실수로 운영 환경(production)을 가리키도록 설정된 단일 통합 테스트가 주말 동안 좁은 루프(tight loop)로 요청을 보내는 경우입니다. 글로벌 한도에 도달하지 않기 때문에 아무런 경고도 울리지 않습니다.
해결책: 사용자별, API 키별, 테넌트별로 속도 제한과 토큰 할당량(token quotas)을 설정해야 합니다. 이를 인증(auth)처럼 취급하세요. 선택 사항이 아니며, 핸들러 깊숙한 곳이 아니라 엣지(edge)에서 강제되어야 합니다.
모니터링은 이제 재무 문제가 되었다
가동 시간 대시보드(Uptime dashboards)는 시스템이 실행되고 있는지 여부만 알려줍니다. 지난 한 시간 동안 운영하는 데 비용이 얼마나 들었는지는 알려주지 않습니다. AI 기능을 위해서는 이 두 가지 모두가 필요합니다:
- 거의 실시간으로 기능별, 사용자별, 테넌트별 토큰 및 지출액(spend)
- 오류율뿐만 아니라 지출률에 대한 경고(alerts)
- 배포 없이도 임계값을 초과할 때 기능을 끌 수 있는 비상 스위치(kill switch)
관점 전환: LLM 호출은 함수 호출이 아닙니다. 그것은 구매 행위입니다. 당신의 아키텍처는 모든 루프, 재시도, 분산 처리(fan-out)를 제한이 붙은 지출 결정으로 취급해야 합니다.
만약 운영 환경에서 하드한 비용 통제 장치가 없다면, 당신은 기능을 실행하는 것이 아닙니다. 열려 있는 탭을 실행하고 있는 것입니다.
AI 기능이 어떤 가장 비싼 루프에 빠졌는지, 그리고 어떤 제한이 그것을 포착할 수 있었을지 궁금합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기