Saltar a contenido

Modelos y providers

¿Decidir en vez de configurar?

Esta página es la maquinaria. Elegir un modelo responde a qué modelo debería usar un agent — pesos abiertos o cerrados, qué es lo que de verdad dispara la factura, y por qué la elección es reversible.

La plantilla de la que creció esta plataforma construía un modelo a partir de variables de entorno.

Eso deja de funcionar en cuanto varias organizaciones comparten un despliegue: cada una necesita su propia clave, su propio valor por defecto y poder rotar cualquiera de los dos sin volver a desplegar.

Así que un modelo se construye por run, a partir de la base de datos:

model profile → credential → unsealed secret → provider client → Model

Nada sobre qué modelo usa un agent vive en .env.

Un perfil de modelo

Una fila dentro de una organización: una etiqueta, un provider, un id de modelo, ajustes por defecto y con qué secreto del vault autenticarse.

El spec de un agent nombra uno con model_profile_id, y el run lo resuelve.

El id de modelo es texto libre a propósito

Hay un selector que ayuda, pero el campo acepta cualquier cosa que escribas.

Un provider publica algo la mañana siguiente a que se calentara cualquier lista de aquí, y un campo que no puede expresar «ese» es un campo que la gente esquiva editando el spec a mano.

Un perfil en el que un agent no puede ejecutarse

Un perfil puede nombrar un modelo que no mantiene una conversación: un modelo de texto a voz como gpt-4o-mini-tts, un modelo de voz en tiempo real, un modelo de transcripción, un modelo de imágenes, un modelo de vídeo o un modelo de embeddings. Un agent en uno de ellos falla en su primer turno. El texto a voz, la generación de imágenes y la transcripción no usan perfiles: cada función nombra su propio provider y su propio modelo.

La plataforma conoce estos modelos por sus propios catálogos (las listas de texto a voz, voz en tiempo real, transcripción, imágenes, vídeo y embeddings). GET /providers/model-profiles marca cada perfil con chat_capable y output_modalities, y GET /providers/{provider}/models marca cada sugerencia con chat_capable. Esos dos campos también leen el listado de un provider que indica qué emite cada modelo (OpenRouter y el router de Hugging Face lo hacen), cuando el proceso de la API ya lo ha obtenido. Ese listado solo cambia lo que ofrece un selector. Nunca rechaza una publicación, porque otro proceso de la API puede no haberlo obtenido.

La consola también actualiza los perfiles guardados cuando el listado llega después. Los alias de provider como openai_codex y google_cloud usan los catálogos del proveedor correspondiente. Entonces:

  • El panel de modelo del Builder, los selectores de revisor y de especialista, los campos del modelo de los pasos siguientes y del modelo de pasos del navegador y el selector del modelo que describe imágenes en la base de conocimiento no ofrecen un modelo así. Si un agent ya nombra uno, el Builder lo sigue mostrando, marcado como un modelo que no es de chat. A un miembro que gestiona conexiones, el Builder también le lista los demás, marcados y sin poder elegirse, para que se puedan eliminar.
  • El selector de modelo del chat y el formulario para añadir un modelo del Builder no sugieren un modelo así y rechazan uno escrito a mano.
  • La publicación rechaza un modelo así como modelo del agent, de un revisor o de un especialista, como modelo de pasos del navegador o como modelo de los pasos siguientes, y lo nombra. También rechaza un perfil cuyos fallbacks incluyen un modelo así. La misma comprobación se ejecuta al volver a una versión, en la comprobación del borrador, en la prueba del Builder y al activar una capability desde el chat. Una versión guardada en un modelo así sigue cargándose, pero no se puede restaurar mientras su perfil nombre un modelo que no es de chat o lo liste como fallback. Apunta ese perfil a un modelo de chat o publica una versión nueva.
  • Un run deja un fallback así fuera de su cadena, igual que uno eliminado, cuando se añadió al perfil después de publicar.
  • Una conversación que nombra un modelo así en lugar del modelo del agent, desde el chat o a través de la API, se rechaza antes de que empiece el run.
  • Un modelo que los catálogos no clasifican, como un modelo de Ollama o un modelo publicado esta mañana, está permitido. Un modelo desconocido no es un rechazo. Un perfil con su propio endpoint (base_url) nunca se clasifica, sea cual sea el id del modelo: los catálogos describen la API propia del provider, y un servidor compatible con OpenAI puede servir un modelo de chat con cualquier nombre.

