프로바이더 선택과 라우팅 (Provider Selection)
프로바이더 선택과 라우팅 (Provider Selection)
OpenRouter는 요청을 그 모델의 **최적 제공자(프로바이더)**로 라우팅해요. 기본적으로는 여러 상위 제공자에 부하를 분산해 가동률(uptime)을 최대화해요. 이 기본 동작을 원하는 대로 바꾸고 싶다면, Chat Completions 요청 본문의 provider 객체로 라우팅을 커스터마이즈할 수 있어요. 이 페이지에서는 provider 객체의 각 필드와 대표적인 라우팅 전략을 살펴볼게요.
출처: https://openrouter.ai/docs/guides/routing/provider-selection
provider 객체 개요
요청 본문의 provider 객체는 다음 필드를 가질 수 있어요.
| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
order |
string[] | - | 우선해서 시도할 제공자 슬러그 목록 (예: ["anthropic", "openai"]) |
allow_fallbacks |
boolean | true |
주 제공자가 없을 때 백업 제공자 사용 허용 여부 |
require_parameters |
boolean | false |
요청의 모든 파라미터를 지원하는 제공자만 사용 |
data_collection |
"allow" | "deny" | allow |
데이터를 저장할 수 있는 제공자 사용 여부 제어 |
zdr |
boolean | - | ZDR(무데이터 보존) 엔드포인트로만 라우팅 |
enforce_distillable_text |
boolean | - | 텍스트 증류 허용 모델로만 라우팅 |
only |
string[] | - | 이 요청에 허용할 제공자 슬러그 목록 |
ignore |
string[] | - | 이 요청에서 건너뛸 제공자 슬러그 목록 |
quantizations |
string[] | - | 필터링할 양자화 레벨 (예: ["int4", "int8"]) |
sort |
string | object | - | 가격·처리량·지연으로 제공자 정렬 (string 또는 by/partition 객체) |
preferred_min_throughput |
number | object | - | 원하는 최소 처리량(초당 토큰). 숫자 또는 백분위(p50/p75/p90/p99) 객체 |
preferred_max_latency |
number | object | - | 원하는 최대 지연(초). 숫자 또는 백분위 객체 |
max_price |
object | - | 이 요청에 지불할 최대 가격 |
추가로, 엔터프라이즈 고객은 EU·US **지역 내 라우팅(in-region routing)**을 지원받아요. 활성화하면 프롬프트와 컴플리션이 선택한 지역 안에서만 처리돼요.
가격 기반 부하 분산 (기본 전략)
기본 동작은 요청을 가격 우선으로 여러 제공자에 부하 분산하는 거예요. 처리량에 더 민감하다면 sort 필드로 처리량 우선을 명시할 수 있어요.
tools나 tool_choice를 보내면 OpenRouter는 도구 사용을 지원하는 것으로 알려진 제공자로 라우팅을 시도해요. max_tokens를 설정하면 그만큼의 응답 길이를 지원하는 제공자로만 라우팅돼요. 기본 부하 분산 전략은 다음과 같아요.
- 지난 30초 안에 큰 장애가 없었던 제공자를 우선해요.
- 안정적인 제공자 중 가장 저렴한 후보를 골라, 가격의 역제곱에 비례하는 가중치로 하나를 선택해요.
- 나머지 제공자들은 폴백으로 남겨 둬요.
부하 분산 예시: 제공자 A는 백만 토큰당 $1, B는 $2, C는 $3인데 B가 최근 장애를 몇 번 겪었다고 해 볼게요.
- 요청은 A로 라우팅돼요. A는 가격의 역제곱 덕분에 C보다 첫 라우팅될 확률이 9배 높아요.
- A가 실패하면 C가 다음으로 시도돼요.
- C마저 실패하면 마지막으로 B가 시도돼요.
sort나 order를 설정하면 부하 분산은 꺼져요.
제공자 정렬 (Provider Sorting)
가격이 아닌 특정 속성을 명시적으로 우선하고 싶다면 provider.sort 필드를 쓰면 돼요. 이때 부하 분산은 꺼지고, 라우터가 제공자를 순서대로 시도해요.
"price": 가장 저렴한 것 우선"throughput": 처리량이 높은 것 우선"latency": 지연이 낮은 것 우선
속성 우선도
속성 우선도는 정렬 시기는 가격이 아니라 선택한 속성으로 제공자를 시도한다는 뜻이에요. 예를 들어 sort를 "latency"로 두면 요청을 가장 응답이 빠른 제공자에게 보내요. 이때 프로바이더 order를 함께 설정하면, sort를 무시하고 order 순서를 우선하는 점에 주의해 주세요 (order와 함께 sort를 쓰면 sort는 무시돼요).
니트로(Nitro) 단축키
어떤 모델 슬러그든 :nitro를 붙이면 처리량으로 정렬하는 단축키가 돼요. 처리량 정렬에 더해 :nitro는 우선 서비스 티어(priority service tier) 엔드포인트까지 자격을 넓혀 줘서, provider.sort를 "throughput"으로 두는 것(정렬만 함)의 상위 집합이에요.
플로어(Floor) 단축키
:floor를 붙이면 가격으로 정렬하는 단축키예요. 가격 정렬에 더해 플렉스 서비스 티어(flex service tier) 엔드포인트까지 자격을 넓혀서, provider.sort를 "price"로 두는 것의 상위 집합이에요.
partition으로 고급 정렬
모델 폴백을 쓸 때 sort를 객체로 줄 수 있어요.
| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
sort.by |
string | - | 정렬 전략: "price", "throughput", "latency" |
sort.partition |
string | "model" |
끝점 그룹화 방식: "model"(기본) 또는 "none" |
기본적으로 여러 모델(폴백)을 지정하면 OpenRouter는 모델별로 끝점을 먼저 그룹화해요. 그래서 성능 특성과 무관하게 주 모델의 끝점이 항상 먼저 시도돼요. partition을 "none"으로 두면 이 그룹화를 없애고, 모든 모델에 걸쳐 끝점을 전역적으로 정렬해요.
성능 임계값 (Percentile)
preferred_max_latency와 preferred_min_throughput으로 원하는 최소 처리량·최대 지연 임계값을 설정할 수 있어요. 임계값을 충족하지 못하는 끝점은 아예 제외되지 않고 목록 뒤로 밀려나는 비우선 처리예요.
OpenRouter는 각 모델·제공자에 대해 5분 롤링 윈도우의 백분위 통계로 지연·처리량을 기록해요.
- p50 (중앙값): 요청의 50%가 이 값보다 나은 성능
- p75: 75%가 이 값보다 나은 성능
- p90: 90%가 이 값보다 나은 성능
- p99: 99%가 이 값보다 나은 성능
높은 백분위(예: p90, p99)는 최악 성능을 더 확실히 담보하고, 낮은 백분위(예: p50)는 전형적 성능을 반영해요. 여러 백분위를 지정하면 모든 임계값을 충족해야 선호 그룹에 들어요.
이 임계값들은 특정 성능의 제공자를 보장하지는 않아요. 다만 임계값을 넘는 제공자·모델을 선호할 뿐이라, 지정한다고 해서 요청 실행이 막히지 않아요. 이 점이 가격이 없으면 요청이 아예 실행되지 않는 max_price와는 달라요.
백분위 선호는 언제 쓸까
- 실시간 애플리케이션: 사용자 대면 기능의 응답 시간 일관성에 p90/p99 지연 임계값 사용
- 배치 처리: 평균 성능이 더 중요하면 p50 처리량 임계값
- SLA 준수: 여러 백분위를 걸쳐 서비스 수준 계약 충족 확인
- 비용 최적화:
sort: "price"와 결합해 성능 요건을 채우는 가장 싼 제공자 선택
다음 예시는 세 모델을 partition: "none" + by: "price"로, p90 처리량 50 tokens/sec 이상을 요구하며 정렬해요. 선호 옵션이 모두 실패해도 이 임계값 미만의 모델·제공자가 폴백으로 남아요.
import { OpenRouter } from '@openrouter/sdk';
const openRouter = new OpenRouter({ apiKey: '<OPEN...Y>' });
const completion = await openRouter.chat.send({
chatRequest: {
models: [
'anthropic/claude-sonnet-4.5',
'openai/gpt-5-mini',
'google/gemini-3-flash-preview',
],
messages: [{ role: 'user', content: 'Hello' }],
provider: {
sort: { by: 'price', partition: 'none' },
preferredMinThroughput: { p90: 50 }, // 지난 5분간 요청의 90%가 50 tokens/sec 이상
},
stream: false,
},
});
여러 백분위를 함께 지정해 전형·최악 성능을 동시에 요구할 수도 있어요.
const completion = await openRouter.chat.send({
chatRequest: {
model: 'deepseek/deepseek-v3.2',
messages: [{ role: 'user', content: 'Hello' }],
provider: {
preferredMaxLatency: { p50: 1, p90: 3, p99: 5 },
preferredMinThroughput: { p50: 100, p90: 50 },
},
stream: false,
},
});
BYOK 사용량 극대화
BYOK(Bring Your Own Key)를 쓰고 있다면 partition: "none"이 자체 API 키 사용을 극대화해 줘요. 주 모델에 BYOK 제공자가 없어도, BYOK를 지원하는 폴백 모델로 라우팅할 수 있기 때문이에요. 예를 들어 OpenAI용 키는 있는데 Anthropic용은 없다면, Claude가 목록 첫머리여도 GPT-4o 끝점을 자체 키로 라우팅할 수 있어요. 제공자에 API 키가 설정되어 있으면 BYOK 끝점은 자동 우선 처리되고, partition: "none"이 그 우선 처리를 모델 경계를 넘어 동작하게 해요.
특정 제공자 순서 지정 (order)
order 필드로 이 요청에서 OpenRouter가 우선할 제공자들을 순서대로 지정할 수 있어요. 이 목록을 우선하되, 지정하지 않으면 가동률을 극대화하도록 상위 제공자에 부하 분산을 해요. 모델 페이지의 제공자 이름 옆 복사 버튼으로 정확한 제공자 슬러그(/turbo 같은 변형 포함)를 얻을 수 있어요.
OpenRouter는 하나씩 시도하다가 동작하지 않으면 다음 제공자로 넘어가요. 다른 제공자를 아예 쓰고 싶지 않다면 allow_fallbacks도 함께 꺼야 해요.
특정 제공자 엔드포인트 지정
같은 제공자도 모델에 따라 여러 엔드포인트를 호스팅할 수 있어요 — 기본 엔드포인트와 특수 "turbo" 엔드포인트, 혹은 google-vertex/us-east5 같은 지역별 엔드포인트처럼요. 모델 상세 페이지의 제공자 이름 옆 복사 버튼으로 정확한 슬러그를 얻을 수 있어요.
기본 슬러그 일치: order, only, ignore 같은 필드에 기본 제공자 슬러그(예: "google-vertex")를 쓰면 그 제공자의 모든 엔드포인트(변형·지역 포함)와 일치해요. 반면 서비스 티어 엔드포인트(예: openai/fast, google-vertex/flex)는 기본 슬러그로 일치하지 않아요 — service_tier 파라미터나 티어 접미사 슬러그로 명시적 옵트인이 필요해요. 특정 변형·지역만 겨냥하려면 접미사를 포함한 전체 슬러그("google-vertex/us-east5", "deepinfra/turbo")를 써야 해요.
| 요청의 슬러그 | 일치 대상 |
|---|---|
"google-vertex" |
모든 Google Vertex 엔드포인트 (전 지역) |
"google-vertex/us-east5" |
us-east5 지역 엔드포인트만 |
"deepinfra" |
모든 DeepInfra 엔드포인트 (기본 + turbo) |
"deepinfra/turbo" |
DeepInfra turbo 엔드포인트만 |
예를 들어 DeepInfra는 DeepSeek R1을 기본(deepinfra)과 turbo(deepinfra/turbo) 두 끝점으로 제공해요. 정확한 슬러그를 복사해 order 배열에 넣으면 원하는 끝점으로 정확히 라우팅할 수 있어요. 제공자의 모든 엔드포인트(전 지역·변형)로 보내려면 접미사 없는 기본 슬러그를 쓰면 돼요.
파라미터 전체 지원 요구 (require_parameters)
기본 라우팅에서는 요청에 지정된 모든 파라미터를 지원하지 않는 제공자도 그 요청을 받을 수 있어요 — 다만 모르는 파라미터는 무시해요. require_parameters를 true로 두면, 그 파라미터를 지원하지 않는 제공자에게는 아예 라우팅되지 않아요.
흥미로운 점은 require_parameters가 false여도 소수의 파라미터(tools, response_format(구조화 출력 포함), verbosity)는 같은 모델의 제공자 사이에서 부드러운 선호(soft preference)로 쓰여요. 한 모델의 일부 제공자만 이 파라미터를 지원하면, 지원하는 제공자로만 라우팅돼요. 아무 제공자도 지원하지 않으면 그 모델로 계속 라우팅되고 파라미터는 무시돼요 — 이 선호가 모델을 후보 목록(models 폴백 목록 포함)에서 빼지는 않아요.
데이터 정책 준수 (data_collection)
data_collection으로 데이터 정책을 준수하는 제공자만 쓰도록 제한할 수 있어요.
allow(기본값): 비일시적으로 사용자 데이터를 저장하고 훈련에 쓸 수 있는 제공자 허용deny: 사용자 데이터를 수집하지 않는 제공자만 사용
일부 모델 제공자는 프롬프트를 로깅할 수 있어서, 모델 페이지에 Data Policy 태그로 표시돼요. 이것이 제3자 데이터 정책의 확정 소스는 아니고 OpenRouter의 최선 지식이에요. 계정 전체 설정으로도 프라이버시 설정에서 훈련용으로 입력을 저장하는 제3자 제공자를 비활성화할 수 있어요.
ZDR 강제 (무데이터 보존)
zdr 파라미터로 요청별 Zero Data Retention을 강제할 수 있어요. true면 프롬프트를 보존하지 않는 ZDR 끝점으로만 라우팅돼요. false거나 제공하지 않으면 라우팅에 영향이 없어요.
ZDR은 프라이버시 설정이나 가드레일(guardrails)로 모델 그룹별·계정 전체로도 강제할 수 있어요. 요청별 zdr 파라미터는 계정 전체·가드레일 ZDR과 "OR"로 동작해요 — 어느 하나라도 켜져 있으면 ZDR 강제가 적용돼요. 요청 레벨 파라미터는 ZDR을 켜기만 할 수 있고, 계정 전체·가드레일 강제를 덮어쓰지는 못해요.
증류 가능 텍스트 강제
enforce_distillable_text를 true로 두면, 작성자가 텍스트 증류를 허용한 모델로만 요청을 라우팅해요. 모델 파인튜닝용이나 증류 워크플로의 데이터셋을 만들 때처럼, 훈련 목적으로 텍스트 증류를 허용한 모델만 쓰고 싶은 애플리케이션에 유용해요.
폴백 비활성화
요청이 최상위(최저가) 제공자에게만 서빙되도록 보장하려면 폴백을 끄면 돼요. 이는 제공자 순서 지정의 order 필드와 결합해, 우선할 제공자를 나열한 목록으로만 요청을 제한할 수 있어요.
특정 제공자만 허용 (only)
provider.only로 이 요청에 허용할 제공자만 지정할 수 있어요. 주의할 점은 일부 제공자만 허용하면 폴백 옵션이 크게 줄어 요청 복구가 제한될 수 있다는 거예요.
계정 전체 허용 제공자도 프라이버시 설정에서 설정할 수 있어요. 요청별로 허용하면 두 제약이 모두 적용돼요 — 계정 전체 허용 목록이 상한(cap) 역할을 하고, 요청의 only 목록이 그 안을 좁혀요. 둘 다 만족하는 제공자가 없으면 404로 실패해요.
제공자 무시 (ignore)
provider.ignore로 이 요청에서 건너뛸 제공자를 지정할 수 있어요. 마찬가지로 여러 제공자를 무시하면 폴백 옵션이 줄 수 있어요. 요청별 ignore 목록은 계정 전체 ignore 목록과 병합돼요.
양자화 (Quantization)
양자화는 성능을 비슷하게 유지하면서 모델 크기와 연산 요구를 줄여요. 오늘날 대부분의 LLM은 훈련·추론에 FP16이나 BF16을 써서 FP32 대비 메모리를 절반으로 줄여요. FP8이나 INT8·INT4 같은 양자화로 더 줄이기도 해요.
provider.quantizations로 양자화 레벨로 제공자를 필터링할 수 있어요. 사용 가능한 값은 int4, int8, fp4(mxfp4/nvfp4 포함), mxfp4, nvfp4, fp6, fp8(mxfp8 포함), mxfp8, fp16, bf16, fp32, unknown이에요. 양자화된 모델은 방법에 따라 특정 프롬프트에서 성능이 저하될 수 있어요. 오픈-가중치 모델의 경우 제공자가 다양한 양자화 레벨을 지원할 수 있어요.
최대 가격 (max_price)
provider.max_price로 지불할 최대 가격을 지정할 수 있어요. 예를 들어 {"prompt": 1, "completion": 2}는 프롬프트 토큰 100만 개당 <= $1, 컴플리션 토큰 100만 개당 <= $2인 제공자로 라우팅돼요. 요청당 과금 제공자는 request 속성으로, 이미지당 과금은 image 속성으로 다뤄요. 실무에서는 sort와 자주 결합해 "토큰당 $x 이상 비싸지만 않으면 처리량이 가장 높은 제공자" 같은 표현을 만든다.
제공자별 헤더
일부 제공자는 특수 헤더로 켜는 베타 기능을 지원해요. OpenRouter는 요청 시 특정 제공자별 베타 헤더를 통과시켜 줘요.
Anthropic 베타 기능
Anthropic 모델(Claude)을 쓸 때 x-anthropic-beta 헤더로 특정 베타 기능을 요청할 수 있어요.
| 기능 | 헤더 값 | 설명 |
|---|---|---|
| Interleaved Thinking | interleaved-thinking-2025-05-14 |
Claude의 사고·추론을 단일 블록이 아니라 일반 출력과 번갈아(interleave) 내보내기 |
| Structured Outputs | structured-outputs-2025-11-13 |
지원되는 Claude 모델에서 엄격한 도구 사용 활성화 (스키마에 맞는 타입 검증) |
OpenRouter가 자동으로 관리하는 Anthropic 기능도 있어요. 프롬프트 캐싱과 확장 컨텍스트는 모델 능력에 따라 켜지고, response_format.type: "json_schema"면 구조화 출력 헤더가 자동 적용돼요. stream: true로 사용자 정의 도구를 보내는 모든 스트리밍 요청에는 각 도구에 eager_input_streaming: true를 설정해, Anthropic이 도구 인자를 버퍼링하지 않고 증분 청크로 내보내게 해요.
엄격한 도구 사용(도구의 strict: true)에는 structured-outputs-2025-11-13 헤더를 꼭 직접 전달해야 해요. 헤더가 없으면 OpenRouter가 strict 필드를 떼고 정상 라우팅해요.
여러 베타 기능은 콤마로 구분해 함께 켤 수 있어요.
x-anthropic-beta: interleaved-thinking-2025-05-14,structured-outputs-2025-11-13
베타 기능은 실험적이라 Anthropic에 의해 바뀌거나 지원 중단될 수 있어요. 최신 정보는 Anthropic의 베타 기능 문서를 확인해 주세요.