AIREITER

LangChain OpenRouter 配置指南:基础 URL、工具调用与常见问题修复

最后更新: 2026-08-28 04:07:29

如果是新建 LangChain 应用,直接使用 ChatOpenRouter。对于暂时无法升级的旧项目,继续让 ChatOpenAI 配合 https://openrouter.ai/api/v1 使用;只有在 Anthropic Agent SDK 这条路径中,才应配置 https://openrouter.ai/api。

先说结论:新 LangChain 项目优先使用原生集成

OpenRouter 负责模型接入与供应商路由,LangChain 则提供聊天模型、链和 Agent 抽象。目前推荐的原生组合是:Python 使用 langchain-openrouter 与 ChatOpenRouter,JavaScript 和 TypeScript 使用 @langchain/openrouter 与 ChatOpenRouter。

你的场景应使用的方案主要原因
新建 LangChain Python 应用langchain-openrouter + ChatOpenRouter集成直接暴露供应商路由、元数据、推理、工具和结构化输出控制
新建 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 专属行为,包括推理内容、结构化输出、路由元数据和追踪标识。如果你的应用并不依赖这些字段,现有的兼容性配置不必立即重写。

先搞清楚端点映射,再决定用哪个框架

不同 SDK 会在基础 URL 后拼接不同的请求路径。OpenAI 兼容路线使用 https://openrouter.ai/api/v1,OpenRouter OpenAI SDK 指南也是这样配置的。而Anthropic Agent SDK 指南要求将 ANTHROPIC_BASE_URL 设置为 https://openrouter.ai/api。

客户端或 SDK应配置的基础 URL典型请求类型
OpenAI Python/JS SDKhttps://openrouter.ai/api/v1OpenAI Chat Completions
旧版 LangChain ChatOpenAIhttps://openrouter.ai/api/v1兼容 OpenAI 的聊天请求
LangChain ChatOpenRouter通常无需自定义基础 URLOpenRouter 原生集成
Vercel AI SDK OpenRouter provider通常无需自定义基础 URL由 Provider 包管理端点
Anthropic Agent SDKhttps://openrouter.ai/api兼容 Anthropic 的 Agent SDK 请求

除非 SDK 明确要求传入完整端点,否则不要把 /chat/completions 也写进基础 URL。如果错误信息里出现 /v1/v1 这类重复路径,先检查 SDK 是如何将基础 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 的Quickstart规定使用 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 注册表,并明确声明对 OpenRouter 的依赖。

从 ChatOpenAI 迁移到 ChatOpenRouter

代码改动并不大,但集成边界会从通用的 OpenAI 适配器,变成针对具体 Provider 的模型类:

# 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 和链调用位置不变。等原生调用确认正常后,再逐步加入 Provider 路由、推理、结构化输出或元数据处理。

LangChain 中的流式输出、回调、工具和结构化输出

model.stream() 会产出消息片段,适合简单的文本消费。stream_events(..., version="v3") 则会暴露完整的生命周期事件,更适合回调式日志、UI 状态更新和追踪;这两种方式都记录在 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() 即可。用量和响应元数据应从完整响应或聚合后的流结果中读取,正如集成文档示例所示,不要从某个随意的首个片段中读取。

工具调用与 Provider 路由

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)

Provider 路由应通过 OpenRouter 专属模型配置来完成,具体可参考 LangChain 集成文档和 OpenRouter Provider 路由指南:

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 用于限制可选 Provider,ignore 用于排除 Provider。allow_fallbacks=True 允许请求在首选顺序之外继续寻找可用 Provider。require_parameters=True 会避开无法支持请求中全部参数的 Provider。这些设置本质上是在可用性和 Provider 控制力之间做取舍。

对于旧版 ChatOpenAI 客户端,OpenRouter 专属字段可能需要通过 extra_body 或 model_kwargs 传递,具体取决于客户端版本。一位用户在 LangChain/OpenRouter Reddit 讨论中提出了这个问题:

“想确认一下,OpenRouter 难道不支持 OpenAI API 规范,以至于 OpenAI 客户端无法工作吗?”—— u/tuxedo0。

专用集成包明确了 OpenRouter 的集成边界,不再要求通用 OpenAI 包装器暴露所有 Provider 专属字段。

结构化输出:检查端点,而不只是模型名称

原生集成通过 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 结构化输出指南解释了为什么 Provider 能力检查、require_parameters 和客户端验证都很重要。

Vercel AI SDK + OpenRouter

