openai-compatible-embedding-endpoint-check · ZH · 2026-10-19

聚合站代理 embeddings 吗:用 OpenAI 兼容客户端调 /embeddings 的实测

很多开发者第一次在聚合站用 Base 上的 USDC 充值后,会问这把 key 能不能调 /embeddings。本文讲清 OpenAI 兼容客户端调用 /embeddings 时该预期什么、不同后端(embedding 能力并非每家都有)可能出现的返回形式,以及在代码里做能力探测与优雅降级的做法,最后说明按官方价 ×1.3 扣费的计费含义。

先分清两件事:协议兼容 ≠ 每个后端都实现

聚合站的卖点是一个 API key、OpenAI 兼容的接口形态,背后路由到 Claude、GPT、DeepSeek、Qwen、GLM、Kimi 等多个模型。但“接口路径长得像 OpenAI”和“每个后端都真的提供 embedding 向量”,是两回事。

  • chat/completions 是几乎所有对话模型都支持的能力,聚合站必然要代理。
  • /embeddings 依赖具体厂商是否开放该端点、以及聚合站是否把它接进来。不同后端、不同接入批次,情况可能不一致。

所以不要假设“我充了 USDC、拿到 key、就能调任意模型名下的 /embeddings”。正确姿势是先探测,再决定链路。

用 OpenAI 兼容客户端怎么发请求

标准写法不用改:base_url 指向聚合站,模型名按站点文档填。

from openai import OpenAI

client = OpenAI(base_url="https://<聚合站域名>/v1", api_key="sk-...")

resp = client.embeddings.create(
    model="<站点文档中标明支持 embedding 的模型名>",
    input=["第一段文本", "第二段文本"],
)
vectors = [d.embedding for d in resp.data]

注意点:

  • base_url 通常是站点根路径加 /v1,具体以文档为准。
  • 请求体字段(input、model、encoding_format 等)走 OpenAI 语义;后端若不支持某字段,可能忽略或报错。
  • 返回的向量维度由具体 embedding 模型决定,不同模型之间不可混用,切换模型等于需要重建索引。

哪些能调、哪些只能 chat:靠探测而不是猜

我们不在这里列“谁支持谁不支持”的固定清单——后端接入会变化,写死的清单很快过期。稳妥做法是运行时判定:

  1. 看文档:站点文档通常会标明哪些模型名对 embedding 端点可用。以文档为第一信息源。
  2. 小样本探测:用一条极短文本发一次 /embeddings,只关心状态码与返回结构,不关心向量内容。
  3. 缓存结论:探测结果按模型名缓存在配置或进程内,避免每次启动都打一遍。

典型的三类结果:

  • 200 且 data[].embedding 是浮点数组:可正常使用。
  • 4xx(如模型不存在、端点未开放、参数不被接受):该模型名在 embedding 上不可用。
  • 200 但结构异常或缺少 embedding 字段:视为不可用,别硬解析。

优雅降级的代码骨架

核心思路是把“向量化”抽象成一个可替换的能力,而不是在业务里直接调 client.embeddings。

class Embedder:
    def __init__(self, client, model, fallback=None):
        self.client = client
        self.model = model
        self.fallback = fallback
        self.ok = None

    def probe(self):
        try:
            r = self.client.embeddings.create(model=self.model, input="ping")
            self.ok = bool(r.data and getattr(r.data[0], "embedding", None))
        except Exception:
            self.ok = False
        return self.ok

    def embed(self, texts):
        if self.ok is None:
            self.probe()
        if self.ok:
            r = self.client.embeddings.create(model=self.model, input=texts)
            return [d.embedding for d in r.data]
        if self.fallback:
            return self.fallback(texts)
        raise RuntimeError("embedding 不可用且未配置降级方案")

降级方案按你的场景选:

  • 换模型重试:文档里若有另一个明确支持 embedding 的模型,先切过去。
  • 本地模型兜底:仓库里跑一个小型开源 embedding 模型,保证检索链路不断。
  • 降级为关键词检索:BM25 之类无需向量,代价是召回质量下降,但服务可用。
  • 关闭相关功能:把向量检索标记为不可用,前端给出提示,而不是抛 500。

关键原则:embedding 不可用应当是“功能降级”,而不是“整站故障”。写索引任务时尤其重要——批量写入前先探测一次,别让几千条文档跑到一半才炸。

与计费的关系

聚合站按官方价 ×1.3 扣费,embedding 调用同样计入消耗(具体单价以站点文档为准)。这意味着:

  • 探测请求虽然文本极短,但仍是一次计费调用,所以探测要缓存、不要放进循环。
  • 大批量重建索引前,先确认模型可用,避免无效请求消耗余额。
  • 充值走 Base 上的 USDC、无 KYC,余额用完即停,做批量任务前先估算量级。

实践清单

  • 用 OpenAI 兼容客户端直连 base_url,不改代码结构。
  • 以站点文档为准确定哪些模型名对 /embeddings 可用,不要凭记忆。
  • 启动或首次使用时做一次短文本探测,结果缓存。
  • 把 embedding 封装成独立能力对象,配好本地或关键词的降级路径。
  • 索引任务分批、可断点续跑,避免中途失败造成半成品索引。