> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# 超越向量RAG：确定性稀疏检索
- URL: https://www.hubwiz.com/blog/beyond-vector-rag-deterministic-sparse-retrieval/
- Published: 2026-08-26T16:27:35.000Z
- Updated: 2026-08-26T16:27:35.000Z
- Description: 经典信息检索如何替代昂贵的向量嵌入，服务于许多检索增强生成工作负载
- Author: admin
- Tags: RAG, #Import 2026-10-14 14:41

检索增强生成（RAG）已成为在私有或特定领域知识上构建LLM应用最常见的架构之一。

标准方法是熟悉的：

**文档 → 嵌入模型 → 向量数据库 → 相似性搜索 → 检索上下文 → LLM**

它工作得非常好。

但它也引入了基础设施、计算成本、延迟和操作复杂性。

每个文档都需要转换为向量表示。这些向量需要存储和索引。查询需要在检索发生之前通过嵌入模型。根据规模和架构，系统可能还需要向量数据库、嵌入服务、GPU资源或外部API调用。

然而，对于许多企业工作负载，检索问题比语义搜索看起来的要简单得多。

如果用户问：

> *"显示客户ACME的发票"*

我们可能不需要神经嵌入模型来理解**ACME**、**客户**和**发票**是重要的检索信号。

经典的信息检索技术如**TF-IDF**可以极其高效地识别这些信号。

这引出了不同的架构：

**文档 → TF-IDF索引 → 查询 → 稀疏检索 → 检索上下文 → LLM**

没有嵌入API。

没有稠密向量。

没有向量数据库。

没有神经检索模型。

只有确定性索引和极快的词汇检索。

本文探讨这种方法，它何时有效，何时失败，以及为什么它对于大规模RAG系统可能出奇地有效。

## 1\. 现代RAG的问题

典型的RAG管道看起来像这样：

**1\. 摄入文档**

文档从文件、数据库、API、源代码或其他系统加载。

**2\. 将文档分割成块**

大型文档被分成更小的部分。

**3\. 生成嵌入**

每个块通过嵌入模型。

**4\. 存储向量**

嵌入存储在向量数据库或另一个相似性搜索索引中。

**5\. 嵌入查询**

用户的问题也被转换为向量。

**6\. 执行相似性搜索**

查询向量与文档向量进行比较。

**7\. 将检索到的块发送给LLM**

最相关的块被放入模型上下文。

这种架构提供语义检索。

例如，查询如：

> *"我们在交通上花了多少钱？"*

可能检索到包含以下内容的文档：

> *"物流和差旅总支出为€82,000。"*

单词不必完全匹配。

这是语义嵌入的主要优势。

然而，这种能力是有代价的。

## 2\. 基于嵌入的RAG的隐性成本

假设我们有：

**1000万文档**

每个文档产生多个块。

如果每个块需要嵌入，我们现在可能有数千万甚至数亿个向量。

这些向量消耗存储空间，需要被索引。

管道还需要在以下情况下执行嵌入生成：

- 新文档到达，
- 文档更改，
- 文档重新索引，
- 嵌入模型更改，
- 或查询到达。

查询本身也需要被嵌入。

因此架构变为：

**查询 → 嵌入模型 → 向量搜索 → 检索**

而不是简单地：

**查询 → 搜索索引 → 检索**

还有另一个重要问题：

**确定性。**

嵌入模型在检索中引入了机器学习组件。

检索结果可能取决于：

- 嵌入模型，
- 模型版本，
- 预处理，
- 分块，
- 向量索引配置，
- 相似性度量，
- 有时是近似最近邻参数。

对于许多企业应用程序，特别是结构化或半结构化数据，这种复杂性可能是不必要的。

## 3\. TF-IDF：1970年代的想法用于现代RAG

TF-IDF代表：

**词频-逆文档频率**

它是信息检索中的经典技术之一。

基本思想很简单：

> *如果一个词在文档中频繁出现，但在整个集合中不频繁出现，那么它对文档很重要。*

例如，想象三个文档：

**文档A**

> *ACME软件许可证发票*

**文档B**

> *ACME咨询服务发票*

**文档C**

> *ACME硬件发票*

单词**发票**无处不在。

因此它携带相对较少的判别信息。

然而，单词**软件**只出现在文档A中。

它成为更强的检索信号。

TF-IDF从数学上捕捉这一点。

## 4\. TF-IDF详解

