AIREITER

Configurer LangChain avec OpenRouter : URLs de base, outils et correctifs

Dernière mise à jour: 2026-08-28 03:55:54

Pour un nouveau projet LangChain, partez sur ChatOpenRouter. Si votre ancien projet ne peut pas être mis à niveau, conservez ChatOpenAI avec https://openrouter.ai/api/v1. L’URL https://openrouter.ai/api est réservée au parcours Anthropic Agent SDK.

La réponse en une minute : choisissez l’intégration native pour les nouveaux projets LangChain

OpenRouter fournit le point d’accès aux modèles et la couche de routage, tandis que LangChain apporte les abstractions de modèles conversationnels, de chaînes et d’agents. L’association native actuelle repose sur langchain-openrouter et ChatOpenRouter en Python, ou sur @langchain/openrouter et ChatOpenRouter en JavaScript et TypeScript.

Votre situationLe bon choixRaison principale
Nouveau projet LangChain en Pythonlangchain-openrouter + ChatOpenRouterL’intégration expose le routage du fournisseur, les métadonnées, le raisonnement, les outils et les contrôles de sortie structurée
Nouveau projet LangChain en JS/TS@langchain/openrouter + ChatOpenRouterLes interfaces natives de LangChain pour les messages, le streaming et les outils sont conservées
Projet LangChain existant et ancienChatOpenAI + base_url="https://openrouter.ai/api/v1"Le changement de compatibilité est minimal
Projet existant utilisant init_chat_modelLangChain v1 avec langchain-openrouterActive le chemin de dispatch model_provider="openrouter"
Projet Claude/Anthropic Agent SDKANTHROPIC_BASE_URL="https://openrouter.ai/api"L’Agent SDK utilise la route compatible Anthropic
Application Next.js utilisant Vercel AI SDK@openrouter/ai-sdk-provider + createOpenRouter()Le projet s’appuie sur streamText() et les abstractions d’outils du AI SDK

L’annonce du package officiel de LangChain précise que l’intégration native conserve certains comportements propres à OpenRouter qu’un wrapper générique ChatOpenAI peut perdre : contenu de raisonnement, sortie structurée, métadonnées de routage et identité de traçage. Si ces informations ne vous sont pas utiles, votre configuration de compatibilité existante ne nécessite pas de réécriture immédiate.

Commencez par cartographier les endpoints, pas par choisir un framework

Chaque SDK ajoute ses propres chemins de requête à l’URL de base. La route compatible OpenAI est https://openrouter.ai/api/v1 ; c’est celle utilisée dans le guide OpenAI SDK d’OpenRouter. Le guide Anthropic Agent SDK, lui, définit ANTHROPIC_BASE_URL sur https://openrouter.ai/api.

Client ou SDKURL de base à configurerFamille de requêtes habituelle
OpenAI Python/JS SDKhttps://openrouter.ai/api/v1Chat Completions OpenAI
Ancien LangChain ChatOpenAIhttps://openrouter.ai/api/v1Appels conversationnels compatibles OpenAI
LangChain ChatOpenRouterGénéralement aucune URL personnaliséeIntégration native OpenRouter
Fournisseur OpenRouter pour Vercel AI SDKGénéralement aucune URL personnaliséeLe package fournisseur gère l’endpoint
Anthropic Agent SDKhttps://openrouter.ai/apiAppels de l’Agent SDK compatibles Anthropic

N’ajoutez pas /chat/completions à l’URL de base d’un SDK, sauf si celui-ci demande explicitement un endpoint complet. Si une erreur affiche un chemin dupliqué comme /v1/v1, vérifiez la façon dont le SDK assemble l’URL de base et le chemin de l’endpoint.

Pour un ancien client LangChain compatible OpenAI, la configuration minimale ressemble à ceci :

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)

Utilisez une clé API OpenRouter, et non une clé OpenAI. Le guide de démarrage rapide d’OpenRouter indique une authentification par jeton Bearer. HTTP-Referer et X-OpenRouter-Title sont des en-têtes facultatifs servant à attribuer l’application ; ils ne remplacent pas Authorization.

LangChain + OpenRouter : configuration actuelle

