Перейти к содержимому
Руководства и аналитика

Создайте каталог /v1/models с поддержкой арендаторов для многомодельного шлюза API

Рассматривайте обнаружение модели как контракт авторизации и готовности маршрута. Создайте каталог /v1/models с поддержкой арендаторов, в котором перечислены только модели, которые каждый ключ API может использовать через каждую поддерживаемую поверхность API.

A gateway should not return every model known to every connected provider from GET /v1/models. It should return the models that the authenticated API key is authorized and operationally able to call.

This distinction matters when one API key provides access to multiple LLM providers. A raw union of upstream catalogs can include models that are forbidden by team policy, unavailable under the tenant's plan, missing a healthy credential, incompatible with the requested API, or not deployed in the required region. Those entries produce broken model pickers and runtime errors that discovery should have prevented.

The practical contract is stronger: every advertised model must pass the same admission checks that would apply to a real request.

Define what “available” means

Provider existence is only one input. A model should appear in a key's default catalog only when all required conditions are true:

  • The gateway has a configured public product for the model.
  • The tenant, team, and API key are entitled to that product.
  • The applicable commercial plan permits its use.
  • Policy allows the model, provider, region, and data-handling mode.
  • At least one compatible upstream deployment or route exists.
  • A usable provider credential is available for that route.
  • The route supports at least one API surface advertised in the catalog.
  • The route is operationally ready under the gateway's health policy.

Expressed as a set operation:

visible_models(key) =
  configured_products
  ∩ tenant_entitlements
  ∩ team_grants
  ∩ key_grants
  ∩ commercial_rights
  ∩ policy_eligible_routes
  ∩ compatible_deployments
  ∩ operationally_ready_routes

This is a recommendation, not a claim about the OpenAI schema. The standard schema does not define all of these gateway-specific controls. They belong in the gateway's control plane and catalog compiler.

Normalize provider discovery without proxying it

Fact: provider discovery APIs expose different concepts. OpenAI's model list supplies identifiers and basic metadata, but not a complete capability matrix for every API surface. Anthropic distinguishes lifecycle states and can return richer capability information when a model or alias is retrieved. Gemini exposes fields such as token limits and supported generation methods. Microsoft Foundry may require a deployment name in the model field, and a deployment can be incompatible with a particular API even when the underlying model exists.

Consequently, forwarding provider responses directly is not a durable design. Treat each provider API as a reconciliation source. Convert its observations into an internal record, then combine them with gateway configuration and tenant policy.

Use a canonical catalog record

A useful internal record separates the public contract from upstream implementation:

{
  "catalog_revision": "cat_2026_11_05_0182",
  "public_model_id": "reasoning-large",
  "lifecycle": "active",
  "api_surfaces": ["chat.completions", "responses"],
  "input_modalities": ["text", "image"],
  "output_modalities": ["text"],
  "limits": {
    "context_tokens": 200000,
    "max_output_tokens": 32000
  },
  "capabilities": {
    "tools": true,
    "structured_output": true,
    "batch": false
  },
  "entitlement_profile": "advanced-reasoning",
  "routes": [
    {
      "provider": "provider-a",
      "target_type": "deployment",
      "target_id": "prod-reasoning-east",
      "region": "us-east",
      "state": "ready"
    }
  ]
}

Do not expose target_id, credential references, or internal routing state through the standard public endpoint. Those fields are control-plane data. Keep them available to route admission, support tooling, and usage attribution.

Separate IDs, aliases, and deployments

A public model ID is a client contract. A provider model ID identifies an upstream model family or version. A deployment name identifies an operator-created serving resource. They are not interchangeable.

Resolve a public alias to an immutable catalog revision before routing. Record both the requested ID and resolved target in the usage event. If the alias changes later, support staff can still reconstruct which deployment handled an earlier call.

Compile the catalog for the authenticated key

The catalog compiler should receive an authenticated principal, not merely a tenant ID. The same tenant may have production keys, development keys, restricted customer keys, and service accounts with different model grants.

A deterministic compilation sequence is:

  1. Load the immutable base catalog revision.
  2. Resolve tenant membership, team membership, and key-specific grants.
  3. Apply plan, geography, data-residency, and provider restrictions.
  4. Remove routes without valid credentials or compatible deployments.
  5. Evaluate route readiness using the current health snapshot.
  6. Aggregate surviving routes into public model records.
  7. Return only API surfaces supported by at least one surviving route.

Use intersection semantics when both team and key grants exist. A key assigned to a restricted team should not recover broader access merely because the tenant owns a wider plan. This makes AI model access control for software teams predictable and reduces accidental disclosure.

Keep list and retrieve behavior identical

GET /v1/models/{model} must run the same authorization predicate as the list operation. Otherwise, an attacker can enumerate hidden identifiers by comparing success, forbidden, and not-found responses.

For a model the key cannot see, return the same public error used for an unknown model. Do not reveal whether another tenant can use it, which provider hosts it, or which entitlement would unlock it. Administrative APIs can expose more detailed reasons to authorized operators.

Represent API compatibility explicitly

A model's existence does not imply support for every endpoint. Chat Completions, Responses, embeddings, image generation, realtime, batch, and Anthropic Messages have different request and streaming contracts.

Route admission should therefore accept both a model and an API surface:

admit(key, public_model_id, api_surface, request_features)