El selector de modelo de proactividad sigue la misma regla. La comprobación de los catálogos estables también se aplica al configurar la proactividad y al resolver un perfil para una petición de texto normal, incluida la descripción de imágenes al configurar y en el worker. Las configuraciones antiguas siguen cargándose; hay que sustituir un modelo incompatible antes de usarlas. Sigue siendo posible desactivar la función. Los nombres de despliegues de Azure no se clasifican a partir de los identificadores de modelos base del catálogo.

Cambiar la clave o el endpoint de un perfil

Los agents nombran un perfil por su id. Para mover un modelo a otra clave, otro endpoint u otra API de OpenAI, edita el perfil en su sitio: PATCH /providers/model-profiles/{id} cambia secret_id, base_url, api, params o label y conserva el id. Cada agent sobre el perfil usa el cambio desde su siguiente run. Nadie tiene que volver a publicar nada.

En el panel de modelo del Builder, cambia la clave, el endpoint o la API del modelo en uso. El botón pasa a decir Update model, y el panel indica que cada agent sobre este modelo cambia con él. Add model sigue siendo el botón para otro provider u otro modelo, y para un modelo al que das un nombre propio. Usa Name it something else para dar solo a este agent un modelo aparte.

Una edición sigue las mismas reglas que la creación y necesita el mismo permiso connections:manage. Una clave nueva debe estar en el vault de esta organización, ser visible para ti y estar guardada para el provider del perfil. Un endpoint nuevo comprueba la clave guardada del mismo modo, porque el endpoint es adonde se envía la clave. Un provider que necesita clave no puede perderla. Un provider keyless sin clave conserva un endpoint. La etiqueta debe seguir siendo única.

Si cambias el endpoint y no envías api, una API que solo era la predeterminada del endpoint anterior pasa a la predeterminada del nuevo, y una API elegida a propósito se mantiene. El registro de auditoría guarda model_profile.updated con los nombres de los campos cambiados, no sus valores. No puedes cambiar el provider ni el id del modelo. Otro modelo es otro perfil.

connections:manage es, por tanto, la autoridad para mover a cada agent sobre un modelo, incluidos los agents que no puedes editar: un endpoint nuevo recibe sus peticiones desde el siguiente run. Concédelo a quienes gestionan los modelos de la organización.

Un perfil sin clave

Si borras una clave del vault, sus perfiles se quedan con secret_id a null. GET /providers/model-profiles los marca con missing_key: true. Un perfil guardado sin clave a propósito es otra cosa: un modelo autoalojado o un gateway que no autentica nada, en un provider keyless con endpoint, como un Ollama en tu red o un servidor compatible con OpenAI. Lo registra como runs_without_key y sigue ejecutándose. Un perfil de gateway que tenía clave y la perdió se marca con missing_key como cualquier otro. Entonces:

  • Los selectores de modelo del agent y del chat no lo ofrecen. Si un agent ya lo nombra, el Builder lo muestra con la marca no key y te pide que le des una clave.
  • La publicación lo rechaza y nombra el modelo. También rechaza un perfil cuyos tres primeros fallbacks incluyen uno sin clave, porque un run lo saltaría. Un run sobre él falla con "no key configured".
  • Para repararlo, abre un agent sobre ese modelo, elige una clave en Model y pulsa Update model. Cada agent sobre el modelo vuelve a funcionar.

Borrar un perfil

DELETE /providers/model-profiles/{id} rechaza un perfil que usan agents. La respuesta es 409 IN_USE, y details.agents lista cada agent que puedes ver, con id y nombre. details.hidden_agents cuenta los agents que no puedes ver. Un perfil está en uso cuando el borrador de un agent, su versión servida o una versión que fija un entorno nombra el perfil en cualquier lugar: como modelo del agent, de un revisor o de un especialista, o en una capability, como el modelo de follow-ups o el modelo de los pasos del navegador.

Los agents archivados cuentan, porque desarchivarlos restaura la versión que servían. El rechazo los marca con archived: un agent archivado no puede publicar, así que bórralo, o restáuralo y muévelo. Las versiones antiguas que nada sirve no cuentan. Mueve primero los demás agents a otro modelo. Para cambiar solo la clave, edita el perfil.

Fallbacks

El runner usa solo los tres primeros fallbacks; solo esos se comprueban al publicar.

Un perfil puede listar perfiles de fallback, probados en orden. La caída de un provider no debería tumbar los agents de una organización cuando esta tiene una segunda clave o un segundo provider configurados.

