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

# bge-reranker-v2-m3 文本重排序

> 多语言重排序模型 bge-reranker-v2-m3：对召回的候选文档逐条打相关性分并重新排序，是 RAG 检索质量最划算的一次升级。API易 已开通 /v1/rerank 端点，$0.01 每 1M tokens。

`bge-reranker-v2-m3` 是智源研究院（BAAI）开源的多语言重排序模型。它解决的是检索系统里最常见的一类问题：**向量召回把相关文档捞回来了，但排在前面的偏偏不是最该看的那几篇。**

API易 已开通标准 `/v1/rerank` 端点，一个令牌即可调用。

<Info>
  **模型名**：`bge-reranker-v2-m3`（大小写敏感）；**端点**：`POST /v1/rerank`；`default` / `svip` 分组均可用。
  本页所有数据来自 API易 2026 年 7 月 30 日 (UTC+8) 的实测，共 60+ 用例。
</Info>

## 它是什么，什么时候该用

重排序模型是**交叉编码器**（Cross-Encoder）：把 query 和每一篇候选文档拼在一起、完整过一遍模型，直接输出一个相关性分数。

这和 embedding 模型有本质区别：

|         | Embedding（向量检索）           | Rerank（重排序）            |
| ------- | ------------------------- | ---------------------- |
| 计算方式    | query 和文档**各自**编码成向量，再算距离 | query 和文档**拼在一起**过模型   |
| 能否预先建索引 | ✅ 文档向量可离线算好存进向量库          | ❌ 必须拿到 query 才能算，无法预计算 |
| 速度      | 快，百万级库毫秒返回                | 慢，与候选数成正比              |
| 准确度     | 一般                        | 高                      |
| 定位      | **召回**：从百万篇里捞出几十篇         | **精排**：从几十篇里挑出最相关的几篇   |

所以它不是向量检索的替代品，而是**接在向量检索后面的第二级**。

<Warning>
  重排序模型**不能建索引、不能做召回**。它没有向量输出，也无法脱离 query 单独处理文档。
  如果你想要的是"把文档存进向量库"，需要的是 [文本向量化](/api-capabilities/text-embedding) 而不是本页的模型。
</Warning>

### 一个实测对比

同一批 10 篇候选文档、同一个查询（"API 请求一直返回 429 错误，怎么解决？"），只改排序方法：

| 排序方法                            | nDCG\@3  | P\@3     | 排在前三的是什么                      |
| ------------------------------- | -------- | -------- | ----------------------------- |
| 纯向量排序（`text-embedding-3-small`） | 0.53     | 0.33     | 直答、**HTTP 4xx 科普**、**机房割接公告** |
| 加一层 `bge-reranker-v2-m3`        | **1.00** | **1.00** | 直答、直答、指数退避说明                  |

向量检索把"HTTP 状态码 4xx 科普"和一篇提到 "4 月 29 日"的机房公告排进了前三——它们和 query 主题接近、字面重合，但**不回答问题**。重排序把这两篇挤了下去。

这就是重排序的核心价值：**把「同一个话题」和「真正回答了问题」区分开。**

## 模型信息

| 项         | 值                                                  |
| --------- | -------------------------------------------------- |
| **模型名称**  | `bge-reranker-v2-m3`（大小写敏感，写错返回 503）               |
| **架构**    | Cross-Encoder，XLM-RoBERTa-large 骨架，基于 bge-m3 微调    |
| **参数量**   | 约 568M（0.6B）                                       |
| **上下文上限** | **8192 tokens，按「query + 单篇文档」计**（实测超限返回 400，不静默截断） |
| **多语言**   | 实测中 / 英 / 日 / 韩 / 俄 / 法 / 阿拉伯语排序均正确，支持跨语言检索        |
| **端点**    | `POST /v1/rerank`                                  |
| **可用分组**  | `default`、`svip`                                   |
| **上游**    | 华为云 ModelArts（官转资源）                                |
| **开源许可**  | Apache 2.0                                         |

## 定价

