Redis&ES——Retriever的抽象实现

Redis&ES------Retriever的抽象实现

Eino 的 Retriever 抽象就是为了屏蔽底层检索实现,Redis 和 Elasticsearch(ES)都可以作为 Retriever 的实现,只不过支持方式有所区别。

Eino 中 Retriever 的定位

Eino 将检索能力统一抽象成了一个接口,大致可以理解成:

go 复制代码
type Retriever interface {
    Retrieve(ctx context.Context, query string, opts ...Option) ([]*schema.Document, error)
}

无论底层是:

  • 向量数据库(Milvus、Qdrant、Chroma)
  • 搜索引擎(Elasticsearch)
  • Redis
  • 自定义数据库

最终都只需要实现这个接口即可。

这样在 Chain 或 Agent 中,只需要依赖 Retriever,而不用关心底层是什么。


1. Elasticsearch

ES 非常适合作为 Retriever。

可以有几种方式:

① BM25 检索

复制代码
User Query
      │
      ▼
Elasticsearch
(match / multi_match)
      │
      ▼
Documents

这种就是传统全文检索。

例如:

复制代码
"如何部署docker"

↓

match:
content:"如何部署docker"

② 向量检索

ES 8.x 已支持 Dense Vector。

流程:

复制代码
Embedding

↓

query_vector

↓

KNN Search

↓

TopK Documents

Retriever 内部:

复制代码
Embedding(query)

↓

ES KNN

↓

返回 Document[]

很多 RAG 都采用:

复制代码
BM25
+
Vector Search
+
RRF

Retriever 完全可以封装这套逻辑。


2. Redis

Redis 也完全可以做 Retriever。

但这里要区分是哪种 Redis。

普通 Redis

例如:

复制代码
GET

HGET

SCAN

它本身没有真正意义上的语义检索。

如果只是:

复制代码
key -> document

那更像 KV Store,不属于典型 Retriever。


Redis Stack(RediSearch)

如果安装了:

复制代码
Redis Stack

或者:

复制代码
RediSearch

就支持:

  • 全文检索
  • Vector Search
  • Hybrid Search

例如:

复制代码
FT.SEARCH

KNN

VECTOR

那么它完全可以作为 Retriever。

流程:

复制代码
Embedding

↓

Redis Vector Index

↓

TopK

↓

Document[]

3. 在 Eino 中如何使用

Eino 不要求 Retriever 一定来自官方。

例如可以自己实现:

复制代码
ESRetriever

RedisRetriever

MilvusRetriever

PGVectorRetriever

QdrantRetriever

它们都满足:

复制代码
Retrieve()

↓

[]Document

Chain 完全不用修改。

例如:

复制代码
KnowledgeRetriever
          │
 ┌────────┴─────────┐
 │                  │
ESRetriever   MilvusRetriever
 │                  │
ES              Milvus

Agent 根本不知道底层是谁。


4. 官方是否内置了 Redis 和 ES?

截至目前,Eino 官方生态主要内置和维护的是对常见向量数据库、Embedding、LLM 等组件的适配Elasticsearch 和 Redis 并不是官方长期维护的核心 Retriever 实现,更多时候需要你自行实现适配,或者基于社区扩展来接入。

由于 Eino 的 Retriever 接口非常简单,实现一个 ESRetrieverRedisRetriever 的成本并不高,只需要把底层查询结果转换成 schema.Document 即可。


总结

检索后端 能否作为 Retriever 是否适合 RAG
Elasticsearch(BM25)
Elasticsearch(Vector)
Elasticsearch(Hybrid) ⭐⭐⭐⭐⭐
Redis(普通 KV) ⚠️ 可以封装,但不属于真正语义检索
Redis Stack / RediSearch
Milvus ⭐⭐⭐⭐⭐
Qdrant ⭐⭐⭐⭐⭐

如果你是在做企业级 RAG 或智能体项目,我更推荐采用"ES + 向量库"的双检索架构(Hybrid Retrieval):ES 负责关键词/BM25 检索,Milvus 或 Qdrant 负责语义向量检索,再通过 RRF、加权融合或重排序(Reranker)合并结果。这也是目前许多生产系统采用的方案。

也就是说,要区分抽象(Interface)**和**具体实现(Implementation)


第一层:Retriever 是抽象

Eino 中真正依赖的是 Retriever 接口,例如:

go 复制代码
type Retriever interface {
    Retrieve(ctx context.Context, query string, opts ...Option) ([]*schema.Document, error)
}

对于 Chain、Agent 来说,它们只认识:

复制代码
Retriever