Python : langchain-openrouter

Installez l’intégration et gardez la clé en dehors du fichier source :

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

Instanciez ensuite le modèle conversationnel natif. L’intégration Python de LangChain documente sous cette forme les paramètres model, temperature, max_tokens et max_retries :

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)

Les noms de modèles OpenRouter suivent généralement le format provider/model, par exemple anthropic/claude-sonnet-4.5, openai/gpt-4o ou deepseek/deepseek-r1. Consultez l’API Models d’OpenRouter avant un déploiement : les identifiants, alias, variantes, disponibilités et paramètres pris en charge peuvent évoluer.

JavaScript et TypeScript : @langchain/openrouter

Installez l’intégration et le cœur de LangChain :

npm install @langchain/openrouter @langchain/core

Le constructeur sous forme d’objet présenté dans l’intégration JavaScript de LangChain est explicite et se compare facilement avec l’exemple 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 utilise max_tokens, tandis que l’exemple JavaScript emploie maxTokens. Les deux intégrations lisent OPENROUTER_API_KEY par défaut. Si un modèle présent dans le catalogue échoue dans le code, vérifiez le slug exact, le suffixe de variante et les paramètres de requête pris en charge.

init_chat_model et le piège des versions

Une erreur fréquente ressemble à ceci :

ValueError: Unsupported model_provider='openrouter'.

Selon un fil de dépannage sur le forum LangChain, ce problème survient lorsqu’une installation antérieure à la v1 est utilisée avec la documentation v1. La solution recommandée consiste à mettre à niveau le framework et le package partenaire ensemble :

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

Utilisez ensuite l’initialiseur générique :

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 le projet ne peut pas passer à LangChain v1, installez langchain-openrouter et construisez directement ChatOpenRouter. Vous contournez ainsi le registre de fournisseurs générique et rendez la dépendance à OpenRouter explicite.

Passer de ChatOpenAI à ChatOpenRouter

La modification de code reste limitée, mais la frontière d’intégration passe d’un adaptateur OpenAI générique à une classe spécifique au fournisseur :

# 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")

Conservez d’abord les mêmes prompts et points d’appel des chaînes. N’ajoutez la gestion du routage fournisseur, du raisonnement, de la sortie structurée ou des métadonnées qu’une fois l’appel natif de base fonctionnel.

Streaming, callbacks, outils et sortie structurée dans LangChain

model.stream() fournit des fragments de messages adaptés à une consommation simple du texte. stream_events(..., version="v3") expose des événements de cycle de vie mieux adaptés aux journaux de type callback, à l’état d’une interface et au traçage ; ces deux interfaces sont documentées dans l’intégration Python de LangChain.

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)

Utilisez un callback lorsque l’application doit recevoir des notifications de début, de jeton, de fin ou d’erreur. Préférez stream() si elle a uniquement besoin des fragments produits par le modèle. Lisez les informations d’utilisation et les métadonnées de réponse dans la réponse terminée ou dans le résultat agrégé du flux, comme l’indique la documentation liée, plutôt que dans un fragment choisi arbitrairement.

Appels d’outils et routage entre fournisseurs

OpenRouter décrit un flux normalisé pour les appels d’outils : le modèle propose un appel, l’application l’exécute, puis lui renvoie le résultat. ChatOpenRouter.bind_tools() accepte les outils LangChain, les fonctions Python, les classes Pydantic et les schémas sous forme de dictionnaire.

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)

Le premier appel renvoie uniquement les appels d’outils proposés par le modèle. Pour effectuer manuellement l’aller-retour complet, créez un ToolMessage pour chaque appel avant de demander au modèle de produire la réponse finale :

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)

Le routage entre fournisseurs se configure dans les paramètres spécifiques à OpenRouter, décrits par l’intégration LangChain et le guide de routage des fournisseurs d’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 définit une préférence. only limite les fournisseurs autorisés, tandis que ignore permet d’en exclure. Avec allow_fallbacks=True, une requête peut être envoyée au-delà de l’ordre préféré. require_parameters=True écarte les fournisseurs qui ne prennent pas en charge tous les paramètres présents dans la charge utile. Ces options arbitrent entre disponibilité et contrôle du fournisseur.

