Skip to content

모델 라우팅: 커스텀 매핑, 와일드카드 우선순위 및 프리셋 전략

클라이언트에서 작성한 model은 Antigravity Tools가 최종적으로 업스트림에 요청할 때 사용하는 "물리 모델"과 반드시 같지는 않습니다. 모델 라우팅은 하는 일이 간단합니다: "대외적으로 안정적인 모델 이름"을 "내부적으로 실제로 사용하는 모델"로 매핑하고, 결과를 응답 헤더 X-Mapped-Model에 넣어, 예상 경로로 갔는지 확인하기 쉽게 합니다.

이 수업을 마치면 할 수 있는 것

  • UI에서 proxy.custom_mapping을 구성할 수 있습니다(정확 매핑 + 와일드카드 매핑)
  • 한 규칙이 어떻게 일치하는지 명확히 설명할 수 있습니다(정확 > 와일드카드 > 기본 매핑)
  • 원클릭으로 프리셋 규칙을 적용하여, 빠르게 OpenAI/Claude 클라이언트와 호환할 수 있습니다
  • curl -i를 사용하여 X-Mapped-Model을 확인하고, "내 생각대로 라우팅하지 않는 이유"를 찾을 수 있습니다

현재의 문제점

  • 클라이언트가 항상 gpt-4o를 작성하도록 원하지만, 업스트림은 안정적으로 특정 Gemini 모델로 떨어지기를 원합니다
  • 버전화된 모델 이름이 많은데(예: gpt-4-xxxx), 매번 수동으로 매핑을 추가하고 싶지 않습니다
  • 요청이 성공했지만, 실제로 어떤 물리 모델이 실행되는지 확실하지 않습니다

언제 이 방법을 사용해야 할까요?

  • 팀에 "고정된 대외 모델 집합"을 제공하고 싶으며, 업스트림 모델 변화를 차단하고 싶습니다
  • 다양한 OpenAI/Claude 모델 이름을 소수의 고성능 모델로 통합 라우팅하고 싶습니다
  • 401/429/0 토큰을 문제 해결할 때, 매핑된 실제 모델을 확인하고 싶습니다

🎒 시작 전 준비

이 수업의 두 가지 핵심 키워드

  • custom_mapping: "커스텀 규칙 테이블"입니다. 키는 클라이언트가 전달한 모델 이름(또는 와일드카드 pattern), 값은 최종적으로 사용할 모델 이름입니다(출처: src/types/config.ts).
  • 와일드카드 *: 모델 이름을 일괄 일치시키는 데 사용됩니다(예: gpt-4*). 일치 구현은 대소문자 구분입니다(출처: src-tauri/src/proxy/common/model_mapping.rs).

핵심 아이디어

백엔드는 요청을 처리할 때, 먼저 mapped_model을 계산합니다:

  1. 먼저 custom_mapping정확히 일치하는 것이 있는지 확인(key가 model과 완전히 같음)
  2. 다음 와일드카드 일치를 시도: "*가 아닌 문자가 더 많은" 규칙을 선택합니다(더 구체적인 규칙 우선)
  3. 모두 일치하지 않으면 시스템 기본 매핑을 사용합니다(예: 일부 OpenAI/Claude 모델 별칭을 내부 모델로 매핑)

mapped_model은 응답 헤더 X-Mapped-Model에 작성됩니다(최소한 OpenAI 핸들러는 이렇게 합니다). 이것을 사용하면 "내가 작성한 model이 결국 무엇이 되었는지"를 확인할 수 있습니다.

핫 리로드 의미(재시작 불필요)

리버스 프록시 서비스가 실행 중일 때, 프론트엔드가 update_model_mapping을 호출하면 백엔드가 즉시 custom_mapping을 메모리의 RwLock에 쓰고, 동시에 영구 구성에도 저장합니다(출처: src-tauri/src/commands/proxy.rs; src-tauri/src/proxy/server.rs).

따라해 보세요

1단계: API Proxy 페이지에서 "모델 라우팅" 카드 찾기

왜 필요한가요? 모델 라우팅 구성 진입점은 UI에 있습니다. 구성 파일을 수동으로 편집할 필요가 없습니다.

