新建 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 SDK | https://openrouter.ai/api/v1 | OpenAI Chat Completions |
舊版 LangChain ChatOpenAI | https://openrouter.ai/api/v1 | OpenAI 相容聊天請求 |
LangChain ChatOpenRouter | 通常不需要自訂 base URL | OpenRouter 原生整合 |
| Vercel AI SDK OpenRouter provider | 通常不需要自訂 base URL | 由 provider 套件管理端點 |
| Anthropic Agent SDK | https://openrouter.ai/api | Anthropic 相容的 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 |
路徑格式錯誤並出現 404 | Base 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 錯誤排除指南。
正式環境遷移檢查清單
- 對齊套件世代。 確保
langchain、langchain-core與langchain-openrouter或@langchain/openrouter相容,不要直接照抄舊教學中的版本。 - 確認正式模型 ID。 使用
/api/v1/models或 OpenRouter 模型目錄;將 alias 視為刻意的行為變更,而不是無害的替代名稱。 - 決定 fallback 邊界。 供應商 fallback 能提高可用性,但模型 fallback 可能改變品質、延遲、能力與成本。請記錄 OpenRouter 最終回傳的
model。 - 需要能力時就明確要求。 工具與結構化輸出請使用供應商能力篩選;不要把支援工具誤認為支援嚴格 JSON Schema。
- 驗證應用程式輸出。 在下游程式採取行動前,先用 Pydantic、Zod 或其他 validator 檢查工具參數與結構化回應。
- 記錄有用的 metadata。 在隱私政策允許的範圍內,保留 request ID、模型、使用量、完成原因與服務供應商資訊。LangChain 整合也記錄了可用於分組請求的
session_id,以及每次請求 metadata 的trace。 - 測試兩種串流模式。 非串流呼叫成功,不代表工具呼叫區塊或 UI 串流也一定正常。
- 演練供應商限制。 如果使用
only、ignore、資料收集篩選或價格上限,務必測試沒有符合資格供應商時的錯誤路徑。 - 憑證只放在伺服器端。 將
OPENROUTER_API_KEY存在伺服器環境或 secret manager,絕不要放進瀏覽器 bundle 或提交到版本庫的.env檔案。
最穩妥的順序是:先驗證 key,再確認模型 ID,接著完成一次純文字呼叫,最後才加入路由、工具、結構化輸出與多步驟串流。