AIREITER

Configuración de LangChain con OpenRouter: URLs base, herramientas y soluciones

Última actualización: 2026-08-28 03:53:11

Para las aplicaciones nuevas de LangChain, usa ChatOpenRouter. Mantén ChatOpenAI con https://openrouter.ai/api/v1 en los proyectos antiguos que no puedas actualizar y reserva https://openrouter.ai/api para la integración con Anthropic Agent SDK.

La respuesta rápida: en los proyectos nuevos, usa la integración nativa

OpenRouter aporta el endpoint del modelo y la capa de enrutamiento; LangChain se encarga de las abstracciones para modelos de chat, cadenas y agentes. La combinación nativa actual es langchain-openrouter con ChatOpenRouter en Python, o @langchain/openrouter con ChatOpenRouter en JavaScript y TypeScript.

Tu situaciónRuta recomendadaMotivo principal
Aplicación nueva de LangChain en Pythonlangchain-openrouter + ChatOpenRouterExpone el enrutamiento del proveedor, los metadatos, el razonamiento, las herramientas y los controles de salida estructurada
Aplicación nueva de LangChain en JS/TS@langchain/openrouter + ChatOpenRouterMantiene las interfaces nativas de LangChain para mensajes, streaming y herramientas
Aplicación antigua de LangChainChatOpenAI + base_url="https://openrouter.ai/api/v1"Es el cambio de compatibilidad más pequeño
Aplicación existente que usa init_chat_modelLangChain v1 más langchain-openrouterActiva la ruta de despacho mediante model_provider="openrouter"
Aplicación con Claude/Anthropic Agent SDKANTHROPIC_BASE_URL="https://openrouter.ai/api"El Agent SDK utiliza la ruta compatible con Anthropic
Aplicación Next.js con Vercel AI SDK@openrouter/ai-sdk-provider + createOpenRouter()Utiliza las abstracciones de streamText() y herramientas del AI SDK

El anuncio del paquete oficial de LangChain explica que la integración nativa conserva comportamientos específicos de OpenRouter que un wrapper genérico de ChatOpenAI puede perder, como el contenido de razonamiento, la salida estructurada, los metadatos de enrutamiento y la identidad de tracing. Si esos campos no son importantes para tu aplicación, no necesitas reescribir de inmediato una configuración de compatibilidad que ya funciona.

Empieza por el mapa de endpoints, no por el nombre del framework

Cada SDK añade rutas distintas a su URL base. La ruta compatible con OpenAI es https://openrouter.ai/api/v1; la guía del SDK de OpenAI para OpenRouter utiliza ese valor. En cambio, la guía de Anthropic Agent SDK configura ANTHROPIC_BASE_URL con https://openrouter.ai/api.

Cliente o SDKURL base que debes configurarFamilia habitual de solicitudes
SDK de OpenAI para Python/JShttps://openrouter.ai/api/v1Chat Completions de OpenAI
ChatOpenAI heredado de LangChainhttps://openrouter.ai/api/v1Llamadas de chat compatibles con OpenAI
ChatOpenRouter de LangChainNormalmente, ninguna URL base personalizadaIntegración nativa con OpenRouter
Proveedor de OpenRouter para Vercel AI SDKNormalmente, ninguna URL base personalizadaEl paquete del proveedor gestiona el endpoint
Anthropic Agent SDKhttps://openrouter.ai/apiLlamadas del Agent SDK compatibles con Anthropic

No introduzcas /chat/completions en la URL base de un SDK salvo que ese SDK solicite explícitamente un endpoint completo. Si un error muestra una ruta duplicada, como /v1/v1, revisa cómo combina el SDK la URL base con la ruta del endpoint.

En un cliente heredado de LangChain compatible con OpenAI, la configuración mínima funcional es:

import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="openai/gpt-4o",
    api_key=os.environ["OPENROUTER_API_KEY"],
    base_url="https://openrouter.ai/api/v1",
)

response = llm.invoke("Explain provider routing in one sentence.")
print(response.content)

Utiliza una clave de API de OpenRouter, no una clave de OpenAI. La guía de inicio rápido de OpenRouter especifica autenticación mediante un token Bearer. HTTP-Referer y X-OpenRouter-Title son cabeceras opcionales para atribuir la aplicación; no sustituyen a Authorization.

LangChain + OpenRouter: configuración actual