Un fallback es invisible en el registro del run

La fila del run se escribe antes de la primera petición, y lleva la etiqueta, el provider y el id de secreto del perfil primario. Si un fallback atendió el turno, el run sigue nombrando al primario.

Así que «cuánto gastamos en OpenAI» y «qué clave está costando más» responden con el perfil al que se preguntó primero, no con el que respondió. Conviene saberlo antes de fiarte de esos números durante una caída.

Ajustes del modelo

Por perfil, y sobrescribibles por agent a través de model_settings del spec: temperature, top_p, max_tokens, parallel_tool_calls, timeout. Ver la referencia del spec.

El caché de prompts está activado por defecto, mediante el ajuste cache de Pydantic AI, neutral respecto al proveedor. Cada petición de un run vuelve a enviar las instrucciones, los esquemas de herramientas y todo el historial, así que el prefijo estable y la conversación se marcan como puntos de caché y cada petición lee la anterior desde la caché. Se aplica donde un proveedor admite caché explícita - Anthropic, los modelos Anthropic y Nova de Bedrock, los modelos Anthropic y Gemini de OpenRouter, OpenAI desde GPT-5.6 - y no cambia nada en uno que cachea por su cuenta, como Google. Un perfil lo apaga con cache: false, o cachea solo instrucciones y herramientas con cache: {"messages": false}. Un indicador propio de un proveedor que el perfil ya fija, como anthropic_cache_messages, sigue mandando para ese perfil.

El esfuerzo de razonamiento no está aquí. Es la capability thinking, porque «razona más» es una decisión sobre para qué sirve el agent y no un mando de una conexión — y porque un spec que lo fija como ajuste del modelo deja de ser portable al cambiar de modelo.

Responses o Chat Completions

OpenAI publica dos APIs para los mismos modelos, y un perfil en openai o azure guarda a cuál de ellas van sus peticiones: responses o chat. Cualquier otro provider sirve una sola API y aquí no guarda nada.

Ninguna es la correcta en todas partes. Los modelos más nuevos de OpenAI solo se sirven por Responses y a Chat Completions responden con un 400, mientras que la mayoría de los servidores compatibles con OpenAI - vLLM, LM Studio, un proxy de LiteLLM - solo implementan Chat Completions. Por eso la elección es un campo del perfil, en Agents → add a model → API, y el formulario empieza en el valor por defecto:

Perfil Por defecto
openai, sin endpoint (la API propia de OpenAI) responses
openai con endpoint chat
azure chat, porque la Responses API necesita una api_version reciente y el secreto puede fijar una anterior

El valor por defecto es solo donde empieza el formulario. Un endpoint regional de OpenAI como https://eu.api.openai.com/v1 es un endpoint que sirve Responses, así que elígela ahí. Una elección omitida se guarda como su valor por defecto, así que cambiar el valor por defecto más adelante no mueve un perfil existente.

Un perfil en Responses no deja conversaciones en OpenAI. La Responses API guarda cada respuesta del lado de OpenAI salvo que se le indique lo contrario, mientras que Chat Completions no guarda nada por defecto, así que un modelo en Responses envía store: false. El razonamiento pasa entre turnos como contenido cifrado y no mediante un id de respuesta guardado, así que nada necesita la copia guardada. Un perfil que la quiera pone openai_store a true en sus ajustes.

Providers

Veintiocho, que es todo lo que trae Pydantic AI a lo que un perfil de chat puede apuntar.

Aquí no hay un constructor por provider. Pydantic AI infiere la clase del provider y el envoltorio del modelo a partir del id, y lo que esta plataforma sigue teniendo que saber es la parte que la inferencia no puede: qué forma de credencial quiere un provider.

Qué significa Custom URL

El SDK del provider nombra un parámetro de endpoint, así que puedes apuntar un perfil a un gateway, a un proxy de LiteLLM o a un servidor de modelos en tu propia red en vez de a la API pública del proveedor.

Es un campo del perfil, no de la clave. Una clave dice qué autentica, un endpoint dice adónde va la petición — así que la misma clave puede estar delante de un proxy de staging y de uno de producción como dos perfiles.

Configúralo en Agents → add a model → Endpoint, que aparece solo para los providers marcados abajo. Guardar uno para un provider que no tiene ninguno se rechaza, en vez de aceptarse y descartarse.

Alojados

