AIREITER

LangChain OpenRouter 設定指南:Base URL、工具與錯誤排除

最近更新: 2026-08-28 04:10:33

新建 LangChain 應用程式時,優先使用 ChatOpenRouter;如果是無法升級的舊專案,則保留 ChatOpenAI 搭配 https://openrouter.ai/api/v1。只有在 Anthropic Agent SDK 的整合路徑中,才使用 https://openrouter.ai/api。

先講結論:新 LangChain 專案直接使用原生整合

OpenRouter 負責模型端點與供應商路由,LangChain 則提供聊天模型、鏈與代理程式抽象層。目前建議的原生搭配是 Python 使用 langchain-openrouter 與 ChatOpenRouter,JavaScript 和 TypeScript 使用 @langchain/openrouter 與 ChatOpenRouter。

你的情境建議路徑主要原因
全新的 LangChain Python 應用程式langchain-openrouter + ChatOpenRouter原生整合提供供應商路由、metadata、推理內容、工具與結構化輸出控制
全新的 LangChain JS/TS 應用程式@langchain/openrouter + ChatOpenRouter保留 LangChain 原生的訊息、串流與工具介面
既有的舊版 LangChain 應用程式ChatOpenAI + base_url="https://openrouter.ai/api/v1"相容性修改幅度最小
已使用 init_chat_model 的既有應用程式LangChain v1 加上 langchain-openrouter啟用 model_provider="openrouter" 分派路徑
Claude/Anthropic Agent SDK 應用程式ANTHROPIC_BASE_URL="https://openrouter.ai/api"Agent SDK 使用 Anthropic 相容路由
使用 Vercel AI SDK 的 Next.js 應用程式@openrouter/ai-sdk-provider + createOpenRouter()採用 AI SDK 的 streamText() 與工具抽象層

LangChain 的官方套件公告指出,原生套件能保留通用 ChatOpenAI 包裝器可能遺失的 OpenRouter 專屬行為,包括推理內容、結構化輸出、路由 metadata 與追蹤識別。如果應用程式不依賴這些欄位,現有的相容性設定不必立刻重寫。

先搞懂端點對應,不要只看框架名稱

不同 SDK 會在 base URL 後面接上不同的請求路徑。OpenAI 相容路由使用 https://openrouter.ai/api/v1,OpenRouter OpenAI SDK 指南也是這樣設定;Anthropic Agent SDK 指南則會把 ANTHROPIC_BASE_URL 設為 https://openrouter.ai/api。

用戶端或 SDK要設定的 Base URL常見請求類型
OpenAI Python/JS SDKhttps://openrouter.ai/api/v1OpenAI Chat Completions
舊版 LangChain ChatOpenAIhttps://openrouter.ai/api/v1OpenAI 相容聊天請求
LangChain ChatOpenRouter通常不需要自訂 base URLOpenRouter 原生整合
Vercel AI SDK OpenRouter provider通常不需要自訂 base URL由 provider 套件管理端點
Anthropic Agent SDKhttps://openrouter.ai/apiAnthropic 相容的 Agent SDK 請求

除非 SDK 明確要求完整端點,否則不要把 /chat/completions 放進 base URL。如果錯誤訊息出現 /v1/v1 這類重複路徑,請檢查 SDK 如何將 base URL 與端點路徑組合。

對舊版 OpenAI 相容 LangChain 用戶端來說,最基本的可用設定如下:

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)

請使用 OpenRouter API key,而不是 OpenAI key。OpenRouter 的快速入門文件指定以 Bearer token 驗證。HTTP-Referer 與 X-OpenRouter-Title 是可選的應用程式識別標頭,不能取代 Authorization。

LangChain + OpenRouter:目前的設定方式

Python:langchain-openrouter

先安裝整合套件,並把 API key 放在原始碼之外:

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

接著建立原生聊天模型。LangChain Python 整合文件以這種形式示範 model、temperature、max_tokens 與 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)

OpenRouter 的模型名稱通常採用 provider/model 格式,例如 anthropic/claude-sonnet-4.5、openai/gpt-4o 或 deepseek/deepseek-r1。部署前請查閱 OpenRouter Models API,因為模型 ID、別名、變體、可用性與支援的參數都可能變動。

JavaScript 與 TypeScript:@langchain/openrouter

安裝整合套件與 LangChain core:

npm install @langchain/openrouter @langchain/core

LangChain JavaScript 整合文件採用物件式建構方式,和 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 使用 max_tokens,JavaScript 範例則使用 maxTokens。兩個整合套件預設都會讀取 OPENROUTER_API_KEY。如果模型明明出現在目錄中,程式卻呼叫失敗,請確認 slug、變體後綴與請求參數是否完全正確。