Antigravity Tools → API Proxy 페이지를 열고, 아래로 스크롤합니다.

보아야 할 것: 제목이 "모델 라우팅 센터"와 유사한 카드가 나타나고, 우측 상단에 두 개의 버튼이 있습니다: "프리셋 매핑 적용"과 "매핑 초기화"(출처: src/pages/ApiProxy.tsx).

2단계: "정확 매핑" 하나 추가(가장 제어 가능)

왜 필요한가요? 정확 매핑의 우선순위가 가장 높습니다. "이 모델 이름은 반드시 이 물리 모델로 떨어지게 하고 싶다"는 경우에 적합합니다.

"매핑 추가" 영역에서:

  • Original에 대외적으로 공개할 모델 이름을 입력합니다. 예: gpt-4o
  • Target에서 드롭다운으로 타겟 모델을 선택합니다. 예: gemini-3-flash

Add를 클릭합니다.

보아야 할 것: 매핑 목록에 gpt-4o -> gemini-3-flash가 나타나고, 저장 성공 프롬프트가 팝업됩니다.

3단계: "와일드카드 매핑" 하나 추가(대량 커버)

왜 필요한가요? 버전화된 모델 이름이 많을 때(예: gpt-4-turbo, gpt-4-1106-preview), 와일드카드를 사용하면 많은 중복 구성을 줄일 수 있습니다.

매핑을 하나 더 추가합니다:

  • Original: gpt-4*
  • Target: gemini-3-pro-high

보아야 할 것: 목록에 gpt-4* -> gemini-3-pro-high가 나타납니다.

규칙 우선순위의 "함정"

gpt-4o가 정확 규칙 gpt-4o와 와일드카드 규칙 gpt-4*를 동시에 만족할 때, 백엔드는 먼저 정확 일치를 거칩니다(출처: src-tauri/src/proxy/common/model_mapping.rs).

4단계: 원클릭으로 프리셋 규칙 적용(빠르게 호환)

왜 필요한가요? 주요 목적이 "빠르게 일반적인 OpenAI/Claude 모델 이름에 적응하는 것"이라면, 프리셋이 한 번에 일괄 와일드카드 규칙을 채워줄 수 있습니다.

"프리셋 매핑 적용"을 클릭합니다.

보아야 할 것: 목록에 여러 규칙이 추가되며, 다음과 유사한 것이 포함됩니다(출처: src/pages/ApiProxy.tsx):

json
{
  "gpt-4*": "gemini-3-pro-high",
  "gpt-4o*": "gemini-3-flash",
  "gpt-3.5*": "gemini-2.5-flash",
  "o1-*": "gemini-3-pro-high",
  "o3-*": "gemini-3-pro-high",
  "claude-3-5-sonnet-*": "claude-sonnet-4-5",
  "claude-3-opus-*": "claude-opus-4-5-thinking",
  "claude-opus-4-*": "claude-opus-4-5-thinking",
  "claude-haiku-*": "gemini-2.5-flash",
  "claude-3-haiku-*": "gemini-2.5-flash"
}

5단계: X-Mapped-Model을 사용하여 라우팅 적용 여부 확인

왜 필요한가요? "구성이 작성되었습니다"를 확인하고 싶을 뿐만 아니라, "요청이 실제로 이 규칙에 따라 진행되었는지"도 확인하고 싶습니다. 가장 쉬운 방법은 X-Mapped-Model을 보는 것입니다.

bash
curl -i http://127.0.0.1:8045/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "hi"}]
  }'
powershell
$resp = Invoke-WebRequest "http://127.0.0.1:8045/v1/chat/completions" -Method Post -ContentType "application/json" -Body '{
  "model": "gpt-4o",
  "messages": [{"role": "user", "content": "hi"}]
}'
$resp.Headers["X-Mapped-Model"]

보아야 할 것: 응답 헤더에 X-Mapped-Model: ...가 있습니다. 2단계에서 gpt-4ogemini-3-flash로 정확 매핑했다면, 여기서 해당 값을 볼 수 있습니다(응답 헤더 작성은 src-tauri/src/proxy/handlers/openai.rs 참조).