Provider id Credencial Custom URL
OpenAI openai clave de API, o ninguna ✓
Anthropic anthropic clave de API ✓
Google Gemini google clave de API ✓
OpenRouter openrouter clave de API ✓
Alibaba Cloud alibaba clave de API ✓
Cerebras cerebras clave de API
DeepSeek deepseek clave de API
Fireworks AI fireworks clave de API
GitHub Models github clave de API
Groq groq clave de API
Heroku AI heroku clave de API ✓
Mistral mistral clave de API
Moonshot AI moonshotai clave de API
Nebius AI Studio nebius clave de API
OVHcloud AI Endpoints ovhcloud clave de API
SambaNova sambanova clave de API ✓
Together AI together clave de API
Vercel AI Gateway vercel clave de API
Z.AI zai clave de API
xAI (Grok) xai clave de API ✓ (api_host)
Cohere cohere clave de API
Hugging Face huggingface clave de API ✓

Autoalojados

Provider id Credencial Custom URL
Ollama ollama ninguna ✓
LiteLLM proxy litellm ninguna ✓ (api_base)

Estos dos son la razón de que «sin credencial» sea un kind almacenado y no una cadena vacía. Un servidor de modelos en tu propia red no suele tener nada contra lo que autenticarse, y el vault rechaza un secreto vacío — así que el resolver decide sobre un conjunto completo en vez de tratar un valor ausente como un caso especial.

Un perfil sin clave necesita su endpoint, y eso es lo único que necesita. El campo de la clave pasa a ser opcional en cuanto se rellena uno. Sin endpoint el perfil se rechaza: no hay una API pública a la que recurrir ni nada con lo que autenticarse.

Lo que marca un perfil como autoalojado es el endpoint, no keyless

keyless también es cierto de openai. Los servidores compatibles con OpenAI (vLLM, LM Studio, un proxy de LiteLLM) hablan su API de Chat Completions, que es por lo que un perfil openai con endpoint la usa por defecto - ver Responses o Chat Completions.

Así que «sin clave» por sí solo no distingue un modelo local deliberado de un perfil al que le borraron la clave — y la clave ajena del secreto es ON DELETE SET NULL, lo que hace que el segundo caso sea corriente. Un run resuelve un perfil sin clave solo cuando este lleva un endpoint; si no, se rechaza con el mismo mensaje de «no key configured» que ha tenido siempre.

Cuando la credencial no es una clave de API

Provider id Credencial
Azure OpenAI azure clave + endpoint + versión de API fijada
AWS Bedrock bedrock id de clave de acceso, clave secreta, región, token de sesión opcional
Google Vertex AI google_cloud JSON de la cuenta de servicio
ChatGPT (suscripción de Codex) openai_codex un inicio de sesión de ChatGPT, guardado iniciando sesión en vez de tecleado

Los tres primeros son la razón de que un secreto tenga un kind. Un formulario que recogiera un único token opaco para Azure recogería algo que se puede rellenar correctamente y que aun así falla en el primer run. Ver los kinds de secreto.

Dos ids se reescriben de camino al SDK

Un perfil openai se construye como openai-chat u openai-responses, y uno azure como azure o azure-responses, según la API que guarda, en lugar de tomar la Responses API que infiere openai a secas. Ver Responses o Chat Completions.

google_cloud se construye como google-cloud. Ninguno de los dos cambia lo que guardas.

Ejecutar con una suscripción de ChatGPT

openai_codex ejecuta modelos de OpenAI en el backend de Codex a través de una suscripción de ChatGPT, en vez de a través de una clave de API medida. Está pensado para uso personal: el inicio de sesión es la suscripción de una persona, y cada run en un perfil que lo usa cuenta contra los límites de ChatGPT de esa persona.

Nadie puede teclear la credencial. En su lugar inicias sesión con ChatGPT:

  1. En Vault → add a secret (o en Agents → add a model, con ChatGPT (Codex subscription) seleccionado), elige Sign in with ChatGPT. Se abre un inicio de sesión de ChatGPT en una pestaña nueva.
  2. Apruébalo. ChatGPT envía entonces el navegador a http://localhost:1455/..., que no carga. Es lo esperado: OpenAI fija esa dirección para todos los clientes salvo el suyo propio.
  3. Copia la dirección completa de la barra de direcciones y pégala de vuelta en el formulario.

El código de esa dirección funciona una sola vez, solo para la persona que inició el inicio de sesión, y solo durante 15 minutos.