第一个组件是**词频（TF）**。

简单版本是：

**TF(t,d) = 词项t在文档d中出现的次数**

归一化版本可以是：

**TF(t,d) = count(t,d) / total\_terms(d)**

第二个组件是**逆文档频率（IDF）**。

常见公式是：

**IDF(t) = log(N / DF(t))**

其中：

- **N** \= 文档总数
- **DF(t)** \= 包含词项`t`的文档数

最终的TF-IDF分数是：

**TF-IDF(t,d) = TF(t,d) × IDF(t)**

这创建了文档集合的稀疏表示。

不是将文档表示为稠密向量如：

**\[0.132, -0.721, 0.043, …, 0.912\]**

我们主要通过实际出现的词项来表示它。

例如：

```
文档：
"ACME软件许可证发票"
TF-IDF表示：
ACME       → 0.42
software   → 0.81
license    → 0.73
invoice    → 0.21

```

大多数可能的词汇词项值为零。

这就是为什么TF-IDF被称为**稀疏表示**。

## 5\. 从TF-IDF到检索

一旦语料库被索引，查询可以使用相同的词汇进行转换。

假设查询是：

> *"ACME软件发票"*

系统计算查询的TF-IDF表示，并与索引文档进行比较。

常见的相似性函数是**余弦相似性**。

公式是：

**cosine\_similarity(A,B) = (A · B) / (|A| × |B|)**

换句话说：

**相似性 = 点积 / 向量长度的乘积**

结果范围大约从：

**0 → 不相关**

到

**1 → 高度相似**

因为TF-IDF向量是稀疏的，系统不需要在每个可能的词汇维度上执行昂贵的比较。

相反，它可以对实际存在的词项进行操作。

## 6\. 重要区别：稀疏与稠密检索

现代嵌入系统通常产生**稠密向量**。

例如：

```
[-0.021, 0.442, -0.118, 0.731, ...]

```

每个维度通常包含一个值。

TF-IDF产生**稀疏向量**：

```
ACME       → 0.42
software   → 0.81
invoice    → 0.21

```

这种区别很重要。

稠密嵌入试图编码**语义含义**。

TF-IDF主要捕获**词汇相关性**。

这意味着：

> *"软件许可证"*

和

> *"应用程序订阅"*

对人类来说可能语义相关，但词汇重叠很少。

稠密嵌入可能识别这种关系。

TF-IDF通常不能。

但反过来也很有价值。

对于精确标识符、名称、代码、ID、错误消息、API名称、数据库字段、产品代码和技术术语，词汇匹配可能非常强大。

## 7\. 关键洞察：并非每个RAG问题都是语义搜索问题

这是这种方法的核心思想。

考虑包含以下内容的企业系统：

- 5000万数据库记录
- 1000万发票
- 500万客户记录
- 源代码仓库
- 配置文件
- API规范
- UI定义
- 技术文档
- 日志
- 元数据

许多检索问题不是真正的语义问题。

它们更接近于：

> *"找到包含此标识符的记录。"*

或：

> *"找到提及此API的文件。"*

或：

> *"找到包含此字段的规范。"*

或：

> *"找到与此客户号相关的文档。"*

在这些情况下，引入神经嵌入模型可能是不必要的。

确定性词汇索引通常可以直接回答问题。

## 8\. 架构

架构变得非常简单：

```
                   离线
                       │
                       ▼
                   文档
                       │
                       ▼
                 文本提取
                       │
                       ▼
                   分词
                       │
                       ▼
                  TF-IDF索引
                       │
                       ▼
                 稀疏搜索索引
                       │
                       │
              ┌────────┴────────┐
              │                 │
              ▼                 ▼
           查询            查询元数据
              │                 │
              └────────┬────────┘
                       ▼
                  TF-IDF搜索
                       │
                       ▼
                 Top-K结果
                       │
                       ▼
                上下文构建器
                       │
                       ▼
                      LLM

```

关键区别是昂贵的检索表示是**一次性**构建的。

LLM不负责发现信息。

确定性检索层首先找到它。

## 9\. 检索成为编译步骤

思考这种架构有一个有趣的方式。

不是让LLM反复推理信息可能存在的位置，我们可以将部分工作转移到确定性预处理层。

系统有效地执行：

**文档 → 索引 → 查询 → 确定性检索 → 上下文**

然后LLM从已经组装好的相关信息开始。

这对于代理系统特别有用。

代理可能传统上执行：

