Langflow OpenAI Compatible 扩展 Bundle:把任意 OpenAI 兼容端点变成一等模型供应商
本文基于仓库中的 lfx-openai-compatible 扩展文档 展开,介绍 Langflow 的 OpenAI Compatible Extension Bundle 如何将 OpenRouter、Together AI、Groq、Fireworks AI 以及自托管 vLLM/TGI/LM Studio 等任意 OpenAI 兼容端点,注册为 Langflow 统一模型选择器中的一等模型供应商。读完本文,你将理解该 Bundle 的 provider 注册机制(extension.json 的 providers[] 块)、/v1/models 实时模型发现与凭据校验的底层实现、SSRF 安全防护策略,以及完整的安装、配置与开发流程。
一、它是什么:一个"无组件"的 Provider 型扩展 Bundle
Langflow 的扩展 Bundle 通常以"组件"(Component)为载体提供功能,但 lfx-openai-compatible 是另一种形态——Provider 型 Bundle:它不携带任何组件,而是通过 extension.json 清单中的 providers[] 块,向 Langflow 的统一模型系统(unified model system)注入一个名为 OpenAI Compatible 的模型供应商。该供应商会出现在 Langflow 的模型选择器中,与内置供应商并列。
任何遵循 OpenAI HTTP API 形态的服务端点都可以通过它接入,README 给出的常见端点如下:
| Provider | Base URL |
|---|---|
| OpenRouter | https://openrouter.ai/api/v1 |
| Together AI | https://api.together.xyz/v1 |
| Groq | https://api.groq.com/openai/v1 |
| Fireworks AI | https://api.fireworks.ai/inference/v1 |
| 自托管 vLLM / TGI / LM Studio | http://localhost:8000/v1 |
从源码结构看,该供应商复用了 ChatOpenAI / OpenAIEmbeddings 这两个 langchain-openai 类,并实时从端点的 /v1/models 路由发现模型。因此同一个模型会同时出现在 Language Model(语言模型)和 Embedding Model(嵌入模型)两类上下文中。整个实现不修改任何 Langflow 核心文件。
二、extension.json 清单:provider 注册的完整契约
extension.json 是整个 Bundle 的注册契约。它声明了 Bundle 元信息与唯一的 provider 条目,关键字段如下:
id/version:lfx-openai-compatible,版本0.1.1;lfx.compat声明兼容 lfx 主版本["1"]。name:OpenAI Compatible,即注册进统一模型系统后显示的供应商名,图标为Plug,max_tokens_field_name为max_tokens。
2.1 用户可配置变量(variables)
metadata.variables 定义了两个字段,也就是用户在 Model Providers 面板中看到的两个输入项:
| variable_name | variable_key | required | is_secret | langchain_param |
|---|---|---|---|---|
| Base URL | OPENAI_COMPATIBLE_BASE_URL |
是 | 否 | base_url |
| API Key | OPENAI_COMPATIBLE_API_KEY |
否 | 是 | api_key |
两个变量都带 component_metadata:当用户在组件字段中内联覆盖时,分别映射到 openai_compatible_base_url 和 api_key 字段(advanced: true),且均可回退到同名环境变量。API Key 标记为 is_secret: true,表示存储与展示时按密钥处理。
2.2 模型类与嵌入类映射
清单同时指定了语言模型与嵌入模型的具体实现类:
"model_class": {
"module": "langchain_openai",
"attr": "ChatOpenAI"
},
"embedding": {
"class_name": "OpenAIEmbeddings",
"module": "langchain_openai",
"attr": "OpenAIEmbeddings",
"param_mapping": {
"model": "model",
"api_base": "base_url",
"dimensions": "dimensions",
"chunk_size": "chunk_size",
"request_timeout": "timeout",
"max_retries": "max_retries",
...
}
}
即:聊天模型用 ChatOpenAI(参数经 mapping.model_param: "model" 传入),嵌入模型用 OpenAIEmbeddings,并把用户配置的 Base URL 注入到 api_base 参数、其余参数(dimensions、chunk_size、timeout 等)逐项透传。
2.3 实时发现与校验钩子
"api_key_required": false,
"live": true,
"live_discovery": "lfx_openai_compatible.discovery:fetch_live_openai_compatible_models",
"validator": "lfx_openai_compatible.discovery:validate_openai_compatible_credentials"
api_key_required: false:本地无鉴权服务可不填 API Key;live: true+live_discovery:以点分路径引用发现函数,由 lfx 的 provider registry 延迟导入并调用;validator:同样以点分路径引用凭据校验函数,在用户保存配置时被 registry 调用。
这一"点分路径 + 延迟调用"的设计使得 Bundle 的导入开销极低:只有当供应商实际被使用时,discovery 模块 才会被导入。该注册机制在 lfx 侧的实现入口位于 provider_registry(其中 live_discovery_for / validator_for 负责按点分路径解析并缓存这两个可调用对象)。
三、实时模型发现与凭据校验的源码解析
discovery.py 提供两个可调用对象,是理解该 Bundle 行为的核心。
3.1 Base URL 归一化
def _models_url(base_url: str) -> str:
"""Return the ``/v1/models`` URL, tolerating a base that already ends in /v1."""
base_url = base_url.rstrip("/")
return f"{base_url}/models" if base_url.endswith("/v1") else f"{base_url}/v1/models"
该函数容忍用户 Base URL 末尾已带 /v1 的情况,避免拼出 .../v1/v1/models。单元测试 中的参数化用例验证了四种输入:http://localhost:8000 → .../v1/models;http://localhost:8000/v1 → .../v1/models(不重复);http://localhost:8000/ → .../v1/models;https://api.groq.com/openai/v1 → .../v1/models。
3.2 实时发现:fetch_live_openai_compatible_models
该函数(discovery.py#L45)的行为要点:
- 读取用户配置:通过
get_provider_variable_value(user_id, ...)取OPENAI_COMPATIBLE_BASE_URL;若未配置,直接返回空列表。API Key 读取被 try/except 包裹——API Key 查询失败不会阻断发现,而是退化为匿名探测(对应测试test_fetch_swallows_api_key_lookup_error)。 - SSRF 安全 GET:使用 ssrf_safe_httpx_get 发起请求,参数为
timeout=5秒、follow_redirects=False。该工具函数会先对 URL 做 connector SSRF 校验与 DNS 固定(DNS pinning),防止 DNS rebinding;不跟随重定向则天然阻断"先 302 到内网元数据地址"一类的攻击(测试test_fetch_does_not_follow_redirects用指向169.254.169.254的 302 响应验证了这一点)。 - 双格式解析:
_parse_model_names兼容 OpenAI 标准{"data": [{"id": ...}]}结构与纯列表两种响应体(部分自建服务直接返回列表),结果按名称排序。 - 打标签:每个模型经
create_model_metadata打上provider="OpenAI Compatible"、icon="Plug"、model_type(llm或embeddings)标签;/v1/models不区分聊天与嵌入模型,所以端点上每个模型都会被返回并打上请求方的model_type——统一目录按类型各取一次,因此同一模型同时进入 Language Model 与 Embedding Model 选择器。tool_calling仅在llm上下文中为真,前MIN_DEFAULT_MODELS个模型标记为默认项。 - 永不抛错:任何传输或解析错误都降级为"无实时模型"(返回空列表并记 debug 日志),保证一个配置错误的端点不会拖垮整个模型目录。
3.3 凭据校验:validate_openai_compatible_credentials
该函数(discovery.py#L87)在用户保存供应商配置时做主动探测,与发现函数形成互补:发现路径"静默降级",校验路径"显式报错"。它同样请求 /v1/models(携带可选的 Authorization: Bearer <key>),并将各类失败翻译成可操作的 ValueError:
- 缺少 Base URL →
Invalid OpenAI-compatible base URL; - HTTP 401/403 →
Authentication failed for the OpenAI-compatible endpoint. Check OPENAI_COMPATIBLE_API_KEY.; - 连接失败(
httpx.ConnectError)→ 提示确认服务已启动且 URL 正确; - 超时 → 明确的 timeout 提示;
- 其他 HTTP 状态错误 → 附带具体状态码与完整
models_url,提示检查 Base URL 是否指向 OpenAI 兼容 API。
四、配置、安装与本地端点注意事项
4.1 配置方式
在 Settings → Model Providers → OpenAI Compatible 面板中设置端点,或通过环境变量:
| 字段 | 环境变量 | 必填 | 说明 |
|---|---|---|---|
| Base URL | OPENAI_COMPATIBLE_BASE_URL |
是 | OpenAI 兼容端点的 Base URL,如 https://openrouter.ai/api/v1 或 http://localhost:8000/v1 |
| API Key | OPENAI_COMPATIBLE_API_KEY |
否 | Bearer token;本地无鉴权服务可留空 |
完整的 UI 操作流程见仓库文档 OpenAI Compatible 组件文档:点击头像 → Settings → Model Providers → 选择 OpenAI Compatible → 填写 Base URL 与 API Key → 点击 Save。保存时 Langflow 会调用上面第 3.3 节的校验函数探测 /v1/models,发现的模型随即出现在 Language Models 与 Embedding Models 分组中;启用所需模型后,即可在任何 Language Model、Embedding Model 或 Agent 字段中选择 OpenAI Compatible 及具体模型。
4.2 单端点限制与并发方案
该供应商一次只持有一个端点。如需同时接入第二个自定义端点,README 建议组合使用内置 OpenAI 供应商的 Base URL 覆盖能力,或 vLLM 供应商 Bundle(lfx-vllm)。
4.3 本地/内网端点的 SSRF 防护
Langflow 默认开启 SSRF 防护,回环与私有地址(localhost、127.0.0.1、::1 等)会被阻断。在保存 http://localhost:8000/v1 之类的 Base URL 之前,需要将该主机加入白名单:
export LANGFLOW_SSRF_ALLOWED_HOSTS=localhost
也可以白名单化 IP 或 CIDR 段,如 127.0.0.1 或 10.0.0.0/8。从测试用例看(test_fetch_allows_literal_loopback_by_default / test_fetch_blocks_literal_loopback_when_connector_policy_opts_out),字面回环地址是否放行受 LANGFLOW_SSRF_PROTECTION_ENABLED、LANGFLOW_CONNECTOR_SSRF_VALIDATION_ENABLED 与 LANGFLOW_CONNECTOR_SSRF_ALLOW_LOOPBACK 这组环境变量控制——默认允许字面回环,但策略显式关闭时直接拦截,且不会发出任何网络请求。
4.4 安装
pip install lfx-openai-compatible
该 Bundle 通过 langflow.extensions entry-point 自动注册;安装后重启 Langflow 服务,即可在任意 Language Model 或 Embedding Model 字段中选中 OpenAI Compatible。另外,据 官方文档 说明,该供应商也随 uv pip install langflow 自动安装,无需单独安装。
五、包结构与开发流程
5.1 打包约定
pyproject.toml 中的关键设计:
-
依赖极简:仅
lfx>=1.12.0.dev0,<2.0.0与httpx>=0.24.0,<1.0.0。注释说明ChatOpenAI/OpenAIEmbeddings由 lfx 提供并延迟解析,Bundle 本身不直接导入它们,因此不必重复声明 langchain-openai 依赖;httpx支撑 SSRF 安全、DNS 固定的实时发现与凭据校验探测。 -
entry-point 注册:
[project.entry-points."langflow.extensions"] lfx-openai-compatible = "lfx_openai_compatible"运行时 Langflow loader 通过该入口发现
extension.json(manifest-shipping 分布通过importlib.metadata.files(dist)定位清单;editable 安装则回退到该 entry-point)。 -
wheel 内容:
extension.json与discovery.py都放在src/lfx_openai_compatible包内,确保 registry 能按点分路径导入发现/校验函数。
5.2 本地开发
cd src/bundles/openai-compatible
pip install -e .
lfx extension validate src/lfx_openai_compatible
lfx extension validate 用于校验清单合法性;该 lfx 版本下限(1.11 起提供 provider-registry 接缝)由 scripts/ci/sync_bundle_lfx_pin.py 在 make patch 时同步。
5.3 测试覆盖
测试文件 覆盖三类关键行为,可作为二次开发时的验收清单:
- 端到端注册(
test_bundle_registers_provider_end_to_end):通过load_extension加载后断言provider_registry.is_registered("OpenAI Compatible")、无组件(result.components == [])、API Key 可选、live 发现与校验函数均已解析,且该供应商出现在get_live_only_providers()中——即未配置时也会进入 Model Providers 对话框供用户配置; - 发现函数:空 Base URL、OpenAI dict / 纯列表两种负载、
/v1去重、Bearer 头转发、无 Key 时不发Authorization头、连接错误与坏负载的静默降级、embedding 上下文的tool_calling=False标记; - 校验函数:缺 URL、401/403、500、连接错误、超时各自的错误信息,以及 SSRF 回环策略与重定向阻断。
六、适用前提与小结
该 Bundle 的适用前提:lfx 1.11+(provider-registry 接缝所在的版本线)、Python >=3.10,<3.15;端点必须遵循 OpenAI HTTP API 形态(至少提供 /v1/models 列表接口)。其设计要点可以概括为:以 extension.json 的 providers[] 块声明式注册供应商,复用 ChatOpenAI/OpenAIEmbeddings 保证行为一致性,用点分路径延迟注入实时发现与校验钩子,并以"发现静默降级 + 校验显式报错 + SSRF 安全请求"三件套兼顾易用性与安全性。对需要在 Langflow 中接入 OpenRouter、Groq 等第三方聚合端点或自托管推理服务的场景,这就是无需改动任何核心代码的标准接入路径。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0625
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00