AIREITER

LangChain-OpenRouter-Setup: Base-URLs, Tools und Fehlerbehebung

Zuletzt aktualisiert: 2026-08-28 03:45:34

Für neue LangChain-Anwendungen ist ChatOpenRouter die richtige Wahl. In älteren Projekten, die sich nicht aktualisieren lassen, bleibt ChatOpenAI mit https://openrouter.ai/api/v1 die kompatible Lösung. Die URL https://openrouter.ai/api gehört ausschließlich zum Pfad über das Anthropic Agent SDK.

Die Kurzfassung: Für neue LangChain-Projekte die native Integration verwenden

OpenRouter stellt den Modell-Endpunkt und das Routing bereit, während LangChain Chat-Modelle, Chains und Agenten abstrahiert. Die aktuelle native Kombination besteht in Python aus langchain-openrouter und ChatOpenRouter; für JavaScript und TypeScript sind @langchain/openrouter und ebenfalls ChatOpenRouter vorgesehen.

Deine SituationGeeigneter PfadWichtigster Grund
Neue LangChain-Python-Anwendunglangchain-openrouter + ChatOpenRouterProvider-Routing, Metadaten, Reasoning, Tools und Optionen für strukturierte Ausgaben werden von der Integration unterstützt
Neue LangChain-JS/TS-Anwendung@langchain/openrouter + ChatOpenRouterDie nativen Message-, Streaming- und Tool-Schnittstellen von LangChain bleiben erhalten
Bestehende ältere LangChain-AnwendungChatOpenAI + base_url="https://openrouter.ai/api/v1"Die kleinste mögliche Kompatibilitätsänderung
Bestehende Anwendung mit init_chat_modelLangChain v1 plus langchain-openrouterAktiviert den Dispatch-Pfad über model_provider="openrouter"
Claude-/Anthropic-Agent-SDK-AnwendungANTHROPIC_BASE_URL="https://openrouter.ai/api"Das Agent SDK verwendet den Anthropic-kompatiblen Pfad
Next.js-Anwendung mit Vercel AI SDK@openrouter/ai-sdk-provider + createOpenRouter()Verwendet die streamText()- und Tool-Abstraktionen des AI SDKs

In der Ankündigung des First-Party-Pakets erklärt LangChain, dass die native Integration OpenRouter-spezifische Funktionen erhält, die bei einem generischen ChatOpenAI-Wrapper verloren gehen können. Dazu zählen Reasoning-Inhalte, strukturierte Ausgaben, Routing-Metadaten und die Identität fürs Tracing. Sind diese Informationen für dein Projekt unerheblich, muss eine bestehende Kompatibilitätslösung nicht sofort umgebaut werden.

Erst die Endpunkte klären, dann das Framework

SDKs hängen an ihre Base-URL unterschiedliche Request-Pfade an. Für die OpenAI-kompatible Route gilt https://openrouter.ai/api/v1; genau diesen Wert verwendet auch der OpenRouter-Leitfaden zum OpenAI SDK. Der Leitfaden zum Anthropic Agent SDK setzt dagegen ANTHROPIC_BASE_URL auf https://openrouter.ai/api.

Client oder SDKZu konfigurierende Base-URLTypische Request-Familie
OpenAI Python-/JS-SDKhttps://openrouter.ai/api/v1OpenAI Chat Completions
Legacy-LangChain-ChatOpenAIhttps://openrouter.ai/api/v1OpenAI-kompatible Chat-Aufrufe
LangChain ChatOpenRouterNormalerweise keine eigene Base-URLNative OpenRouter-Integration
Vercel-AI-SDK-OpenRouter-ProviderNormalerweise keine eigene Base-URLDas Provider-Paket verwaltet den Endpunkt
Anthropic Agent SDKhttps://openrouter.ai/apiAnthropic-kompatible Agent-SDK-Aufrufe

Setze /chat/completions nicht in die Base-URL eines SDKs, sofern dieses nicht ausdrücklich einen vollständigen Endpunkt verlangt. Taucht in einem Fehler ein doppelter Pfad wie /v1/v1 auf, solltest du prüfen, wie das SDK Base-URL und Endpunkt zusammensetzt.

Für einen älteren OpenAI-kompatiblen LangChain-Client sieht die kleinste funktionierende Konfiguration so aus:

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)

Verwende einen OpenRouter-API-Key, keinen OpenAI-Key. Der Quickstart von OpenRouter beschreibt die Authentifizierung per Bearer-Token. HTTP-Referer und X-OpenRouter-Title sind optionale Header zur App-Zuordnung und kein Ersatz für Authorization.

LangChain + OpenRouter: die aktuelle Einrichtung