```
推理
  ↓
搜索
  ↓
读取结果
  ↓
推理
  ↓
再次搜索
  ↓
读取结果
  ↓
推理

```

确定性检索系统可以构建更大的初始状态：

```
所需信息
        ↓
确定性检索
        ↓
上下文构建
        ↓
LLM推理

```

检索层因此表现得几乎像**代理内存的编译器**。

它将大型外部信息空间转换为紧凑的推理状态。

## 10\. 示例：企业客户搜索

想象一个包含1亿记录的数据库。

用户问：

> *"找到与客户ACME GmbH相关的所有内容。"*

向量RAG管道可以：

1. 嵌入查询。
2. 搜索向量数据库。
3. 检索语义相似的块。
4. 将它们传递给LLM。

TF-IDF系统可以识别高度判别的词项：

```
ACME
GmbH
customer

```

索引可以立即定位包含这些词项的文档。

检索到的文档可能包括：

```
Customer: ACME GmbH
Customer ID: C-18492
Invoices:
INV-10293
INV-10384
INV-10922
Projects:
PRJ-421
PRJ-882
Contracts:
CTR-182
CTR-193

```

LLM不需要搜索客户。

它接收相关信息。

## 11\. 示例：源代码检索

这种方法对软件工程系统可以变得更有趣。

假设仓库包含200万行代码。

开发人员问：

> *"reconcileUIController在哪里使用？"*

TF-IDF检索自然适合这类问题。

搜索索引可以识别：

```
reconcileUIController
reconcile.ui.spec.ts
reconcile.uicontroller.ts
reconcileUIController.test.ts

```

精确标识符成为极强的检索信号。

语义嵌入可能理解以下两者之间的关系：

> *"UI协调控制器"*

和

> *"负责同步UI状态的组件"*

但对于找到实际符号：

> `reconcileUIController`

词汇检索通常正是我们想要的。

## 12\. 示例：错误检索

考虑包含数百万历史错误的应用程序。

开发人员收到：

```
TypeError: Cannot read properties of undefined

```

词汇检索系统可以立即搜索：

```
TypeError
Cannot
read
properties
undefined

```

并检索历史出现。

然后它可以向LLM提供：

```
先前出现 #1
----------------------
File: user.controller.ts
Line: 184
Cause: user object was not initialized.
先前出现 #2
----------------------
File: project.service.ts
Line: 92
Cause: missing database result.

```

这可能非常有效，因为错误消息包含高度判别的词项。

## 13\. 为什么它可以非常快

主要的性能优势来自稀疏检索的性质。

想象一个词汇表：

**1,000,000个词项**

稠密嵌入可能为每个文档生成具有数百或数千个维度的向量。

稀疏索引只需要维护实际出现的词项的倒排列表。

概念上：

```
"ACME"
   ↓
文档17
文档92
文档19382
文档84722

```

这类似于传统搜索引擎的架构。

不是问：

> *"这些数百万向量中哪个在数学上最接近？"*

我们可以问：

> *"哪些文档包含这些高价值词项？"*

该查找可能非常高效。

## 14\. 索引是重要的部分

性能不仅仅来自计算TF-IDF。

重要的架构决策是**预计算索引**。

不是在每个查询上执行：

```
文档
   ↓
分词
   ↓
计算TF-IDF
   ↓
搜索

```

我们做：

```
离线
文档
   ↓
分词
   ↓
计算TF-IDF
   ↓
构建倒排索引
   ↓
持久化索引

```

然后查询变为：

```
查询
  ↓
分词
  ↓
查找词项
  ↓
评分候选
  ↓
Top-K

```

这种分离至关重要。

昂贵的工作发生在索引期间。

在线路径保持轻量级。

## 15\. 倒排索引

底层数据结构可以是倒排索引。

例如：

```
词项        文档
------------------------------
ACME        [12, 18, 42, 91]
invoice     [12, 18, 19, 42, 91]
software    [12, 42]
license     [12, 42, 77]

```

当查询包含：

```
ACME software

```

系统只需要考虑相关倒排列表的交集或并集。

因此候选集可以比整个语料库小得多。

这是经典搜索引擎能够以极低延迟操作巨大集合的原因之一。

## 16\. TF-IDF不需要向量数据库

这是一个重要的架构区别。

TF-IDF检索系统本质上不需要向量数据库。

你可以使用以下方式存储索引：