El access token caduca y se renueva mientras los modelos se ejecutan. Cada renovación gasta el refresh token, así que el par nuevo se vuelve a sellar en el mismo secreto del vault de inmediato. Dos runs que renuevan en el mismo momento aún pueden competir. El que pierde se rechaza, y la solución es Reconnect en el secreto, que vuelve a iniciar sesión sin cambiar su id.

Lo que no es un inicio de sesión de ChatGPT

  • No es el auth.json de la CLI de Codex. Ese archivo guarda la concesión propia de la CLI. Los refresh tokens son de un solo uso, así que cualquiera de los dos que renovara primero cerraría la sesión del otro.
  • No es una credencial de la organización. Un secreto se crea privado por defecto, y un modelo sobre él solo funciona para quien puede ver ese inicio de sesión en el vault y pregunta él mismo. Para cualquier otro - un visitante de una página pública o un embed, quien llama con una clave API - y para el trabajo en segundo plano como describir las imágenes de un documento, el modelo se rechaza y un fallback sobre él se omite.
  • El gasto mostrado no es tu factura. Un run se tarifa a los precios de la API de OpenAI para el mismo modelo, que es lo que un budget puede razonar. La suscripción en sí la factura OpenAI a tarifa plana.
  • Algunos ajustes se ignoran. El backend de Codex descarta max_tokens, temperature y top_p.

Ausentes a propósito

Cuatro nombres que Pydantic AI conoce no están aquí. sentence-transformers y voyageai son modelos de embeddings, bedrock-mantle no es un provider de chat al que un perfil pueda apuntar, y gateway no resuelve a una clase de provider — es un prefijo de enrutado sobre los demás.

tests/test_model_profiles.py construye cada entrada del catálogo, así que un provider no puede ser seleccionable en el Builder sin ser construible en tiempo de ejecución.

Qué lista responde a qué pregunta

Seis cosas de este repositorio saben algo sobre modelos y providers, y no son seis copias de una misma lista. Cada una responde a una pregunta distinta, y aquella de la que se derivan todas es la primera:

Pregunta Respondida por
¿A qué providers puede apuntar un perfil, y qué credencial quiere cada uno? PROVIDERS en backend/app/agents/model_resolver.py — la fuente de verdad, y solo para la parte que la inferencia del modelo no puede saber
¿Cómo construyo el cliente? El propio infer_provider_class / infer_model de pydantic_ai. No es asunto de esta plataforma, y deliberadamente no se repite aquí
¿Cómo leo la lista de modelos en vivo de este provider? backend/app/core/catalog/model_listings.json
¿Qué sugiero cuando no se le puede preguntar al provider? backend/app/core/catalog/curated_models.json
¿Cuánto cuesta este modelo, y cuánto contexto acepta? el snapshot de genai-prices, a través de model_catalog.priced_model
¿Qué modelos dibujan imágenes? backend/app/core/catalog/image_models.json, más la propia respuesta del SDK sobre qué providers pueden dibujar

Todo lo que hay bajo la primera fila se deriva de ella

Una copia derivada que se desvía no falla nada en tiempo de ejecución. Muestra un selector para un provider que no existe, o deja fuera uno que sí.

tests/test_model_catalog.py::TestOneAnswerPerQuestion es lo que en su lugar convierte eso en una build fallida — y exige que cada provider aparezca en esta página.

Cada clave de cualquiera de los dos archivos de catálogo tiene que nombrar un provider que PROVIDERS tenga. También cada entrada del catálogo de imágenes. Y cada provider tiene que aparecer en esta página. Añadir el vigesimonoveno es una edición más lo que ese test pida después.

Merece la pena conocer dos cruces, porque son búsquedas que pueden no responder nada:

  • El snapshot de precios escribe cuatro providers de otra forma — xai es x-ai, bedrock es aws, google_cloud es google, y openai_codex se tarifa como openai — y _PRICE_PROVIDER_ALIASES los puentea.
  • El catálogo de imágenes lleva su propio par provider y prefix, que es un tercer vocabulario otra vez.

Qué modelos ofrece un provider

El campo del id de modelo se rellena desde dos fuentes, en este orden — y desde ninguna de las dos para siete providers, cosa que la respuesta dice en voz alta.

En vivo

Veinte providers publican un endpoint de listado, y es la única fuente que sabe de un modelo publicado esta mañana:

anthropic, openai, google, openrouter, groq, mistral, together, cohere, deepseek, xai, sambanova, vercel, ovhcloud, huggingface, cerebras, fireworks, nebius, moonshotai, zai, alibaba.