Python: langchain-openrouter

Instala la integración y mantén la clave fuera del archivo de código:

pip install -U langchain-openrouter
export OPENROUTER_API_KEY="sk-or-..."

Después, crea una instancia del modelo de chat nativo. La integración de LangChain para Python documenta model, temperature, max_tokens y max_retries con esta estructura:

from langchain_openrouter import ChatOpenRouter

model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    temperature=0,
    max_tokens=1024,
    max_retries=2,
)

response = model.invoke([
    ("system", "You are a concise technical assistant."),
    ("human", "What does OpenRouter add to a LangChain application?"),
])

print(response.content)

Los nombres de modelo de OpenRouter suelen seguir el formato provider/model, por ejemplo anthropic/claude-sonnet-4.5, openai/gpt-4o o deepseek/deepseek-r1. Consulta la API de modelos de OpenRouter antes de desplegar, porque los identificadores, alias, variantes, disponibilidad y parámetros compatibles pueden cambiar.

JavaScript y TypeScript: @langchain/openrouter

Instala la integración y el núcleo de LangChain:

npm install @langchain/openrouter @langchain/core

El constructor basado en objetos de la integración de LangChain para JavaScript resulta explícito y facilita compararlo con el ejemplo de Python:

import { ChatOpenRouter } from "@langchain/openrouter";

const model = new ChatOpenRouter({
  model: "anthropic/claude-sonnet-4.5",
  temperature: 0,
  maxTokens: 1024,
});

const response = await model.invoke([
  { role: "system", content: "You are a concise technical assistant." },
  { role: "user", content: "Explain the provider/model format." },
]);

console.log(response.content);

Python utiliza max_tokens; el ejemplo de JavaScript usa maxTokens. Ambas integraciones leen OPENROUTER_API_KEY de forma predeterminada. Si un modelo aparece en el catálogo pero falla en el código, comprueba el slug exacto, el sufijo de variante y los parámetros admitidos por la solicitud.

init_chat_model y la trampa de las versiones

Un error habitual es:

ValueError: Unsupported model_provider='openrouter'.

Un hilo de troubleshooting del foro de LangChain atribuye este caso a una instalación de LangChain anterior a v1 utilizada con documentación de v1. La solución recomienda actualizar el framework y el paquete del proveedor conjuntamente:

pip install -U "langchain>=1" langchain-openrouter

Después, utiliza el inicializador genérico:

import os
from langchain.chat_models import init_chat_model

os.environ["OPENROUTER_API_KEY"] = "sk-or-..."

model = init_chat_model(
    "anthropic/claude-sonnet-4.5",
    model_provider="openrouter",
)

print(model.invoke("Say hello in one sentence.").content)

Si el proyecto no puede migrar a LangChain v1, instala langchain-openrouter y crea directamente ChatOpenRouter. Así evitas el registro genérico de proveedores y dejas explícita la dependencia de OpenRouter.

Migrar de ChatOpenAI a ChatOpenRouter

El cambio de código es pequeño, pero el límite de integración pasa de un adaptador genérico de OpenAI a una clase específica del proveedor:

# Before: OpenAI-compatible workaround
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model="anthropic/claude-sonnet-4.5",
    base_url="https://openrouter.ai/api/v1",
    api_key=os.environ["OPENROUTER_API_KEY"],
)

# After: native OpenRouter integration
from langchain_openrouter import ChatOpenRouter

model = ChatOpenRouter(model="anthropic/claude-sonnet-4.5")

Conserva primero los mismos prompts y puntos de llamada de las cadenas. Añade el enrutamiento del proveedor, el razonamiento, la salida estructurada o el tratamiento de metadatos solo después de comprobar que la llamada nativa básica funciona.

Streaming, callbacks, herramientas y salida estructurada en LangChain

model.stream() devuelve fragmentos de mensaje para consumir texto de forma sencilla. stream_events(..., version="v3") expone eventos del ciclo de vida, más adecuados para registrar callbacks, actualizar el estado de una interfaz y hacer tracing; ambas opciones están documentadas en la integración de LangChain para Python.

model = ChatOpenRouter(model="openai/gpt-4o")

for event in model.stream_events(
    "Explain why OpenRouter has provider fallbacks.",
    version="v3",
):
    if event["event"] == "on_chat_model_stream":
        chunk = event["data"]["chunk"]
        print(chunk.text, end="", flush=True)