6단계: "순수 기본 매핑"으로 돌아가려면, custom_mapping 초기화

왜 필요한가요? 문제 해결할 때, 종종 "커스텀 규칙의 영향"을 먼저 제외하고 싶습니다. custom_mapping을 비우는 것이 가장 직접적인 롤백 방법입니다.

"매핑 초기화"를 클릭합니다.

보아야 할 것: 매핑 목록이 비어 있습니다. 이후 요청에서 커스텀 규칙에 일치하지 않으면 시스템 기본 매핑을 사용합니다(출처: src/pages/ApiProxy.tsx; src-tauri/src/proxy/common/model_mapping.rs).

체크포인트 ✅

  • [ ] UI에서 custom_mapping 규칙을 추가/삭제할 수 있습니다
  • [ ] 정확 규칙이 왜 와일드카드 규칙보다 우선하는지 설명할 수 있습니다
  • [ ] curl -i 또는 PowerShell을 사용하여 X-Mapped-Model을 읽을 수 있습니다

일반적인 실수

시나리오할 수 있는 것(❌)추천 방법(✓)
와일드카드가 적용되지 않음GPT-4*를 작성하여 gpt-4-turbo를 일치시키기를 기대함소문자 gpt-4* 사용; 백엔드 와일드카드 일치는 대소문자 구분임
두 와일드카드가 모두 일치함동시에 gpt-*gpt-4*를 작성하고, 어떤 규칙을 따를지 확실하지 않음더 구체적인 규칙이 더 "길게" 만들어, *가 아닌 문자가 더 많게 함
규칙이 맞는 것 같지만 변하지 않음응답 body만 보고, 응답 헤더를 보지 않음curl -i를 사용하여 X-Mapped-Model을 확인합니다(이것은 백엔드가 명시적으로 반환한 결과임)
두 규칙이 "동일하게 구체적임"두 와일드카드 규칙을 작성했고, *가 아닌 문자 수가 같음이러한 구성을 피하세요; 소스 코드 주석은 이 경우 결과가 HashMap 순회 순서에 의존하며 불안정할 수 있다고 설명합니다(출처: src-tauri/src/proxy/common/model_mapping.rs)

이 수업 요약

  • proxy.custom_mapping은 "대외 모델 이름 → 물리 모델"을 제어하는 주 진입점입니다
  • 백엔드 라우팅 우선순위는: 정확 일치 > 와일드카드 일치(더 구체적인 것 우선) > 시스템 기본 매핑
  • X-Mapped-Model은 가장 신뢰할 수 있는 검증 수단입니다. 문제 해결할 때 우선적으로 보세요

다음 수업 예고

다음 수업에서는 쿼터 거버넌스: Quota Protection + Smart Warmup의 조합 전술을 계속 살펴봅니다(해당 장: advanced-quota).


부록: 소스 코드 참조

클릭하여 소스 코드 위치 확인

업데이트 시간: 2026-01-23

기능파일 경로라인
구성 필드: proxy.custom_mapping(프론트엔드 타입)src/types/config.ts6-20
UI: 쓰기/초기화/프리셋(update_model_mapping 호출)src/pages/ApiProxy.tsx371-475
UI: 모델 라우팅 카드(프리셋 매핑 적용 / 매핑 초기화 / 목록 및 추가 양식)src/pages/ApiProxy.tsx1762-1931
백엔드 명령: 핫 리로드 및 custom_mapping 영구화src-tauri/src/commands/proxy.rs344-365
서버 상태: custom_mappingRwLock<HashMap<..>>로 저장src-tauri/src/proxy/server.rs16-53
라우팅 알고리즘: 정확 > 와일드카드(더 구체적인 것 우선) > 기본 매핑src-tauri/src/proxy/common/model_mapping.rs180-228
와일드카드 일치: 다중 * 지원, 대소문자 구분src-tauri/src/proxy/common/model_mapping.rs134-178
요청에서 mapped_model 계산(예: OpenAI 핸들러)src-tauri/src/proxy/handlers/openai.rs154-159
---------

핵심 함수:

  • resolve_model_route(original_model, custom_mapping): 모델 라우팅 주 진입점(src-tauri/src/proxy/common/model_mapping.rs 참조)