모델 변형 접미사: 설계 기록¶
모델 변형 접미사는 opt-in 방식의 요청별 선택 수단입니다. 클라이언트가 모델 이름 뒤에 :nitro, :floor, :thinking, :online을 붙이면 라우터가 그 요청 자체의 디스패치에 해당 선호를 적용합니다(이슈 #2405). 스위치를 켜지 않으면 아무것도 바뀌지 않습니다.
설정¶
proxy.variant_suffixes.enabled: true를 설정합니다. 기본값은 false입니다.
문법은 /v1/chat/completions에서만, 버퍼링과 스트리밍 모두에서 해석합니다. /v1/completions, /v1/responses, Anthropic Messages를 포함한 다른 인그레스는 기존 동작을 유지하며, 그 경로에서 접미사가 붙은 이름은 알 수 없는 모델입니다. 스위치는 즉시 재로드됩니다. 채팅 핸들러가 디스패치에 쓰는 것과 같은 설정 스냅숏에서 이름을 해석하기 때문입니다.
해석 순서¶
요청한 이름 전체를 먼저 해석하며, /v1/chat/completions가 이미 쓰는 계층을 그대로 따릅니다. 활성 백엔드의 model_configs에 선언된 ID나 별칭, 계층화된 모델 메타데이터 캐시, 설정된 models: 항목, 백엔드가 있는 라이브 카탈로그 항목 순서입니다. 이 해석이 실패한 경우에만 알려진 끝 접미사를 찾아 마지막 :에서 분리하고 베이스 ID를 해석합니다.
그 결과는 세 가지이며, 모두 테스트로 확인합니다.
- 백엔드가 실제로 서빙하는 이름은 그대로 해석됩니다. Ollama의
name:tag를 변형으로 잘못 읽지 않습니다. - 라우터가 해석할 수 없는 베이스에 붙은 접미사는 알 수 없는 모델로 남습니다. 오류는 지금처럼 요청한 이름 전체를 가리킵니다.
- 알 수 없는 끝 단어는 절대 분리하지 않습니다.
base:cheap과base:free는 알 수 없는 모델로 실패합니다. 다른 곳에서 쓰이는:free와:extended는 구현하지 않았습니다.
접미사 동작¶
| 접미사 | 동작 |
|---|---|
:nitro | 정상이고 승인 가능한 후보 중 최신 generation_throughput_tps가 가장 높은 서버로 좁힌 뒤, 설정된 전략이 동률 후보 중에서 고릅니다. |
:floor | 이 요청의 추정 비용이 가장 낮은 서버로 좁힙니다. least_cost 선택과 같은 가격 메타데이터와 요청 비용 추정을 쓰고 동률이면 출력 단가로 가른 뒤, 설정된 전략이 동률 후보 중에서 고릅니다. |
:thinking | 메타데이터가 thinking 지원을 선언한 모델에서, 클라이언트가 지정하지 않은 reasoning_effort를 high로 올립니다. 클라이언트가 지정한 값이 우선합니다. |
:online | 기존 라우터 관리 web_search 루프를 실행합니다. |
nitro와 floor는 후보를 좁힐 뿐 선택을 대체하지 않습니다. 상태 필터링과 엔진 포화 승인 게이트가 좁히기보다 먼저 실행되므로, 선호는 어차피 요청을 처리할 수 있었던 서버 중에서만 고를 수 있습니다. 순위에는 데이터가 필요합니다. 최신 엔진 통계 스냅숏이 없는 서버는 :nitro에 처리량 정보를 주지 않으며, 비교 가능한 가격이 없는 서버는 :floor 대상에서 빠집니다. 순위를 매길 후보가 하나도 없으면 집합을 그대로 두고 일반 선택이 요청을 처리하며, 응답은 선호를 적용하지 못했다고 알립니다.
거부¶
두 변형은 충족할 수 없을 수 있으며, 이때 베이스 모델로 조용히 대체하지 않고 거부합니다.
- 메타데이터에
thinking패턴도, 비어 있지 않은reasoning_efforts도 없는 모델의:thinking. - 사용할 수 있는 실행기가 없는
:online.web_search가 비활성이거나 없음, 라우터가 주입하지 않는 상용 백엔드, 또는 버퍼링 웹 검색 루프로 처리할 수 없는 스트리밍 요청입니다.
응답은 HTTP 404이며 error.type은 "invalid_request_error", error.code는 "unsupported_model_variant"이고, 메시지가 모델과 접미사를 명시합니다. :nitro와 :floor는 거부하지 않습니다.
식별자와 집계¶
요청의 대상은 베이스 ID입니다. 키별 allowed_models, 모델별 레이트 리밋, 모델별 토큰 예산은 모두 베이스 ID를 기준으로 하므로, 접미사로 모델에 설정된 한도를 벗어날 수 없고 베이스로 범위가 정해진 키는 그 변형을 쓸 수 있습니다. 백엔드에는 베이스 ID가 전달됩니다.
정확 일치 우선 규칙은 이 게이트에도 적용됩니다. 접미사 단어로 끝나더라도 그 자체가 서빙되거나 선언된 모델인 이름은 원래 식별자를 유지합니다. 따라서 base:nitro라는 이름으로 실제 서빙되는 모델은 base:nitro로 허용되고 집계되며, base로 취급되지 않습니다.
접미사는 클라이언트와 운영자가 확인할 수 있는 곳에 유지됩니다.
- 응답의 최상위
model을 요청한 이름으로 바꿉니다. JSON 본문과 스트림의 데이터 라인 모두 해당합니다. x-continuum-model-variant는 변형 단어(nitro,floor,thinking,online)를 담습니다.x-continuum-model-variant-applied: false는:nitro나:floor선호를 평가했지만 적용하지 못한 경우에만 붙습니다.continuum_model_variant_requests_total{variant, applied}가 변형별, 선호 적용 여부별로 요청을 집계합니다.
변형은 요청 자체의 첫 시도에 속합니다. 폴백 체인 홉은 다른 모델을 디스패치하므로 접미사를 물려받지 않습니다. x-backend 선호는 지금처럼 첫 시도를 가져가며, 이때 후보 순위를 우회하므로 변형은 적용되지 않은 것으로 보고됩니다.
한계¶
- 변형은 응답 캐시 식별자를 바꾸지 않습니다. 라우팅이 이미 후보를 한 백엔드로 좁힌 경우
base:nitro요청과base요청이 같은 캐시 항목을 공유할 수 있습니다. 캐시 식별자는 요청 표기가 아니라 경로를 따릅니다. 이는:nitro,:floor,:thinking에 적용됩니다. :online은 정확, 접두사, 시맨틱 캐시 경로에서 응답 캐시를 읽지도 쓰지도 않습니다. 캐시 키는web_search도구가 주입되기 전의 페이로드로 만들어지므로, 캐시 항목을 제공하면 검색 없이 응답하게 되고, 사용 가능한 executor가 없는 배포에서도 캐시된 응답을 재생하는 대신 거부해야 합니다.- 스트리밍
:online은 검색 없이 처리하지 않고 거부합니다. 라우터 관리 루프는 버퍼링 경로에만 있기 때문입니다. :thinking은 reasoning effort를 설정할 뿐입니다. 모델 메타데이터가 이미 설명하지 않은 제공자별 thinking 예산을 켜지 않습니다.
미해결 질문¶
- 이슈에 함께 언급된
:free와:extended가 자체 호스팅 환경에서 무엇을 의미하는지. 둘 다 구현하지 않았습니다. /v1/completions나 Responses API처럼/v1/chat/completions외의 인그레스까지 문법을 확장할지.