Python: langchain-openrouter

Installiere die Integration und halte den Key aus dem Quellcode heraus:

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

Danach erzeugst du das native Chat-Modell. Die Python-Integration von LangChain dokumentiert model, temperature, max_tokens und max_retries in dieser Form:

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)

OpenRouter-Modellnamen folgen meist dem Schema provider/model, etwa anthropic/claude-sonnet-4.5, openai/gpt-4o oder deepseek/deepseek-r1. Prüfe vor dem Deployment die OpenRouter Models API, denn Modell-IDs, Aliase, Varianten, Verfügbarkeit und unterstützte Parameter können sich ändern.

JavaScript und TypeScript: @langchain/openrouter

Installiere die Integration zusammen mit LangChain Core:

npm install @langchain/openrouter @langchain/core

Der Konstruktor im Objektstil aus der JavaScript-Integration von LangChain ist eindeutig und lässt sich leicht mit dem Python-Beispiel vergleichen:

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

In Python heißt der Parameter max_tokens, im JavaScript-Beispiel maxTokens. Beide Integrationen lesen standardmäßig OPENROUTER_API_KEY. Wenn ein Modell im Katalog auftaucht, aber im Code fehlschlägt, prüfe den exakten Slug, den Variantenzusatz und die unterstützten Request-Parameter.

init_chat_model und die Versionsfalle

Ein typischer Fehler sieht so aus:

ValueError: Unsupported model_provider='openrouter'.

Ein Troubleshooting-Thread im LangChain-Forum führt diesen Fall darauf zurück, dass eine Installation vor v1 mit der v1-Dokumentation verwendet wird. Empfohlen wird, Framework und Partnerpaket gemeinsam zu aktualisieren:

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

Anschließend kannst du den generischen Initialisierer verwenden:

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)

Kann das Projekt nicht auf LangChain v1 wechseln, installiere langchain-openrouter und erzeuge ChatOpenRouter direkt. Damit umgehst du die generische Provider-Registry und machst die OpenRouter-Abhängigkeit explizit.

Von ChatOpenAI zu ChatOpenRouter wechseln

Die Codeänderung ist klein. Die Integrationsgrenze verschiebt sich jedoch von einem generischen OpenAI-Adapter zu einer providerspezifischen Klasse:

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

Behalte zunächst Prompts und Aufrufstellen deiner Chains unverändert. Routing, Reasoning, strukturierte Ausgaben oder Metadaten solltest du erst ergänzen, wenn der einfache native Aufruf funktioniert.

Streaming, Callbacks, Tools und strukturierte Ausgaben in LangChain

model.stream() liefert Message-Chunks für die einfache Textausgabe. stream_events(..., version="v3") stellt Lebenszyklus-Events bereit und eignet sich besser für Callback-Logging, UI-Zustände und Tracing. Beide Schnittstellen sind in der Python-Integration von LangChain dokumentiert.

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)

Verwende Callbacks, wenn die Anwendung Benachrichtigungen über Start, Tokens, Ende oder Fehler benötigt. stream() reicht aus, wenn nur Modell-Chunks verarbeitet werden sollen. Usage-Daten und Response-Metadaten solltest du aus der vollständigen Antwort oder dem aggregierten Stream-Ergebnis lesen, wie es die verlinkte Integrationsdokumentation zeigt – nicht aus einem beliebigen ersten Chunk.

Tool-Aufrufe und Provider-Routing

OpenRouter beschreibt einen normalisierten Tool-Calling-Ablauf: Das Modell schlägt einen Tool-Aufruf vor, die Anwendung führt ihn aus und sendet das Ergebnis anschließend zurück. ChatOpenRouter.bind_tools() akzeptiert LangChain-Tools, Python-Funktionen, Pydantic-Klassen und Dictionary-Schemas.

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)

Der erste Aufruf liefert lediglich die vom Modell vorgeschlagenen Tool-Aufrufe. Für den vollständigen manuellen Ablauf erzeugst du für jeden Aufruf eine ToolMessage, bevor du das Modell erneut nach der endgültigen Antwort fragst:

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)

Das Provider-Routing gehört in die OpenRouter-spezifische Modellkonfiguration, die in der LangChain-Integration und im OpenRouter-Leitfaden zum Provider-Routing beschrieben wird:

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

order legt eine bevorzugte Reihenfolge fest. Mit only beschränkst du die zulässigen Provider, mit ignore schließt du Provider aus. allow_fallbacks=True kann eine Anfrage über die bevorzugte Reihenfolge hinaus weiterleiten. require_parameters=True verhindert, dass ein Request an Provider geht, die nicht sämtliche Parameter der Payload unterstützen. Diese Einstellungen wägen Verfügbarkeit gegen Provider-Kontrolle ab.

