당신의 AI 비용 문제는 모델 가격 문제가 아니라 분산 시스템 문제입니다
요약
AI 모델 비용 급증의 근본 원인은 모델 가격이 아니라 분산 시스템의 설계 문제인 경우가 많습니다. 호출 그래프를 분석하여 재시도 폭풍, 팬아웃, 캐시 오류 등 시스템적 결함을 찾아내는 엔지니어링적 접근법을 강조합니다.
핵심 포인트
- AI 비용 문제는 모델 가격보다 분산 시스템의 버그일 가능성이 높음
- 토큰 단위의 비용을 네트워크 호출(HTTP) 관점에서 디버깅해야 함
- 재시도 폭풍, 숨겨진 팬아웃, 캐시 미작동 등을 주요 원인으로 파악
- 단순 가격 비교 대신 호출 그래프(Call Graph) 분석이 필수적임
제가 도와주고 있던 한 팀은 단 한 달 만에 모델 비용이 평소보다 몇 배나 급증하는 것을 목격했습니다. 토큰 미터(token meter)는 이를 예측하지 못했습니다. 회의실에서 나온 첫 번째 질문은 거의 모든 사람이 던지는 질문이었습니다. 제공업체가 가격을 올렸는가, 아니면 더 저렴한 모델로 옮겨야 하는가?
두 질문 모두 틀렸으며, 교훈적인 측면에서 틀렸습니다. 만약 동일한 엔지니어들이 AWS 송신(egress) 비용이 세 배로 뛰었다면, 결코 _AWS가 가격을 올렸는가_라는 질문으로 시작하지 않았을 것입니다. 대신 그들은 _무엇이 더 많이 호출되고 있는가_를 묻고, 요청 그래프(request graph)를 불러와 증폭(amplification) 요인을 찾기 시작했을 것입니다. 단위가 HTTP 호출일 때는 이러한 본능이 정확하고 자동적으로 작동합니다. 하지만 단위가 토큰(tokens)이 되는 순간, 사람들은 이 본능을 잃어버립니다.
그 간극이 바로 이 글의 주제입니다.
놀라운 AI 비용은 증상일 뿐입니다. 질병은 거의 항상 분산 시스템(distributed systems)의 버그, 재시도 폭풍(retry storm), 숨겨진 팬아웃(fanout), 작동을 멈춘 캐시(cache), 한계 없이 커지는 대화 등입니다. 만약 이것이 토큰이 아닌 네트워크 호출로 표시되었다면 당신은 즉시 알아차렸을 것입니다. 모델 가격이 아니라 호출 그래프(call graph)를 디버깅하세요.
이는 가능한 곳에서는 결정론을, 필요한 곳에서는 판단을 그리고 검증은 단언이 아니라 루프이다와 같은 동일한 제1원칙(first-principles)의 맥락에 있습니다. 앞선 글들이 정확성에 관한 것이라면, 이 글은 비용에 관한 것이며, 접근 방식은 동일합니다. 즉, AI라는 가면을 쓰고 있어 새로워 보이는 문제를 가져와 그 아래에 숨겨진 오래된 형태를 인식하는 것입니다. 아키텍처 측면에서는 텔레메트리(telemetry)를 구축하는 방법에 관한 AI API 호출을 위한 관측성 및 과금(Observability and Billing for AI API Calls)과 짝을 이룹니다. 이 글은 수치가 급증할 때 그것을 어떻게 읽어야 하는지에 관한 것입니다.
진단적 전환
백엔드 엔지니어의 데이터 송신(egress) 비용이 급증할 때, 반사적으로 무엇이 호출 그래프(call graph)에서 변했는지를 묻게 됩니다. 누구도 가장 먼저 가격에 대해 벤더에게 이메일을 보내지는 않습니다. 하지만 AI 엔지니어의 모델 비용이 급증할 때, 그 반사 작용은 너무나 자주 뒤집힙니다. 가장 먼저 의심하는 것은 가격표와 모델 선택이며, 호출 그래프는 가장 마지막에 확인하는 대상이 됩니다.
이것들은 옷만 다르게 입었을 뿐 동일한 질문입니다. 무엇이 지출을 유도하고 있는가, 그리고 그 유도 요인이 의도한 대로 작동하고 있는가? 우리는 HTTP 단위에 대해 수년간의 근육 기억(muscle memory)을 가지고 있기 때문에 이를 정확히 파악합니다. 하지만 토큰(token)의 경우, 단위가 생소하고 결정적으로 청구서가 이를 생성한 그래프를 숨긴 채 단일 달러 금액으로 사전 집계(pre-aggregated)되어 도착하기 때문에 잘못 파악하게 됩니다. 달러 금액은 문제에 대한 가장 유용하지 않은 관점이며, 대개 사람들이 시작하는 유일한 관점이기도 합니다.
그러므로 다른 무엇보다도, 가격에 대한 질문을 거부하십시오. 지출은 오작동한 다운스트림 서비스(downstream-service)의 지출이라고 가정하고, 그 오작동을 찾아내십시오. 그것은 거의 항상 다섯 가지 형태 중 하나일 것입니다.
토큰으로 표현되는 다섯 가지 실패 모드
1. 재시도 폭풍 (Retry storms). 일시적인 제공업체 오류가 SDK 계층에서의 재시도를 유발하고, 다시 에이전트(agent) 계층에서, 그리고 다시 워크플로 오케스트레이터(workflow orchestrator)에서 재시도를 유발합니다. 이 세 계층 모두 탄력적(resilient)으로 작성되었지만, 서로의 존재를 알지 못하기 때문입니다. 단 하나의 사용자 요청이 여러 번의 과금되는 호출로 변합니다. 이것은 중첩된 재시도 정책이 조정(coordinate)되는 대신 배가되는, 성능이 저하된 다운스트림 HTTP 서비스에서 디버깅해 본 바로 그 재시도 폭풍과 정확히 일치합니다. 해결책도 같습니다. 세 개의 희망적인 재시도 정책을 쌓아두는 것이 아니라, 한 곳에서 관리되는 단 하나의 재시도 예산(retry budget)을 가져야 합니다.
2. 팬아웃 증폭 (Fanout amplification). 에이전트가 여러 개의 병렬 도구 호출 (tool calls)을 생성하고, 각 도구는 구현 내부 어딘가에서 결과값을 파싱하거나 요약하기 위해 자체적인 모델 호출을 수행하며, 이 각각의 결과가 다시 메인 대화로 피드백됩니다. 단 한 번의 사용자 요청이 조용히 수많은 모델 호출로 변하며, 그중 대부분은 아무도 살펴보지 않는 도구 코드 내부에 숨겨져 있습니다. 이는 요청 팬아웃 증폭 (request fanout amplification)이며, 각 컴포넌트가 스스로 데이터를 가져올 때 단 한 번의 페이지 로딩이 40개의 백엔드 호출을 유발할 수 있는 것과 같은 이유입니다.
3. 캐시가 적중해야 할 곳에서의 캐시 미스 (Cache misses). 제공업체는 안정적인 프롬프트 접두사 (prompt prefix) 캐싱을 지원하지만, 당신은 이를 사용하지 않고 있습니다. 따라서 동일한 시스템 프롬프트와 동일한 긴 서문 (preamble)이 매 호출마다 다시 토큰화 (retokenized)되고 다시 비용이 청구됩니다. 이는 모든 요청을 오리진 (origin)으로 전달하도록 실수로 설정된 CDN과 같습니다. 콘텐츠는 전혀 변하지 않았음에도 불구하고, 당신은 매번 이를 다시 계산하는 비용을 지불하고 있습니다.
4. 무제한적인 대화 성장 (Unbounded conversation growth). 대화 기록이 압축 (compaction) 없이 턴마다 계속 추가되므로, 턴당 청구되는 토큰은 세션의 길이에 따라 증가하며, 세션의 총비용은 길이에 따라 이차 함수적으로 (quadratically) 증가합니다. 이는 채널을 메시지 전달처럼 취급하는 것이 유발하는 것과 같은 부류의 누수 (leak)인 무제한 버퍼 (unbounded buffer)와 같지만, 버퍼가 대화 기록(transcript)이며 누수가 힙 프로파일 (heap profile) 대신 청구서에 나타난다는 점이 다릅니다.
5. 작업에 맞지 않는 모델 (Wrong model for the job). 기본적으로 모든 호출에서, 프론티어 모델 (frontier model)이 더 작은 모델로도 충분히 완벽하게 처리할 수 있는 작업을 수행하고 있습니다. 이는 분석용 데이터 웨어하우스 (warehouse)가 아닌, 단순히 가지고 있던 연결 문자열 (connection string) 때문에 트랜잭션 클러스터 (transactional cluster)에 임시 분석 쿼리를 실행하는 것과 같습니다. 또한, 기법 경계 (technique boundary)의 관점에서 보면, 더 저렴한 기법으로 충분한 곳에 가장 비싼 기법을 사용하는 것이며, 이는 해당 글에서 정확성 (correctness)에 대해 설명한 것과 동일한 실수의 비용 측면에서의 모습입니다.
이 다섯 가지 중 네 가지는 증폭 버그 (amplification bugs)입니다. 즉, 작업에 필요한 것보다 더 많은 호출 (calls)이 발생하거나, 호출당 더 많은 토큰 (tokens)이 생성되고 있는 상태를 의미합니다. 다섯 번째는 계층화 실수 (tiering mistake)입니다. 이 중 그 어떤 것도 가격 변동이 아니며, 모델을 교체한다고 해서 해결되지도 않습니다. 바로 이것이 모델 교체를 가장 먼저 시도하는 것이 실망스러운 결과를 초래하는 정확한 이유입니다.
순서에 따른 포렌식 (The forensics, in order)
진단은 매번 동일한 순서로 진행되며, 각 단계는 토큰 미터 (token meter)의 숫자가 아니라 호출 그래프 (call graph)에서 분산 시스템 지표 (distributed systems metric)를 읽어냅니다.
1. 사용자 요청당 호출 수 (Calls per user request)
워크플로의 이론적 최소치에 근접한가? -> 정상 (healthy)
최소치의 몇 배에 달하는가? -> 재시도 폭풍 (retry storm) 또는 숨겨진 팬아웃 (hidden fanout) (모드 1, 2)
...
순서가 중요합니다. 제공업체의 거부 (Provider rejects)는 목록의 가장 아래에 위치하지만, 인과 관계의 사슬 (causal chain)에서는 뿌리에 해당합니다. 일시적인 거부 (transient rejects)의 증가는 목록 최상단에 있는 재시도 폭풍 (retry storm)을 촉발하는 원인이기 때문입니다. 증상을 국지화하려면 그래프를 위에서 아래로 읽고, 원인을 찾으려면 아래에서 위로 읽으십시오.
이런 방식으로 나열하는 이유는 이 중 어느 것도 새로운 것이 아니기 때문입니다. 여러분의 관측성 스택 (observability stack)은 이미 요청당 호출 수, 꼬리 분포 (tail distributions), 트래픽 구성 (traffic mix), 그리고 에러율 (error rates)을 계산하는 방법을 알고 있습니다. 여러분은 의존하고 있는 다른 모든 다운스트림 서비스 (downstream service)에 대해서도 이 값들을 계산하고 있습니다. 유일하게 새로운 점은 동일한 메커니즘을 모델 제공업체로 향하게 하는 것뿐입니다.
사용자 요청 (User request)
|
v
...
해당 그래프의 엣지 (edge)에 있는 모든 승수 (multiplier)는 토큰당 가격은 변하지 않으면서 청구 금액이 급증할 수 있는 지점입니다. 인보이스 (invoice)는 가장 오른쪽에 있는 노드 (node)만을 보여줍니다. 누수 (leak)는 항상 엣지 (edge)에서 발생합니다.
빌링 (Billing)은 비용 포렌식이 아니다
위의 과정들을 수행할 수 있는지 여부를 결정짓는 기준은 다음과 같습니다. 만약 여러분의 AI 관측성 (AI observability)이 각 호출에 대해 토큰 수에 가격을 곱한 값만을 출력하고 거기서 멈춘다면, 그것은 빌링 (billing)입니다. 여러분은 얼마를 지불했는지는 알 수 있습니다. 하지만 왜 그렇게 되었는지는 알 수 없습니다. 왜냐하면 그 '이유'는 호출 그래프의 엣지 (edges)에 존재하는데, 호출당 토큰 수만 계산하면 그래프를 버리게 되기 때문입니다.
비용 포렌식 (Cost forensics)을 위해서는 그래프를 온전하게 유지해야 합니다. 즉, 최초 사용자 요청으로 소급되는 호출 (calls), 도구(tool)당 팬아웃 (fanout) 계수, 프롬프트 접두사 (prompt prefix)별 캐시 적중률 (cache hit rates), 레이어별 재시도 분포 (retry distributions), 시간에 따른 모델 믹스 (model mix) 등이 필요합니다. 이는 이미 HTTP 의존성 (dependencies)을 위해 유지하고 있는 텔레메트리 (telemetry) 형태와 동일하며, 이를 의도적으로 구축하는 것이 T자형 아키텍처 관련 글의 주제입니다. 여기서 중요한 진단적 포인트는 다음과 같습니다. 만약 해당 데이터가 존재하지 않는다면, 아무리 숙련된 엔지니어라 할지라도 비용이 어디서 새고 있는지 알려줄 수 없습니다. 수집 단계에서 증거가 폐기되었기 때문입니다. 그래프를 추가한다면, LLM을 다뤄본 적은 없지만 HTTP 비용 포렌식에 능숙한 엔지니어도 누수 지점을 찾아낼 수 있습니다. 토큰은 단지 인지적 내용이 담긴 바이트 (byte)일 뿐이며, 모델 제공업체는 단지 페이로드 (payload)에 따라 과금하는 다운스트림 서비스 (downstream service)에 불과하기 때문입니다.
모델 전환이 실제로 정답인 경우
결코 아니라는 뜻은 아닙니다. 재시도 (retries), 팬아웃 (fanout), 캐시 미스 (cache misses), 대화량 증가 (conversation growth)를 모두 배제한 후에도 문제가 남는다면, '모드 5'는 실제적이고 흔한 진단 결과이며, 특정 클래스의 호출을 더 작은 모델로 옮기는 것이 올바른 해결책입니다. 다만 핵심은 순서에 대한 규율입니다. 증폭 모드 (amplification modes)를 배제하기 전에 모델을 전환하면, 재시도 폭풍 (retry storm)이 여전히 발생하는 더 저렴한 모델로 착륙하게 될 수 있습니다. 이 경우 작은 모델조차 미스터리하게 비싸 보이는 현상이 나타나며, 결국 하나의 혼란스러운 청구서 대신 두 개의 혼란스러운 청구서를 마주하게 됩니다. 그래프 문제를 먼저 배제하십시오. 그러면 모델 전환은 막연한 추측이 아닌 측정에 기반한 결정이 되며, 그 효과가 지속될 가능성이 높습니다.
오래된 위생 관리, 새로운 청구서
만약 당신의 팀에 HTTP 재시도 예산 (retry budgets), 요청 팬아웃 (request fanout), 캐시 적중률 (cache hit ratios), 그리고 페이로드 크기 분포 (payload-size distributions)에 대한 감각이 뛰어난 사람이 있다면, 그 사람은 이미 당신의 모델 비용 문제를 디버깅할 수 있습니다. 모든 것이 그대로 전이됩니다. 재시도 예산은 재시도 예산이고, 팬아웃은 팬아웃이며, 캐시되지 않은 접두사 (uncached prefix)는 캐시되지 않은 접두사입니다. 서비스 제공자 (provider)는 당신이 이미 객체 스토리지 (object storage), 관리형 데이터베이스 (managed databases), 그리고 제3자 API (third-party APIs)에 적용하고 있는 것과 동일한 위생 관리 (hygiene)에 반응하는 또 하나의 다운스트림 서비스일 뿐입니다.
청구서는 버그가 마지막으로 나타나는 지점이자, 이를 확인하기에 가장 비용이 많이 드는 지점입니다. 왜냐하면 청구서에 버그가 나타날 때쯤이면 이미 비용이 지불되었기 때문입니다. 청구서보다 한 단계 앞선 호출 그래프 (call graph)에서 이를 확인하십시오. 그곳에서는 이 다섯 가지 모드 각각이 엣지 (edge) 상의 승수 (multiplier)로 가시화되어 있으며, 당신은 이미 수년 동안 이 각각을 수정하는 방법을 알고 있었습니다. 당신의 AI 비용은 새로운 종류의 문제가 아닙니다. 그것은 익숙하지 않은 단위를 가진 오래된 종류의 문제일 뿐이며, 단위를 다시 원래대로 변환하는 순간 당신은 이미 무엇을 해야 할지 알게 될 것입니다.
이 글은 Generative Systems, First Principles 시리즈의 일부입니다. 관련 글: Determinism Where You Can, Judgement Where You Must 및 Validation Is a Loop, Not an Assertion. 아키텍처 관련 글: Observability and Billing for AI API Calls.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기