Usa un callback cuando la aplicación necesite notificaciones de inicio, tokens, finalización o errores. Elige stream() cuando solo necesites los fragmentos del modelo. Lee el uso y los metadatos de respuesta de la respuesta completada o del resultado agregado del stream, como muestra la documentación enlazada de la integración, no de un fragmento inicial elegido arbitrariamente.

Llamadas a herramientas y enrutamiento del proveedor

OpenRouter documenta un flujo normalizado de llamadas a herramientas: el modelo propone una llamada, la aplicación la ejecuta y después envía el resultado de la herramienta al modelo. ChatOpenRouter.bind_tools() acepta herramientas de LangChain, funciones de Python, clases de Pydantic y esquemas en forma de diccionario.

from pydantic import BaseModel, Field

class GetWeather(BaseModel):
    """Get current weather for a city."""

    location: str = Field(
        description="City and state, for example San Francisco, CA"
    )

model_with_tools = model.bind_tools(
    [GetWeather],
    strict=True,
)

result = model_with_tools.invoke("What is the weather in San Francisco?")
print(result.tool_calls)

La primera llamada solo devuelve las herramientas que el modelo propone utilizar. Para completar manualmente el ciclo, crea un ToolMessage por cada llamada antes de pedir al modelo la respuesta final:

from langchain_core.messages import HumanMessage, ToolMessage
from langchain_core.tools import tool

@tool
def get_weather(location: str) -> str:
    """Get the current weather in a location."""
    return f"Sunny in {location}."

model_with_tools = model.bind_tools([get_weather])
messages = [HumanMessage("What is the weather in San Francisco?")]
ai_msg = model_with_tools.invoke(messages)
messages.append(ai_msg)

for call in ai_msg.tool_calls:
    tool_output = get_weather.invoke(call["args"])
    messages.append(
        ToolMessage(
            content=tool_output,
            tool_call_id=call["id"],
        )
    )

final_msg = model_with_tools.invoke(messages)
print(final_msg.content)

El enrutamiento del proveedor se configura en el modelo mediante las opciones específicas de OpenRouter que describen la integración de LangChain y la guía de selección de proveedores de OpenRouter:

routed_model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    openrouter_provider={
        "order": ["Anthropic", "Google"],
        "allow_fallbacks": True,
        "require_parameters": True,
        "data_collection": "deny",
    },
)

order expresa una preferencia. only limita los proveedores elegibles y ignore excluye proveedores. allow_fallbacks=True permite que una solicitud se envíe fuera del orden preferido. require_parameters=True evita utilizar proveedores que no admitan todos los parámetros incluidos en la carga útil. Estas opciones equilibran disponibilidad y control sobre el proveedor.

En los clientes antiguos de ChatOpenAI, los campos específicos de OpenRouter quizá deban enviarse mediante extra_body o model_kwargs, según la versión del cliente. Un usuario preguntó en un hilo de Reddit sobre LangChain y OpenRouter:

«Me pregunto, ¿OpenRouter no admite la especificación de la API de OpenAI de forma que el cliente de OpenAI funcione?» — u/tuxedo0.

El paquete específico deja claro el límite de integración con OpenRouter, en lugar de exigir que un wrapper genérico de OpenAI exponga todos los campos propios del proveedor.

Salida estructurada: comprueba el endpoint, no solo el nombre del modelo

La integración nativa ofrece salida tipada mediante with_structured_output(). La documentación de LangChain para Python muestra el método nativo con JSON Schema:

from pydantic import BaseModel, Field

class Movie(BaseModel):
    title: str
    year: int
    director: str
    rating: float = Field(description="Rating from 0 to 10")

structured_model = ChatOpenRouter(
    model="openai/gpt-5.5",
).with_structured_output(
    Movie,
    method="json_schema",
    strict=True,
)

movie = structured_model.invoke("Give details about the movie Inception.")
print(movie)

La integración también documenta function_calling; strict no es compatible con json_mode. El comportamiento de la salida estructurada de OpenRouter puede variar según el endpoint que sirva la petición, así que el nombre del modelo por sí solo no ofrece garantías. La guía de OpenRouter sobre salida estructurada explica por qué son importantes las comprobaciones de capacidades del proveedor, require_parameters y la validación en el cliente.

Vercel AI SDK + OpenRouter

