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 接口非常简单,实现一个 ESRetriever 或 RedisRetriever 的成本并不高,只需要把底层查询结果转换成 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 等)。
  • MilvusRetriever :Retriever 的一个具体实现,只负责调用 Milvus,因此不能直接用于其他向量数据库。
  • 如果更换向量数据库,应实现对应的 QdrantRetriever、PGVectorRetriever 等,只要都实现 Retriever 接口,Agent 和 Chain 无需修改。

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

相关推荐
信可维6 分钟前
AI 说「改完了」怎么确认真改完了:git diff + 测试 + 一张验收表的 3 步复核
人工智能·git
CoderIsArt9 分钟前
消除喷头残余振荡方案
人工智能·喷墨打印
范中勤11 分钟前
LLM 动态加载与多用户缓存架构技术文档
redis·langchain·llm·缓存架构·多用户隔离
镜象科技12 分钟前
AI情感陪伴大模型是什么?孤独时代的科技解法与它的专业底线
人工智能
吴佳浩 Alben13 分钟前
单卡5090跑125B 大模型:从安装、验证到基准测试的完整操作教程
人工智能
马剑威(威哥爱编程)14 分钟前
【AI全栈后端12-11】Spring Boot 把 AI 接口真正上线扛量:限流 / 降级 / 可观测
人工智能·spring boot·后端
数智顾问21 分钟前
(172页PPT)某大型集团数字化转型采购供应链及财务管控业务流程蓝图规划方案(附下载方式)
大数据·人工智能
做个有深度的老李24 分钟前
中小机加工车间协作机器人落地难点|从集成交付能力角度选型
大数据·人工智能·机器人·自动化·柔性机器人
行业研究员28 分钟前
Agent Memory降低Token消耗原理解析
数据库·人工智能·oracle·腾讯云·智能体
LONGZETECH29 分钟前
新能源技术实训难题破解:纯电动汽车五大核心系统三维仿真解决方案
大数据·c语言·人工智能·安全·汽车