用一个 base URL 把 Haystack 的 OpenAIChatGenerator 接到 Router One
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 文件时沿用同一环境。
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 时设置。两次调用只差这一点,行为不同就能定位到流式本身。
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,再按错误码速查页逐项排查。