| 项目 | 价格                 |
| -- | ------------------ |
| 输入 | \$0.01 / 1M tokens |
| 输出 | 无（本模型不产生输出 token）  |

<Info>
  **便宜到可以忽略**：一次 100 篇候选（约 2700 tokens）的重排序约合 \$0.000027，一百万次也才 \$27。
  重排序几乎从不是 RAG 系统的成本瓶颈——**瓶颈是延迟，不是钱**，调优时优先看候选集大小对延迟的影响。
</Info>

**usage 口径**（实测）：

* `prompt_tokens` = query（计一次）+ 全部候选文档。实测严格线性：`≈ 26.9 × 文档数 + 7`（拟合偏差 \< 0.31%），可在客户端精确预估
* `total_tokens` 比 `prompt_tokens` 大，差值随候选数增长——相当于把 query 按「query + 每篇文档」这一对重复计入
* `input_tokens` / `output_tokens` 该通道**恒为 0**，不要用
* `top_n` 和 `return_documents` **都不影响用量**——所有候选都要过一遍模型，只是少返回几条

<Warning>
  本轮测试**未能通过账单反推确认实际扣费依据是 `prompt_tokens` 还是 `total_tokens`**
  （测试令牌读不到账户余额接口）。两者在 100 篇候选时相差约 45%。
  对成本敏感的场景请以控制台账单为准，不要直接拿 `usage` 字段做财务核算。
</Warning>

