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 的核心思想:上层依赖统一抽象,下层可以自由替换具体实现。

相关推荐
A8ai_napiai1 小时前
Claude内部发现“J空间“:AI可解释性从“黑箱猜测“到“结构验证“
人工智能
xywww1681 小时前
AWS 账号权限怎么分:根用户和 IAM 用户区别及日常使用建议
大数据·开发语言·人工智能·python·gpt·云计算·aws
一键生成网站1 小时前
AI原型工具企业需求分析:私有化部署与安全协作选购指南
人工智能·安全·需求分析·
俞凡1 小时前
基于 Qwen 打造低幻觉千万级文档 RAG 流水线
人工智能
G.O.G.O.G1 小时前
《LeetCode SQL 从入门到进阶(MySQL)》06(下)
数据库·sql·oracle
AI的探索之旅1 小时前
飞书里跟 AI 聊天,让 Hermes + LCEDA Pro 结合本地llmwiki理解电路
人工智能·飞书
极客笔记Jack1 小时前
企业级RAG知识库架构设计:从文档处理到检索优化的完整方案
人工智能
Larcher2 小时前
MCP协议实战:让AI Agent跨进程调用工具的正确姿势
人工智能·后端
清禾无为2 小时前
电商投放做投流素材,易元 AI 和剪映 AI 哪个更适合批量合规翻拍视频?
人工智能