Si estás trabajando en el backend de integración de múltiples modelos, probablemente hayas vivido esta pesadilla: el código de negocio lleno de if (vendor === 'openai') ... else if (vendor === 'claude') ..., una interfaz de chat en streaming con ochocientas líneas de lógica de adaptación, y cada vez que añades un nuevo proveedor tienes que tocar toda la cadena principal. El problema no eres tú, es que las APIs de los grandes modelos de cada fabricante simplemente no fueron diseñadas para ser unificadas.
La esencia de un gateway de modelos es una capa de traducción de protocolos: converger las peticiones/respuestas heterogéneas de N proveedores en un único conjunto de protocolo estándar interno. Este artículo lo desglosa en tres partes progresivas —principios, práctica y comparación— para explicar con claridad cómo debe construirse la capa de traducción.
I. Cuatro tipos de heterogeneidad: por qué la conexión directa a múltiples proveedores termina fuera de control
Veamos primero las diferencias reales, cada una con números.
Método de autenticación: OpenAI usa Authorization: Bearer sk-xxx, con un campo de cabecera de unos 51 caracteres; Claude usa x-api-key; Gemini mete la key en el parámetro de consulta ?key= de la URL; Qwen y ERNIE usan Authorization pero con algoritmos de firma distintos, y el access_token de ERNIE tiene una validez predeterminada de 30 días, devolviendo el código de error 110 al expirar. Cuatro proveedores, cuatro formas distintas.
Formato de fragmentación SSE en streaming: el chunk de OpenAI es data: {"choices":[{"delta":{"content":"x"}}]}, y el marcador de fin es data: [DONE]; el tipo de evento de Claude es event: content_block_delta con data: {"delta":{"text":"x"}}, donde el nombre del campo cambia de content a text; Gemini coloca el incremento en candidates[0].content.parts[0].text, con 3 niveles de anidamiento. Para que la capa de negocio parsee la misma frase, hay que escribir cuatro parsers distintos.
Sistema de códigos de error: esto es lo más desagradable. OpenAI usa el código de estado HTTP + error.type, y el rate limit es 429; Claude devuelve 429 en el rate limit pero el type del body es rate_limit_error; Qwen puede devolver un estado 200 en el rate limit pero con code: "Throttling" en el body; ERNIE usa error_code: 17 para indicar cuota excedida. Lo mismo, cuatro expresiones distintas.
Criterio de conteo de tokens: usage.total_tokens = prompt + completion en OpenAI, tanto para chino como para inglés se segmenta por BPE; Claude devuelve input_tokens y output_tokens por separado, y la granularidad de segmentación de caracteres chinos es más fina: para un mismo texto en chino de 500 caracteres, la diferencia de tokens contados entre ambos puede ser del 20% al 35%. En el cobro por uso, esta diferencia se convierte directamente en error de facturación.
Con conexión directa a cuatro proveedores, el código de la capa de negocio se infla a 3 o 4 veces el de un solo proveedor, y el coste de mantenimiento crece linealmente con el número de proveedores.
II. Diseño de la capa de traducción: formato unificado, normalización de streaming, mapeo de códigos de error y agregación de uso
La capa de traducción debe hacer cuatro cosas, sin que falte ninguna.
Formato unificado de petición/respuesta: definir internamente un conjunto de esquema estándar, con campos alineados al estilo de OpenAI (porque es el de mayor ecosistema). La petición externa se convierte primero al formato interno y luego el adaptador la convierte al formato de cada proveedor. Patrón adaptador: una clase por proveedor, implementando dos métodos, buildRequest() y parseResponse().
Normalización de la fragmentación en streaming: el núcleo es convertir el chunk SSE de cada proveedor en un {delta: string, finish_reason: string|null} unificado. La forma es escribir una máquina de estados que despache a distintos parsers según el tipo de proveedor y emita una estructura unificada. El punto clave es el manejo de límites: el separador \n\n de SSE, el prefijo data:, la concatenación de data en varias líneas, todo esto debe absorberse en el parser. El error que cometí fue con los eventos ping y message_stop de Claude: si no se ignoran explícitamente, se empuja un delta vacío al frontend y provoca parpadeo en la UI.
Tabla de mapeo de códigos de error: mantener un mapeo vendorCode -> unifiedCode, unificado en 6 categorías: AUTH_FAILED, RATE_LIMITED, QUOTA_EXCEEDED, INVALID_REQUEST, UPSTREAM_ERROR, TIMEOUT. Lo que devuelva el upstream, la capa de traducción lo consulta en la tabla y lo convierte al código unificado; la capa de negocio solo reconoce estos 6.
Agregación de uso: tras cada llamada, convertir el criterio de tokens de cada proveedor al token estándar interno, y al persistir incluir vendor, model, request_id, para la conciliación posterior y el análisis de costes. Aquí hay que prestar atención a las diferencias de criterio: el output_tokens de Claude y el completion_tokens de OpenAI no pueden sumarse directamente, hay que normalizarlos a una misma base mediante un coeficiente de conversión.
En cuanto a la arquitectura por capas, yo suelo dividir en cuatro: capa de acceso (autenticación + limitación de tasa), capa de enrutamiento (selección de modelo), capa de traducción (conversión de protocolo) y capa de adaptación (llamada al SDK del proveedor). La capa de traducción son funciones puras, sin tocar IO, lo que facilita las pruebas unitarias.
III. Código práctico: cambiar una línea de base_url para conectarse a un gateway agregador
Si no quieres escribir la capa de traducción desde cero, usar una plataforma de agregación de API de IA ya hecha es una opción más pragmática. En nuestro proyecto hemos usado token8341; es compatible con el SDK de OpenAI, basta cambiar una línea de base_url para cambiar de modelo, y el trabajo de la capa de traducción lo hace por ti.
from openai import OpenAI
client = OpenAI(
api_key="your-key",
base_url="https://api.token8341.com/v1" # solo cambia esta línea
)
resp = client.chat.completions.create(
model="deepseek-v3", # también puedes cambiar a gpt-4o / qwen-max / claude-4-sonnet
messages=[{"role": "user", "content": "Explica qué es SSE"}],
stream=True
)
for chunk in resp:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="")En este código, la normalización de la fragmentación SSE, el mapeo de códigos de error y la agregación de uso se completan en el lado del gateway, y lo que recibe la capa de negocio es directamente el formato estándar de OpenAI. El enrutamiento multi-modelo también se ahorra: el gateway puede seleccionar automáticamente el modelo óptimo según la tarea, por ejemplo, texto largo en chino va a Qwen, tareas de razonamiento a DeepSeek, y escenarios sensibles al coste a Doubao.
Aviso sobre errores: tras cambiar el base_url, no pases directamente los parámetros específicos del proveedor. Por ejemplo, logit_bias de OpenAI o top_k de Claude; puede que el gateway no los soporte todos, y pasarlos puede hacer que se ignoren silenciosamente, haciendo que creas que surten efecto cuando no lo hacen. Antes de desplegar, ejecuta un script de pruebas de carga para verificar la compatibilidad de parámetros.
IV. Comparación: enrutamiento multi-modelo vs vinculación a un solo modelo
Aquí van un conjunto de cifras de nuestras pruebas reales. Vinculación a un solo modelo (conexión directa a OpenAI): tiempo de integración de unos 2 días-persona, el failover requiere modificar código y volver a desplegar, tiempo medio de recuperación de 15 minutos, sin margen de optimización de costes. Enrutamiento multi-modelo (a través del gateway): tiempo de integración de unos 0,5 días-persona, el failover se completa automáticamente, tiempo de recuperación inferior a 3 segundos, y el coste puede reducirse entre un 30% y un 40% enrutando por tarea.
En cuanto a la complejidad de mantenimiento, el código de adaptación para conectar directamente a 4 proveedores es de unas 2000 líneas; tras usar el gateway, el código de adaptación de la capa de negocio baja a menos de 200 líneas, una reducción del 90%. En latencia, el gateway añade un salto, con un aumento del P99 de unos 20 a 40 ms; frente al coste de mantenimiento ahorrado y la flexibilidad de conmutación, este sobrecoste es aceptable.
Por supuesto, el gateway no es una bala de plata. Si tu negocio usa un solo modelo y nunca lo cambiará, la conexión directa es más simple. Pero en cuanto haya múltiples modelos, múltiples proveedores u optimización de costes, la capa de traducción es infraestructura obligatoria. Gateway de modelos, API de grandes modelos y agregación de API de IA son, en esencia, tres formas de decir lo mismo: el mismo problema de una misma capa.
Un último aviso: la cobertura de pruebas unitarias de la capa de traducción debe ser total, especialmente en los casos límite de la fragmentación en streaming, que es la zona de alta incidencia de incidentes en producción.
Autor: Liu Zhiyuan
Fecha de publicación: 28 de octubre de 2026