The result should identify a compatible catalog revision and one or more eligible routes. For example, a model can support chat.completions but not responses, or support Responses only when built-in tools are absent. A single Boolean such as supports_responses may be insufficient when compatibility depends on requested features.

Recommendation: publish conservative capabilities. Advertise a feature only when the gateway can enforce it across the eligible route set or can select a route that supports it deterministically. Do not infer image input, tool calling, or structured output from a provider family name.

Preserve SDK compatibility while adding metadata

Keep the standard fields expected by OpenAI-compatible clients stable:

{
  "id": "reasoning-large",
  "object": "model",
  "created": 1793836800,
  "owned_by": "gateway",
  "x_gateway": {
    "catalog_revision": "cat_2026_11_05_0182",
    "lifecycle": "active",
    "api_surfaces": ["chat.completions", "responses"],
    "input_modalities": ["text", "image"],
    "availability": "available"
  }
}

A namespaced extension reduces collision risk, but some clients discard unknown fields. If applications need detailed selection data, provide a separate authenticated model-information endpoint with a versioned schema. Keep /v1/models small enough for SDKs, command-line tools, and model pickers.

Choose stable or health-filtered listings

Two reasonable availability policies exist.

Health-filtered catalog: hide a model when no route is currently healthy. This minimizes failed calls, but catalogs can fluctuate during incidents and invalidate client-side selections.

Stable catalog: continue listing entitled products while reporting availability: temporarily_unavailable. This is easier for automation and migration tooling, but clients may still attempt calls unless they understand the extension.

A practical default is to hide models that are undeployed, forbidden, retired, or credential-ineligible, while retaining temporarily unavailable models with an explicit status for trusted clients. The minimal compatibility endpoint can omit unavailable entries if existing clients cannot interpret status metadata.

Prediction: richer model-selection clients will increasingly depend on capability and availability metadata. Until that behavior is broadly reliable, server-side route admission must remain authoritative.

Cache compiled catalogs without serving stale grants

Compile catalogs outside the request path where possible. A cache key should include at least:

(tenant_id, key_id, entitlement_version, catalog_revision, policy_revision)

Invalidate affected entries when team membership, model grants, pricing plans, provider credentials, deployment state, or routing policy changes. Short time-to-live values are not a substitute for revocation events: even a brief stale window can expose a newly forbidden model.

Provider reconciliation can be asynchronous. During a provider control-plane outage, preserve the last known catalog, record its observation time, and prevent newly uncertain routes from becoming eligible. This keeps listing responsive without treating stale discovery as proof that a new route is usable.

Test the catalog as an admission contract

The strongest conformance property is simple: for every model and API surface returned to a key, route admission must succeed under the same catalog and health revision.

Add automated tests for:

  • A permitted key seeing and retrieving its assigned models.
  • A forbidden key seeing neither list entries nor retrievable metadata.
  • Team restrictions narrowing, rather than broadening, key access.
  • A chat-only deployment not being advertised for Responses.
  • A disabled credential removing its dependent routes.
  • An alias resolving to the expected immutable catalog revision.
  • A retired model disappearing from the default catalog.
  • Cache invalidation after grants, memberships, or policies change.
  • Unknown and hidden model IDs producing indistinguishable public errors.
  • Every advertised capability having at least one eligible route.

Synthetic probes can add evidence that a route works, but they consume quota, may cost money, and cannot cover every feature combination. Use them for representative route classes and combine them with deployment state, credential checks, and real traffic health.

Record enough evidence to explain decisions

For each accepted or rejected request, record the catalog revision, requested public model ID, API surface, resolved route, capability contract, policy revision, and a structured admission reason. Avoid storing prompt content solely for this purpose.

The implementation sequence is straightforward: define the canonical record, build provider reconcilers, compile per-key views, make list and retrieve share one authorization predicate, connect route admission to the same revision, and add negative tests before enabling caches. Once these pieces are in place, /v1/models becomes a dependable answer to “what can this key call?” rather than a loosely filtered inventory.

Related reading

FAQ

Часто задаваемые вопросы

Должен ли /v1/models возвращать каждую модель, настроенную в шлюзе?
Нет. Ответ по умолчанию должен содержать только модели, которым аутентифицированный ключ имеет право и может вызывать. Административная инвентаризация должна использовать отдельную привилегированную конечную точку.
Должны ли временно неработоспособные модели исчезнуть из каталога?
Это зависит от клиентского договора. Их сокрытие уменьшает количество немедленных сбоев, а сохранение их с явным статусом недоступности обеспечивает автоматизацию более стабильного каталога. Допуск к маршруту должен оставаться авторитетным в любом варианте.
Можно ли использовать API-интерфейсы списка моделей поставщиков в качестве каталога шлюзов?
Они должны быть исходными данными для сверки, а не самим общедоступным каталогом. Схемы поставщиков различаются и не содержат прав арендатора шлюза, коммерческих прав, правил политики, состояния учетных данных или полной совместимости конечных точек.
Чем должны отличаться скрытые и неизвестные идентификаторы моделей?
Обычно они не должны отличаться общедоступным API. Возвращайте ту же форму и состояние ошибки, чтобы вызывающие абоненты не могли перечислить права другого клиента или конфигурацию внутреннего поставщика.
Что должно сделать недействительным кэш каталога моделей для каждого ключа?
Сделайте его недействительным при изменении разрешений модели, членства в команде, прав на план, учетных данных поставщика, состояния развертывания, версий каталога или политик маршрутизации. Включите соответствующие версии или версии прав в ключ кэша.