API compatible con OpenAI: cambiar en tres líneas
Qué significa de verdad compatible con OpenAI, las tres líneas que llevan tu app a una API europea y una lista honesta de lo que no se puede migrar.
Tres líneas. Apuntas la base_url del cliente al nuevo proveedor, cambias la clave de API y sustituyes el nombre del modelo por el nombre de un tier. Todo lo demás en una llamada de chat completions, el array de mensajes, el streaming, las herramientas, los JSON schemas, se queda exactamente igual, porque compatible con OpenAI significa implementar el mismo contrato HTTP, no solo parecerse a él.
Lo interesante de una migración no es el código. Es lo que no se puede trasladar: los endpoints que aún no existen, el comportamiento del modelo que cambia con el mismo prompt y el único código de error que probablemente nunca has gestionado.

Qué significa de verdad «compatible con OpenAI»
Significa el contrato de un endpoint: POST /v1/chat/completions, con el mismo cuerpo de petición y la misma forma de respuesta, incluido el formato de server-sent events para el streaming. Ese contrato se convirtió en la interfaz por defecto del sector igual que la API de S3 se convirtió en el estándar del almacenamiento de objetos, y por el mismo motivo: todo estaba ya escrito contra ella.
Los SDK oficiales son clientes finos sobre ese contrato. En la librería de Python de OpenAI la base URL es un argumento del constructor, así que apuntarla a otro sitio es una operación soportada, no un apaño. Tu lógica de reintentos, tu gestor de streaming y tus definiciones de tipos siguen funcionando.
Lo que no significa es paridad de funciones en toda la plataforma. Los servicios compatibles implementan bien el endpoint de chat y a partir de ahí divergen, y por eso la versión honesta de este artículo es sobre todo una lista de diferencias.
from openai import OpenAIclient = OpenAI(api_key=os.environ["UNION_API_KEY"],base_url="https://api.europeanailab.eu/v1",)response = client.chat.completions.create(model="eu-standard",messages=[{"role": "user", "content": prompt}],stream=True,)
Cambian 3 líneas: la clave, la base URL y un nombre de tier en lugar de un nombre de modelo.
Todo lo demás en la llamada es el mismo contrato: mensajes, streaming, herramientas, JSON schemas. Lo que cambia no es la forma de la petición sino qué modelo escribe la respuesta, y por eso el checklist de más abajo trata de evaluación y no de código.
Las tres líneas, en la práctica
Este es el cambio completo en Python. Los SDK de Node, Go y .NET aceptan los mismos dos argumentos con otros nombres.
from openai import OpenAI
client = OpenAI(
api_key=os.environ["UNION_API_KEY"],
base_url="https://api.europeanailab.eu/v1",
)
response = client.chat.completions.create(
model="eu-standard",
messages=[{"role": "user", "content": prompt}],
stream=True,
)
Si tu código ya lee la base URL de una variable de entorno, algo que merece la pena hacer antes de cualquier migración, esto es un cambio de configuración y no un despliegue de código nuevo. Así además tienes la marcha atrás más barata posible: vuelves a apuntarla donde estaba.
Qué se mantiene, qué cambia y qué falta
La tabla que de verdad quieres tener antes de planificar el trabajo.
| Función | Estado | Qué hacer |
|---|---|---|
| Chat completions | Funciona sin cambios | Nada |
| Streaming (SSE) | Funciona sin cambios | Pide el consumo en el stream para que la medición sea exacta |
| Function calling y herramientas | Mismas formas | Vuelve a probar qué herramienta elige el modelo, no si sabe hacerlo |
| Salida estructurada (JSON schema) | Mismas formas | Sigue validando por tu lado, siempre |
| System prompts | Funcionan | Cuenta con reajustar la redacción, no la estructura |
| Nombres de modelo | Cambian | Usa un tier: eu-lite, eu-standard, eu-long, eu-pro |
| Consumo y coste | Cambian | Lee las cabeceras de la respuesta en lugar de un panel |
| Embeddings, imagen, voz | Faltan | Mantén tu proveedor actual para esto |
| API de batch | Falta | En la hoja de ruta, aún no disponible |
| API con estado al estilo Assistants | Falta | No está prevista; guarda el estado por tu lado |
Tres de esas filas son ausencias. Las publicamos como lista en la página de inicio en lugar de dejar que las descubras a mitad de la migración, porque «compatible» es una palabra que se ha estirado demasiado con servicios que implementan medio contrato y lo dan por terminado.
Por qué los nombres de modelo pasan a ser nombres de tier
Compras un tier, no un modelo. eu-standard es el tier para todo, eu-long admite un millón de tokens de contexto, eu-pro es el de razonamiento pesado, y cada uno corresponde a un modelo open-weight concreto, publicado con su licencia en la página de transparencia de la IA.
El motivo es la rotación. Los modelos open-weight se sustituyen cada pocos meses, y fijar en el código el nombre del modelo de hoy supone volver a desplegar cada vez que el sector avanza. Un tier es una promesa de capacidad y precio que sobrevive a que se cambie el modelo de debajo, y cuando lo cambiamos, lo decimos en lugar de alterar en silencio lo que hace tu código.
Las licencias también importan, y son lo bastante cortas como para leerlas. Casi todo lo que ejecutamos está bajo Apache 2.0 o MIT, y por eso esos mismos pesos pueden servirse legalmente desde hardware europeo.

