모델 폴백

`models[]` 로 후보 체인을 직접 정한다

model 하나 대신 models 배열을 보내면, 앞에서부터 시도해서 처음 응답한 후보에서 멈춥니다. 과금은 실제로 응답한 그 하나에만 됩니다.

json
{
  "models": ["lgai/exaone-4.0-32b", "google/gemma-4-26b-a4b"],
  "messages": [{ "role": "user", "content": "요약해 줘." }]
}

models 가 있으면 그쪽이 이기고 model 은 무시됩니다. 둘 다 없으면 서비스 기본 모델인 google/gemma-4-26b-a4b 로 갑니다.

체인이 만들어지는 순서

여러분이 준 목록은 체인 그 자체가 아니라 체인의 입력입니다.

  1. 전개. 각 모델 id 가 그 모델을 서빙하는 provider 전부로 치환되고, priority 오름차순으로 정렬됩니다. 로컬 GPU 슬롯의 priority 가 가장 낮으므로 맨 앞에 옵니다. 로컬 우선 라우팅 을 보세요.
  2. 연결. 전개된 목록들을 여러분이 준 순서대로 이어 붙입니다. 같은 provider/모델 쌍은 한 번만 남으므로 같은 모델을 두 번 적어도 아무 일도 일어나지 않습니다.
  3. 필터. provider{} 조건, 컨텍스트 창 검사, 쿨다운이 후보를 제거합니다. Provider 라우팅 을 보세요.
  4. 실행. 앞에서부터 하나가 응답할 때까지 시도합니다.

그래서 A 가 로컬 슬롯 1개 + 외부 엔드포인트 1개를 갖고 B 가 외부 엔드포인트 1개를 갖는다면, ["A", "B"] 는 두 번이 아니라 세 번의 시도가 될 수 있는 체인이 됩니다.

모르는 모델 id

modelmodels 의 규칙이 다릅니다. 의도적입니다.

요청동작
"model": "nope/nope"400 model_not_found
"models": ["nope/nope", "google/gemma-4-26b-a4b"]모르는 항목은 조용히 빠지고 google/gemma-4-26b-a4b 로 실행
"models": ["nope/nope", "also/nope"]400 model_not_found

배열은 "이 중에 되는 걸로"라는 뜻이므로, 서빙할 수 없는 항목은 그냥 후보가 아닐 뿐입니다 — 그게 폴백 목록의 존재 이유입니다. 반면 단일 model 은 특정 지시이므로 오타는 오류입니다.

재시도는 언제까지 하는가

후보가 요청을 거부하거나, 연결 단계에서 타임아웃하거나, 2xx 가 아닌 상태를 돌려주면 아직 여러분에게 아무것도 보내지 않은 상태이므로 다음 후보로 넘어갑니다. 반대로 후보가 응답을 시작한 뒤에 실패하면 다른 모델로 몰래 다시 시작할 수 없습니다 — 이미 첫 번째 모델의 답 일부를 받으셨기 때문입니다. 대신 이렇게 됩니다.

  • 스트리밍: 스트림에 오류 이벤트를 실어 보내고 스트림을 끝냅니다. 스트리밍 을 보세요.
  • 비스트리밍: 502 provider_error 로 드러납니다.

X-MyIP-Model 이 권위 있는 이유가 이것입니다 — 여러분이 받은 바이트를 실제로 만든 모델이 거기 적힙니다.

체인이 전부 실패하면

상태error_type의미
404no_endpoints_found필터를 거치고 나니 시도할 것이 남지 않음
408timeout후보 중 하나 이상이 업스트림 타임아웃에 걸림
502provider_error후보들이 실패. metadata.provider_code 에 마지막 업스트림 상태
503model_loading모든 후보가 제때 못 깨어난 로컬 슬롯. metadata.retry_after_secRetry-After 헤더가 재시도 시점을 알려 줌

전부 과금하지 않습니다. 토큰을 만들지 못한 요청은 비용이 0 입니다.

무슨 일이 있었는지 확인하기

응답 헤더가 승자를 알려 줍니다.

X-MyIP-Model: google/gemma-4-26b-a4b
X-MyIP-Provider: MyIP Local GPU
X-MyIP-Generation-Id: gen-01JD8Q2K7M4X9N

시도한 후보 전부와 각각의 상태·소요 시간은 generation 기록에 남습니다.

bash
curl "https://openrouter.myip.co.kr/api/v1/generation?id=gen-01JD8Q2K7M4X9N" \
  -H "Authorization: Bearer $MYIP_API_KEY"

응답의 provider_responses 가 시도 로그입니다. 요청이 예상보다 오래 걸린 이유를 찾을 때 가장 먼저 볼 곳입니다.

예제

curl https://openrouter.myip.co.kr/api/v1/chat/completions \
  -H "Authorization: Bearer $MYIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "models": ["lgai/exaone-4.0-32b", "google/gemma-4-26b-a4b"],
    "messages": [{ "role": "user", "content": "다음 문단을 세 줄로 요약해 줘." }]
  }' -D -

curl 예제의 -D - 는 응답 헤더를 출력합니다. 어느 모델이 이겼는지 가장 빨리 확인하는 방법입니다.

실전 패턴: 콜드스타트 보험

로컬 모델은 잠들어 있을 수 있습니다. 첫 모델 뒤에 다른 로컬 모델을 두면 503 model_loading 대신 "조금 다른 답"을 받게 됩니다.

json
{ "models": ["lgai/exaone-4.0-32b", "google/gemma-4-26b-a4b"] }

GPU 노드가 배타적이라 둘 중 지금 상주 중인 쪽이 즉시 응답합니다. 로컬 모델 하나만 고정해 두고 503 마다 재시도하는 것보다 대개 나은 기본값입니다.

route

"route": "fallback" 은 받아들이지만 아무 일도 하지 않습니다 — models[] 가 이미 하는 동작을 서술한 값이기 때문입니다. 거부하지 않고 받는 것은 다른 게이트웨이용으로 짠 코드가 그대로 돌아가게 하려는 것입니다. 오토 라우터도, 비용·품질 프론티어도, 모델 융합도 없습니다. 체인은 여러분이 선언한 그대로입니다. 서비스 원칙 을 보세요.

provider 조건과 함께 쓰기

models[]어떤 모델을 고르고, provider{} 는 그 모델의 어떤 엔드포인트를 어떤 순서로 쓸지를 고릅니다. 둘은 함께 적용됩니다.

json
{
  "models": ["google/gemma-4-26b-a4b", "lgai/exaone-4.0-32b"],
  "provider": { "only": ["local-gpu"], "allow_fallbacks": true }
}

주의할 점 하나. provider.allow_fallbacks: false체인 전체를 첫 후보 하나로 잘라냅니다 — models[] 뒤쪽 항목에서 나온 후보까지 포함해서요. 폴백 목록을 쓰려면 이 값은 건드리지 마세요.

마지막 수정 2026. 9. 5.