모델로 가는 하나의 문, 1부. 중앙 LLM 게이트웨이를 세워야 하는 이유
한 회사가 GenAI 앱 5개를 운영하면서 각각의 비용을 말하지 못한다. 1부는 시나리오와 Azure에서의 구축 대 구매, 이 시리즈가 만들 게이트웨이를 다룬다.

한 대기업 IT 조직이 생성형 AI 애플리케이션 5개를 프로덕션에서 운영하고, 모델 배포 11개가 Azure 구독 3개에 흩어져 있으며, 월 청구액은 약 38,000유로인데, 그 돈을 다섯 앱 중 누가 썼는지 믿을 만하게 답할 방법이 없다. 고장 난 것은 없다. 모든 앱이 동작하고, 모든 팀이 출시를 마쳤으며, 당시 기준으로는 모든 보안 검토도 통과했다. 존재하지 않는 것은 토큰이 집계되고, 호출자가 식별되고, 모델이 퇴역 처리되는 단일한 장소이며, 그 부재가 바로 이 10부작 시리즈가 만들 대상이다. 모든 애플리케이션이 통과하고, 그 무엇도 우회하지 않는, Azure 위의 거버넌스를 갖춘 GenAI 게이트웨이 하나다.
이 회사, 그리고 실제로 치르고 있는 비용
있는 그대로 부르자면 자리 잡은 기업 IT 조직이다. 엔지니어 약 400명이 약 40개 제품 팀에 걸쳐 있고, 대부분의 워크로드는 Azure에 있으며, 랜딩 존과 CI 템플릿을 이미 소유한 플랫폼 조직이 있다. 생성형 AI는 늘 그렇듯 가장자리에서 안쪽으로 들어왔다. 예산을 가진 프로덕트 오너 덕에 고객 상담 어시스턴트가 먼저 출시되었다. 그다음 IT 운영 요약기, 사내 코드 어시스턴트, 제품 문서를 대상으로 한 리테일 지식 검색, 마케팅 카피 도구가 뒤따랐다. 다섯 팀, 다섯 번의 결정, Azure OpenAI에 대한 다섯 개의 직접 연동이다.
그 결정 하나하나는 따로 보면 옳았다. 하지만 합쳐지면 이제는 익숙해진 특정한 모양이 만들어진다.
- 구독 3개에 걸친 모델 배포 11개. 그중 둘은 같은 리전에 같은 모델을 중복 배포한 것인데, 이미 가진 리소스에 쿼터를 붙이지 못한 팀이 만든 결과다.
- 월 약 38,000유로의 모델 지출이 비용 관리에는 구독 단위로만 잡힌다. 재무팀에는 총액을 말해줄 수 있지만, 어느 프로덕트 오너에게도 자기 몫의 숫자를 말해줄 수 없다는 뜻이다.
- 다섯 앱 중 넷이 애플리케이션 설정에 키를 보관한다. 하나는 시크릿 스캐너가 찾아내기 전까지 저장소에 키를 두고 있었다. 엔지니어가 해당 앱의 설정을 직접 고치지 않고서는 어떤 앱의 접근도 개별적으로 회수할 수 없다.
- 60일 모델 퇴역 공지가 이메일로 도착했고, 플랫폼 조직은 어떤 애플리케이션이 깨질지 알아내려 이틀 동안 저장소를 grep했다. 어느 앱이 어느 모델 버전을 호출하는지 기록해 둔 것이 아무것도 없었기 때문이다.
그리고 결정을 실제로 강제한 인시던트가 있었다. 마케팅 카피 도구의 배치 작업이 약 40분 동안 공유 배포의 tokens-per-minute 쿼터 대부분을 소비했다. 같은 배포를 공유하던 고객 상담 어시스턴트는 실제 고객에게 HTTP 429를 반환하기 시작했다. 어느 팀도 잘못한 것이 없다. "한 호출자가 다른 호출자가 의존하는 쿼터를 소진해서는 안 된다"를 표현할 수 있는 메커니즘이 경로 위에 없었다. 공유된 경로 자체가 없었기 때문이다.
이것이 게이트웨이를 세워야 하는 솔직한 근거다. "중앙 통제가 좋은 아키텍처다"가 아니다. 쿼터, 비용 귀속, 자격 증명 로테이션, 모델 라이프사이클은 모두 호출의 속성이고, 모든 호출을 보는 컴포넌트가 없다면 그 어느 것도 관례에 기대는 것 말고는 어디에서도 강제할 수 없다는 것이다.
앱별 패턴이 실제로 치르는 비용
직접 연동은 첫날에는 정말로 더 싸다. SDK 클라이언트 하나, 키 하나, 엔드포인트 하나, 그리고 크리티컬 패스에 플랫폼팀이 없다. 비용은 나중에 도착하고, 그 선택을 한 팀이 아닌 다른 곳에 떨어진다. 바로 그래서 이 선택이 계속 반복된다.
누적되는 비용은 세 가지인데, 사실은 같은 비용이 옷만 갈아입은 것이다. 변경 비용: 모델 퇴역, 가격 변경, 리전 이전, 프로바이더 장애를 애플리케이션마다 한 번씩, 백로그도 관심도도 제각각인 다섯 팀이 처리해야 한다. 귀속 비용: 지출이 리소스 단위로는 보이고 소비자 단위로는 보이지 않으니 누구에게도 예산을 줄 수 없고, 그 말은 누구에게도 한도를 줄 수 없다는 뜻이다. 거버넌스 비용: 프롬프트 로깅, PII 마스킹, EU AI Act 투명성 요구 같은 새 통제 하나하나를 다섯 번 구현하고 다섯 번 검증해야 하며, 검토 노력이 통제의 수가 아니라 애플리케이션의 수에 비례해 커진다.
게이트웨이는 이 비용들을 없애주지 않는다. 플랫폼팀이 한 번만 치르면 되는 한 곳으로 옮겨줄 뿐이다. 그것이 논거의 전부이며, 이보다 더 화려한 버전의 논거는 의심하는 편이 좋다.
Azure에서의 구축 대 구매
팀은 세 가지 형태를 검토했고, 답은 엔지니어가 바라는 그 답이 아니다.
AI 게이트웨이로서의 Azure API Management. API Management는 언어 모델 트래픽을 명시적으로 겨냥한 기능 세트를 제공하며, 그 목록은 직접 읽어보기 전에 짐작하는 것보다 길다. llm-token-limit 정책은 구독 키, 호출자 IP, 임의의 정책 표현식을 포함한 어떤 카운터 키에 대해서든 tokens-per-minute 또는 시간, 일, 주, 월, 연 단위 토큰 쿼터를 강제하고, 게이트웨이에서 프롬프트 토큰을 미리 계산해 한도를 넘는 요청이 백엔드에 아예 도달하지 않게 할 수 있다. llm-semantic-cache-store와 llm-semantic-cache-lookup 정책은 Azure Managed Redis나 다른 RediSearch 호환 캐시를 대상으로 컴플리션의 벡터 유사도 캐싱을 수행한다. llm-emit-token-metric 정책은 커스텀 디멘션과 함께 토큰 수를 Application Insights로 내보내는데, 이것이 소비자별 귀속의 원재료다. 백엔드는 라운드 로빈, 가중치, 우선순위 기반, 세션 인지 로드 밸런싱을 지원하고, 트립 지속 시간이 백엔드 자신의 Retry-After 헤더를 존중하는 circuit breaker도 있어서, 포화된 Provisioned Throughput Unit 배포의 오버플로를 누구도 재시도 코드를 짜지 않고 종량제 엔드포인트가 흡수할 수 있다.
프로바이더 커버리지가 여기서 중요하고, 틀리기도 쉽다. API Management는 OpenAI Chat Completions와 Responses 스키마, (v2 티어의) Anthropic Messages API, Google Vertex AI API를 따르는 언어 모델 API를 중개하며, 대상은 Microsoft Foundry에 배포된 모델이든 Amazon Bedrock을 포함한 비 Microsoft 프로바이더의 모델이든 상관없다. 이 글을 쓰는 시점에 프리뷰인 unified model API는 여러 백엔드를 OpenAI 호환 단일 엔드포인트 뒤에 노출하고 포맷을 변환해 주므로, 하나의 거버넌스 정책 세트가 프로바이더 전반에 적용된다. Anthropic Claude, Mistral, Llama는 각각 별도의 연동을 요구하는 대신 이 레이어를 통해 도달할 수 있다.
AKS 위의 오픈소스 프록시. LiteLLM과 그 유사 프로젝트들은 완전히 직접 통제하는 컨테이너 안에서 프로바이더 변환과 라우팅을 제공하고, 원하는 기능에 더 빨리 닿을 수 있으며 프리뷰에 대한 의존도 없다. 대신 이제 회사의 모든 AI 요청 앞에 놓이는 컴포넌트의 온콜 로테이션을 떠안게 되고, API Management가 이미 인증까지 받아 둔 아이덴티티, 네트워크, 감사 작업도 함께 물려받는다.
맞춤형 FastAPI 서비스. 통제력은 최대이고, 모든 실패가 온전히 자기 몫인 유일한 선택지다. 정말로 특이한 요구사항을 가진 컴포넌트라면 합리적이지만, 토큰을 세는 리버스 프록시는 그런 컴포넌트가 아니다.
이 시리즈가 따르는 결정은 이것이다. API Management가 데이터 플레인이고, API Management가 하지 못하는 것들은 AKS 위의 작은 Python 컨트롤 플레인으로 만든다. 이 분리가 내면화할 가치가 있는 지점인데, 대부분의 게이트웨이 프로젝트가 여기서 어긋나기 때문이다. 팀들은 모든 것을 정책 XML로 표현하려다 아무도 테스트할 수 없는 유지 불가능한 산출물을 만들거나, 트래픽을 자기 서비스로 통과시키면서 레이트 리미팅을 어설프게 재구현한다. 게이트웨이는 요청을 나른다. 컨트롤 플레인은 상태를 나른다. 어떤 모델이 존재하는지, 누가 호출할 수 있는지, 호출 비용이 얼마인지, 모델이 퇴역하면 무슨 일이 일어나는지가 그 상태다.
그래도 직접 만들어야 하는 것
다섯 가지이고, 하나하나가 이 시리즈의 이후 편이다.
- 모델 카탈로그와 라이프사이클. 어떤 논리적 모델 이름이 존재하고, 어떤 물리적 배포가 그것을 뒷받침하며, 무엇이 사용 중단 예정이고 언제 사라지는지. 애플리케이션은 배포 이름이 아니라 반드시
chat-default를 호출해야 한다. 그렇지 않으면 60일 퇴역 이메일이 다시 60일짜리 마이그레이션 프로젝트가 된다. - 테넌트 아이덴티티와 온보딩. 팀은 클라이언트 자격 증명, 쿼터, 모델 허용 목록, 코스트 센터를 받는데, 티켓이 아니라 코드로 프로비저닝된다.
- 비용 귀속과 차지백. 테넌트 디멘션이 붙은 토큰 메트릭은 입력일 뿐이다. 그것을 재무팀이 받아들이는 팀별 월간 수치로 바꾸는 일은 자체 테스트를 갖춘 데이터 파이프라인이다.
- 파이프라인의 평가 게이트. 새 모델 버전의 승격은 곧 배포다. 평가 결과가 붙지 않은 채 모델 동작을 바꾸는 배포는 고객이 발견해 주기를 기다리는 장애다.
- 비동기와 장기 실행 작업. 지원 티켓의 배치 요약은 첫 토큰을 기다리는 고객과 같은 동기 경로에 있을 일이 아니다. 그 분리는 타임아웃 설정이 아니라 큐다.
목표 아키텍처
이 플랫폼은 의도적으로 지루하고 의도적으로 추가적(additive)이다. 컨트롤 플레인이 다운되어도 데이터 플레인은 마지막으로 알고 있던 구성으로 트래픽을 계속 처리한다. 컨트롤 플레인 장애에 닫혀 버리는(fail closed) 게이트웨이는 곧 전사 장애이기 때문이다.
graph TD
subgraph consumers["Consumer apps"]
A1["customer-service assistant"]
A2["IT-ops summarizer"]
A3["code assistant"]
A4["retail knowledge search"]
A5["marketing copy tool"]
end
subgraph gw["Data plane: API Management"]
POL["policies:
llm-token-limit, semantic cache,
emit-token-metric, JWT validate"]
LB["backend pool:
priority + weighted, circuit breaker"]
end
subgraph cp["Control plane: Python on AKS"]
CAT["model catalog"]
TEN["tenant registry"]
COST["cost attribution job"]
end
subgraph models["Model layer"]
FDRY["Microsoft Foundry:
GPT deployments, PTU + PAYG"]
ANTH["Anthropic Claude"]
OSS["Mistral, Llama"]
end
ID["Microsoft Entra ID"]
RED["Azure Managed Redis
semantic cache"]
SRCH["Azure AI Search
retrieval"]
MON["Azure Monitor +
Application Insights"]
A1 --> POL
A2 --> POL
A3 --> POL
A4 --> POL
A5 --> POL
ID -. "OAuth2 client credentials" .-> POL
POL --> LB
POL <--> RED
LB --> FDRY
LB --> ANTH
LB --> OSS
POL -- token metrics, prompt logs --> MON
CAT -. "backend + policy config" .-> gw
TEN -. "subscriptions, quotas" .-> gw
MON --> COST
A4 -. "grounding data" .-> SRCH
이 다이어그램에서 두 가지 속성이 하중을 받친다. 첫째, 모델 레이어로 들어가는 모든 화살표는 API Management 내부에서 출발한다. 즉 Foundry 리소스의 네트워크 규칙이 그 외의 모든 것을 거부한다는 뜻이다. 게이트웨이는 권고가 아니라, 경로가 존재하는 유일한 길이다. 둘째, 컨트롤 플레인은 구성을 게이트웨이에 써 넣고 텔레메트리를 Azure Monitor에서 읽어 오지만, 요청 경로 위에는 결코 앉지 않는다. 한낮에도 재배포할 수 있다.
스택 한눈에 보기
열 편이 다루는 것들을 여기서 미리 보여, 시리즈의 모양이 이 지점에서부터 보이게 한다. 인프라는 Terraform 코드로 만들되, Bicep과 ARM과의 비교는 당연한 것으로 치워 버리지 않고 2부에서 정직하게 다룬다. 컨트롤 플레인은 Docker 이미지와 AKS. 파이프라인, 버저닝, 릴리스 관리는 Azure DevOps. 로직이 사는 곳은 모두 Python이다. Microsoft Entra ID와 OAuth2 client credentials를 쓰고, 레거시 호출자가 더 나은 방식을 쓸 수 없는 곳에는 API 키를 쓴다. 검색에는 Azure AI Search와 전용 벡터 데이터베이스를 두고, 선언이 아니라 비교로 다룬다. 시맨틱 캐싱은 Azure Managed Redis. 텔레메트리는 Azure Monitor와 Application Insights, 그 옆에 LangSmith와 Openlayer의 LLM 특화 관측 가능성, 그리고 데이터 사이언스 팀이 이미 살고 있는 곳에는 Dataiku. 오케스트레이션은 프레임워크가 제값을 하는 그 한 편에서 LangChain을 쓰고, 제값을 못 하는 편들도 그대로 보여준다. 스트리밍은 server-sent events로 하고, 세션이 정말로 양방향인 곳에는 WebSockets를, 지금 당장 답이 필요 없는 모든 것에는 메시지 큐를 쓴다.
열 편의 순서는 이렇다. 게이트웨이를 세워야 하는 이유, Terraform 대 Bicep과 ARM, 프로바이더 추상화와 스트리밍, 비동기와 이벤트 기반 작업, 아이덴티티와 쿼터와 차지백, 시맨틱 캐싱, Azure AI Search 대 실제 벡터 데이터베이스의 검색, 게이트웨이 위의 오케스트레이션, Azure DevOps에서의 CI/CD와 모델 라이프사이클, 그리고 AI 거버넌스를 포함한 관측 가능성이다.
완성된 모습
마지막 편은 다시 이 항목들로 돌아온다. 앞서 정리한 잡무 목록의 네 숫자를 측정 가능하게 만든 것이다.
- 모든 프로덕트 오너가 이번 달 자신의 토큰 지출을, 발생 후 하루 안에, 플랫폼팀에 묻지 않고 볼 수 있다.
- 어떤 애플리케이션도 장기 유효한 모델 자격 증명을 보유하지 않는다. 한 팀의 접근을 회수하는 일은 그 팀 앱 설정을 고치는 것이 아니라 테넌트 레지스트리의 구성 변경이다.
- 모델 퇴역 공지는 조사가 아니라 쿼리 하나로 끝난다. 지난 30일 동안 어느 테넌트가 그 배포로 해석되었는지 카탈로그가 이미 알고 있다.
- 한 테넌트가 다른 테넌트의 쿼터를 소진할 수 없으며, 위의 429 인시던트를 게이트웨이에 대한 부하 테스트로 재연해 검증한다.
- 게이트웨이가 더하는 지연의 중앙값은 캐시되지 않은 호출 기준 95퍼센타일에서 60밀리초 아래를 유지하고, 시맨틱 캐시 히트는 모델 호출의 몇 분의 일에 해당하는 시간에 반환된다.
첫날부터 지켜봐야 할 실패 모드
세 가지이고, Terraform을 한 줄이라도 쓰기 전에 이름 붙여 둘 가치가 있다. 게이트웨이는 단일 장애점이 된다. 유일한 경로가 되는 순간 그렇게 되는데, 그것이 애초의 목적이므로, 게이트웨이의 가용성 목표는 그 뒤에 있는 가장 까다로운 애플리케이션보다 높아야 하고, 배포는 첫 인시던트 이후가 아니라 첫 apply부터 존 다중화여야 한다. 정책 스프롤은 조용히 도착한다. 정책 XML은 코드이고, 모든 요청마다 실행되며, 아무도 리뷰하지 않는 곳에서 작성되기 쉽다. 정책은 플랫폼의 나머지와 함께 버전 관리에 속하고, 파이프라인으로 적용되어야 하며, 포털에서 직접 편집해서는 안 된다. 그리고 우회 경로는 다른 모든 것을 무력화한다. 단 한 팀이 Foundry 엔드포인트로 가는 직접 키를 계속 갖고 있으면 모든 귀속 수치와 모든 쿼터 보장이 근사치가 되기 때문이다. 이것은 정책 문서가 아니라 네트워크 규칙과 알림으로 해결할 일이다.
다음으로 읽을 글
- 2부, Terraform인가, Bicep인가, ARM인가, 위의 아키텍처가 HCL이 되는 편으로, 티어 결정, 프로덕션을 움직이는 모델 배포 기본값, 그리고 state 레이아웃을 다룬다.
- Why Platform Teams End Up Building LLM Gateways, 이 시리즈가 실제 구축으로 바꾸어 가는 더 짧은 논증이며, Azure가 아니라 AWS 쪽에서 본 이야기다.
- FinOps Budget Alerts with Terraform (ercan.cloud), 모델이 등장하기 전의 똑같은 귀속 문제를 예산과 알림으로 푼 이야기다.
이런 플랫폼을 대규모로 운영할 때의 인프라와 플랫폼 쪽 이야기는 ercan.cloud에, 허브는 ercanermis.com에 있다.
참고 자료
- AI gateway capabilities in Azure API Management
- Azure API Management policy reference: llm-token-limit
- Azure API Management policy reference: llm-semantic-cache-store
- Create and manage a unified model API (preview)
- Azure OpenAI Provisioned Throughput Units
- RFC 6749, The OAuth 2.0 Authorization Framework
- Azure-Samples/ai-gateway, AI gateway capability labs
Ercan의 다른 글
같은 저자, 다른 영역의 사이트 두 개.