init_chat_model 與版本陷阱

常見錯誤如下:

ValueError: Unsupported model_provider='openrouter'.

根據LangChain Forum 的排錯討論,這通常是因為安裝的是 v1 以前的 LangChain,卻照著 v1 文件操作。討論中的建議是同時升級框架與 partner 套件:

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

完成後即可使用通用初始化器:

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)

如果專案無法升級到 LangChain v1,請安裝 langchain-openrouter,直接建立 ChatOpenRouter。這樣可以繞過通用 provider registry,並明確宣告 OpenRouter 依賴。

從 ChatOpenAI 遷移到 ChatOpenRouter

程式碼修改幅度不大,但整合邊界會從通用 OpenAI adapter 改成供應商專屬類別:

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

第一步先保留原本的 prompt 與 chain 呼叫位置。確認原生呼叫正常後,再加入供應商路由、推理內容、結構化輸出或 metadata 處理。

LangChain 中的串流、callbacks、工具與結構化輸出

model.stream() 會針對簡單的文字消費情境產生訊息區塊;stream_events(..., version="v3") 則會暴露生命週期事件,更適合 callback 式記錄、UI 狀態更新與 tracing。兩種介面都收錄在 LangChain 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)

當應用程式需要開始、token、結束或錯誤通知時,使用 callback;如果只需要模型區塊,使用 stream() 即可。使用量與回應 metadata 應從完整回應或聚合後的串流結果讀取,如整合文件所示,不要任意取第一個區塊當作最終資料。

工具呼叫與供應商路由

OpenRouter 在工具呼叫文件中說明了標準流程:模型提出工具呼叫,應用程式執行工具,再把工具結果回傳給模型。ChatOpenRouter.bind_tools() 接受 LangChain 工具、Python 函式、Pydantic 類別與字典 schema。

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)

第一次呼叫只會回傳模型提出的工具呼叫。完整的手動往返流程,必須為每個呼叫建立 ToolMessage,再請模型產生最終答案:

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)

供應商路由應放在 OpenRouter 專屬的模型設定中,相關做法可參考 LangChain 整合文件與 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 表示偏好順序;only 限制可使用的供應商,ignore 則排除指定供應商。allow_fallbacks=True 可能讓請求超出偏好順序,改送到其他供應商。require_parameters=True 會避開不支援 payload 中所有參數的供應商。這些設定是在可用性與供應商控制力之間取捨。

對舊版 ChatOpenAI 用戶端來說,OpenRouter 專屬欄位可能必須透過 extra_body 或 model_kwargs 傳遞,實際方式取決於用戶端版本。一位使用者在LangChain/OpenRouter Reddit 討論串中提出疑問:

「想請問,OpenRouter 不是支援 OpenAI API 規格,所以 OpenAI client 應該能運作嗎?」— u/tuxedo0。

專用套件把 OpenRouter 的整合邊界清楚表達出來,不必再依賴通用 OpenAI wrapper 來暴露每一個供應商專屬欄位。

結構化輸出:確認端點,不要只看模型名稱

原生整合透過 with_structured_output() 提供具型別的輸出。LangChain Python 文件示範了原生 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)

整合套件也支援 function_calling;strict 不支援搭配 json_mode 使用。OpenRouter 的結構化輸出行為可能因服務端點而異,因此光看模型名稱並不能保證支援。OpenRouter 結構化輸出指南說明了為什麼供應商能力檢查、require_parameters 與用戶端驗證都很重要。

Vercel AI SDK + OpenRouter

如果你正在開發使用 Vercel AI SDK 的 Next.js 或 TypeScript 應用程式,先安裝 OpenRouter provider:

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

以下精簡範例涵蓋文字串流與本機 Zod 工具。OpenRouter Vercel AI SDK 指南使用相同的 createOpenRouter() 與 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 會提供文字增量。如果應用程式需要推理內容、工具呼叫、工具結果、步驟邊界或完成事件,請改用 fullStream;AI SDK 的 streamText() 參考文件列出了這些結果介面。上方的天氣執行器只是 mock,並沒有真的呼叫即時 API。

一則公開的OpenRouter provider issue回報,在 @openrouter/ai-sdk-provider 2.2.3、AI SDK 6.0.81、Node.js 24 與 openai/gpt-5.2 的某條多區塊工具呼叫路徑中,可能出現感覺上的 buffering。回報指出缺少 tool-input-end 事件。這是特定版本問題,不應視為所有情境都會發生。如果你也遇到同樣問題,該 issue 提供了以下替代方案:

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

請另外安裝 @ai-sdk/openai,並鎖定你實際測試過的版本。這個 workaround 會更換 provider adapter,因此要確認哪些 OpenRouter 專屬選項仍然可用。