Las formas de la respuesta no coinciden — el array está en data, en models o en la raíz del documento; el id es id, name o model; Gemini lo prefija con models/ — así que cada uno se describe con datos y no con una rama. Se cachean en el proceso durante una hora; estas listas se mueven en el orden de semanas.

Cinco de ellos no necesitan credencial alguna — openrouter, sambanova, vercel, ovhcloud y huggingface — que es lo que los hace valiosos: el selector se rellena antes de que nadie haya guardado una clave para ese provider. A los otros quince se les pregunta con la clave propia de la organización cuando la hay.

Seis providers siguen sin publicar nada que esto pueda leer: github (su ruta de catálogo ya no está), heroku, azure, bedrock, google_cloud, y un proxy litellm cuya lista es lo que el despliegue haya puesto detrás. ollama responde en la red del propio despliegue y no en un host fijo, así que tampoco está en la lista.

Una lista de modalidades vacía significa no declarado, nunca «solo texto»

openrouter y el router de Hugging Face llevan los dos architecture.output_modalities, y una entrada de listado puede nombrar esa ruta. Nadie más lo declara.

Un cliente que filtre por ella tiene que tratar la ausencia como desconocido, o esconderá modelos que funcionan. Son metadatos por los que un cliente puede estrechar; no son cómo la capability de imagen elige sus modelos, que es un archivo de catálogo más la propia respuesta del SDK sobre qué providers pueden dibujar — ver Generación de imágenes.

Curados

Una lista corta por provider, usada cuando el provider no publica nada, cuando la llamada falla, o cuando no hay clave con la que hacerla.

Vive en backend/app/core/catalog/curated_models.json junto a los demás catálogos del despliegue, así que añadir un modelo es una entrada y no una edición de Python — y los propios listados son model_listings.json en el mismo directorio, que es lo que convierte también en datos el endpoint de un provider nuevo.

Es deliberadamente corta y deliberadamente no se toma de genai-prices, que ya es una dependencia y sí lista modelos.

Ese es un conjunto de datos de precios. Lleva ada y babbage bajo OpenAI, claude-2 bajo Anthropic, 690 filas bajo OpenRouter, y no marca casi nada como obsoleto — ordenado alfabéticamente, lo primero que un selector ofrecería para OpenAI es ada. Una lista corta y actual gana a una larga y engañosa.

Para lo que la biblioteca sí se usa es para la mitad que se pudre. Cada longitud de contexto sale del snapshot en el momento de leerla, así que aquí no se escribe ninguna ventana; dos que lo estaban ya se habían quedado obsoletas, una de ellas anotada dos veces con dos cifras distintas.

Y un id curado del que el snapshot nunca ha oído hablar hace fallar la suite de tests, que es como se pilla una errata o un modelo retirado en vez de publicarlo como un desplegable al que el provider responde 404. Un modelo que el snapshot conoce pero no tarifa simplemente no tiene ventana, que es el nulo descrito más abajo.

Provider ids curados
anthropic claude-opus-5, claude-sonnet-5, claude-fable-5, claude-haiku-4-5
openai gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.3-codex
openai_codex los mismos cuatro que openai
google gemini-3.6-flash, gemini-3.5-flash, gemini-3.5-flash-lite, gemini-3.1-pro-preview
deepseek deepseek-v4-pro, deepseek-v4-flash
xai grok-4.5, grok-4.3
groq openai/gpt-oss-120b, llama-3.3-70b-versatile
openrouter cinco ids comunes entre providers

Ninguna de las dos, y lo dice

Siete providers no publican ningún listado que esta plataforma pueda leer y no tienen entrada curada — github, heroku, ollama, litellm, azure, bedrock y google_cloud.