- 倒排索引，
- 搜索引擎，
- 内存映射文件，
- SQLite，
- 自定义二进制结构，
- 本地文件，
- 或专用稀疏矩阵结构。

重要的对象是**稀疏检索索引**，而不是向量数据库。

这可以大大简化部署。

一个小服务可以执行：

```
索引加载
      ↓
查询
      ↓
稀疏检索
      ↓
Top-K文档

```

而无需运行单独的向量数据库集群。

## 17\. 内存效率

稀疏表示也可以比稠密表示小得多。

假设词汇表包含：

**1,000,000个词项**

稠密表示概念上在所有维度上分配空间。

稀疏表示只存储出现的词项。

对于包含500个有意义词项的文档，我们可能存储大约：

```
词项ID
权重

```

而不是维护百万维的稠密结构。

实际内存消耗很大程度上取决于：

- 词汇表大小，
- 平均文档长度，
- 文档数量，
- 索引结构，
- 数值精度，
- 压缩，
- 和实现。

但基本优势仍然存在：

**存储存在的内容，而不是存储零。**

## 18\. 检索质量

显而易见的问题是：

> *如果TF-IDF如此简单，为什么我们需要嵌入？*

因为嵌入解决的是不同的问题。

考虑：

**查询：**

> *"如何终止员工？"*

**文档：**

> *"雇佣关系可由任何一方在适用的通知期后终止。"*

词汇重叠可能很少。

语义嵌入可能连接这些概念。

TF-IDF可能不能。

这就是语义检索获胜的地方。

因此，正确的结论不是：

> *TF-IDF比嵌入更好。*

更准确的结论是：

> ***当词汇信号足够时，TF-IDF通常是更好的检索机制。***

## 19\. TF-IDF特别有效的场景

基于TF-IDF的检索对以下情况特别有吸引力：

### 精确标识符

```
CUST-18293
INV-92881
PRJ-182

```

### 名称

```
ACME GmbH
Everest Systems

```

### 技术术语

```
reconcileUIController
actionType
EveDocument
columnDefs

```

### 错误消息

```
TypeError
ECONNREFUSED
ENOENT

```

### 配置键

```
database.connection.timeout
feature.enablePlaybook

```

### API名称

```
getCustomerInvoices()
createProject()

```

### 结构化业务数据

```
customer
invoice
contract
project
employee
timesheet

```

### 具有一致术语的文档

企业系统通常使用受控词汇表。

这使得词汇检索出奇地强大。

## 20\. 混合检索更加强大

最实用的架构可能不是：

**TF-IDF 或 嵌入**

而是：

**TF-IDF + 嵌入**

例如：

```
                 查询
                   │
          ┌────────┴────────┐
          │                 │
          ▼                 ▼
      TF-IDF搜索      向量搜索
          │                 │
          └────────┬────────┘
                   ▼
              合并结果
                   │
                   ▼
              重新排序
                   │
                   ▼
                  LLM

```

TF-IDF可以提供高度精确的词汇匹配。

嵌入可以恢复语义匹配。

两种检索机制互补。

## 21\. 更有趣的优化：使用查询本身

还有另一种可能性。

不是嵌入每个文档，我们可以使用TF-IDF首先识别重要的查询词项。

例如：

> *"显示ACME GmbH与软件许可相关的所有发票。"*

检索系统可以识别：

```
ACME
GmbH
invoice
software
licensing

```

并优先处理最强的词项。

然后LLM接收检索到的上下文。

这创建了一个管道，其中机器学习在提供最大价值的地方使用：

**推理 → LLM**

而检索保持：

**确定性 → TF-IDF**

这种分离可以使整个系统更容易调试和操作。

## 22\. 确定性是一个特性

词汇检索最被低估的属性之一是确定性。

给定：

```
相同文档
+
相同索引
+
相同查询
+
相同评分配置

```

检索系统应该产生相同的结果。

这使得调试变得简单得多。

假设LLM给出了错误的答案。

使用确定性检索，你可以检查：

```
查询
  ↓
检索到的文档
  ↓
上下文
  ↓
LLM
  ↓
答案

```

你可以确定故障发生在：

**检索**

或

**推理。**

这种分离在生产AI系统中很有价值。

## 23\. RAG变得更容易观察

传统RAG管道可能难以调试，因为许多组件交互：

```
分块
嵌入
向量索引
相似性度量
ANN参数
查询嵌入
检索
重新排序
提示构建
LLM

```

