SiCore TokenWorks
LLM APIAPI Gateway

Cómo cambiar entre proveedores de LLM sin modificar tu código

SiCore TokenWorks Team·2026-09-03

La mayoría de las personas no empiezan un proyecto pensando en la portabilidad entre proveedores. Toman una clave del proveedor que sea más fácil de registrar, escriben la integración y lanzan. Unos meses después leen un benchmark, o abren una factura, o chocan contra un límite de tasa, y quieren probar otra cosa. Ahí es cuando aparece el dolor, porque metieron suposiciones sobre el primer proveedor en la capa HTTP.

La solución no es una biblioteca de abstracción. Es un formato de cable. La API de chat completions de OpenAI se ha convertido silenciosamente en el protocolo por defecto para hablar con LLMs, y una vez que escribes contra ella, cambiar de proveedor es en su mayoría cuestión de cambiar dos cadenas.

La API que todos copiaron

OpenAI definió un contrato simple: haces POST de JSON a /v1/chat/completions, y recibes de vuelta una cadena choices[0].message.content. La petición se ve así:

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Explain DNS in one paragraph"}]
  }'

Casi todos los modelos importantes ahora hablan este dialecto. DeepSeek, Qwen, ERNIE, Doubao y los demás exponen un endpoint que acepta el mismo cuerpo y devuelve la misma forma. Eso significa que tu código cliente no se preocupa por quién está al otro lado. Puedes intercambiar la cadena model y el endpoint y nada más cambia.

Aquí está la misma llamada apuntada a un agregador que lleva varios de estos modelos bajo una sola URL base:

curl https://api.token8341.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKENWORKS_API_KEY" \
  -d '{
    "model": "deepseek-chat",
    "messages": [{"role": "user", "content": "Explain DNS in one paragraph"}]
  }'

Un cliente, muchos modelos

En Python normalmente instancias el SDK de OpenAI una vez y pasas un nombre de modelo por petición. Si tu proveedor soporta la API compatible, configuras base_url una vez y mantienes todo lo demás idéntico:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.token8341.com/v1",
    api_key="sk-your-tokenworks-key",
)

def ask(model: str, prompt: str) -> str:
    resp = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": prompt}],
    )
    return resp.choices[0].message.content

# Same function, three different model families.
print(ask("gpt-4o", "Summarize this log for me."))
print(ask("deepseek-chat", "Summarize this log for me."))
print(ask("qwen-max", "Summarize this log for me."))

La función no cambia. La cadena del modelo cambia. Ese es todo el truco. El streaming funciona de la misma manera:

stream = client.chat.completions.create(
    model="deepseek-chat",
    messages=[{"role": "user", "content": "Write a haiku about databases"}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta.content or ""
    print(delta, end="")

El function calling, el modo JSON y los embeddings también caben en la misma superficie compatible, así que no estás limitado al chat simple cuando cambias.

Lo que cambiar no te da

Quiero ser claro sobre la parte que no cambia gratis. El transporte es portable; los modelos no.

Distintos modelos responden a los prompts de manera diferente. Un system prompt ajustado para GPT-4o puede rendir por debajo en un modelo de razonamiento que quiere una estructura distinta. Las ventanas de contexto difieren, a veces mucho: un modelo puede aceptar 128k tokens mientras otro acepta 32k. Los tokenizers también difieren, así que el mismo documento cuesta un número distinto de tokens en cada modelo. La longitud máxima de salida es otra perilla que es por modelo, no por protocolo.

Así que "cambiar sin modificar el código" es en realidad "cambiar sin reescribir tu cliente HTTP". Aún te debes a ti mismo una ejecución de evaluación antes de apuntar el tráfico de producción a un nuevo modelo. La buena noticia es que la API compatible hace que esa evaluación sea barata de ejecutar, porque el arnés es solo un bucle sobre nombres de modelos.

Un patrón práctico

Lo que realmente hago en proyectos secundarios es mantener una pequeña tabla de configuración, no cambios de código:

MODELS = {
    "fast": "deepseek-chat",
    "smart": "qwen-max",
    "frontier": "gpt-4o",
}

def run(task, prompt):
    return ask(MODELS[task], prompt)

¿Quieres probar un modelo más barato para el carril fast? Cambia una línea. ¿Quieres recurrir a un segundo proveedor cuando el primero está limitado por tasa? Captura la excepción y reintenta con la siguiente cadena de modelo. Nada de esto toca la construcción de la petición.

Ese patrón de fallback es donde un endpoint multimodelo se gana su lugar. Con una sola URL base y una sola clave puedes enrutar, reintentar y hacer pruebas A/B entre proveedores, todo a través de las mismas dos líneas de configuración del cliente que escribiste el primer día.

Rarezas de respuesta a las que prestar atención

El transporte es compatible, pero algunas diferencias a nivel de respuesta todavía se filtran. Los modelos de razonamiento a veces devuelven un campo extra como reasoning_content junto al mensaje normal. El código que lee choices[0].message.content sigue funcionando igual, pero quizá quieras mostrar ese texto de razonamiento en una vista de depuración. Los mensajes de error también varían: un proveedor devuelve una cadena útil insufficient_quota, otro devuelve un 429 pelado sin cuerpo. Si estás construyendo reintentos, trata cualquier 429 o 5xx como "retrocede e inténtalo de nuevo" en lugar de analizar texto específico del proveedor.

Nada de esto es una razón para quedarte bloqueado con un solo proveedor. Es una razón para mantener tu manejo de errores genérico y tu elección de modelo como una variable.

Esta es la postura que adopta SiCore TokenWorks: un endpoint compatible con OpenAI en https://api.token8341.com/v1 donde la cadena del modelo es lo único que cambia cuando te mueves entre GPT-4o, Claude, Gemini, DeepSeek, Qwen, ERNIE, Doubao, Spark y Pangu.