Anthropic Agent SDK + OpenRouter

Anthropic Agent SDK 是另一個獨立的整合邊界。OpenRouter 的官方 Agent SDK 指南指出,SDK 使用 Claude Code 作為執行環境,並接受以下環境設定:

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

ANTHROPIC_API_KEY 留空是刻意的。OpenRouter key 應放在 ANTHROPIC_AUTH_TOKEN,而這個 Agent SDK 設定使用的 /api 路徑,不應改成 OpenAI 相容的 /api/v1。

指南中的 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 提供模型端點,Agent SDK 則保留代理程式迴圈與工具執行環境。請在實際部署的路徑上測試工具、串流、上下文行為與模型專屬選項,因為 Anthropic 原生功能並不會自動完全相容。

401、404,以及「curl 可以、SDK 卻不行」

先找出失敗發生在哪一層,再決定是否要換模型。驗證、URL 組合、模型查找、供應商篩選與參數驗證,需要的是不同修正方式。

症狀可能出錯的層級第一個檢查項目
401 Missing Authentication header標頭或環境變數載入確認 Authorization: Bearer ...;測試 /api/v1/key
有 key 卻出現 401 Unauthorized錯誤、撤銷或空白的 key確認程序讀得到 OPENROUTER_API_KEY,並使用 OpenRouter key
路徑格式錯誤並出現 404Base URL 組合OpenAI 相容用戶端使用 /api/v1;Agent SDK 使用 /api;檢查是否重複加入 /v1
404 Invalid model 或 model_not_found模型識別碼查詢 /api/v1/models,使用回傳的 id 或文件列出的別名
404 No allowed providers are available供應商篩選或端點可用性檢查 only、ignore、max_price、require_parameters 與資料政策設定
top_k、min_p、工具或 JSON Schema 出現 400能力不相容檢查 supported_parameters;路由時要求相容供應商
curl 成功,但框架程式碼失敗SDK 路徑、大小寫、序列化或遺失的標頭比較最終 URL、驗證標頭、模型 ID 與 JSON body

OpenRouter 將 GET /api/v1/key 定義為經驗證的 API key 檢查端點。開始排查 LangChain 前,先執行:

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

接著確認模型探索端點:

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

在加入工具前,可以使用 Models API 篩選支援工具的模型:

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

404 也可能代表模型本身存在,但套用請求篩選條件後已沒有符合資格的供應商。若要檢查路由決策,可啟用選用的 X-OpenRouter-Metadata: enabled 標頭;Router Metadata 文件說明了回傳的 openrouter_metadata 物件與錯誤行為。

開發期間,請在遮蔽 key 後比對實際產生的請求:base URL、最終路徑、是否帶有 Authorization、精確的模型 ID,以及 request body 中的供應商專屬欄位。若要針對驗證問題進一步排查,可參考 AIReiter 的無效 API key 與 401/403 錯誤排除指南。

正式環境遷移檢查清單

  1. 對齊套件世代。 確保 langchain、langchain-core 與 langchain-openrouter 或 @langchain/openrouter 相容,不要直接照抄舊教學中的版本。
  2. 確認正式模型 ID。 使用 /api/v1/models 或 OpenRouter 模型目錄;將 alias 視為刻意的行為變更,而不是無害的替代名稱。
  3. 決定 fallback 邊界。 供應商 fallback 能提高可用性,但模型 fallback 可能改變品質、延遲、能力與成本。請記錄 OpenRouter 最終回傳的 model。
  4. 需要能力時就明確要求。 工具與結構化輸出請使用供應商能力篩選;不要把支援工具誤認為支援嚴格 JSON Schema。
  5. 驗證應用程式輸出。 在下游程式採取行動前,先用 Pydantic、Zod 或其他 validator 檢查工具參數與結構化回應。
  6. 記錄有用的 metadata。 在隱私政策允許的範圍內,保留 request ID、模型、使用量、完成原因與服務供應商資訊。LangChain 整合也記錄了可用於分組請求的 session_id,以及每次請求 metadata 的 trace。
  7. 測試兩種串流模式。 非串流呼叫成功,不代表工具呼叫區塊或 UI 串流也一定正常。
  8. 演練供應商限制。 如果使用 only、ignore、資料收集篩選或價格上限,務必測試沒有符合資格供應商時的錯誤路徑。
  9. 憑證只放在伺服器端。 將 OPENROUTER_API_KEY 存在伺服器環境或 secret manager,絕不要放進瀏覽器 bundle 或提交到版本庫的 .env 檔案。

最穩妥的順序是:先驗證 key,再確認模型 ID,接著完成一次純文字呼叫,最後才加入路由、工具、結構化輸出與多步驟串流。