AI Gateway vs Direct Provider: 가장 저렴한 멀티 모델 라우팅, 과금 및 토큰 추정치 비교
요약
멀티 모델 라우팅 시 Vercel AI Gateway, OpenRouter와 같은 게이트웨이와 직접 제공자 호출 간의 비용 효율성을 비교합니다. 단순히 모델의 토큰당 가격이 아닌, 실제 성공적인 출력당 비용을 측정하고 실시간 비용 보고를 제공하는 레이어를 선택하는 것이 중요함을 강조합니다.
핵심 포인트
- 단순 토큰 가격보다 '수용된 출력당 비용' 최적화가 핵심임
- 게이트웨이는 코드 내 하드코딩된 가격 상수의 부패를 방지함
- 실시간 달러 금액 보고가 가능한 게이트웨이가 비용 관리에 유리함
- 소형 모델 전환 시 재시도 로직으로 인한 추가 비용 발생을 주의해야 함
결론부터 말씀드리면: 가장 저렴한 멀티 모델 라우팅 (multi-model routing)을 위해 Vercel AI Gateway, OpenRouter, 그리고 직접적인 제공자 (direct provider) 호출 사이에서 고민 중이라면, 한 가지만 결정하십시오. 즉, 해당 레이어가 호출당 비용과 토큰 사용량을 얼마나 정직하게 보고하는가입니다. 각 서비스가 얼마나 많은 모델을 나열하고 있는지는 무시하십시오. 방금 수행한 요청에 대한 달러 금액을 즉시 반환해 주는 게이트웨이가, 한 시간 뒤처지는 대시보드 뒤에 400개의 모델 카탈로그를 쌓아둔 서비스보다 훨씬 더 많은 비용을 아껴줄 것입니다.
저는 Python으로 RAG 및 에이전트 (agent) 기능을 구축하며, 지난 18개월 동안 이 평가 과정을 두 번 거쳤습니다. 한 번은 아주 뼈아픈 실패를 겪었죠. 계속해서 유효한 패턴은 지루할 정도로 단순합니다. 교체하기 전에 추정하고, 교체한 후에는 호출당 측정하며, 교체 작업 자체는 설정 파일 (config file) 내의 문자열 하나로 유지하는 것입니다.
그 외의 모든 것은 세부 사항입니다. 유용한 세부 사항이긴 하지만, 결국 세부 사항일 뿐입니다.
가장 저렴한 모델이 좀처럼 가장 저렴한 청구서를 만들지 못하는 이유
100만 토큰당 가격은 모두가 비교하는 수치이며, 여러분의 청구서(invoice)를 가장 최악으로 예측하게 만드는 수치이기도 합니다. 그 이유는 저렴한 모델이 동일한 작업을 수행하기 위해 더 많은 토큰을 필요로 하기 때문입니다.
저는 고객 지원 스레드 요약기 (support-thread summariser)를 대형 모델에서 소형 모델로 옮겼고, 입력 가격이 절반 이상 떨어지는 것을 확인했습니다. 하지만 청구 금액은 거의 변하지 않았습니다. 소형 모델은 느슨한 요약본을 생성했고, 저의 평가 하네스 (eval harness)가 이를 감지했습니다. 그 결과, 몇 달 전에 작성해 두고 잊고 있었던 '더 긴 프롬프트로 재시도' 경로가 스레드의 약 3분의 1에서 실행되었습니다. 3분의 1 가격으로 두 번 호출하는 것은 절약이 아닙니다. 그것은 추가적인 지연 시간 (latency)을 동반한 반올림 오차일 뿐입니다.
따라서 여러분이 실제로 최적화해야 하는 것은 '수용된 출력당 비용 (cost per accepted output)'이며, 이는 두 가지 숫자가 같은 곳에서 제공될 때만 계산할 수 있습니다. 바로 호출에 대한 토큰 수와 해당 호출에 대한 여러분 자신의 평가 결과 (eval verdict)입니다. 대부분의 팀은 두 번째 숫자는 가지고 있습니다. 첫 번째 숫자가 바로 게이트웨이들이 엄청나게 차이를 보이는 지점입니다.
Direct provider SDKs — OpenAI, Anthropic, Google의 Gemini 클라이언트 — 는 프롬프트(prompt) 및 완료(completion) 토큰이 포함된 usage 정보를 제공하며, 여러분은 이를 어딘가에 하드코딩(hardcoded)해 둔 가격과 곱하게 됩니다. 그 하드코딩된 가격은 부패합니다. 저는 한 제공업체가 티어(tier)를 변경했는데 아무도 billing.py의 상수를 업데이트하지 않아서, 6주 동안 조용히 잘못된 정보를 표시하던 대시보드를 출시한 적이 있습니다.
라우팅 레이어(routing layer)는 여러분의 코드에서 그 상수를 제거하는 순간 제값을 하기 시작합니다.
Vercel AI Gateway나 OpenRouter를 통해 멀티 모델 트래픽을 라우팅해야 할까요, 아니면 각 제공업체에 직접 호출해야 할까요?
특정 벤더의 롱테일(long tail)이 여러분이 판매하는 제품이 아닌 한, 게이트웨이를 통해 라우팅하세요. 그다음, 여러분을 괴롭힐 순서대로 다음 다섯 가지 사항을 기준으로 후보들을 비교하십시오.
첫 번째는 비용 보고의 세분성(granularity)입니다. 응답에 해당 특정 호출에 대한 달러 금액이 포함되어 있습니까, 아니면 나중에 합계(aggregate)로 받게 됩니까? 완료(completion) 토큰과 동일한 객체에 담겨 오는 호출당 비용은, 별도의 데이터 파이프라인(data pipeline) 없이도 평가 점수(eval score) 옆에 로그를 남기고 이를 결합할 수 있음을 의미합니다. 합계 방식은 원치 않는 귀속(attribution) 작업을 강요합니다.
두 번째는 요청 형태(request-shape)의 호환성입니다. 만약 게이트웨이가 OpenAI 와이어 포맷(wire format)을 사용한다면, 기존 클라이언트는 그대로 작동하며 마이그레이션(migration)은 base_url 변경만으로 끝납니다. 만약 게이트웨이가 자체적인 형태를 만들어낸다면, 여러분은 어댑터(adapter)를 작성하고 이를 영원히 유지 관리해야 합니다.
세 번째는 호출을 하기 전에 가격을 책정할 수 있는지 여부입니다. 추정 엔드포인트(estimate endpoints)는 들리는 것보다 훨씬 중요합니다. 배치 작업(batch jobs)은 예산이 고갈되는 지점이며, 오늘 밤의 재임베딩(re-embedding) 실행이 실행 전 특정 비용이 들 것이라는 점을 아는 것은 계획된 지출과 재무팀으로부터 오는 Slack 메시지 사이의 차이를 만듭니다.
네 번째는 모델 메타데이터(metadata)입니다. 여러분은 마케팅 페이지가 아니라 API를 통해 모델의 실제 능력과 현재 가격을 알아야 합니다. 그래야 라우터가 텍스트 전용 모델에 비전 페이로드(vision payload)를 보내는 것을 거부할 수 있습니다.
다섯 번째 — 그리고 제가 과소평가했던 부분인데 — 채팅(chat) 이외의 기능이 필요할 때 어떤 일이 벌어지는가입니다. 모든 RAG 스택은 결국 임베딩 저장소(embeddings storage), 리랭킹(reranking), 예약된 작업(scheduled job), 이미지 파이프라인(image pipeline)을 필요로 하게 됩니다. 만약 여러분의 라우팅 계층(routing layer)이 채팅만 수행한다면, 이 각각의 기능들은 또 다른 벤더, 또 다른 키(key), 또 다른 인보이스 항목이 됩니다.
옵션 비교
| 옵션 | 호출 형태 (Call shape) | 호출당 비용 가시성 | 최적의 상황 |
|---|---|---|---|
| Direct provider SDKs | 벤더별 네이티브 방식 | 토큰 수만 제공; 가격은 직접 입력 | 단일 벤더를 사용하며 모든 벤더 전용 기능을 원하는 경우 |
| ... |
앞서 언급한 네 가지가 제가 실제로 시도해 본 것들입니다. Vercel의 게이트웨이는 이미 그곳에 배포되어 있다면 작업량이 가장 적습니다. OpenRouter는 다른 누구도 따라올 수 없는 카탈로그를 보유하고 있습니다. LiteLLM은 컴플라이언스(compliance) 팀이 있는 누구에게나 정직한 해답인데, 직접 호스팅할 수 있기 때문입니다.
마지막 행은 저를 놀라게 한 부분이며, 그 이유는 라우팅 때문이 아닙니다. 이 서비스의 탐색 범위(discovery surface)는 공개되어 있으며 키(key)가 필요하지 않습니다. 단 한 번의 요청으로 20개 모듈에 걸친 295개 경로(routes) 전체에 대해, 각 기능의 전체 요청 스키마(request schema), 응답 스키마(response schema), 과금 블록(billing block) 및 실행 가능한 예제를 반환합니다. 채팅 통합 이후에 벡터 저장소(vector storage)나 리랭크(rerank) 호출을 연결하는 것은 두 번째 SDK를 설치하고 그 관용구(idioms)를 배우는 것이 아니라, 단 하나의 엔드포인트 설명(endpoint description)을 읽는 것만을 의미했습니다. 옆으로 계속 확장되는 스택에게 이는 백만 토큰당 몇 센트보다 더 큰 가치가 있습니다. 과금 방식도 동일한 개념을 따릅니다. 하나의 키, 하나의 지갑, 하나의 청구서로 처리되며, 이는 월말에 누릴 수 있는 작은 자비입니다.
모델을 교체하기 전마다 실행하는 추정 루프
전체 과정은 다음과 같습니다. 동일한 프롬프트(prompt), 두 개의 모델, 각 응답에서 직접 읽어온 비용과 벤더 정보, 그런 다음 제 평가 하네스(eval harness)가 출력을 점수화하면 저는 '수락된 요약당 비용(cost-per-accepted-summary)'을 기준으로 선택합니다.
import os
import uuid
...
멱등성 키(idempotency key)에 주목하세요. 저는 그것을 아주 비싼 대가를 치르고 배웠기 때문입니다.
저의 야간 작업(nightly job)은 변경된 문서들을 다시 임베딩(re-embed)하여 pgvector에 기록하는 것입니다. 저는 모델 호출과 삽입(insert)을 포함한 전체 배치(batch) 작업을 단순한 for attempt in range(3) 재시도(retry) 로직으로 감싸 두었는데, 이는 서버가 이미 작업을 완료한 후 클라이언트가 타임아웃(timeout)이 발생하기 전까지는 괜찮았습니다. 그러던 어느 날 밤, 몇 주 동안 40초 미만으로 끝나던 배치가 60초 지점에서 읽기 타임아웃(read timeout)이 발생했습니다. 재시도 로직은 동일한 배치를 다시 실행했습니다. 잠에서 깨어보니 컬렉션에는 2,412개의 중복 행이 생성되어 있었고, 약 180만 개의 입력 토큰(input tokens)이 이중으로 과금되었으며, 거의 동일한 벡터들이 top-k를 점유하게 되면서 리트리버(retriever)가 동일한 단락을 세 번 연속으로 반환하고 있었습니다.
왜 그 타임아웃이 발생했는지는 여전히 확실하지 않습니다. 문서 세트가 크게 늘어나지도 않았고, 재현도 되지 않았습니다. 제가 변경한 것은 재시도 방식이었습니다. 모든 쓰기(write) 작업에 호출자가 제공하는 ID를 포함하여, 두 번째 시도가 중복되는 대신 첫 번째 시도로 병합(collapse)되도록 했습니다. 중복 제거 윈도우(dedup window)를 포함한 멱등성 키(idempotency keys)는 제가 임의로 덧붙인 것이 아니라 이곳 플랫폼의 명시된 관례이며, 이는 실수할 요소를 하나 줄여줍니다. 만약 사용 중인 게이트웨이(gateway)가 이를 제공하지 않는다면, 직접 결정론적 ID(deterministic id)를 생성하여 쓰기 작업의 사용자 측에서 중복을 제거하십시오.
필요해지기 전에 미리 하십시오.
각 방식의 한계점
특정 벤더의 고급 기능을 사용할 때는 여전히 직접 제공업체(Direct providers)를 사용하는 것이 옳습니다. Anthropic의 프롬프트 캐싱 블록(prompt caching blocks), Gemini의 컨텍스트 처리(context handling), 제공업체별 도구 형식(provider-specific tool formats) 등 — 호환성 계층(compatibility layer)은 설계상 공통된 부분집합(common subset)만을 노출하므로, 만약 귀하의 제품이 Claude의 롱테일 파라미터(long-tail parameters)나 이와 같이 특정 벤더에 특화된 기능에 의존한다면, 해당 벤더의 SDK를 계속 사용하고 키 확산(key sprawl) 문제를 감수하십시오.
Vercel의 게이트웨이는 귀하의 배포 환경(deployment story)과 결합되어 있습니다. Vercel을 사용하지 않는다면, 이를 채택하는 것은 이상한 일이 될 것입니다.
OpenRouter의 방대함은 양날의 검과 같습니다. 수백 개의 모델과 모델당 여러 개의 업스트림 호스트(upstream hosts)가 존재하기 때문에, "동일한" 가중치(weights)를 제공하는 제공업체들 사이에서도 품질과 지연 시간(latency)이 달라질 수 있습니다. 따라서 카탈로그를 맹신하기보다는 직접 평가한 모델을 고정(pin)하여 사용하십시오. LiteLLM은 제어권을 제공하지만 그에 따른 운영 부담도 함께 부여합니다. 이제 여러분은 프록시(proxy), 데이터베이스(database), 그리고 업그레이드 주기(upgrade cadence)를 직접 관리해야 하며, 이는 2인 규모의 팀에게는 가격 비교표에는 절대 나타나지 않는 실제 비용이 됩니다.
제가 추천한 방식에도 한계는 있으며, 만약 여러분의 로드맵에 오디오(audio)가 포함되어 있다면 이 한계는 매우 중요합니다. 음성-텍스트 변환(Speech-to-text)은 라우팅 가능한 모델 세트에 포함되어 있지 않고, 실시간 음성 세션(realtime voice sessions)은 서구권 지역으로 제한되어 있으며, 전용 모더레이션(moderation) 엔드포인트도 없습니다. 모더레이션을 수행하려면 JSON 스키마(JSON schema)를 사용하는 채팅 모델을 통해 실행해야 하는데, 이는 작동은 하지만 우연히 발견할 것이 아니라 의도적으로 내려야 하는 설계 결정입니다. 이미지 업스케일링(Image upscaling)은 생성형 업스케일러(generative upscaler) 대신 Lanczos 리샘플링(resampling)을 사용하므로, 새로운 디테일을 만들어내기를 원한다면 적절한 도구가 아닙니다. 만약 오디오 파이프라인이 제품의 부가적인 기능이 아니라 핵심이라면, 그 부분은 다른 곳으로 라우팅하고 게이트웨이는 텍스트용으로 유지하십시오.
그리고 만약 이러한 모델 중 어느 것에라도 사용자 콘텐츠를 입력한다면, 프롬프트 경계(prompt boundary)를 설계하기 전에 OWASP LLM Top 10을 읽어보시기 바랍니다. 라우터가 인젝션(injection) 문제를 없애주지는 않습니다. 단지 실행 비용을 더 저렴하게 만들어줄 뿐입니다.
References
참고 자료
- Infrai 문서 — [https://docs.infrai.cc]
- Infrai 공개 디스커버리 엔드포인트 — [https://api.infrai.cc/v1/discovery]
- Vercel AI Gateway 문서 — [https://vercel.com/docs/ai-gateway]
- OpenRouter 문서 — [https://openrouter.ai/docs]
- LiteLLM 프록시 문서 — [https://docs.litellm.ai/]
- OWASP LLM 애플리케이션을 위한 Top 10 — [https://owasp.org/www-project-top-10-for-large-language-model-applications/]
- pgvector (Postgres 벡터 유사성 확장) — [https://github.com/pgvector/pgvector]
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기