确定性TF-IDF管道更容易检查：

```
查询
  ↓
词项
  ↓
词项权重
  ↓
候选文档
  ↓
分数
  ↓
Top-K
  ↓
上下文

```

你几乎可以解释为什么文档被检索到。

例如：

```
文档：invoice_18293
匹配词项：
ACME       → 0.82
invoice    → 0.31
software   → 0.67
总分：
1.80

```

这使得检索**可解释**。

## 24\. 实用架构

生产实现可能如下所示：

```
                 ┌────────────────────┐
                 │    数据源          │
                 └─────────┬──────────┘
                           │
                           ▼
                 ┌────────────────────┐
                 │   文档处理器       │
                 └─────────┬──────────┘
                           │
                           ▼
                 ┌────────────────────┐
                 │      分词         │
                 └─────────┬──────────┘
                           │
                           ▼
                 ┌────────────────────┐
                 │   TF-IDF构建器    │
                 └─────────┬──────────┘
                           │
                           ▼
                 ┌────────────────────┐
                 │    倒排索引       │
                 └─────────┬──────────┘
                           │
                           │
                      在线路由
                           │
                           ▼
                       用户查询
                           │
                           ▼
                 ┌────────────────────┐
                 │   查询分词        │
                 └─────────┬──────────┘
                           │
                           ▼
                 ┌────────────────────┐
                 │    稀疏检索       │
                 └─────────┬──────────┘
                           │
                           ▼
                         Top-K
                           │
                           ▼
                 ┌────────────────────┐
                 │    上下文构建     │
                 └─────────┬──────────┘
                           │
                           ▼
                           LLM

```

## 25\. 示例伪代码

最小实现概念上如下所示：

```
documents = load_documents()
vectorizer = TfidfVectorizer(
    lowercase=True,
    stop_words="english"
)
document_matrix = vectorizer.fit_transform(documents)
def search(query, k=10):
    query_vector = vectorizer.transform([query])
    scores = cosine_similarity(
        query_vector,
        document_matrix
    )[0]
    top_indices = scores.argsort()[-k:][::-1]
    return [
        (documents[i], scores[i])
        for i in top_indices
    ]

```

重要的观察是需要多少基础设施。

索引可以构建一次并重复使用。

## 26\. 扩展方法

对于小型数据集，稀疏矩阵实现可能已经足够。

对于更大的数据集，架构可以演变为：

```
分词器
    ↓
词汇表
    ↓
词项 → 倒排列表
    ↓
压缩索引
    ↓
候选检索
    ↓
评分

```

系统可以额外支持：

- 文档过滤，
- 元数据过滤，
- 字段特定权重，
- 前缀匹配，
- 精确匹配，
- 短语匹配，
- 词干提取，
- 停用词移除，
- 同义词扩展，
- 查询扩展，
- BM25，
- 结果缓存，
- 增量索引。

到那时，系统开始类似于传统搜索引擎。

这不是巧合。

**RAG检索从根本上是一个信息检索问题。**

## 27\. TF-IDF vs BM25

TF-IDF不一定是最终的经典检索算法。

自然的演进是**BM25**。

BM25改进了传统TF-IDF检索的几个方面，特别是：

- 文档长度归一化，
- 词频饱和，
- 相关性评分。

BM25分数可以表示为：

**score(D,Q) = Σ IDF(qᵢ) × \[ TF(qᵢ,D) × (k₁ + 1) \] / \[ TF(qᵢ,D) + k₁ × (1 — b + b × |D| / avgdl) \]**

其中：

- `qᵢ` 是查询词项
- `TF(qᵢ,D)` 是它在文档D中的频率
- `|D|` 是文档长度
- `avgdl` 是平均文档长度
- `k₁` 控制词频饱和
- `b` 控制长度归一化

对于生产词汇RAG系统，BM25可能比原始TF-IDF更强的基线。

更广泛的思想保持不变：

**确定性稀疏检索而不是神经嵌入。**

## 28\. 真正的权衡

TF-IDF和稠密嵌入之间的比较不应简化为：

**旧 vs 新** 或 **简单 vs 先进**

它们解决不同的检索问题。

### TF-IDF / BM25

TF-IDF和BM25主要使用**词汇相似性**。

当重要信息已经直接存在于文本中时，它们特别有效。

典型示例包括：

- 标识符
- 客户名称
- API名称
- 数据库字段
- 错误消息
- 配置键
- 技术术语
- 产品代码