Bei älteren ChatOpenAI-Clients müssen OpenRouter-spezifische Felder je nach Client-Version möglicherweise über extra_body oder model_kwargs übergeben werden. In einem Reddit-Thread zu LangChain und OpenRouter fragte ein Nutzer:

„Wondering, doesn't openrouter support the openai API spec such that the openai client works?“ — u/tuxedo0.

Das dedizierte Paket macht die Integrationsgrenze zu OpenRouter sichtbar, statt von einem generischen OpenAI-Wrapper zu verlangen, jedes providerspezifische Feld bereitzustellen.

Strukturierte Ausgaben: Nicht nur den Modellnamen prüfen

Die native Integration stellt typisierte Ausgaben über with_structured_output() bereit. Die Python-Dokumentation von LangChain zeigt die native JSON-Schema-Methode:

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)

Die Integration dokumentiert außerdem function_calling; zusammen mit json_mode wird strict nicht unterstützt. Das Verhalten strukturierter Ausgaben kann bei OpenRouter je nach Serving-Endpunkt variieren. Ein Modellname allein ist daher keine Garantie. Der Leitfaden zu strukturierten Ausgaben mit OpenRouter erklärt, warum Provider-Fähigkeitsprüfungen, require_parameters und clientseitige Validierung wichtig sind.

Vercel AI SDK + OpenRouter

Für eine Next.js- oder TypeScript-Anwendung mit dem Vercel AI SDK installierst du den OpenRouter-Provider:

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

Dieses kompakte Beispiel kombiniert Text-Streaming mit einem lokalen Zod-Tool. Der OpenRouter-Leitfaden zum Vercel AI SDK verwendet dasselbe Muster mit createOpenRouter() und 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 stellt Text-Deltas bereit. Wenn die Anwendung Reasoning, Tool-Aufrufe, Tool-Ergebnisse, Schrittgrenzen oder Finish-Events benötigt, solltest du fullStream verwenden. Die Referenz zu streamText() im AI SDK dokumentiert diese Ergebnis-Schnittstellen. Der Wetter-Executor im Beispiel ist ein Mock und ruft keine Live-API auf.

In einem öffentlichen Issue zum OpenRouter-Provider wurde bei einem mehrteiligen Tool-Call mit @openrouter/ai-sdk-provider 2.2.3, AI SDK 6.0.81, Node.js 24 und openai/gpt-5.2 ein wahrgenommenes Puffern gemeldet. Laut Bericht fehlte ein tool-input-end-Event. Das solltest du als versionsabhängiges Problem verstehen, nicht als allgemeines Verhalten. Wenn der Fehler bei dir auftritt, nennt das Issue folgenden Workaround:

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

Installiere @ai-sdk/openai separat und pinne die von dir getesteten Versionen. Der Workaround verändert den Provider-Adapter. Prüfe daher, welche OpenRouter-spezifischen Optionen weiterhin verfügbar sind.

Anthropic Agent SDK + OpenRouter

Das Anthropic Agent SDK bildet eine eigene Integrationsgrenze. Laut dem offiziellen OpenRouter-Leitfaden zum Agent SDK verwendet das SDK Claude Code als Laufzeitumgebung und akzeptiert folgende Konfiguration:

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

Dass ANTHROPIC_API_KEY leer bleibt, ist Absicht. Der OpenRouter-Key gehört in ANTHROPIC_AUTH_TOKEN. Für dieses Agent-SDK-Setup darf der Pfad /api nicht durch den OpenAI-kompatiblen Pfad /api/v1 ersetzt werden.

Der TypeScript-Aufbau aus dem Leitfaden sieht so aus:

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 liefert den Modell-Endpunkt; das Agent SDK behält die Agentenschleife und die Tool-Laufzeit. Teste Tools, Streaming, Kontextverhalten und modellspezifische Optionen auf genau der Route, die du später produktiv einsetzen willst. Eine automatische Funktionsgleichheit mit nativen Anthropic-Funktionen ist nicht garantiert.

401, 404 und „Mit curl funktioniert es, aber nicht im SDK“

Bevor du das Modell wechselst, solltest du die fehlerhafte Schicht eingrenzen. Authentifizierung, URL-Zusammensetzung, Modellsuche, Provider-Filter und Parameterprüfung benötigen jeweils andere Lösungen.