如果你是在 Next.js 或 TypeScript 应用中使用 Vercel AI SDK,可以安装 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() 参考文档中。上面的天气执行器只是模拟实现,并不会调用真实天气 API。

一个公开的 OpenRouter Provider issue 报告称,在 @openrouter/ai-sdk-provider 2.2.3、AI SDK 6.0.81、Node.js 24 和 openai/gpt-5.2 的某条多片段工具调用路径中,用户感知到输出被缓冲。报告提到缺少 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,并固定你实际测试过的版本。这个方案更换了 Provider 适配器,因此要重新确认哪些 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 则保留 Agent 循环和工具运行时。由于 Anthropic 原生能力并不会自动实现完全一致,务必在最终部署所用的准确路由上测试工具、流式输出、上下文行为和模型专属选项。

401、404,以及“curl 能用但 SDK 不行”

先定位失败发生在哪一层,再考虑更换模型。认证、URL 拼接、模型查询、Provider 过滤和参数校验,对应的是完全不同的修复方式。

现象可能出错的层首先检查什么
401 Missing Authentication header请求头或环境变量加载确认存在 Authorization: Bearer ...;测试 /api/v1/key
带有 key 仍返回 401 UnauthorizedKey 错误、已撤销或为空确认进程能读取 OPENROUTER_API_KEY;使用 OpenRouter key
路径格式异常的 404基础 URL 拼接兼容 OpenAI 的客户端使用 /api/v1;Agent SDK 使用 /api;检查是否重复出现 /v1
404 Invalid model 或 model_not_found模型标识符查询 /api/v1/models,使用返回的 id 或文档中记录的别名
404 No allowed providers are availableProvider 过滤或端点可用性检查 only、ignore、max_price、require_parameters 和数据策略设置
top_k、min_p、工具或 JSON Schema 返回 400能力不匹配检查 supported_parameters;进行路由时要求 Provider 具备兼容能力
curl 能用,但框架代码失败SDK 路径、大小写、序列化或请求头丢失逐项对比最终 URL、认证请求头、模型 ID 和 JSON 请求体

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 也可能意味着模型本身存在,但请求过滤条件执行后已经没有符合要求的 Provider。要查看路由决策,可以启用可选的 X-OpenRouter-Metadata: enabled 请求头;Router Metadata 文档介绍了返回的 openrouter_metadata 对象及其错误行为。

开发阶段可以在脱敏 API key 后,对比实际生成的请求:基础 URL、最终路径、是否存在 Authorization 请求头、准确的模型 ID,以及请求体中的 Provider 专属字段。若要集中排查认证问题,可以参考 AIReiter 的无效 API key 与 401/403 错误排查指南。

上线前的迁移检查清单

  1. 统一依赖版本。 确保 langchain、langchain-core 与 langchain-openrouter 或 @langchain/openrouter 彼此兼容,不要直接照抄旧教程中的版本号。
  2. 确认规范模型 ID。 使用 /api/v1/models 或 OpenRouter 模型目录;如果改用别名,应把它视为一次有意的行为变更。
  3. 明确回退边界。 Provider 回退可以提升可用性,但模型回退可能改变质量、延迟、能力和成本。记录 OpenRouter 最终返回的 model。
  4. 在能力重要时强制校验。 对工具调用和结构化输出请求使用 Provider 能力过滤;支持工具调用并不等于支持严格 JSON Schema。
  5. 校验应用输出。 在下游代码使用工具参数和结构化响应之前,应通过 Pydantic、Zod 或其他校验器进行检查。
  6. 记录有用的元数据。 在隐私政策允许的范围内保留请求 ID、模型、用量、结束原因和服务 Provider 信息。LangChain 集成还记录了用于请求分组的 session_id 以及用于单次请求元数据的 trace。
  7. 测试两种流式模式。 非流式调用成功,并不能证明工具调用片段或 UI 流式输出一定正常。
  8. 演练 Provider 限制场景。 如果使用了 only、ignore、数据收集过滤器或价格上限,务必测试没有可用 Provider 时的失败路径。
  9. 凭据只放在服务端。 将 OPENROUTER_API_KEY 存放在服务端环境或密钥管理器中,绝不要打包进浏览器 Bundle,也不要提交包含它的 .env 文件。

最稳妥的顺序是:先验证 key,再验证模型 ID,先完成一次普通文本调用,最后逐步加入路由、工具、结构化输出和多步骤流式处理。