例如：

```
查询：reconcileUIController

```

如果文档包含精确标识符`reconcileUIController`，稀疏检索可以为其分配非常强的相关性分数。

不需要语义解释。

### 稠密嵌入

稠密嵌入主要使用**语义相似性**。

当查询和相关文档使用不同单词表达相同想法时，它们很有用。

例如：

```
查询：如何终止雇佣合同？

```

相关文档可能包含：

```
终止雇佣需要四周通知期。

```

精确单词重叠有限，但含义密切相关。

这就是稠密嵌入有价值的地方。

### 实践中的差异

思考这两种方法的一种有用方式是：

```
TF-IDF / BM25

精确单词
    ↓
标识符
    ↓
名称
    ↓
技术术语
    ↓
错误消息
    ↓
高度精确的词汇检索

```

稠密检索工作方式不同：

```
稠密嵌入

含义
    ↓
同义词
    ↓
释义
    ↓
相关概念
    ↓
不同措辞
    ↓
语义检索

```

操作差异也很重要。

使用TF-IDF或BM25：

```
文档
    ↓
本地索引
    ↓
稀疏索引
    ↓
快速查询

```

检索路径中没有嵌入模型。

使用稠密检索：

```
文档
    ↓
嵌入模型
    ↓
稠密向量
    ↓
向量索引
查询
    ↓
嵌入模型
    ↓
向量搜索

```

这引入了额外的模型依赖。

如果嵌入模型更改，语料库可能也需要重新嵌入。

使用TF-IDF，更改LLM不需要重建检索表示。

### 考虑源代码

想象一个仓库包含：

```
actionType
ProjectTimesheet
reconcileUIController
ERR_CONNECTION_TIMEOUT
customerId

```

这些值已经提供强烈的检索信号。

搜索：

```
customerId

```

不需要理解客户标识符的含义。

标识符本身就足够了。

在这种情况下，将每个源代码块转换为稠密嵌入可能会增加成本和复杂性，而不会提供显著的额外检索价值。

### 现在考虑自然语言

假设用户问：

```
如何取消我的雇佣合同？

```

但知识库包含：

```
雇员可以通过提供书面通知来终止协议。

```

TF-IDF可能因为重要单词不同而遇到困难：

```
cancel      ≠ terminate
contract    ≠ agreement

```

语义嵌入可以识别这些表达描述相关概念。

这就是稠密检索提供明确价值的场景类型。

### 那么应该使用哪一个？

决策不应该是：

**TF-IDF还是嵌入？**

更好的问题是：

**数据中存在什么样的信息信号？**

如果相关性主要由精确术语决定：

**使用稀疏检索。**

如果相关性严重依赖于含义而非措辞：

**使用稠密检索。**

如果两种类型的信息都存在：

**使用混合检索。**

例如：

```
                     查询
                       │
              ┌────────┴────────┐
              │                 │
              ▼                 ▼
        TF-IDF / BM25      稠密搜索
              │                 │
              ▼                 ▼
        精确匹配          语义匹配
              │                 │
              └────────┬────────┘
                       ▼
                  合并结果
                       │
                       ▼
                      LLM

```

因此目标不是在所有地方都替换嵌入。

目标是避免在检索问题已经可以确定性解决时支付语义检索的成本。

一个有用的设计原则是：

> ***当必须推断含义时使用语义检索。当信息已经明确时使用确定性检索。***

## 29\. 检索的经济学

考虑一个语料库频繁变化的系统。

使用嵌入，每个新修改的块可能需要嵌入操作。

使用TF-IDF，可以执行本地索引。

这改变了成本结构。

不是：

**数据 → 外部嵌入API → 向量数据库**

我们可以有：

**数据 → 本地索引 → 本地搜索**

因此系统可以减少：

- API成本
- 网络延迟
- 外部依赖
- 基础设施需求
- 操作复杂性

对于处理大量数据的组织，节省可能变得显著。

## 30\. 最重要的限制

有一点这种方法不应该声称：

**TF-IDF不能替代语义理解。**

考虑：

> *"如何解雇员工？"*

和：

> *"终止雇佣关系的流程是什么？"*

人类看到这些是相关的。

TF-IDF看到的是大部分不同的单词。

这是根本限制。

因此，最强的架构通常是选择性的。

当查询包含强词汇信号时使用词汇检索。

当语义相似性必要时使用语义检索。