Si tu aplicación de Next.js o TypeScript utiliza el AI SDK de Vercel, instala el proveedor de OpenRouter:

npm install @openrouter/ai-sdk-provider ai zod

Este ejemplo compacto cubre el streaming de texto y una herramienta local basada en Zod. La guía de OpenRouter para Vercel AI SDK utiliza el mismo patrón con createOpenRouter() y openrouter("provider/model").

import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { isStepCount, streamText, tool } from "ai";
import { z } from "zod";

const openrouter = createOpenRouter({
  apiKey: process.env.OPENROUTER_API_KEY,
});

const result = streamText({
  model: openrouter("openai/gpt-4o"),
  tools: {
    getWeather: tool({
      description: "Get the current weather in a location",
      inputSchema: z.object({
        location: z.string().describe("City and state"),
      }),
      execute: async ({ location }) => ({
        location,
        temperature: 18,
        unit: "celsius",
      }),
    }),
  },
  stopWhen: isStepCount(3),
  prompt: "What is the weather in San Francisco?",
});

for await (const textPart of result.textStream) {
  process.stdout.write(textPart);
}

textStream expone los deltas de texto. Usa fullStream cuando la aplicación necesite razonamiento, llamadas a herramientas, resultados de herramientas, límites entre pasos o eventos de finalización; la referencia de streamText() del AI SDK documenta esas superficies de resultado. El ejecutor del tiempo en el ejemplo es simulado, no una llamada a una API real.

Un issue público del proveedor de OpenRouter informó de un posible buffering en una ruta de llamadas a herramientas con varios chunks usando @openrouter/ai-sdk-provider 2.2.3, AI SDK 6.0.81, Node.js 24 y openai/gpt-5.2. El informe describía la ausencia del evento tool-input-end. Trátalo como un problema específico de esa versión, no como un comportamiento universal. Si puedes reproducirlo, el issue propone esta solución alternativa:

import { createOpenAI } from "@ai-sdk/openai";

const openrouter = createOpenAI({
  apiKey: process.env.OPENROUTER_API_KEY,
  baseURL: "https://openrouter.ai/api/v1",
});

const model = openrouter.chat("openai/gpt-5.2");

Instala @ai-sdk/openai por separado y fija las versiones que hayas probado. Esta alternativa cambia el adaptador del proveedor, así que comprueba qué opciones específicas de OpenRouter siguen disponibles.

Anthropic Agent SDK + OpenRouter

Anthropic Agent SDK utiliza un límite de integración independiente. La guía oficial de Agent SDK de OpenRouter indica que el SDK utiliza Claude Code como runtime y acepta esta configuración de entorno:

export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
export ANTHROPIC_AUTH_TOKEN="$OPENROUTER_API_KEY"
export ANTHROPIC_API_KEY=""

Dejar ANTHROPIC_API_KEY vacío es intencionado. La clave de OpenRouter va en ANTHROPIC_AUTH_TOKEN, y en esta configuración del Agent SDK la ruta /api no debe sustituirse por la ruta compatible con OpenAI, /api/v1.

La estructura TypeScript de la guía es:

npm install @anthropic-ai/claude-agent-sdk
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Find and explain the bug in auth.py.",
  options: {
    allowedTools: ["Read"],
  },
})) {
  if (message.type === "assistant") {
    console.log(message.message.content);
  }
}

OpenRouter proporciona el endpoint del modelo; Agent SDK conserva el bucle del agente y el runtime de herramientas. Prueba las herramientas, el streaming, el comportamiento del contexto y las opciones específicas del modelo en la ruta exacta que vayas a desplegar, porque la paridad automática con las funciones nativas de Anthropic no está garantizada.

Errores 401, 404 y «funciona con curl, pero no con el SDK»

Identifica primero qué capa está fallando antes de cambiar de modelo. La autenticación, la construcción de la URL, la búsqueda del modelo, los filtros de proveedores y la validación de parámetros requieren soluciones diferentes.

