프로덕션 환경에서의 Multi-LLM 라우팅: 아무도 경고하지 않는 실패 모드들
요약
프로덕션 환경에서 Multi-LLM 라우팅을 구현할 때 발생하는 숨겨진 실패 모드와 비용/지연 시간 문제를 다룹니다. 단순한 토큰 비용 절감을 넘어 재라우팅 비용과 지연 시간 분포를 고려한 엔드 투 엔드 최적화의 중요성을 강조합니다.
핵심 포인트
- 재라우팅 시 발생하는 추가 호출 비용과 지연 시간(re-route tax)을 반드시 고려해야 함
- 단순 토큰 가격이 아닌 '성공한 작업당 비용'을 기준으로 라우팅을 최적화해야 함
- 지연 시간은 고정된 값이 아닌 분포로 이해하고 꼬리 지연 시간(tail latency)에 대비해야 함
- 실패한 요청에 대한 정밀한 계측(instrumentation)이 필수적임
프로덕션 환경에서의 Multi-LLM 라우팅: 아무도 경고하지 않는 실패 모드들
Multi-LLM 라우팅 (routing)의 제안은 깔끔합니다. 저렴한 요청은 저렴한 모델로, 어려운 요청은 강력한 모델로 라우팅하고, 제공업체(provider)에 문제가 생겼을 때를 대비한 폴백(fallback)을 유지하면, 품질을 유지하면서 작업당 비용을 낮출 수 있다는 것입니다. 저도 이를 구축해 보았습니다. 작동합니다. 하지만 실제 프로덕션 환경과 맞닥뜨려 살아남은 버전은 아키텍처 다이어그램에 있는 것과는 매우 다르게 생겼으며, 그 차이는 스스로를 알리지 않는 실패 모드(failure modes)들로 채워져 있습니다.
제가 이를 혹독하게 배운 시스템 중 하나는 실제 컴플라이언스(compliance)가 걸려 있는 KYC 파이프라인이었습니다. 그 빌드에서 모델을 선택하는 것은 쉬운 부분이었습니다. 진짜 엔지니어링은 라우팅 결정 주변의 모든 것이었습니다. 즉, 라우팅이 조용히 저하되고 있다는 것을 어떻게 아는지, 폴백이 지연 시간(latency)과 정확도 측면에서 실제로 어떤 비용을 초래하는지, 그리고 저렴한 모델의 성공과 우연히 유효해 보이는 텍스트를 반환한 저렴한 모델의 실패를 어떻게 구분하는지와 같은 것들입니다. 이것들이 바로 아무도 경고해주지 않는 부분들입니다.
더 많은 비용이 드는 비용 최적화
팀들이 가장 먼저 하는 일은 비용에 따라 라우팅하는 것입니다. 간단한 작업은 작은 모델로 보내고, 필요할 때만 상위 모델로 에스컬레이션(escalate)합니다. 스프레드시트상의 계산은 설득력이 있습니다.
하지만 프로덕션에서의 계산은 다릅니다. 라우팅은 공짜가 아니며, 재라우팅(re-routing)은 비용이 많이 들기 때문입니다. 작은 모델이 당신이 잡아낼 수 있는 방식으로 요청을 잘못 처리하면, 대형 모델에서 다시 실행하게 됩니다. 이제 그 요청은 두 번의 호출 비용에 두 번의 왕복 지연 시간(latency), 그리고 탐지 단계(detection step)에 드는 비용까지 모두 소모하게 됩니다. 라우팅 임계값(threshold)을 약간만 너무 공격적으로 설정해도, 트래픽의 상당 부분에 대해 저렴한 모델과 비싼 모델 모두에 비용을 지불하면서, 차라리 강력한 모델을 직접 사용했을 때보다 더 나쁜 지연 시간을 제공하게 된다는 사실을 깨닫게 될 것입니다.
함정은 토큰당 가격(per-token price)은 눈에 보이지만, 재라우팅 비용(re-route tax)은 보이지 않는다는 점입니다. 성공한 요청들에 대해서는 더 저렴한 청구서를 보게 됩니다. 하지만 별도의 계측(instrumentation)을 하지 않았다면, 실패한 요청들에서 발생하는 복합적인 비용은 자동으로 나타나지 않습니다. 대부분의 팀은 이를 수행하지 않으며, 따라서 자신의 단점을 숨기고 있는 수치를 향해 최적화를 진행하게 됩니다.
해결책은 비용 기반 라우팅(cost routing)을 포기하는 것이 아닙니다. 재시도(retries)와 에스컬레이션(escalations)을 포함하여, 엔드 투 엔드(end-to-end)로 '성공한 작업당 비용(cost-per-successful-task)'을 측정하고 이를 기준으로 라우팅하는 것입니다. 저렴한 모델은 해당 모델이 얼마나 자주 실패하는지를 고려한 후에도 승리할 때만 유효합니다.
지연 시간(Latency)은 숫자가 아니라 분포입니다
두 번째 실패 모드는 제공자(provider)의 지연 시간을 한 번 조회하면 끝나는 속성으로 취급하는 것입니다. 지연 시간은 그렇지 않습니다. 그것은 제공자의 부하, 시간대, 컨텍스트(context)의 길이, 그리고 용량이 부족할 때 우선순위가 밀리는 티어(tier)에 속해 있는지 여부에 따라 움직이는 분포(distribution)입니다.
중앙값 지연 시간(median latency)에 맞춰 튜닝된 라우터는 제공자의 꼬리 지연 시간(tail latency)이 폭발하기 직전까지는 즐겁게 라우팅을 수행하겠지만, 그 직후에는 한 시간 전의 중앙값이 괜찮았다는 이유로 당신이 선택한 느린 경로 때문에 p99 사용자가 기다리게 됩니다. 만약 그 위에 폴백(fallback)을 계층화했다면, 타임아웃(timeout)에 의해 트리거되는 폴백은 지연 시간을 제거하는 것이 아니라 오히려 추가하게 됩니다. 사용자는 첫 번째 모델이 타임아웃될 때까지 기다린 다음, 두 번째 모델을 위해 다시 처음부터 기다려야 합니다.
당신이 실제로 원하는 것은 지속적으로 측정되는 경로별 지연 시간 예산(latency budgets)이며, 라우터는 정적 설정(static config)이 아닌 최근의 꼬리 동작(tail behavior)을 바탕으로 결정을 내려야 합니다. 또한 폴백 정책은 "타임아웃 시 폴백"이 "때로는 두 번의 지연 시간을 모두 지불해야 함"을 의미한다는 사실을 정직하게 반영해야 합니다. 실시간 경로(real-time path)의 경우, 이는 종종 잘못된 트레이드오프(trade-off)가 되며, 차라리 처음부터 더 신뢰할 수 있는 제공자로 라우팅하여 더 높은 하한선(floor)을 받아들이는 것이 더 타이트한 상한선(ceiling)을 확보하는 데 유리합니다.
Dean과 Barroso의 _The Tail at Scale_은 이러한 전략의 더 날카로운 버전을 제시합니다. 폴백(fallback)을 실행하기 위해 하드 타임아웃(hard timeout)이 발생할 때까지 기다리는 대신, 요청이 이미 대부분의 요청보다 오래 실행된 시점(예: p90) 근처에서 조기에 폴백을 실행하고, 먼저 돌아오는 응답을 채택하는 방식입니다. 더 타이트한 테일(tail)을 확보하기 위해 추가적인 요청 비용을 지불하는 것입니다. 이는 두 번째 호출이 절약되는 지연 시간(latency)에 비해 진정으로 저렴한 경우에만 효과가 있으므로, 모든 곳에 적용하는 기본 설정이 아니라 핫 패스(hot path)를 위한 도구로 사용해야 합니다. 하지만 지연 시간 분포가 이미 알려주고 있는 사실을 타임아웃이 인정할 때까지 느린 요청을 붙잡고 있는 것보다는 훨씬 낫습니다.
평가 기반 라우팅(Eval-driven routing), 또는 느낌에 의존하는 라우팅(routing on vibes)
시스템과 데모를 구분 짓는 지점이 바로 여기입니다. 어떤 모델이 어떤 요청을 처리할지 어떻게 결정하시나요? 대부분의 초기 라우터는 키워드 매칭, 토큰 수, 또는 "코드 질문은 여기로 보낸다"와 같은 수동으로 작성된 규칙 등 휴리스틱(heuristics)에 의존합니다. 그러한 규칙은 첫날 내린 추측을 인코딩한 것이며, 결코 재검토되지 않습니다. 트래픽이 변하는 순간 규칙은 어긋나기 시작하며, 당신은 그것이 어긋났다는 사실조차 알 방법이 없습니다.
평가 기반 라우팅(Eval-driven routing)은 작업에 대한 측정 가능한 성공 정의를 가지고 있으며, 대표적인 트래픽을 통해 모든 제공자를 해당 정의에 따라 점수화하고, 라우팅 결정이 그 점수들에 따라 이루어지는 것을 의미합니다. 새로운 모델을 온보딩할 때, 그것이 더 나은지 추측하는 것이 아니라 평가(eval)를 실행하여 확인합니다. 제공자가 안정적인 이름 뒤에서 몰래 모델을 변경하더라도, 당신의 평가는 사용자가 알아차리기 전에 성능 저하(regression)를 잡아냅니다.
중요한 모든 작업에서 이는 타협할 수 없는 사항입니다. KYC(고객 확인 절차) 파이프라인에서 "모델이 확신에 찬 답변을 반환했다"와 "모델이 정확한 답변을 반환했다"는 완전히 다른 사건이며, 그 사이의 간극에 컴플라이언스(compliance) 리스크가 존재합니다. 이 두 가지를 구분할 방법 없이는 책임감 있는 라우팅을 할 수 없습니다. 그리고 그 방법은 파일럿 단계에서 한 번 실행한 벤치마크가 아니라, 지속적으로 실행되는 평가(evaluation)입니다.
HTTP 200을 반환하는 실패들
당신의 알림(alerting) 시스템은 예외(exception)와 타임아웃(timeout)을 감시합니다. 하지만 가장 큰 비용을 초래하는 라우팅 실패들은 깨끗하고 잘 구성된(well-formed) 본문과 함께 HTTP 200을 반환하며, 그 어떤 알림도 울리지 않습니다.
한 제공업체의 성능이 저하되어 여전히 파싱(parsing)은 가능하지만 더 짧고 성의 없는 완료(completion)를 반환하기 시작할 수 있습니다. 혹은 모델 업데이트로 인해 출력 형식이 미세하게 변경되어, 다운스트림 추출(downstream extraction) 과정에서 특정 필드가 조용히 누락될 수도 있습니다. 또는 폴백(fallback)이 작동하여 백업 모델이 실제 작업에 훨씬 뒤떨어지는 성능을 보임에도 불구하고, 모든 응답이 잘 구성된 형태로 돌아오기 때문에 아무런 경보도 울리지 않을 수 있습니다. 이것들은 침묵하는 실패(silent failures)이며, 오직 에러와 타임아웃만을 감시하는 라우터는 이 모든 것에 눈이 멀어 있습니다.
Multi-LLM 라우팅을 위한 관측성(Observability)은 가동 시간(uptime) 그 이상을 넘어서야 합니다. 라우트별로 평가(evals)를 통한 품질 점수(quality scores), 폴백 활성화율, 성공적인 작업당 비용(cost-per-successful-task), 그리고 시간에 따른 출력의 형태(shape of the outputs)를 추적해야 합니다. 폴백 비율의 상승은 기본 제공업체의 성능이 저하되고 있다는 선행 지표입니다. 에러율은 0을 유지하면서 품질 점수가 하락하는 것은 침묵하는 퇴보(silent regression)의 전형적인 징후입니다. 만약 이를 모니터링하고 있지 않다면, 고객을 통해 문제를 알게 될 것이며, 이는 가장 비용이 많이 드는 학습 방식이 될 것입니다.
이러한 직관은 1,000만 명의 사용자를 대상으로 99.9%의 가동 시간을 유지하는 결제 플랫폼을 운영하는 데서 직접적으로 얻은 것입니다. 그런 세상에서는 당신에게 페이지(page)를 보내는 실패가 오히려 운이 좋은 경우라는 것을 배우게 됩니다. 적어도 그 사실은 알고 있기 때문입니다. 데이터를 손상시키면서 조용히 성공을 반환하는 실패들이 가장 비용이 많이 드는 실패이며, Multi-LLM 시스템은 그러한 실패들로 가득 차 있습니다. 라우팅은 바로 그 실패들이 숨어 있는 곳입니다.
따라서 이러한 시스템을 구축한다면, 단 하나의 비용 임계값 (cost threshold)을 조정하기 전에 먼저 '조용한 실패 (silent failures)'를 측정할 수 있는 계측 (instrumentation) 체계를 갖추십시오. 토큰당 비용 (Cost-per-token)은 눈에 잘 보이는 수치입니다. 하지만 시스템이 실제로 제대로 작동하고 있는지를 알려주는 수치는 성공한 작업당 비용 (Cost-per-successful-task), 폴백 비율 (fallback rate), 그리고 일정한 에러율 내에서의 품질 드리프트 (quality drift)이며, 이 수치들은 의도적으로 구축해 나가야 하는 것들입니다. 라우팅 다이어그램 (routing diagram)은 오후 한나절이면 그릴 수 있는 부분입니다. 하지만 계측 (instrumentation)은 해당 시스템이 프로덕션 환경에서 한 달을 버텨낼 수 있을지를 결정하는 부분입니다.
출처
- Dean & Barroso, The Tail at Scale (Google Research) — 지연 시간 (latency)이 왜 분포 (distribution)인지, 왜 꼬리 부분의 동작 (tail behavior)이 사용자 대면 시스템을 지배하는지, 그리고 그 꼬리를 줄이기 위한 헤징 요청 (hedged-request) 기술에 대하여.
- OpenAI — Latency optimization — LLM 시스템에서 요청당 지연 시간 (per-request latency) 뒤에 숨겨진 레버 (levers)와 트레이드오프 (tradeoffs).
- OpenAI — Evals — 모델 선택 결정의 근거로서 측정 가능하고 반복 가능한 평가 (evaluations)를 구축하는 방법.
- OpenAI — Production best practices — 프로덕션 환경에서 LLM 호출을 실행하기 위한 폴백 (fallbacks), 재시도 (retries) 및 운영 가이드.
- Anthropic — Streaming Messages — 부분적/스트리밍 완료 (partial/streamed completions)가 성공적인 HTTP 응답을 통해 전달되는 방식, 그리고 형식은 올바르지만 품질이 저하된 출력 (well-formed-but-degraded output)이 숨어 있는 지점.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기