当问题受益于两者时同时使用两者。

## 31\. 思考RAG的新方式

RAG通常被呈现为：

> ***让LLM访问外部知识。***

但实际上有两个独立的问题：

**1\. 信息检索**

找到正确的信息。

**2\. 信息推理**

理解信息并产生答案。

这些不一定需要相同的技术。

LLM非常擅长推理。

它并不意味着它也必须负责每个检索操作。

确定性检索层可以处理第一个问题。

LLM可以专注于第二个。

这导致更清晰的架构：

```
               外部知识
                       │
                       ▼
             确定性检索
                       │
                       ▼
                 相关上下文
                       │
                       ▼
                      LLM
                       │
                       ▼
                 最终答案

```

## 32\. 检索作为编译器

这个想法可以更进一步。

编译器将高级表示转换为高效的可执行表示。

确定性RAG检索层可以执行类似的转换：

```
大型知识库
        ↓
   检索规则
        ↓
   稀疏索引
        ↓
   查询执行
        ↓
  相关上下文
        ↓
       LLM

```

LLM不是从空状态开始。

检索系统已经构建了推理所需的信息状态。

从这个意义上说：

> ***检索可以被视为将外部知识编译为LLM就绪的推理上下文。***

这种观点对代理系统特别有趣。

## 33\. 走向确定性RAG

这暗示了一个更广泛的架构，可以称为：

### 确定性RAG

原则是：

> ***将不需要概率推理的检索工作从LLM中移出，转移到确定性算法中。***

可能的组件包括：

```
精确搜索
     +
TF-IDF
     +
BM25
     +
元数据过滤
     +
结构化查询
     +
图遍历
     +
语义检索
     +
LLM推理

```

目标不是消除AI。

目标是仅在AI提供独特价值的地方使用它。

## 34\. 简单的决策框架

构建RAG系统时，问：

#### 查询是否包含精确标识符？

使用：**TF-IDF / BM25**

#### 语料库是否使用一致的领域术语？

使用：**TF-IDF / BM25**

#### 语义相似性是否必要？

使用：**嵌入**

#### 文档是否高度异构？

考虑：**混合检索**

#### 检索成本是否变得显著？

考虑：**先稀疏检索**

#### 可解释性是否重要？

优先：**确定性词汇检索**

#### 你是否在构建基于结构化企业数据的代理？

考虑：**确定性检索 + 结构化查询 + LLM**

## 35\. 更大的教训

LLM的兴起导致许多系统默认用神经模型替换经典算法。

但并非每个问题都需要神经解决方案。

搜索在LLM之前就存在了。

索引在嵌入之前就存在了。

信息检索背后有数十年的优化。

有趣的问题不是：

> *"嵌入模型能检索这个吗？"*

当然可以。

更好的问题是：

> ***"我需要嵌入模型来检索这个吗？"***

如果答案是否定的，经典稀疏索引可能提供：

- 更低成本，
- 更低延迟，
- 更低基础设施复杂性，
- 确定性行为，
- 更好的可解释性，
- 和出色的检索质量。

## 36\. 结束语

基于嵌入的RAG很强大，但它不应该自动成为每个检索问题的默认架构。

当信息主要通过词汇信号识别时，TF-IDF提供了出奇强大的替代方案。

架构很简单：

**索引一次。快速搜索。给LLM正确的上下文。**

重要的概念分离是：

**如果信息空间已经提供强烈的确定性信号，检索不需要是智能的。**

对于标识符、名称、技术术语、错误消息、配置键、源代码、结构化业务数据和许多企业数据集，稀疏词汇检索可以是非常有效的基础。

当语义理解真正必要时，TF-IDF不需要消失。

它可以与嵌入一起工作。

因此RAG的未来可能不是：

**一切都变成向量。**

它可能是：

**使用解决检索问题的最简单检索机制，并将昂贵的神经推理保留给真正需要它的问题。**

---

原文链接：[Beyond Vector RAG: Deterministic Sparse Retrieval with TF-IDF for Large-Scale LLM Applications](https://medium.com/@thenoir.ami/beyond-vector-rag-deterministic-sparse-retrieval-with-tf-idf-for-large-scale-llm-applications-65da1bd44483?source=home%5Ffor%5Fyou---------57-98--------------------e3a418a7%5F70f4%5F4139%5F9e3b%5Feba189ca5a9f-------15-------)

汇智网翻译整理，转载请标明出处