SíntomaCapa probablePrimera comprobación
401 Missing Authentication headerCabecera o carga de variables de entornoConfirma Authorization: Bearer ... y prueba /api/v1/key
401 Unauthorized con una clave presenteClave incorrecta, revocada o vacíaConfirma que el proceso ve OPENROUTER_API_KEY y que utilizas una clave de OpenRouter
404 con una ruta mal formadaComposición de la URL baseLos clientes compatibles con OpenAI usan /api/v1; Agent SDK usa /api; busca un /v1 duplicado
404 Invalid model o model_not_foundIdentificador del modeloConsulta /api/v1/models y utiliza el id devuelto o un alias documentado
404 No allowed providers are availableFiltros de proveedores o disponibilidad del endpointRevisa only, ignore, max_price, require_parameters y la configuración de política de datos
400 para top_k, min_p, herramientas o JSON SchemaIncompatibilidad de capacidadesComprueba supported_parameters y exige proveedores compatibles al enrutar
curl funciona, pero falla el código del frameworkRuta del SDK, mayúsculas y minúsculas, serialización o cabeceras descartadasCompara la URL final, la cabecera de autenticación, el ID del modelo y el cuerpo JSON

OpenRouter documenta GET /api/v1/key como una comprobación autenticada de la clave de API. Ejecútala antes de depurar LangChain:

curl -sS https://openrouter.ai/api/v1/key \
  -H "Authorization: Bearer $OPENROUTER_API_KEY"

Después, verifica la disponibilidad de modelos:

curl -sS https://openrouter.ai/api/v1/models \
  -H "Authorization: Bearer $OPENROUTER_API_KEY"

La API de modelos permite filtrar los modelos compatibles con herramientas antes de añadirlas:

curl -sS \
  "https://openrouter.ai/api/v1/models?supported_parameters=tools" \
  -H "Authorization: Bearer $OPENROUTER_API_KEY"

Un 404 también puede indicar que el modelo existe, pero que ningún proveedor elegible queda disponible después de aplicar los filtros de la solicitud. Para inspeccionar las decisiones de enrutamiento, activa la cabecera opcional X-OpenRouter-Metadata: enabled; la documentación de Router Metadata describe el objeto openrouter_metadata resultante y su comportamiento ante errores.

Durante el desarrollo, compara la solicitud generada después de ocultar la clave: URL base, ruta final, presencia de Authorization, ID exacto del modelo y campos específicos del proveedor en el cuerpo. Para un seguimiento centrado en la autenticación, consulta la guía de AIReiter para resolver errores de clave de API no válida y errores 401/403.

Checklist de migración para producción

  1. Alinea las generaciones de los paquetes. Mantén compatibles langchain, langchain-core y langchain-openrouter o @langchain/openrouter, en lugar de copiar versiones de un tutorial antiguo.
  2. Resuelve los IDs canónicos de los modelos. Utiliza /api/v1/models o el catálogo de modelos de OpenRouter; considera los alias un cambio de comportamiento deliberado.
  3. Define el límite del fallback. El fallback entre proveedores mejora la disponibilidad. El fallback entre modelos puede cambiar la calidad, la latencia, las capacidades y el coste. Registra el model final que devuelve OpenRouter.
  4. Exige las capacidades importantes. Usa filtros de capacidades del proveedor para las solicitudes con herramientas y salida estructurada; no consideres que admitir herramientas demuestra compatibilidad con JSON Schema estricto.
  5. Valida las salidas de la aplicación. Pydantic, Zod u otro validador debe comprobar los argumentos de las herramientas y las respuestas estructuradas antes de que el código posterior actúe sobre ellas.
  6. Registra metadatos útiles. Conserva el ID de la solicitud, el modelo, el uso, el motivo de finalización y la información del proveedor que sirvió la petición cuando tu política de privacidad lo permita. La integración de LangChain también documenta session_id para agrupar solicitudes y trace para los metadatos de cada petición.
  7. Prueba los dos modos de streaming. Que una llamada sin streaming funcione no demuestra que los fragmentos de llamadas a herramientas o el streaming de la interfaz funcionen correctamente.
  8. Prueba las restricciones de proveedores. Si utilizas only, ignore, filtros de recopilación de datos o un límite de precio, comprueba también el flujo de error cuando no haya proveedores elegibles.
  9. Mantén las credenciales en el servidor. Guarda OPENROUTER_API_KEY en el entorno del servidor o en un gestor de secretos, nunca en un bundle del navegador ni en un archivo .env incluido en el repositorio.

El orden más fiable es este: verifica la clave, verifica el ID del modelo, realiza una llamada sencilla de texto y después añade el enrutamiento, las herramientas, la salida estructurada y el streaming de varios pasos.