# 用一个 base URL 把 Haystack 的 OpenAIChatGenerator 接到 Router One

> https://router.one/zh/integrations/haystack 的 Markdown 镜像，供 AI 助手与爬虫使用。Router One 是 OpenAI 兼容的统一 LLM API 网关。
> 最后更新：2026-09-11

Haystack 是 deepset 开源的 Python 框架，用组件搭建 pipeline 和 Agent。它的 OpenAIChatGenerator 发送的是 Chat Completions 请求，指向 Router One 后就能调用目录里在 /v1/chat/completions 上提供服务的所有聊天模型，每次请求都有成本和延迟 Trace；pipeline、Agent 循环和检索组件仍在你的进程里由 Haystack 运行。本指南用 api_base_url、从环境变量读取的 Key 和模型 ID 配置一个 generator，先验证一次普通回复和一次流式回复，再说明加上工具、图片或检索 pipeline 时要核对什么。最后划清边界：embedder 和 document store 不由网关提供。

## 安装 haystack-ai 并设置凭证

使用 Python 3.10 或更新版本，安装 haystack-ai：OpenAIChatGenerator 和它调用的 OpenAI Python SDK 都在核心包里，本指南不需要额外的集成包。下面是 macOS/Linux 的 shell 示例，运行前替换两个占位符：一把 Router One Key，以及当前目录中支持 Chat Completions 的精确模型 ID。ROUTER_ONE_* 是本示例自己定义并显式读取的变量名；generator 拿到的是专属 Secret，所以不需要设置 OPENAI_API_KEY。运行 Python 文件时沿用同一环境。

`terminal`

```bash
python -m pip install haystack-ai
export ROUTER_ONE_API_KEY="sk-your-router-one-key"
export ROUTER_ONE_MODEL_ID="<exact-model-id-from-/models>"
```

## 把 Haystack 配置到 Router One base URL

保存为 haystack_router_one.py，再运行 python haystack_router_one.py。Secret.from_env_var("ROUTER_ONE_API_KEY") 替换了 generator 默认的 OPENAI_API_KEY Secret，在构造 generator 时解析；变量缺失会抛出点名该变量的 ValueError。model 原样传入目录里的模型 ID，若 ID 自带 provider 前缀也要保留。api_base_url 填带 /v1 的 base URL，generator 内部的 OpenAI 客户端会自行拼接 /chat/completions，所以每次 run() 就是一个 POST /v1/chat/completions。第一次 run() 发送一条用户 ChatMessage，从 replies[0].text 读取回复文本；Haystack 3.0 起也可以直接传一个字符串。第二次 run() 复用同一个 generator，加上 streaming_callback=print_streaming_chunk，每个 chunk 到达时立即打印；这个回调也可以在构造 generator 时设置。两次调用只差这一点，行为不同就能定位到流式本身。

`haystack_router_one.py`

```python
import os

from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.generators.utils import print_streaming_chunk
from haystack.dataclasses import ChatMessage
from haystack.utils import Secret

llm = OpenAIChatGenerator(
    api_key=Secret.from_env_var("ROUTER_ONE_API_KEY"),
    model=os.environ["ROUTER_ONE_MODEL_ID"],
    api_base_url="https://api.router.one/v1",
)

# 1. One plain Chat Completions request; the reply is a ChatMessage
result = llm.run(messages=[ChatMessage.from_user("Reply with one short greeting.")])
print(result["replies"][0].text)

# 2. The same generator, streaming: chunks print as they arrive
llm.run(
    messages=[ChatMessage.from_user("Count from 1 to 5, one number per line.")],
    streaming_callback=print_streaming_chunk,
)
```

## Haystack 的哪个调用发出哪种请求

Haystack 的组件不共用一个客户端：每个 generator 实例各自带着 api_key、model 和 api_base_url，Agent、LLM 这类包装组件接收的是 generator 实例而不是 URL。下表按本指南这个 generator 的各项功能，说明到达网关的请求是什么，以及使用前要在模型详情页确认的能力。

