multi-llm-routing-pattern
Skill0 starsChanged 6 months agoMITView on GitHub
여러 LLM 백엔드(vLLM, OpenAI, TGI 등)를 단일 게이트웨이에서 라우팅하는 검증된 패턴. 사용 시점 — "모델 라우팅", "upstream_map", "fallback 모델", "weighted routing", "사용자별 모델", "플랜별 LLM", "모델 ID 매핑". 5 패턴 (정적 매핑, weighted, fallback, 사용자/플랜별, A/B test) + GEM-LLM 검증.
- Reads credentials
In this repository61 other files it gives its agents.
- api-contract-testing-patternSkill
- api-key-lifecycle-patternSkill
- api-route-consistency-patternSkill
- bash-cli-best-practicesSkill
- bilingual-book-authoringSkill
- blue-green-deployment-patternSkill
- book-builderSkill
- bulk-user-onboarding-patternSkill
- cicd-github-actions-patternSkill
- claude-code-skill-authoringSkill
- cloudflare-tunnel-setupSkill
- cloudflare-tunnel-ssh-access-patternSkill
- concurrent-load-testing-patternSkill
- coverage-instrumentation-patternSkill
- dependency-vulnerability-fixSkill
- deployment-checklistSkill
- developer-onboarding-doc-patternSkill
- env-isolation-patternSkill
- exam-systemSkill
- fastapi-async-patternsSkill
- fastapi-gateway-patternSkill
- gem-llm-admin-cliSkill
- gem-llm-build-docsSkill
- gem-llm-cli-clientSkill
- gem-llm-cloudflare-tunnelSkill
- gem-llm-debug-mcpSkill
- gem-llm-deploy-vllmSkill
- gem-llm-gateway-debugSkill
- gem-llm-load-testSkill
- gem-llm-overviewSkill
- gem-llm-review-promptSkill
- gem-llm-supervisorSkill
- gem-llm-test-inferenceSkill
- gem-llm-troubleshootingSkill
- gem-llm-vllm-debugSkill
- html-static-dashboard-patternSkill
- k8s-cron-alternativesSkill
- k8s-pod-autostartSkill
- korean-tech-blog-authoringSkill
- llm-eval-multi-modelSkill
- llm-serving-performance-tuningSkill
- md-raid-deadlock-recoverySkill
- mermaid-diagram-authoringSkill
- multi-agent-autonomous-loop-patternSkill
- multi-agent-git-collaboration-patternSkill
- multi-agent-orchestratorSkill
- observability-bundleSkill
- pandoc-bilingual-buildSkill
- playbook-authoring-patternSkill
- pod-process-autostart-patternSkill
- postgres-migration-from-sqliteSkill
- production-postmortem-patternSkill
- project-bootstrapSkill
- prometheus-fastapi-metricsSkill
- pytest-fastapi-patternSkill
- quota-rate-limit-patternSkill
- shell-cli-dispatch-patternSkill
- sqlite-wal-safe-opsSkill
- subagent-prompt-engineering-patternSkill
- vllm-bootstrapSkill
- The first 60 shown.
The file
Files
multi-llm-routing-pattern
여러 LLM 백엔드를 단일 OpenAI 호환 게이트웨이 뒤에 두고 클라이언트 요청의 model 파라미터(또는 사용자/플랜)로 라우팅하는 패턴. GEM-LLM Gateway 가 qwen2.5-coder-32b → :8001, qwen3-coder-30b → :8002 정적 매핑으로 28일 + 100 동접 부하를 통과한 사례를 일반화했다. 정적 매핑에서 시작해 weighted / fallback / 사용자별 / A/B canary 까지 단계적으로 확장 가능.
1. 사용 시점
- "vLLM 모델을 2개 이상 띄웠다, 어떻게 한 endpoint 로 라우팅?"
upstream_map같은 모델 ID → URL 매핑 설계- "모델 한 대가 죽으면 다른 모델로 fallback 하고 싶다"
- "free 사용자는 작은 모델, pro 는 큰 모델"
- A/B canary (5% 트래픽만 새 모델로)
- 두 vLLM instance 에 weighted load balancing
- 외부 provider (OpenAI, Anthropic) 와 자체 vLLM 혼합
라우팅이 한 모델 = 한 URL 인 prototype 에는 과한 패턴. 모델 ≥ 2 개거나 fallback / 플랜별 분기가 필요하면 이 패턴.
2. 5 라우팅 패턴
(1) 정적 매핑 (가장 흔함, GEM-LLM 사례)
upstream_map = {
"qwen2.5-coder-32b": "http://localhost:8001",
"qwen3-coder-30b": "http://localhost:8002",
}- key = OpenAI API 의
model파라미터 그대로 - value = 백엔드 URL (
/v1/chat/completions가 붙는 base) - 단순, 디버그 쉬움, GEM-LLM 1차 운영의 기본형
(2) Weighted routing (load balancing)
import random
upstream_map = {
"qwen2.5-coder-32b": [
("http://vllm-1:8001", 0.7),
("http://vllm-2:8001", 0.3),
],
}
def pick(model: str) -> str:
candidates, weights = zip(*upstream_map[model])
return random.choices(candidates, weights=weights, k=1)[0]- 두 vLLM instance 에 7:3 분산 (GPU 1 trafico 가 2 보다 큰 경우)
- 사용자 sticky 가 필요 없을 때만 — 같은 user 가 매 요청 다른 백엔드 → 캐시 miss
(3) Fallback chain
fallback_chain = {
"qwen3-coder-30b": [
"http://localhost:8002", # primary
"http://localhost:8003", # fallback 1 (warm spare)
"openai-gpt-4-turbo", # fallback 2 (외부 provider)
],
}흐름: primary 502/timeout → 다음 url 시도. 4xx (400/401/422) 는 fallback 안 함 (클라이언트 잘못).
(4) 사용자/플랜별 라우팅
def route(model: str, user_plan: str) -> str:
if user_plan == "free":
return "http://localhost:8001" # 32B (작은 모델)
elif user_plan == "pro":
return "http://localhost:8002" # 30B v3
elif user_plan == "enterprise":
return "http://gpt-4-proxy:9000" # 외부 best
raise ValueError(f"unknown_plan: {user_plan}")- DB 의
users.plan컬럼 → 라우팅 결정 model파라미터 무시 또는 화이트리스트 강제
(5) A/B test (canary)
def route(user_id: str) -> str:
bucket = hash(user_id) % 100
if bucket < 5: # 5% canary
return "http://vllm-new:8001" # 신모델
return "http://vllm-stable:8001" # 기존hash(user_id)로 sticky (같은 사용자 항상 같은 bucket)- canary 비율 5% 권장 — 50% 는 위험 (롤백 비용 큼)
- prom metric 으로 canary 응답 시간/에러율 비교 → 안전 시 비율 증가
3. 구현 — FastAPI Gateway
# config.py
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
vllm_32b_url: str = "http://localhost:8001"
vllm_30b_url: str = "http://localhost:8002"
@property
def upstream_map(self) -> dict[str, str]:
return {
"qwen2.5-coder-32b": self.vllm_32b_url,
"qwen3-coder-30b": self.vllm_30b_url,
}# proxy.py
def resolve_upstream(model: str) -> str:
settings = get_settings()
if model not in settings.upstream_map:
raise HTTPException(400, f"unknown_model: {model}")
return settings.upstream_map[model]라우팅 로직은 proxy 진입 직후 한 곳. 인증/quota 통과 → resolve_upstream(payload.model) → httpx 로 forward.
4. 새 모델 추가 워크플로
- vLLM 새 모델 띄움 — 새 포트 (예:
8003) .env또는config.py에 URL 추가 —vllm_70b_url=http://localhost:8003upstream_map에 모델 ID → URL 매핑 한 줄routes/models.py의served_model_names에도 추가 (/v1/models응답)- Gateway 재시작
원자성 — 위 1~5 가 atomic 이어야 함. 3 만 추가하고 4 누락 → /v1/models 에서는 안 보이지만 chat 은 됨 (UI 혼란).
5. fallback 구현 (proxy.py)
import httpx
class UpstreamError(Exception): ...
async def chat_with_fallback(payload: dict, model: str) -> dict:
chain = fallback_chain.get(model, [resolve_upstream(model)])
last_err: Exception | None = None
for url in chain:
try:
return await call_upstream(url, payload)
except httpx.HTTPStatusError as e:
if e.response.status_code < 500:
raise # 4xx 는 즉시 반환 (클라이언트 잘못)
last_err = e
continue # 5xx 는 fallback
except (httpx.RequestError, httpx.TimeoutException) as e:
last_err = e
continue # network/timeout → fallback
raise UpstreamError(f"all_fallbacks_exhausted: {last_err}")원칙:
- 4xx 는 fallback 안 함 — 400/401/422 는 클라이언트 입력이 잘못된 것. fallback 해도 같은 결과.
- 5xx 와 network error 만 fallback — 502/503/timeout/connection refused.
- 마지막 에러 보존 — 모두 실패하면 마지막 원인 메시지 노출 (디버그용).
6. metrics 통합
from prometheus_client import Counter
gateway_routing_decisions_total = Counter(
"gateway_routing_decisions_total",
"Routing decisions by model and result",
["model", "decision"], # decision: primary | fallback_1 | fallback_2 | exhausted
)
# 사용
gateway_routing_decisions_total.labels(model=model, decision="primary").inc()라벨 cardinality 주의 — user_id 를 라벨에 넣으면 폭발. model + decision 만 (수백 라벨 이내).
7. 흔한 함정
- 모델 ID typo —
gem-31bvsqwen2.5-coder-32b(case 11 마이그레이션).served_model_names와upstream_mapkey 가 완전히 동일 해야 함. 테스트로 강제:assert set(served_model_names) == set(upstream_map.keys()). - fallback chain 무한 루프 — 모든 url 이 unreachable 인데 retry 하면 client 가 timeout 까지 대기. chain 길이 ≤ 3 + 각 호출 timeout 30s.
- weighted routing 의 hash 일관성 —
random.choices는 매 요청 새로 → sticky session 깨짐. 사용자 sticky 가 필요하면hash(user_id) % total_weight로 결정. - A/B canary 비율 폭주 — 5% 권장. 50% 는 롤백 시 절반의 사용자 영향 → 위험. 단계적 5% → 10% → 25% → 100%.
- new model 등록 시 served_model_names 누락 —
/v1/models가 거짓말. 4번 워크플로 atomic 으로 강제. model=null또는 빈 문자열 — pydantic 으로model: str = Field(min_length=1). 안 그러면KeyError500 응답.- upstream URL trailing slash 불일치 —
http://x:8001vshttp://x:8001/→ httpx 에서 path 합칠 때//v1/...발생. config 단계에서.rstrip("/")표준화.
8. GEM-LLM 검증
- 정적 매핑 5+ 라운드 — 28일 운영 + 100 동접 부하 (
gem-llm-load-test) 통과 - 50:50 라우팅 — 두 모델 동시 호출에서 응답 시간 분포 균등
- 신규 모델 추가 atomic commit —
config.py(URL) +routes/models.py(served_model_names) 를 한 commit 으로 (case 11 typo 사고 이후 정책) - fallback 미적용 (의도) — 30B 한 대가 죽으면 알람 → 수동 복구. 자동 fallback 은 원인 은폐 위험이 커서 GEM-LLM 은 미채택. 외부 SaaS 게이트웨이는 fallback 권장.
9. 관련 skill
fastapi-gateway-pattern— 본 패턴이 들어가는 5계층 게이트웨이 (라우팅 = proxy 계층)prometheus-fastapi-metrics—gateway_routing_decisions_total같은 라우팅 메트릭vllm-bootstrap— 백엔드 모델을 새로 띄울 때 (4번 워크플로 step 1)quota-rate-limit-pattern— 플랜별 라우팅 시 RPM/daily 한도와 짝blue-green-deployment-pattern— A/B canary 의 cutover 전략 (점진 전환)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