SymptomWahrscheinliche SchichtErste Prüfung
401 Missing Authentication headerHeader oder Laden der UmgebungsvariablenAuthorization: Bearer ... bestätigen und /api/v1/key testen
401 Unauthorized trotz vorhandenem KeyFalscher, widerrufener oder leerer KeyPrüfen, ob der Prozess OPENROUTER_API_KEY sieht; einen OpenRouter-Key verwenden
404 mit fehlerhaftem PfadZusammensetzen der Base-URLOpenAI-kompatible Clients verwenden /api/v1, das Agent SDK /api; auf ein doppeltes /v1 prüfen
404 Invalid model oder model_not_foundModellkennung/api/v1/models abfragen und die zurückgelieferte id oder einen dokumentierten Alias verwenden
404 No allowed providers are availableProvider-Filter oder Verfügbarkeit des Endpunktsonly, ignore, max_price, require_parameters und Datenschutz-Einstellungen prüfen
400 bei top_k, min_p, Tools oder JSON SchemaFähigkeitskonfliktsupported_parameters prüfen und beim Routing kompatible Provider verlangen
curl funktioniert, der Framework-Code aber nichtSDK-Pfad, Schreibweise, Serialisierung oder verworfene HeaderFinale URL, Auth-Header, Modell-ID und JSON-Body vergleichen

OpenRouter dokumentiert GET /api/v1/key als authentifizierte Prüfung des API-Keys. Führe diesen Test aus, bevor du LangChain untersuchst:

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

Danach prüfst du, ob die Modellsuche funktioniert:

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

Die Models API kann vor dem Hinzufügen von Tools nach tool-fähigen Modellen filtern:

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

Ein 404 kann außerdem bedeuten, dass das Modell existiert, nach Anwendung der Request-Filter aber kein geeigneter Provider übrig bleibt. Um Routing-Entscheidungen zu untersuchen, aktiviere den optionalen Header X-OpenRouter-Metadata: enabled. Die Dokumentation zu Router Metadata beschreibt das daraus entstehende openrouter_metadata-Objekt und das Verhalten bei Fehlern.

Vergleiche in der Entwicklung den erzeugten Request, nachdem du den Key entfernt hast: Base-URL, finaler Pfad, Vorhandensein des Authorization-Headers, exakte Modell-ID und providerspezifische Felder im Body. Für eine gezielte Untersuchung der Authentifizierung gibt es den Troubleshooting-Leitfaden von AIReiter zu ungültigen API-Keys sowie 401-/403-Fehlern.

Checkliste für die Migration in die Produktion

  1. Aufeinander abgestimmte Paketversionen verwenden. Halte langchain, langchain-core und langchain-openrouter beziehungsweise @langchain/openrouter kompatibel, statt Versionsnummern aus einem alten Tutorial zu übernehmen.
  2. Kanonische Modell-IDs auflösen. Verwende /api/v1/models oder den OpenRouter-Modellkatalog. Behandle Aliase als bewusst gewählte Verhaltensänderung.
  3. Die Fallback-Grenze festlegen. Provider-Fallbacks erhöhen die Verfügbarkeit. Ein Modell-Fallback kann dagegen Qualität, Latenz, Fähigkeiten und Kosten verändern. Speichere das von OpenRouter zurückgelieferte model.
  4. Fähigkeiten erzwingen, wenn sie relevant sind. Nutze Provider-Fähigkeitsfilter für Tool- und Structured-Output-Anfragen. Tool-Unterstützung allein ist kein Beleg für Unterstützung von strikt eingehaltenem JSON Schema.
  5. Ausgaben der Anwendung validieren. Pydantic, Zod oder ein anderer Validator sollte Tool-Argumente und strukturierte Antworten prüfen, bevor nachgelagerter Code darauf reagiert.
  6. Nützliche Metadaten protokollieren. Bewahre Request-ID, Modell, Usage, Finish-Reason und Serving-Provider auf, sofern es deine Datenschutzrichtlinie erlaubt. Die LangChain-Integration dokumentiert außerdem session_id zur Gruppierung von Requests und trace für Metadaten pro Request.
  7. Beide Streaming-Modi testen. Ein erfolgreicher Aufruf ohne Streaming beweist nicht, dass Tool-Call-Chunks oder UI-Streaming korrekt funktionieren.
  8. Provider-Beschränkungen durchspielen. Wenn du only, ignore, Filter zur Datensammlung oder eine Preisobergrenze verwendest, teste auch den Fehlerpfad ohne verfügbaren Provider.
  9. Zugangsdaten auf dem Server halten. Speichere OPENROUTER_API_KEY in der Serverumgebung oder einem Secret Manager – niemals in einem Browser-Bundle oder einer versionierten .env-Datei.

Die zuverlässige Reihenfolge lautet: Key prüfen, Modell-ID prüfen, einen einfachen Textaufruf ausführen und erst danach Routing, Tools, strukturierte Ausgaben und mehrstufiges Streaming ergänzen.