| Haystack 调用 | 到达网关的请求 | 需要核对 |
| --- | --- | --- |
| OpenAIChatGenerator.run(messages=...) | 每次 run() 一个 POST /v1/chat/completions，即示例中的调用 | 模型详情页列出 POST /v1/chat/completions |
| streaming_callback=print_streaming_chunk，构造时或 run() 时传入 | 同一个 Chat Completions 请求，开启流式 | 模型页的流式支持；普通调用通过后再单独测 |
| tools=[...]（用 Tool 或 @tool 定义），或 Agent(chat_generator=..., tools=...) | 带工具定义的 Chat Completions；Agent 每执行完一次工具就再调一次 generator，直到满足 exit_conditions（默认 ["text"]）或达到 max_agent_steps（默认 100） | 模型页的工具调用能力；循环的每一步都是独立请求 |
| ChatMessage.from_user(content_parts=[text, ImageContent]) | 用户消息带图片内容的 Chat Completions | 模型页的视觉 / 图片输入能力 |
| OpenAIResponsesChatGenerator，api_base_url 相同 | POST /v1/responses | 模型页列出 POST /v1/responses；目前为 GPT 系列和 DeepSeek 的 ID |

## 网关不提供什么，以及怎样给一次 pipeline 运行设预算

一条 Haystack RAG pipeline 串起 embedder、document store、retriever、ChatPromptBuilder 和 generator，其中只有 generator 的请求会到达 Router One。OpenAITextEmbedder 和 OpenAIDocumentEmbedder 调用的是 embeddings API，网关没有这个端点，把它们的 api_base_url 指向 Router One 不可能成功。向量化改用本地 sentence-transformers embedder（pip install sentence-transformers-haystack，这些组件在 Haystack 3.0 移出了核心包），或换用其他 embedding 服务商及其自己的 Key，并保证索引和查询用同一个 embedding 模型。cross-encoder ranker 和 document store 同样运行在你的进程里或各自的服务上。此外，一次 pipeline 运行可能产生多次模型请求：generator 内部的 OpenAI 客户端会对连接错误以及 408、409、429、5xx 响应重试，上限是 max_retries（Haystack 默认 5，也可用 OPENAI_MAX_RETRIES 设置）；Agent 每一步都会再调一次 generator；FallbackChatGenerator 遇到任何异常就切到下一个 generator。每一次到达网关的尝试在 Dashboard → Logs 里都是独立请求，有各自的 request_id、Trace 和费用。给 pipeline 单独建一把设了 maxSpend 的 Key，批处理任务调低 max_retries，限制 max_agent_steps，并用 Agent 输出的 token_usage 和 step_count 与 Logs 对账。默认 30 秒超时（OPENAI_TIMEOUT）对慢模型可以用 timeout= 调高。Router One 只记录模型调用元数据，不执行你的工具、不存文档，也不保存 pipeline 状态。

## Haystack 该填哪个模型 ID？

从 /models 页复制精确的模型 ID，保留大小写、连字符和版本后缀，不要用展示名称代替。打开该模型的详情页，核对支持的 API 端点、上下文窗口和工具调用等能力，再与 Haystack 当前选择的 provider 和功能对应。模型出现在目录里，不等于当前客户端能调用它的所有功能。建议为每个工具单独建 API Key，并设置 maxSpend 消费上限。

## Haystack 用的是哪种 API 协议？

OpenAI 兼容描述的是接口格式，不能据此推断 Chat Completions（/v1/chat/completions）、Responses（/v1/responses）和 Anthropic Messages（/v1/messages）可以互换。先核对工具当前版本、provider 配置和实际请求路径，再查模型详情与 API 兼容性事实页。一次普通对话成功，也不能证明服务端工具、历史状态或文件编辑功能都受支持。

## 在 trace 里验证 Haystack 的调用

先在 Haystack 发出一次简单文本请求，再到 Dashboard → Logs 按时间、模型和 request_id 核对 trace：tokens、花费、延迟和状态码。成功后再分别验证流式输出、工具调用和多轮历史。失败时保留实际请求路径、完整错误消息及 request_id；没有对应日志时，先查客户端配置和网络，不能仅凭客户端报错认定是网关或上游故障。

## 常见问题

### 接 Router One 该用 OpenAIChatGenerator 还是 OpenAIResponsesChatGenerator？

先用 OpenAIChatGenerator。它发送 Chat Completions，而 /v1/chat/completions 服务目录里的所有聊天模型，所以一个 generator 就能用 /models 上的任意当前 ID。OpenAIResponsesChatGenerator 的 api_key、model 和 api_base_url 参数相同，但发送的是 Responses 请求，网关只对目前列出的 GPT 系列和 DeepSeek ID 原生提供这个端点；填入 Claude 系列 ID 会在调用任何模型之前收到 400 invalid_request_error，消息为 model '<id>' must be called via …。只有需要 reasoning summary、previous_response_id 这类 Responses 专属功能，并且模型详情页列出了 POST /v1/responses 时，才切换过去。

