> ## Documentation Index
> Fetch the complete documentation index at: https://langchain-docs-zh.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# ChatOpenRouter 集成

> 使用 LangChain Python 集成 ChatOpenRouter 对话模型。

这将帮助您快速上手OpenRouter [对话模型](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/models.md)。OpenRouter是一个统一的API，通过单一端点访问来自多个供应商（OpenAI、Anthropic、Google、Meta等）的模型。

> [!TIP]
>
> **API Reference**
>
> 欲获取所有功能及配置选项的详细文档，请访问@\[`ChatOpenRouter`] API参考。

欲查看所有可用模型列表，请访问[OpenRouter模型页面](https://openrouter.ai/models)。

## 概述

### 集成细节

| 类别 | 包 | 可序列化 | JS/TS支持 | 下载 | 最新版本 |
| :- | :- | :-: | :-: | :-: | :-: |
| @\[`ChatOpenRouter`] | @\[`langchain-openrouter`] | beta | ❌ | [![Downloads per month](https://static.pepy.tech/badge/langchain-openrouter/month)](https://pypi.org/project/langchain-openrouter/) | [![PyPI - Latest version](https://img.shields.io/pypi/v/langchain-openrouter?style=flat-square\&label=%20\&color=orange)](https://pypi.org/project/langchain-openrouter/) |

### 模型特性

| [工具调用](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/tools.md) | [结构化输出](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/structured-output.md) | [图像输入](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/messages.md#多模态) | 音频输入 | 视频输入 | [Token级流式输出](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/streaming.md) | 原生异步 | [Token使用量](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/models.md#token-使用) | [对数概率](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/models.md#对数概率) |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

## 配置

要通过OpenRouter访问模型，您需要创建一个[OpenRouter账户](https://openrouter.ai/)，获取API密钥并安装`langchain-openrouter`集成包。

### 安装

LangChain OpenRouter集成包位于`langchain-openrouter`包中：

```bash pip theme={null}
pip install -U langchain-openrouter
```

```bash uv theme={null}
uv add langchain-openrouter
```

### 凭据

前往[OpenRouter密钥页面](https://openrouter.ai/settings/keys)注册并生成API密钥。配置完成后设置`OPENROUTER_API_KEY`环境变量：

```python theme={null}
import getpass
import os

if not os.getenv("OPENROUTER_API_KEY"):
    os.environ["OPENROUTER_API_KEY"] = getpass.getpass("Enter your OpenRouter API key: ")
```

要启用模型调用自动追踪功能，请设置您的[LangSmith](https://docs.langchain.com/langsmith/observability) API密钥：

```python theme={null}
os.environ["LANGSMITH_API_KEY"] = getpass.getpass("Enter your LangSmith API key: ")
os.environ["LANGSMITH_TRACING"] = "true"
```

## 实例化

现在可以实例化模型对象并生成对话补全：

```python theme={null}
from langchain_openrouter import ChatOpenRouter

model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    temperature=0,
    max_tokens=1024,
    max_retries=2,
    # other params...
)
```

***

## 调用

```python theme={null}
messages = [
    (
        "system",
        "You are a helpful assistant that translates English to French. Translate the user sentence.",
    ),
    ("human", "I love programming."),
]
ai_msg = model.invoke(messages)
ai_msg.content
```

```text theme={null}
"J'adore la programmation."
```

***

## 流式输出

```python theme={null}
stream = model.stream_events("Write a short poem about the sea.", version="v3")
for token in stream.text:
    print(token, end="", flush=True)
```

异步流式输出也受支持：

```python theme={null}
stream = await model.astream_events("Write a short poem about the sea.", version="v3")
async for token in stream.text:
    print(token, end="", flush=True)
```

***

## 工具调用

OpenRouter采用OpenAI兼容的工具调用格式。您可以通过描述工具及其参数，使模型返回包含要调用的工具及其输入的JSON对象。

### 绑定工具

使用`ChatOpenRouter.bind_tools`，可传入Pydantic类、字典模式、LangChain工具或函数作为工具传递给模型。底层会将这些对象转换为OpenAI工具 schema 并在每次模型调用时传递。

```python theme={null}
from pydantic import BaseModel, Field


class GetWeather(BaseModel):
    """Get the current weather in a given location"""

    location: str = Field(description="The city and state, e.g. San Francisco, CA")


model_with_tools = model.bind_tools([GetWeather])
```

```python theme={null}
ai_msg = model_with_tools.invoke(
    "what is the weather like in San Francisco",
)
ai_msg
```

```text theme={null}
AIMessage(content='', response_metadata={'finish_reason': 'tool_calls'}, tool_calls=[{'name': 'GetWeather', 'args': {'location': 'San Francisco, CA'}, 'id': 'call_abc123', 'type': 'tool_call'}], usage_metadata={'input_tokens': 68, 'output_tokens': 17, 'total_tokens': 85})
```

### 工具调用

AIMessage对象具有`tool_calls`属性，其中包含标准化格式的工具调用，与模型供应商无关。

```python theme={null}
ai_msg.tool_calls
```

```text theme={null}
[{'name': 'GetWeather',
  'args': {'location': 'San Francisco, CA'},
  'id': 'call_abc123',
  'type': 'tool_call'}]
```

### 严格模式

传递`strict=True`以确保模型输出严格匹配工具定义的JSON Schema：

```python theme={null}
model_with_tools = model.bind_tools([GetWeather], strict=True)
```

欲了解更多关于工具绑定及调用输出的细节，请参考[工具调用](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/tools.md)文档。

***

## 结构化输出

`ChatOpenRouter`支持通过[`with_structured_output`](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/models#结构化输出)方法实现结构化输出。提供两种方法：`function_calling`（默认）和`json_schema`。

> [accordion] Individual model calls
>
> 使用`with_structured_output`生成结构化模型响应。指定`method="json_schema"`以启用基于JSON Schema的结构化输出；否则该方法默认使用函数调用。
>
> ```python theme={null}
> from langchain_openrouter import ChatOpenRouter
> from pydantic import BaseModel, Field
>
> model = ChatOpenRouter(model="openai/gpt-5.5")
>
> class Movie(BaseModel):
>     """A movie with details."""
>     title: str = Field(description="The title of the movie")
>     year: int = Field(description="The year the movie was released")
>     director: str = Field(description="The director of the movie")
>     rating: float = Field(description="The movie's rating out of 10")
>
> structured_model = model.with_structured_output(Movie, method="json_schema")  # [!code highlight]
> response = structured_model.invoke("Provide details about the movie Inception")
> response
> ```
>
> ```python theme={null}
> Movie(title='Inception', year=2010, director='Christopher Nolan', rating=8.8)
> ```

> [accordion] Agent response format
>
> 在生成智能体最终响应时，通过指定`response_format`与[`ProviderStrategy`](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/structured-output)启用结构化输出。
>
> ```python theme={null}
> from langchain.agents import create_agent
> from langchain.agents.structured_output import ProviderStrategy
> from pydantic import BaseModel
>
> class Weather(BaseModel):
>     temperature: float
>     condition: str
>
> def weather_tool(location: str) -> str:
>     """Get the weather at a location."""
>     return "Sunny and 75 degrees F."
>
> agent = create_agent(
>     model="openrouter:openai/gpt-5.5",
>     tools=[weather_tool],
>     response_format=ProviderStrategy(Weather),  # [!code highlight]
> )
>
> result = agent.invoke({
>     "messages": [{"role": "user", "content": "What's the weather in SF?"}]
> })
>
> result["structured_response"]
> ```
>
> ```python theme={null}
> Weather(temperature=75.0, condition='Sunny')
> ```

使用`strict=True`与`function_calling`、`json_schema`方法强制遵循精确Schema。`strict`参数不支持与`json_mode`组合使用。

```python theme={null}
structured_model = model.with_structured_output(Movie, method="json_schema", strict=True)
```

***

## 推理输出

对于支持推理的模型（如`anthropic/claude-sonnet-4.5`、`deepseek/deepseek-r1`），可通过`reasoning`参数启用推理Token。详见[OpenRouter推理文档](https://openrouter.ai/docs/guides/best-practices/reasoning-tokens)：

```python theme={null}
model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    max_tokens=16384,
    reasoning={"effort": "high", "summary": "auto"},
)

ai_msg = model.invoke("What is the square root of 529?")

# Access reasoning content via content_blocks
for block in ai_msg.content_blocks:
    if block["type"] == "reasoning":
        print(block["reasoning"])
```

欲了解更多内容块信息，请参考[标准内容块](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/messages.md#标准内容块)指南。

`reasoning`字典包含两个键：

* `effort`：控制推理Token预算。取值：`"xhigh"`、`"high"`、`"medium"`、`"low"`、`"minimal"`、`"none"`。
* `summary`：控制推理摘要返回的详细程度。取值：`"auto"`、`"concise"`、`"detailed"`。

推理Token使用量包含在`usage_metadata`中：

```python theme={null}
print(ai_msg.usage_metadata)
# {'input_tokens': ..., 'output_tokens': ..., 'total_tokens': ...,
#  'output_token_details': {'reasoning': ...}}
```

> [!NOTE]
>
> 努力与预算的映射关系取决于具体模型。例如，Google Gemini模型将努力值映射到内部`thinkingLevel`而非精确Token预算。详见[OpenRouter推理文档](https://openrouter.ai/docs/guides/best-practices/reasoning-tokens)。

***

## 多模态输入

OpenRouter支持[多模态输入](https://langchain-docs-zh.mintlify.site/langchain/oss/langchain/messages.md#多模态)（仅限支持该特性的模型）。具体支持的模态需参考[OpenRouter模型页面](https://openrouter.ai/models)。

### 支持的输入方式

| 方法 | 图像 | 音频 | 视频 | PDF |
| - | :-: | :-: | :-: | :-: |
| HTTP/HTTPS URL | ✅ | ❌ | ✅ | ✅ |
| Base64内联数据 | ✅ | ✅ | ✅ | ✅ |

> [!NOTE]
>
> 并非所有模型都支持所有模态。具体支持情况请查阅[OpenRouter模型页面](https://openrouter.ai/models)。

### 图像输入

将图像输入与文本通过@\[`HumanMessage`]的列表内容格式组合传递。

```python URL theme={null}
from langchain_openrouter import ChatOpenRouter
from langchain.messages import HumanMessage

model = ChatOpenRouter(model="openai/gpt-4o")

message = HumanMessage(
    content=[
        {"type": "text", "text": "Describe this image."},
        {
            "type": "image",
            "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg",
        },
    ]
)
response = model.invoke([message])
```

```python Base64 encoded theme={null}
import base64
import httpx
from langchain_openrouter import ChatOpenRouter
from langchain.messages import HumanMessage

model = ChatOpenRouter(model="openai/gpt-4o")

image_url = "https://picsum.photos/id/237/200/300"
image_data = base64.b64encode(httpx.get(image_url, follow_redirects=True).content).decode("utf-8")

message = HumanMessage(
    content=[
        {"type": "text", "text": "Describe this image."},
        { # [!code highlight]
            "type": "image", # [!code highlight]
            "base64": image_data, # [!code highlight]
            "mime_type": "image/jpeg", # [!code highlight]
        }, # [!code highlight]
    ]
)
response = model.invoke([message])
```

### 音频输入

提供与文本一起的音频输入。音频以内联Base64数据形式传递。

```python theme={null}
import base64
from pathlib import Path
from langchain_openrouter import ChatOpenRouter
from langchain.messages import HumanMessage

model = ChatOpenRouter(model="google/gemini-2.5-flash")

audio_data = base64.b64encode(Path("/path/to/audio.wav").read_bytes()).decode("utf-8")

message = HumanMessage(
    content=[
        {"type": "text", "text": "Transcribe this audio."},
        { # [!code highlight]
            "type": "audio", # [!code highlight]
            "base64": audio_data, # [!code highlight]
            "mime_type": "audio/wav", # [!code highlight]
        }, # [!code highlight]
    ]
)
response = model.invoke([message])
```

### 视频输入

视频输入会自动转换为OpenRouter的 `video_url` 格式。

```python URL theme={null}
from langchain_openrouter import ChatOpenRouter
from langchain.messages import HumanMessage

model = ChatOpenRouter(model="google/gemini-2.5-pro-preview")

message = HumanMessage(
    content=[
        {"type": "text", "text": "Describe this video."},
        {
            "type": "video",
            "url": "https://example.com/video.mp4",
        },
    ]
)
response = model.invoke([message])
```

```python Base64 encoded theme={null}
import base64
from pathlib import Path
from langchain_openrouter import ChatOpenRouter
from langchain.messages import HumanMessage

model = ChatOpenRouter(model="google/gemini-2.5-pro-preview")

video_data = base64.b64encode(Path("/path/to/video.mp4").read_bytes()).decode("utf-8")

message = HumanMessage(
    content=[
        {"type": "text", "text": "Describe this video."},
        { # [!code highlight]
            "type": "video", # [!code highlight]
            "base64": video_data, # [!code highlight]
            "mime_type": "video/mp4", # [!code highlight]
        }, # [!code highlight]
    ]
)
response = model.invoke([message])
```

### PDF输入

提供与文本一起的PDF文件输入。

```python URL theme={null}
from langchain_openrouter import ChatOpenRouter
from langchain.messages import HumanMessage

model = ChatOpenRouter(model="google/gemini-2.5-pro-preview")

message = HumanMessage(
    content=[
        {"type": "text", "text": "Summarize this document."},
        {
            "type": "file",
            "url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
            "mime_type": "application/pdf",
        },
    ]
)
response = model.invoke([message])
```

```python Base64 encoded theme={null}
import base64
from pathlib import Path
from langchain_openrouter import ChatOpenRouter
from langchain.messages import HumanMessage

model = ChatOpenRouter(model="google/gemini-2.5-pro-preview")

pdf_data = base64.b64encode(Path("/path/to/document.pdf").read_bytes()).decode("utf-8")

message = HumanMessage(
    content=[
        {"type": "text", "text": "Summarize this document."},
        { # [!code highlight]
            "type": "file", # [!code highlight]
            "base64": pdf_data, # [!code highlight]
            "mime_type": "application/pdf", # [!code highlight]
        }, # [!code highlight]
    ]
)
response = model.invoke([message])
```

***

## 令牌使用元数据

每次调用后，令牌使用信息会出现在响应的 `usage_metadata` 属性中：

```python theme={null}
ai_msg = model.invoke("Tell me a joke.")
ai_msg.usage_metadata
```

```text theme={null}
{'input_tokens': 12,
 'output_tokens': 25,
 'total_tokens': 37}
```

当底层服务提供商包含详细的令牌拆分信息时，这些字段会自动显示。当提供商未报告这些信息或值为零时，字段会被省略。

### 推理令牌

`output_token_details.reasoning` 表示模型用于内部思维链推理的令牌数。此字段会在使用推理模型（例如 `deepseek/deepseek-r1`、`openai/o3`）或显式启用推理时出现：

```python theme={null}
from langchain_openrouter import ChatOpenRouter

model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    reasoning={"effort": "high"},
)

ai_msg = model.invoke("What is the square root of 529?")
ai_msg.usage_metadata
```

```text theme={null}
{'input_tokens': 39,
 'output_tokens': 98,
 'total_tokens': 137,
 'output_token_details': {'reasoning': 62}}
```

### 缓存输入令牌

`input_token_details.cache_read` 报告从提供商提示缓存中使用的输入令牌数，而 `input_token_details.cache_creation` 报告首次调用时写入缓存的令牌数。

提示缓存需要显式在消息内容块中设置 `cache_control` 断点。在内容块中传递 `{"cache_control": {"type": "ephemeral"}}` 以标记要缓存的区域：

```python theme={null}
from langchain_openrouter import ChatOpenRouter

model = ChatOpenRouter(model="anthropic/claude-sonnet-4.5")

long_system = "You are a helpful assistant. " * 200
messages = [
    ("system", [{"type": "text", "text": long_system, "cache_control": {"type": "ephemeral"}}]),
    ("human", "Say hi."),
]

# First call writes to cache
ai_msg = model.invoke(messages)
ai_msg.usage_metadata
```

```text theme={null}
{'input_tokens': 1210,
 'output_tokens': 12,
 'total_tokens': 1222,
 'input_token_details': {'cache_creation': 1201}}
```

```python theme={null}
# Second call reads from cache
ai_msg = model.invoke(messages)
ai_msg.usage_metadata
```

```text theme={null}
{'input_tokens': 1210,
 'output_tokens': 12,
 'total_tokens': 1222,
 'input_token_details': {'cache_read': 1201}}
```

> [!NOTE]
>
> 未在内容块中设置 `cache_control` 时，提供商不会缓存提示，这些字段也不会显示。

当流式输出时，从完整响应中获取令牌使用情况：

```python theme={null}
stream = model.stream_events("Tell me a joke.", version="v3")
full = stream.output
full.usage_metadata
```

```text theme={null}
{'input_tokens': 12,
 'output_tokens': 25,
 'total_tokens': 37}
```

***

## 响应元数据

每次调用后，提供商和模型元数据会出现在 `response_metadata` 属性中：

```python theme={null}
ai_msg = model.invoke("Tell me a joke.")
ai_msg.response_metadata
```

```text theme={null}
{'model_name': 'anthropic/claude-sonnet-4.5',
 'id': 'gen-1771043112-yLUz3txgvHSjkyCQK8KQ',
 'created': 1771043112,
 'object': 'chat.completion',
 'finish_reason': 'stop',
 'logprobs': None,
 'model_provider': 'openrouter'}
```

若存在，`native_finish_reason` 字段会包含底层提供商原始的完成原因，可能与归一化的 `finish_reason` 不同。

***

## 提供商路由

许多OpenRouter上的模型由多个提供商托管。`openrouter_provider` 参数允许您控制请求由哪些提供商处理及如何选择。

### 排序和过滤提供商

使用 `order` 设置优先提供商序列。OpenRouter按顺序尝试每个提供商，若不可用则降级到下一个：

```python theme={null}
model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    openrouter_provider={
        "order": ["Anthropic", "Google"],
        "allow_fallbacks": True,  # default; fall back beyond the order list if needed
    },
)
```

为限制请求仅使用特定提供商，使用 `only`。要排除某些提供商，使用 `ignore`：

```python theme={null}
# Only use these providers (no fallback to others)
model = ChatOpenRouter(
    model="openai/gpt-4o",
    openrouter_provider={"only": ["OpenAI", "Azure"]},
)

# Use any provider except DeepInfra
model = ChatOpenRouter(
    model="meta-llama/llama-4-maverick",
    openrouter_provider={"ignore": ["DeepInfra"]},
)
```

### 按成本、速度或延迟排序

默认情况下，OpenRouter会负载均衡选择成本较低的提供商。使用 `sort` 可更改优先级：

```python theme={null}
# Prefer the fastest providers (highest tokens/second)
model = ChatOpenRouter(
    model="openai/gpt-4o",
    openrouter_provider={"sort": "throughput"},
)

# Prefer the lowest-latency providers
model = ChatOpenRouter(
    model="openai/gpt-4o",
    openrouter_provider={"sort": "latency"},
)
```

### 数据收集政策

如需提供商不存储或训练您的数据，设置 `data_collection` 为 `"deny"`：

```python theme={null}
model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    openrouter_provider={"data_collection": "deny"},
)
```

### 量化过滤

对于开放权重模型，可限制路由到特定精度级别：

```python theme={null}
model = ChatOpenRouter(
    model="meta-llama/llama-4-maverick",
    openrouter_provider={"quantizations": ["fp16", "bf16"]},
)
```

### 路由参数

`route` 参数控制高层路由行为：

* `"fallback"`：启用自动跨提供商降级（默认行为）。
* `"sort"`：按 `openrouter_provider` 中配置的排序策略路由。

```python theme={null}
model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    route="fallback",
)
```

### 组合选项

提供商选项可组合使用：

```python theme={null}
model = ChatOpenRouter(
    model="openai/gpt-4o",
    openrouter_provider={
        "order": ["OpenAI", "Azure"],
        "allow_fallbacks": False,       # strict—only use providers in order
        "require_parameters": True,     # skip providers that don't support all params
        "data_collection": "deny",
    },
)
```

查看 [OpenRouter提供商路由文档](https://openrouter.ai/docs/guides/routing/provider-selection) 获取完整选项列表。

***

## 应用归属

OpenRouter支持通过HTTP头实现应用归属。可通过初始化参数或环境变量设置：

```python theme={null}
model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    app_url="https://myapp.com",   # or OPENROUTER_APP_URL env var
    app_title="My App",            # or OPENROUTER_APP_TITLE env var
)
```

***

## 可观测性与追踪

OpenRouter 可以将请求数据广播到配置的观测目标。`ChatOpenRouter` 提供了两个相关参数：`session_id` 用于将相关请求归入单个逻辑工作流，`trace` 用于请求级别的追踪元数据。详见 [OpenRouter 广播文档](https://openrouter.ai/docs/guides/features/broadcast/overview)。

### 使用 `session_id` 分组请求

向 `session_id` 中传递值以将多个请求关联到同一工作流（如对话、智能体运行、批处理任务、CI 运行等）。最大长度 256 字符。

```python theme={null}
model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    session_id="workflow-abc-123",   # or OPENROUTER_SESSION_ID env var
)
```

当未显式提供 `session_id` 时，`OPENROUTER_SESSION_ID` 环境变量会在初始化时被读取，从而无需通过应用代码传递值即可为每个请求打标签。

您也可以在每次调用时覆盖该值：

```python theme={null}
model.invoke("Summarize the doc", session_id="workflow-abc-123-step-1")
```

### 通过 `trace` 添加追踪元数据

向 `trace` 中传递值以附加每个请求的元数据，OpenRouter 会将此信息转发至广播目标。支持键包括 `trace_id`、`trace_name`、`span_name`、`generation_name` 和 `parent_span_id`；其他键会被作为自定义元数据传递。

```python theme={null}
model = ChatOpenRouter(
    model="anthropic/claude-sonnet-4.5",
    trace={
        "trace_id": "trace-789",
        "span_name": "summarize",
    },
)
```

`session_id` 和 `trace` 是独立的——`session_id` 在 OpenRouter 端将请求分组为逻辑工作流，而 `trace` 为单个请求添加注释。

***

## API 参考文档

所有 `ChatOpenRouter` 功能和配置的详细文档请访问 @\[`ChatOpenRouter`] API 参考文档。

关于 OpenRouter 平台、模型和功能的更多信息，请参阅 [OpenRouter 文档](https://openrouter.ai/docs)。

***

> 官方原文：[src/oss/python/integrations/chat/openrouter.mdx](https://github.com/langchain-ai/docs/blob/main/src/oss/python/integrations/chat/openrouter.mdx) · 非官方翻译，译文由 AI 生成，以英文原文为准。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.