并不知道下面到底是谁。

例如:

复制代码
                Retriever
                    ▲
     ┌──────────────┼──────────────┐
     │              │              │
MilvusRetriever  ESRetriever  RedisRetriever
     │              │              │
  Milvus            ES         Redis Stack

Agent 调用的永远都是

复制代码
Retrieve(...)

所以 Retriever 抽象可以对应任意数据库


第二层:MilvusRetriever 是具体实现

MilvusRetriever 的内部代码一般会直接调用 Milvus SDK,例如:

go 复制代码
client.Search(...)

它知道:

  • collection
  • vector field
  • metric type
  • topK

例如:

复制代码
User Query
      │
Embedding
      │
MilvusRetriever
      │
Milvus SDK
      │
Milvus Server

因此:

MilvusRetriever 不可能直接去查 ES。

因为:

ES 的 API 是

复制代码
POST /_search

Milvus 是

复制代码
Search()

参数完全不同。


第三层:如果数据库换了怎么办?

假设今天不用 Milvus,而换成:

  • Qdrant
  • Weaviate
  • PGVector
  • Chroma

那么应该:

复制代码
                Retriever
                    ▲
        ┌───────────┴───────────┐
        │                       │
 MilvusRetriever         QdrantRetriever
        │                       │
     Milvus                 Qdrant

只需要:

go 复制代码
type QdrantRetriever struct {
    client *qdrant.Client
}

func (r *QdrantRetriever) Retrieve(...) {
    ...
}

即可。

整个 Agent 一行代码都不用改。


为什么要这样设计?

这就是经典的依赖倒置(Dependency Inversion)

例如:

以前:

复制代码
Agent
  │
  ▼
Milvus

Agent 被绑死了。

现在:

复制代码
Agent
  │
  ▼
Retriever
  │
  ├── Milvus
  ├── ES
  ├── Redis
  ├── PGVector
  └── Qdrant

Agent 根本不知道下面是谁。

以后替换数据库:

复制代码
Milvus
↓

Qdrant

Agent 完全不用改。


Eino 为什么要这样抽象?

因为一个 Retriever 并不一定对应一个数据库,它甚至可以组合多个数据源。

例如:

复制代码
HybridRetriever
      │
 ┌────┴────┐
 │         │
ES      Milvus
 │         │
BM25   Vector Search
 └────┬────┘
      ▼
 Rank Fusion
      ▼
 Documents

对于 Agent 来说,它依然只是:

go 复制代码
docs, err := retriever.Retrieve(ctx, query)

它不知道内部实际上调用了:

  • ES
  • Milvus
  • Reranker

甚至可以再加:

  • Redis Cache
  • Knowledge Graph
  • MySQL

都可以。


一句话总结

  • Retriever:Eino 定义的抽象接口,可以适配任意检索后端(Milvus、Qdrant、ES、Redis Stack、PGVector 等)。
  • MilvusRetrieverRetriever 的一个具体实现,只负责调用 Milvus,因此不能直接用于其他向量数据库。
  • 如果更换向量数据库,应实现对应的 QdrantRetrieverPGVectorRetriever 等,只要都实现 Retriever 接口,Agent 和 Chain 无需修改。

这也是 Eino 将组件分为 Loader → Transformer → Indexer → Retriever → Reranker 的核心思想:上层依赖统一抽象,下层可以自由替换具体实现。

相关推荐
updayday8547 小时前
离职域账号状态变更与Ping64操作记录核对
大数据·网络·数据库·安全·智能路由器
baopixiaoz7 小时前
BeeQuant × BeeAgent:用AI加速策略验证
大数据·人工智能·python·区块链
咸鱼老弟7 小时前
AI Agent 的"自主性悖论"——为什么给它的自由度越大,越要配一套更硬的护栏
前端·人工智能
tq10867 小时前
对字节AI战略的评价
人工智能
Nturmoils7 小时前
只恢复一张表,别把整个库都还回去
数据库
张某布响丸辣7 小时前
附件下载的安全边界:路径白名单、NAS 哨兵文件与 Redis Lua 一次性令牌
java·redis·redis lua·nas哨兵
专职八阿哥8 小时前
GPT-6 Astar 是什么?从模型名称、A*算法到实际接入讲清楚
人工智能
龙腾AI白云8 小时前
大语言模型:从语言理解到通用智能的跃迁
数据库·人工智能·机器学习·知识图谱
EatFans8 小时前
AI Agent 为什么总是失忆?一篇讲透 Agent Memory
人工智能
sijiaoh8 小时前
用 Jev 写了个按意思搜的 grep
人工智能