Avec les anciens clients ChatOpenAI, les champs propres à OpenRouter doivent parfois transiter par extra_body ou model_kwargs, selon la version du client. Dans un fil Reddit consacré à LangChain/OpenRouter, un utilisateur demandait :

« Je me demande si OpenRouter prend en charge la spécification d’API OpenAI, au point que le client OpenAI fonctionne ? » — u/tuxedo0.

Le package dédié rend explicite la frontière d’intégration OpenRouter, au lieu de demander à un wrapper OpenAI générique d’exposer chaque champ spécifique aux fournisseurs.

Sortie structurée : vérifiez l’endpoint, pas seulement le nom du modèle

L’intégration native expose une sortie typée via with_structured_output(). La documentation Python de LangChain présente la méthode native 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)

L’intégration documente également function_calling ; strict n’est pas compatible avec json_mode. Le comportement de la sortie structurée d’OpenRouter peut varier selon l’endpoint de service : le nom d’un modèle ne constitue donc pas une garantie suffisante. Le guide OpenRouter sur la sortie structurée explique pourquoi les vérifications de capacité du fournisseur, require_parameters et la validation côté client sont importantes.

Vercel AI SDK + OpenRouter

Pour une application Next.js ou TypeScript utilisant le AI SDK de Vercel, installez le fournisseur OpenRouter :

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

Cet exemple compact couvre le streaming de texte et un outil Zod local. Le guide OpenRouter pour Vercel AI SDK utilise le même schéma createOpenRouter() et 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 expose les deltas de texte. Utilisez fullStream si l’application doit gérer le raisonnement, les appels d’outils, leurs résultats, les limites entre les étapes ou les événements de fin ; la référence AI SDK de streamText() documente ces différents résultats. L’exécuteur météo ci-dessus est un mock, pas un appel à une API réelle.

Un ticket public du fournisseur OpenRouter a signalé un buffering perçu dans un parcours d’appel d’outil en plusieurs fragments avec @openrouter/ai-sdk-provider 2.2.3, AI SDK 6.0.81, Node.js 24 et openai/gpt-5.2. Le rapport mentionnait l’absence de l’événement tool-input-end. Considérez cela comme un problème lié à une version précise, et non comme un comportement général. S’il se reproduit, le ticket propose le contournement suivant :

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");

Installez séparément @ai-sdk/openai et verrouillez les versions que vous testez. Ce contournement change l’adaptateur fournisseur : vérifiez donc quelles options propres à OpenRouter restent disponibles.

Anthropic Agent SDK + OpenRouter

L’Anthropic Agent SDK constitue une frontière d’intégration distincte. Dans son guide officiel consacré à l’Agent SDK, OpenRouter indique que le SDK utilise Claude Code comme environnement d’exécution et accepte cette configuration :

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

La valeur vide de ANTHROPIC_API_KEY est volontaire. La clé OpenRouter doit être placée dans ANTHROPIC_AUTH_TOKEN, et le chemin /api ne doit pas être remplacé par le chemin compatible OpenAI /api/v1 dans cette configuration de l’Agent SDK.

Le guide propose cette structure TypeScript :

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 fournit l’endpoint du modèle ; l’Agent SDK conserve la boucle de l’agent et l’environnement d’exécution des outils. Testez les outils, le streaming, le comportement du contexte et les options propres au modèle sur la route exacte que vous déploierez : la parité avec les fonctionnalités natives d’Anthropic n’est pas automatique.

Erreurs 401, 404 et cas où « curl fonctionne, mais pas le SDK »

Identifiez la couche en échec avant de changer de modèle. L’authentification, la construction de l’URL, la recherche du modèle, les filtres de fournisseurs et la validation des paramètres ne se corrigent pas de la même manière.