Qué cambia en las respuestas, no en la API
Esta es la parte que sorprende a los equipos, así que resérvale tiempo. Cambiar de proveedor es cambiar de modelo, y los modelos se diferencian en cosas que ninguna capa de compatibilidad puede ocultar.
El formato se desvía. Un prompt ajustado para que un modelo devuelva markdown limpio puede producir un preámbulo en otro. Suele arreglarse con una línea, pero hay que arreglarlo.
El criterio para llamar a herramientas cambia. La forma de una llamada a función es idéntica; las ganas del modelo de hacerla, no. Hay modelos que llaman demasiado pronto y modelos que responden de memoria.
Las negativas cambian. Algunos modelos open-weight esquivan preguntas factuales sobre política o historia. Lo tratamos como un defecto y redirigimos una vez a un modelo sin ese punto ciego, y te lo decimos en la cabecera X-EU-Routed cuando lo hacemos. Todo está descrito en la página de transparencia de la IA.
La respuesta práctica es un conjunto de pruebas. Guarda veinte peticiones reales con sus salidas esperadas, lánzalas contra los dos proveedores y lee tú mismo las diferencias. Veinte bastan para detectar regresiones de formato y de elección de herramientas, y son pocas como para que de verdad lo hagas.
Coste y medición después del cambio
El precio por token es la misma idea en todas partes, pero cambia dónde lees las cifras. Cada respuesta lleva lo que ha costado la petición:
X-EU-Tokens-InyX-EU-Tokens-Out, los tokens medidos.X-EU-Cost-EUR, lo que se ha descontado de tu saldo por esta petición.X-EU-Balance-EUR, lo que te queda.X-EU-Model-Tier, el tier que la ha ejecutado de verdad.
Eso significa que tus propios logs pueden responder a la pregunta del coste por función, por cliente y por endpoint, sin esperar a que una factura mensual te lleve la contraria. Las tarifas detrás de esas cifras están en la página de precios, y cómo pensar en el coste por token en general, incluido por qué la salida es más cara que la entrada, lo explicamos en cuánto cuesta una API de IA por token.
Un hábito que merece la pena llevarse: pon max_tokens en cada llamada. Es el control de costes más eficaz de cualquier API por token, y es una línea.
Errores, límites y el 402 que no has gestionado
Tu gestión de errores probablemente cubre el 429 y el 500. El crédito prepago añade uno más.
- 402, saldo insuficiente. La petición se rechaza con un enlace para recargar, no se factura nada después y tu saldo nunca baja de cero. Trátalo como un error de autenticación: avisa, no reintentes en bucle.
- 429, límite de peticiones o tope de gasto. Respeta
Retry-After. Los topes los fijas tú, por clave, en euros al día y al mes. - 502 y 503, servicio de origen no disponible. Reintenta con backoff. Qué pasa durante una caída, y la limitación de depender de un solo proveedor que hay detrás, lo explicamos en la página de estado.
- Las peticiones fallidas son gratis. Si no ha vuelto ninguna respuesta útil, no se descuenta nada de tu saldo, y una petición redirigida a un modelo más débil se cobra a la más baja de las dos tarifas.
El tope de las cuentas nuevas pilla a la gente una vez: 25 € al día durante las primeras 48 horas, tengas el saldo que tengas. Existe porque una clave filtrada el primer día es el error más caro que puede cometer una integración nueva.
¿La compatibilidad te hace de verdad portable?
En parte, y conviene precisar en qué parte. El contrato de comunicación es portable: cualquier servicio que hable chat completions puede ponerse detrás del mismo cliente. Solo eso ya elimina la forma más burda de dependencia, aquella en la que irte significa reescribir tu capa de integración.
Lo que no es portable es todo lo que has construido encima de un modelo concreto. Prompts ajustados durante meses, ejemplos few-shot elegidos para las manías de un modelo, conjuntos de evaluación puntuados contra el estilo de salida de un modelo y cualquier umbral que hayas fijado viendo cómo se comporta ese modelo. Nada de eso se traslada limpiamente, y nada de eso aparece en un diagrama de arquitectura.
Así que trata el modelo como una dependencia con versión, no como una constante. Guarda los prompts en archivos en lugar de repartidos por el código, guarda el conjunto de pruebas en el repositorio y apunta por qué un umbral es el que es. Los equipos que lo hacen cambian de proveedor en una tarde. Los que no, se pasan un trimestre descubriendo qué estaban compensando sus prompts.
Checklist de migración
Media jornada para un servicio pequeño, un sprint para algo con tráfico real.
- Pasa la base URL a la configuración si todavía no lo está. Todo lo que sigue es más fácil a partir de ahí.
- Elige un tier según la carga de trabajo, no por el nombre. La clasificación y la extracción van en el tier barato; solo el trabajo con mucho razonamiento necesita el caro.
- Monta el conjunto de pruebas. Veinte peticiones reales, salidas esperadas, subidas al repositorio.
- Ejecuta los dos proveedores en paralelo con una pequeña parte del tráfico y compara los resultados.
- Conecta las cabeceras de coste a lo que ya estés registrando.
- Añade la ruta del 402, y de paso un tope por clave.
- Mantén configurado el proveedor anterior durante quince días. Una migración que puedes deshacer con un cambio de configuración es una migración que puedes hacer un martes cualquiera.
Contra qué proveedor hacer esa evaluación es otra pregunta, y las cuatro opciones realistas las comparamos en proveedores europeos de IA comparados. Las diez primeras peticiones son gratis y la recarga mínima es de 10 €, así que la evaluación cuesta menos que la reunión para decidir si hacerla. El contrato completo, con curl y Python para copiar, está en la documentación de la API, y dónde se procesan esas peticiones, salto a salto, lo contamos en adónde van tus prompts.
Preguntas frecuentes
¿Qué significa que una API sea compatible con OpenAI?
Significa que el servicio implementa el mismo contrato HTTP que el endpoint de chat completions de OpenAI: el mismo cuerpo de petición, la misma forma de respuesta y el mismo formato de streaming. Como los SDK oficiales son envoltorios finos sobre ese contrato, normalmente basta con apuntar uno a otra base URL.
¿Cómo cambio de la API de OpenAI a otro proveedor?
Cambia la clave de API, pon en base_url la dirección del nuevo proveedor y sustituye el nombre del modelo. En los SDK de OpenAI para Python y Node la base URL es un argumento del constructor, así que el cambio son tres líneas: la clave, la base URL y el nombre del modelo.
¿Siguen funcionando el streaming y el function calling después del cambio?
En Union AI, sí. El streaming usa el mismo formato de server-sent events y puede devolver el consumo de tokens al final del stream, y el function calling y la salida estructurada con JSON schema mantienen las mismas formas de petición y respuesta. Lo que cambia es el criterio del modelo sobre cuándo llamar a una herramienta, y eso conviene probarlo.
¿Qué funciones de OpenAI faltan en las API compatibles?
Depende del proveedor, y los honestos publican la lista. En Union AI, la versión 1 es solo el contrato de chat completions: no hay endpoints de embeddings, imagen ni voz, no hay API de batch ni API con estado al estilo Assistants. Están nombrados en la hoja de ruta en lugar de dar a entender que existen, así que comprueba esas mismas cuatro carencias en cualquier proveedor compatible.
¿Mis prompts darán las mismas respuestas en un modelo open-weight?
No, y nunca hay dos modelos que lo hagan. Las instrucciones de formato, el comportamiento con herramientas y la forma de negarse cambian, así que trata un cambio de proveedor como un cambio de modelo: guarda veinte peticiones reales como conjunto de pruebas y compara las salidas antes de hacer el cambio.
¿Cómo comparo el coste antes de cambiar?
Toma una semana de tráfico real, cuenta por separado los tokens de entrada y de salida y calcula el precio de ambos lados por millón de tokens con sus tarifas de lista. La salida domina la mayoría de las facturas, así que un proveedor que parece barato en la entrada puede salir más caro en una carga de trabajo que genera mucho texto.
¿Puedo seguir usando el SDK de OpenAI?
Sí. Los SDK oficiales de OpenAI funcionan sin cambios con cualquier servicio que implemente el mismo contrato, que es justo la gracia de la compatibilidad. Conservas tu lógica de reintentos, tu gestión del streaming y tus tipos, y solo cambias adónde van las peticiones.