### 为什么在 generator 上设置 api_base_url，而不是用环境变量？

因为这就是官方文档给出的开关：Haystack 文档把 api_base_url 定义为自定义部署和 OpenAI 兼容 API 的参数，并没有定义任何 base URL 环境变量。generator 内部的 OpenAI Python 客户端只在 api_base_url 为 None 时才回退读取 OPENAI_BASE_URL；显式写出这个值，目标地址在代码和组件的序列化结果里都一目了然——to_dict 会记录 api_base_url、model、timeout 和 max_retries，Key 则以环境变量引用的形式保存。Key 要保持为环境变量 Secret：用 Secret.from_token 传入的 token 无法序列化；变量缺失时会在构造阶段抛出点名该变量的 ValueError，比到 Logs 里排查 401 直接得多。

### 我的代码用的是 OpenAIGenerator，回复是纯字符串，现在变了什么？

Haystack 3.0 移除了旧的 OpenAIGenerator 和其他非 chat 类 generator，替代品就是 OpenAIChatGenerator。它的 replies 是 ChatMessage 对象：用 .text 读文本，用 .meta 读用量元数据；3.0 起 messages 也接受纯字符串。temperature、response_format 这类参数改放进 generation_kwargs，构造时和 run() 时都能传，run() 时的值会覆盖构造时的值。所选模型不接受的参数会得到 HTTP 400：到 Logs 里看完整错误消息和 request_id，如果这个 400 点名了该参数，就针对该模型调整这个参数，不要去改 base URL 或模型 ID。

### Haystack 能通过网关用哪些模型？

选用当前目录中同时支持 Haystack 所用端点和所需功能的模型。精确 ID、当前单价与能力以 /models 及模型详情为准；不要仅按 GPT、Claude 等系列名判断兼容性。客户端能列出模型，只证明模型发现成功，仍需验证实际调用。

### 能列出模型，但调用报 400 或 404，怎么办？

先记录实际请求路径和错误消息，再核对精确模型 ID。400 可能是参数、工具类型或模型与端点不匹配；404 可能是请求路径或资源不存在，不能直接判定模型下线。若错误提示 must be called via，按它指明的端点调整客户端 provider，或换用支持当前端点的模型。不要在所有工具里统一增删 /v1 或 /chat/completions。

### 中国大陆能直连吗？

能。网关在大陆可直连、无需 VPN，配置与全球环境完全一致。

### 报 401/402/403/429 怎么排查？

先到 Dashboard → Logs 核对请求及错误消息。401 查 Key 是否传入和有效；402 查钱包余额与 maxSpend；403 查 Key 权限和访问限制；429 查请求频率、token 限额及上游限流，按错误来源处理。保留 request_id，再按错误码速查页逐项排查。

## 相关页面

- 全部接入指南：https://router.one/zh/integrations
- Haystack 的 API 错误排查：https://router.one/zh/llm-api-error-codes
- API 兼容性：端点与功能对照：https://router.one/zh/facts/api-compatibility.md
- Responses API 配置与限制：https://router.one/zh/codex-responses-api
- AnythingLLM 接入：https://router.one/zh/integrations/anythingllm
- FastGPT 接入：https://router.one/zh/integrations/fastgpt
- OpenAI Python SDK 接入：https://router.one/zh/integrations/openai-sdk
- 工具调用的 API 要求：https://router.one/zh/llm-tool-calling
- 按 Key 追踪模型调用成本：https://router.one/zh/llm-cost-tracking
- Haystack 官方文档：OpenAIChatGenerator：https://docs.haystack.deepset.ai/docs/openaichatgenerator
- Haystack 官方文档：Secret 管理：https://docs.haystack.deepset.ai/docs/secret-management
- Haystack 官方文档：Agent 组件：https://docs.haystack.deepset.ai/docs/agent
- 网关层负责什么：https://router.one/zh/llm-api-gateway
- OpenAI 兼容 API：https://router.one/zh/openai-compatible-api
- API 文档：https://router.one/zh/docs
- 本页规范地址：https://router.one/zh/integrations/haystack
- 模型与每模型 token 价格：https://router.one/zh/models （markdown：https://router.one/zh/models.md ）
- 定价：https://router.one/zh/pricing
- API 文档（markdown）：https://router.one/zh/docs.md
- 公司事实（markdown）：https://router.one/zh/facts/company.md