Para esos, el source de la respuesta es unlisted, no curated. Una lista corta vacía no es una lista corta, y afirmar que lo es es lo que convierte «esta plataforma no puede enumerar este provider» en «este provider no tiene modelos» (#923). El selector pide el id en su lugar.

ollama y litellm son los que merece la pena conectar — los dos publican un /v1/models con forma de OpenAI en el endpoint que el perfil ya guarda — y eso exige decirle al listado una URL base, cosa que un ListingSpec.url fijo no puede ser.

Ninguna de las dos fuentes es autoritativa, que es por lo que el campo sigue siendo texto libre.

La ventana que acepta un modelo se lee una vez y se guarda

Un listado suele llevar cuántos tokens acepta el modelo, y el perfil lo anota como context_length cuando se crea.

Ese número es sobre el que se dispara la gestión de contexto: compactar a una fracción de la ventana es el único ajuste que sigue siendo correcto cuando un agent se muda a otro modelo.

Por qué se guarda en vez de resolverse por run

El camino de la petición no debe llamar a un provider, y lo único que podría consultar si no es el snapshot de precios incluido — que aquí se equivoca en la dirección que rompe un run.

Ese snapshot registra 1.000.000 para anthropic:claude-sonnet-4-5 frente a unos 200.000 reales, así que un disparo al 90 % cae por encima del techo real y la compactación nunca se activa antes de que el provider rechace la petición. Un perfil con fallbacks es peor: construye un FallbackModel cuyo id compuesto no resuelve a nada en absoluto.

Nulo significa no anotado, no cero: un perfil más antiguo que la columna, un provider que no publica longitud, una lista curada, o un listado al que no se pudo llegar. La capability resuelve entonces la ventana ella misma, exactamente como hacía antes.

Si sabes más que las dos, pon context_window en el binding. Un provider publica el máximo que se puede hacer aceptar a un modelo, y un despliegue limitado por beta o por nivel obtiene menos.

Una cadena de fallbacks lleva el número del primario. Un FallbackModel no tiene ventana propia, y a qué modelo llega un run no se sabe hasta que uno ha rechazado.

Lo que cuesta un run

Los precios vienen de un snapshot de genai-prices incluido en el paquete. Nada llama a casa para conseguirlos, lo que significa dos cosas que conviene saber:

  • Un modelo demasiado nuevo para el snapshot está sin tarifar, y un run que contenga uno se registra como parcialmente tarifado y no como si no costara nada. Un budget que tratara en silencio un modelo desconocido como gratis sería un budget con un agujero.
  • Un vendor/model de un agregador que el snapshot no conoce se tarifa como el modelo propio del proveedor, y una versión con punto se prueba también con guiones: el anthropic/claude-sonnet-5.5 de OpenRouter cuesta lo que el claude-sonnet-5-5 de Anthropic.
  • Actualizar los precios es subir una dependencia.

Un provider sin clave no registra gasto

El gasto se atribuye al secreto del vault al que resolvió el run, y un provider sin clave no tiene ninguno al que atribuirlo.

El coste se comprueba antes de cada petición al modelo y se registra incluso cuando el run falla. Ver Budgets.

Una delegación resuelve su propio perfil

Un run puede implicar varios modelos.

Un delegate funciona sobre el perfil que nombra su propio spec, resuelto cuando el runner recorre el árbol de delegación. Un especialista inline que no nombra ninguno funciona sobre el perfil del agent que lo llamó — a la vez la respuesta menos sorprendente y la única que funciona cuando el del padre es el único perfil que eligió el autor.

Esas peticiones se miden contra el único libro de cuentas del run padre, pero se tarifan por provider: el guard del delegate comparte el libro, los topes y las líneas base del mes, y toma su propio provider.

Compartir directamente el del padre tarifaría un delegate de Anthropic contra el catálogo de OpenAI — en silencio, y normalmente como sin tarifar, lo que subestima el run y marca uno perfectamente tarifable como un suelo.

La fila del run hijo que escribe una delegación nombra el modelo que la respondió, así que el panel de costes agrupa un turno delegado bajo el modelo que realmente se ejecutó y no bajo el del padre.

Modelos realtime

Una llamada de voz no usa un perfil de modelo. Su modelo se elige de un catálogo que trae este despliegue, backend/app/core/catalog/realtime_models.json, que lee backend/app/services/realtime_models.py y que se sirve al Builder en GET /api/v1/providers/realtime-models. La clave se nombra en la sección Voice del agent como un secreto del vault, no en un perfil. Es la misma forma que usa la voz a texto: una elección del catálogo más una clave explícita.

Cada entrada nombra un provider, sus modelos y, para cada modelo:

Campo Qué decide
transport webrtc (el navegador habla con el provider; este despliegue mantiene un sideband) o relay (el audio pasa por el socket de este despliegue)
input_sample_rate, output_sample_rate Las frecuencias PCM a las que el navegador graba y reproduce, a través del relay
voices, default_voice Lo que ofrece la sección Voice, y lo que significa no elegir nada
supports_thinking Si la capability de thinking del agent se traduce al ajuste de razonamiento propio del modelo
context_window Dónde una reconexión pasa de reproducir los turnos a un resumen de los más antiguos
pricing kind (tokens o per_minute), worst_case_usd_per_minute para la comprobación previa a una llamada, y usd_per_minute para un modelo por minuto

La familia gpt-realtime de OpenAI funciona sobre WebRTC y es el único provider probado en vivo. Azure OpenAI, Gemini Live y xAI funcionan sobre el relay y no están verificados en vivo. GPT-Live no está en el catálogo: no puede recibir historial después de que empiece una sesión, así que una reconexión no podría continuar una llamada.

Azure es un deployment más un modelo base. El nombre de un deployment lo elige su propietario y no dice nada de lo que ejecuta, así que la sección Voice toma el nombre del deployment como texto libre y el modelo del catálogo que ejecuta como base_model. El modelo base decide las voces y el precio: los tokens de una llamada de Azure se tarifan como ese modelo en OpenAI. El endpoint y la versión de la API vienen del secreto azure_openai.

Precios. Los modelos tarifados por token se tarifan por respuesta a partir del mismo snapshot incluido que los runs de texto. Un modelo por minuto (xAI) se factura por el tiempo conectado al usd_per_minute del catálogo. Un modelo tarifado por token que el snapshot no sabe tarifar se rechaza cuando empieza una llamada, en vez de funcionar con un budget que no puede hacer cumplir.

Resumen

  • Un perfil es un modelo con nombre más una clave con nombre, y los agents apuntan a perfiles para que rotar cualquiera de los dos toque una sola fila.
  • 28 providers, y lo único que esta plataforma sabe de cada uno es la forma de la credencial — construirlo es trabajo de Pydantic AI.
  • El id de modelo es texto libre, porque ninguna lista es autoritativa.
  • La longitud de contexto se lee una vez y se guarda, porque el snapshot de precios se equivoca sobre ella en la dirección que rompe un run.
  • El coste viene de un snapshot incluido, un modelo desconocido se registra como sin tarifar y no como gratis, y un provider sin clave no registra gasto alguno.
  • Los modelos realtime de las llamadas de voz son una elección del catálogo más una clave con nombre, sin perfil; solo los de OpenAI están verificados en vivo.

Configurar uno

El recorrido del primer agent hace esto de principio a fin. En resumen: guarda una clave de provider en Settings → Secrets, añade un perfil de modelo que la nombre y después apunta el spec de un agent a ese perfil.

make platform-bootstrap BOOTSTRAP_API_KEY=sk-...

hace las tres cosas para un despliegue nuevo.

Para usar la API regional de OpenRouter, conserva OpenRouter como proveedor e introduce https://eu.openrouter.ai/api/v1 en Endpoint del formulario del modelo. El perfil mantiene su clave OpenRouter del Vault, el tratamiento nativo de modelos y los controles de caché. Las sugerencias se obtienen de ese endpoint y se almacenan en una caché independiente; si falla la lista regional, no se utiliza el catálogo global. En las bases de conocimiento, configura el endpoint de embeddings por separado al crear la colección o editar su proveedor de embeddings. Las configuraciones existentes mantienen el endpoint global. El enrutamiento EU requiere un plan OpenRouter Business o Enterprise adecuado; el enrutamiento regional y ZDR son políticas distintas de OpenRouter.

Un endpoint regional sirve menos modelos de embeddings que el global: eu.openrouter.ai sirve mistralai/mistral-embed-2312, mistralai/codestral-embed-2505 y google/gemini-embedding-2, y ninguno de OpenAI. El formulario de creación ofrece solo los modelos que lista el endpoint, y se rechaza una colección cuyo modelo el endpoint no sirve, tanto al crearla como al moverla a él. Los dos modelos de Mistral no están en la instantánea de precios incluida, así que su gasto se registra como valorado en parte.

Actualiza todos los procesos de API y workers antes de configurar endpoints regionales. Las versiones anteriores ignoran el endpoint personalizado de OpenRouter.

Para otro endpoint con el mismo proveedor y modelo, elija Añadir modelo separado en el Builder. El nombre automático incluye el endpoint y el perfil existente no cambia. Actualizar modelo modifica el perfil compartido. Los catálogos personalizados están limitados a 2 MiB, 2048 modelos y longitudes de campos acotadas, con un máximo de 16 catálogos en caché por proceso. Una respuesta comprimida o demasiado grande permite escribir el ID del modelo sin recurrir a una lista global.