## 最简调用

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.apiyi.com/v1/rerank \
    -H "Authorization: Bearer $APIYI_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "bge-reranker-v2-m3",
      "query": "杭州有哪些适合旅游的景点？",
      "documents": [
        "西湖是杭州著名的旅游景点，拥有断桥、苏堤和雷峰塔等景观。",
        "上海外滩位于黄浦江畔，是上海的标志性景点。",
        "灵隐寺位于杭州西湖区，是中国著名的佛教寺院。"
      ],
      "top_n": 2
    }'
  ```

  ```python Python theme={null}
  import os, requests

  resp = requests.post(
      "https://api.apiyi.com/v1/rerank",
      headers={"Authorization": f"Bearer {os.environ['APIYI_API_KEY']}"},
      json={
          "model": "bge-reranker-v2-m3",
          "query": "杭州有哪些适合旅游的景点？",
          "documents": [
              "西湖是杭州著名的旅游景点，拥有断桥、苏堤和雷峰塔等景观。",
              "上海外滩位于黄浦江畔，是上海的标志性景点。",
              "灵隐寺位于杭州西湖区，是中国著名的佛教寺院。",
          ],
          "top_n": 2,
      },
      timeout=60,
  ).json()

  for r in resp["results"]:
      print(f"{r['relevance_score']:.4f}  {r['document']['text']}")
  ```

  ```javascript Node.js theme={null}
  const resp = await fetch('https://api.apiyi.com/v1/rerank', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.APIYI_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'bge-reranker-v2-m3',
      query: '杭州有哪些适合旅游的景点？',
      documents: [
        '西湖是杭州著名的旅游景点，拥有断桥、苏堤和雷峰塔等景观。',
        '上海外滩位于黄浦江畔，是上海的标志性景点。',
        '灵隐寺位于杭州西湖区，是中国著名的佛教寺院。',
      ],
      top_n: 2,
    }),
  });

  const data = await resp.json();
  data.results.forEach((r) => console.log(r.relevance_score, r.document.text));
  ```
</CodeGroup>

响应：

```json theme={null}
{
  "results": [
    { "document": { "text": "西湖是杭州著名的旅游景点..." }, "index": 0, "relevance_score": 0.97265625 },
    { "document": { "text": "灵隐寺位于杭州西湖区..." },   "index": 2, "relevance_score": 0.1181640625 }
  ],
  "usage": { "prompt_tokens": 70, "total_tokens": 91 }
}
```

<Tip>
  **`index` 是最重要的字段**。它是该文档在你传入的 `documents` 数组中的**原始下标**，
  用它回填你自己的文档对象（ID、URL、元数据），而不是拿返回的 `text` 去反查。
</Tip>

## 请求参数

| 参数                 | 类型        | 必填 | 说明                                |
| ------------------ | --------- | -- | --------------------------------- |
| `model`            | string    | ✓  | 固定 `bge-reranker-v2-m3`，**大小写敏感** |
| `query`            | string    | ✓  | 检索问题。空字符串返回 400                   |
| `documents`        | string\[] | ✓  | 候选文档，**只接受字符串数组**。空数组返回 400       |
| `top_n`            | int       |    | 返回前 N 条。省略 / 传 0 / 传负数都返回全部。不影响用量 |
| `return_documents` | bool      |    | 是否回显原文。**当前通道该参数不生效**，详见下方已知问题    |

## 实测能力矩阵

| 能力                        | 实测结果                                                   |
| ------------------------- | ------------------------------------------------------ |
| 中文语义排序                    | ✅ nDCG\@3 = 1.00                                       |
| 关键词干扰抵抗                   | ✅ Top-2 正确，但干扰项绝对分可能很高（见下）                             |
| 跨语言检索（中↔英）                | ✅ 排序正确，但绝对分数被压低 1–2 个数量级                               |
| 多语言（日 / 韩 / 俄 / 法 / 阿）    | ✅ 5 语种全部排序正确                                           |
| **否定语义理解**                | ❌ **明显弱项**，nDCG\@3 = 0.47（见下）                          |
| 结果确定性                     | ✅ 同请求重复 10 次得分逐位一致；打乱候选顺序漂移仅 3.7e-4                    |
| 重复文档一致性                   | ✅ 相同文档得分逐位一致                                           |
| 单请求候选上限                   | ✅ 实测 2000 条可用；**建议 ≤ 100 条**                           |
| 单文档长度上限                   | 8192 tokens/对，超限返回 400（不静默截断）                          |
| **上游配额**                  | ⚠️ TPM 20,000 / RPM 120，并发槽位约 4–5；100 篇候选约 15 次/分钟（见下） |
| `return_documents: false` | ❌ 参数被忽略                                                |

## 三个必须知道的坑

<AccordionGroup>
  <Accordion title="1. relevance_score 不是跨 query 可比的绝对置信度" icon="triangle-alert">
    很多人第一反应是"设个 0.5 的阈值过滤一下"。**实测这样做会出事**：

    | 场景                  | 真正相关文档的得分区间                  |
    | ------------------- | ---------------------------- |
    | 中文 query × 中文文档     | 0.289 – 1.000（中位数 0.948）     |
    | 非中文同语言（日/韩/俄/法/阿）   | **0.005 – 0.998**（中位数 0.241） |
    | **跨语言（中↔英）**        | **0.0038 – 0.205**           |
    | 关键词高度重合但**不相关**的干扰项 | 最高冲到 **0.945**               |

    也就是说：一个 0.5 的阈值会**滤掉全部跨语言正确结果**、滤掉多数非中文场景的第二名，
    同时**放行**那篇讲苹果种植的干扰文档。

    **正确做法**：把它当排序依据，不要当绝对置信度。要过滤就用相对阈值
    （`score >= top1_score × 0.3`）或直接取 Top-N，并在你自己的数据上标注一批样本来定阈值。
  </Accordion>

  <Accordion title="2. 否定语义是这个模型的明确弱项" icon="circle-x">
    查询"哪些景点适合冬天去？"，候选里放两篇**明确说不适合冬天**的文档：

    | 排名 | 得分    | 文档               | 是否真的相关 |
    | -- | ----- | ---------------- | ------ |
    | #1 | 0.811 | 哈尔滨冰雪大世界⋯⋯冬季旅游首选 | ✅      |
    | #2 | 0.769 | 北戴河⋯⋯**不适合冬季旅游** | ❌      |
    | #3 | 0.531 | 青海湖⋯⋯**不建议冬天前往** | ❌      |
    | #4 | 0.375 | 雾凇岛⋯⋯冬季必去        | ✅      |
    | #5 | 0.289 | 三亚⋯⋯冬天避寒热门       | ✅      |

    模型看到的是"冬天 + 景点 + 旅游"的话题匹配，**没有理解"不"字**。nDCG\@3 只有 0.47。

    **应对**：涉及否定、排除、条件判断（"不含麸质的"、"除了北京以外"、"未成年人不适用"）的查询，
    重排序之后必须再过一层大模型做判断，不能直接把 Top-N 喂给用户。
  </Accordion>

  <Accordion title="3. 长文档会同时稀释相关性、抬高噪声" icon="scissors">
    实测同一句命中内容，后面接不同长度的无关填充：

    | 文档总长    | 命中句在**开头**的得分 | 命中句在**结尾**的得分 |
    | ------- | ------------- | ------------- |
    | 528 字符  | 0.933         | 0.720         |
    | 1028 字符 | 0.931         | 0.500         |
    | 4028 字符 | 0.907         | 0.351         |
    | 8028 字符 | 0.828         | 0.181         |

    同时，**无关内容变长反而会抬高得分**：同一篇不相关文档，短版 0.029、长版 0.121，翻了 4 倍。

    **应对**：把长文档切成 200–500 字的小块再送进重排序，用「块的最高分」代表文档得分。
    切块是这个模型上收益最大的一步预处理。
  </Accordion>
</AccordionGroup>

完整的调参方法、切块策略、阈值确定流程见 [RAG 实战调优](/api-capabilities/rerank/rag-best-practices)。

## 已知问题

<Warning>
  **`return_documents` 参数不生效**（2026-07-30 实测）：无论传 `true`、`false` 还是省略，
  响应中都会回显 `document.text`。对带宽敏感的场景（大候选集 + 长文档），
  响应体会比预期大很多，请自行按 `index` 回填原文，不要依赖此开关裁剪响应。
</Warning>

<Warning>
  **模型名写错返回 503 而不是 404**：错误信息为
  `Current group default has no available channels for model xxx`。
  模型名**大小写敏感**，`BGE-Reranker-v2-M3` 会被当作不存在的模型。
  接入时如果收到 503，先核对模型名拼写，再考虑是不是真的没有可用渠道。
</Warning>

<Warning>
  **上游配额是这个模型最硬的约束，接入前必须先算 token 预算。**

  上游（华为云 MaaS）给本模型的配额是 **TPM 20,000 / RPM 120**——
  同平台的 BGE-M3 向量化模型是 1,200,000 TPM，**差 60 倍**。

  实测分离出两个**互相独立**的机制：

  | 机制                  | 实测表现                                                                       |
  | ------------------- | -------------------------------------------------------------------------- |
  | **并发槽位约 4–5 个在途请求** | 10 并发只成功 4 个、20 并发只成功 5 个（此时 token 仅占 3–4% TPM）；**串行 20 次则 20/20 全过**      |
  | **TPM 20,000 滑动窗口** | **完全串行**也会触发：连发 1.3K tokens 的请求，第 8 个在累计 16,093 tokens 时 429，连挂 9 个后窗口滑动恢复 |

  超出槽位的请求**直接 429、不排队**，错误信息统一是 `当前分组上游负载已饱和`，
  无法区分撞的是哪一个，只能自己按预算推算。

  **接入建议**：并发控制在 4 以内 + 指数退避重试，并按下方表格核算每分钟的检索次数上限。
</Warning>

### 每分钟能跑多少次检索

按实测 `≈26.9 tokens/文档` 折算（TPM 20,000）：

| 每次查询的候选数 | 单次 tokens | 理论上限          |
| -------- | --------- | ------------- |
| 50 条     | 673       | 约 29 次/分钟     |
| 100 条    | 1,325     | **约 15 次/分钟** |
| 200 条    | 2,629     | 约 7 次/分钟      |

这也解释了为什么**单请求候选集不能太大**：1000 条候选就是 26,867 tokens，
**一个请求就吃掉整分钟预算的 134%**，必然 429。2000 条是 269%。

<Info>
  **配额正在扩容中**：上述 TPM 20,000 是上游给到的初始配额，API易 已在向平台申请扩容。
  如果你的业务量超出上表的测算，**请直接联系 API易客服评估提升上游配额**，
  不必按当前数字自行降级方案。
</Info>

<Warning>
  **只有 `/v1/rerank` 是有效路径**。实测请求 `/rerank` 或 `/v2/rerank`（Cohere SDK v2 的默认路径）
  会返回 **HTTP 200 + 网站的 HTML 首页**，而不是 JSON 404——客户端只会看到一个诡异的解析错误。
  接入平台时若出现"返回内容无法解析"，先确认地址是否带 `/v1`。
</Warning>

## 常见问题

<AccordionGroup>
  <Accordion title="重排序和向量检索，我只用一个行不行？">
    只用向量检索：能跑，但 Top-N 的精度会明显低于加了重排序（实测 nDCG\@3 从 1.00 掉到 0.53）。

    只用重排序：**不行**。它没有向量输出，必须先有候选集。百万篇文档逐条打分既不现实也不经济。

    标准做法是两段式：向量/BM25 召回 50–100 篇 → 重排序精排出 3–5 篇 → 送进大模型。
  </Accordion>

  <Accordion title="应该召回多少条送进重排序？">
    实测延迟随候选数近似线性增长（短文档）：10 条约 2 秒、100 条约 5 秒、500 条约 15 秒、1000 条约 33 秒。

    **推荐 50–100 条**。低于 20 条，重排序能挽回的漏排有限；超过 200 条，延迟开始明显影响交互体验，
    而召回列表尾部本来就很少含有正确答案。

    还要看 TPM 预算：100 篇候选约 1,325 tokens，在 TPM 20,000 下每分钟只能跑约 15 次检索。
    候选数翻倍，吞吐就减半——**候选数的选择同时是质量决策和容量决策**。
  </Accordion>

  <Accordion title="能用 Cohere / Jina 的 SDK 直接调吗？">
    **`cohere` SDK v2 实测不可用**：它默认请求 `/v2/rerank`，该路径返回 HTML 首页而非 JSON，SDK 直接抛解析错误。

    参数名（`query` / `documents` / `top_n` / `return_documents`）确实与 Cohere Rerank v1 一致，
    但 `documents` **只接受字符串数组**（传 `[{"text": "..."}]` 返回 400），响应体也没有
    Cohere 的 `id` / `meta` 字段。**最省事的做法是自己包一层 HTTP 调用**，
    [RAG 实战调优](/api-capabilities/rerank/rag-best-practices) 里有 LangChain / LlamaIndex 的现成封装。

    实测可用的客户端：`requests` 裸 POST ✅、`openai` SDK 的 `client.post("/rerank", ...)` 逃生舱 ✅。
  </Accordion>

  <Accordion title="结果可以缓存吗？">
    可以，而且很稳。**同一请求重复 10 次，得分逐位一致**（漂移 0）。
    只有在**打乱候选顺序**重发时才会出现 3.7e-4 量级的漂移（bf16 批处理抖动），排序不受影响。

    缓存 key 用 `query 归一化 + 候选文档内容哈希（有序）`。
    注意：由于顺序会带来微小漂移，**不要把 relevance\_score 本身当幂等标识或去重 key**。
  </Accordion>

  <Accordion title="超过 8192 tokens 会怎样？">
    直接返回 400，错误信息为 `This model's maximum context length is 8192 tokens`，
    **不会静默截断**。这个上限是按「query + 单篇文档」这一对算的，不是整个请求的总量——
    实测单请求 400 篇 × 1000 字符（合计 33 万 tokens）可以正常返回。
  </Accordion>
</AccordionGroup>

## 相关文档

* [重排序 API 在线调试](/api-capabilities/rerank/rerank-api)
* [RAG 实战调优：怎么用好重排序](/api-capabilities/rerank/rag-best-practices)
* [文本向量化](/api-capabilities/text-embedding)
* [模型价格](/models)