SymptômeCouche probablement en causePremière vérification
401 Missing Authentication headerEn-tête ou chargement de l’environnementConfirmez Authorization: Bearer ... et testez /api/v1/key
401 Unauthorized alors qu’une clé est présenteClé incorrecte, révoquée ou videVérifiez que le processus voit OPENROUTER_API_KEY et utilisez une clé OpenRouter
404 avec un chemin mal forméAssemblage de l’URL de baseLes clients compatibles OpenAI utilisent /api/v1 ; l’Agent SDK utilise /api ; vérifiez la duplication de /v1
404 Invalid model ou model_not_foundIdentifiant du modèleInterrogez /api/v1/models et utilisez l’id renvoyé ou un alias documenté
404 No allowed providers are availableFiltres de fournisseurs ou disponibilité de l’endpointExaminez only, ignore, max_price, require_parameters et les paramètres de politique des données
400 pour top_k, min_p, les outils ou JSON SchemaIncompatibilité de capacitésVérifiez supported_parameters et exigez des fournisseurs compatibles lors du routage
curl fonctionne, mais le framework échoueChemin du SDK, casse, sérialisation ou en-têtes supprimésComparez l’URL finale, l’en-tête d’authentification, l’identifiant du modèle et le corps JSON

OpenRouter documente GET /api/v1/key comme un contrôle authentifié de la clé API. Exécutez-le avant de chercher le problème dans LangChain :

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

Vérifiez ensuite la découverte des modèles :

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

L’API Models permet de filtrer les modèles compatibles avec les outils avant d’en ajouter :

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

Une erreur 404 peut aussi indiquer que le modèle existe, mais qu’aucun fournisseur éligible ne reste après application des filtres de la requête. Pour examiner les décisions de routage, activez l’en-tête facultatif X-OpenRouter-Metadata: enabled ; la documentation Router Metadata décrit l’objet openrouter_metadata obtenu ainsi que son comportement en cas d’erreur.

En développement, comparez la requête générée après avoir masqué la clé : URL de base, chemin final, présence de l’en-tête Authorization, identifiant exact du modèle et champs spécifiques au fournisseur dans le corps. Pour approfondir les problèmes d’authentification, consultez le guide de dépannage d’AIReiter consacré aux clés API invalides et aux erreurs 401/403.

Checklist de migration pour la production

  1. Alignez les générations de packages. Gardez des versions compatibles de langchain, langchain-core et langchain-openrouter ou @langchain/openrouter, plutôt que de reprendre les versions d’un ancien tutoriel.
  2. Utilisez les identifiants canoniques des modèles. Appuyez-vous sur /api/v1/models ou sur le catalogue des modèles OpenRouter ; considérez les alias comme une modification de comportement intentionnelle.
  3. Définissez la frontière des replis. Le fallback entre fournisseurs améliore la disponibilité. Le fallback entre modèles peut modifier la qualité, la latence, les capacités et le coût. Enregistrez le model finalement renvoyé par OpenRouter.
  4. Exigez les capacités nécessaires. Utilisez les filtres de capacité des fournisseurs pour les requêtes avec outils ou sortie structurée ; ne considérez pas la prise en charge des outils comme une preuve de compatibilité avec JSON Schema strict.
  5. Validez les sorties applicatives. Pydantic, Zod ou un autre validateur doit contrôler les arguments des outils et les réponses structurées avant toute action du code en aval.
  6. Journalisez les métadonnées utiles. Conservez l’identifiant de requête, le modèle, l’utilisation, la raison de fin et les informations sur le fournisseur de service lorsque votre politique de confidentialité l’autorise. L’intégration LangChain documente aussi session_id pour regrouper les requêtes et trace pour les métadonnées par requête.
  7. Testez les deux modes de streaming. Un appel sans streaming réussi ne garantit pas que les fragments d’appels d’outils ou le streaming de l’interface fonctionneront correctement.
  8. Testez les restrictions de fournisseurs. Si vous utilisez only, ignore, des filtres de collecte de données ou un plafond de prix, testez le chemin d’échec lorsqu’aucun fournisseur n’est éligible.
  9. Gardez les identifiants côté serveur. Stockez OPENROUTER_API_KEY dans l’environnement serveur ou un gestionnaire de secrets, jamais dans un bundle navigateur ni dans un fichier .env versionné.

L’ordre fiable est le suivant : vérifier la clé, vérifier l’identifiant du modèle, effectuer un premier appel en texte brut, puis ajouter le routage, les outils, la sortie structurée et le streaming en plusieurs étapes.