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

相关推荐
没有气的汽水5 小时前
一次生产 Redis 内存打满的排查、清理和复盘
redis
Ai-_Man5 小时前
Coze扣子还是不可以导出左侧所有对话,只能点进去单条内容导出,方法不对吗?
开发语言·人工智能·ai·小程序·1024程序员节
时间售卖铺6 小时前
Oracle DQL精髓:从基础到高级实战
运维·数据库·云原生·oracle
机器学习之心6 小时前
基于贝叶斯物理信息神经网络的矿产预测与不确定性量化,MATLAB代码及复现报告
人工智能·神经网络·matlab·贝叶斯物理信息神经网络
weixin_449229386 小时前
Skill应用11:详细设计自动生成|强制“文字先行”,杜绝AI只堆代码不讲设计
人工智能·agent·架构设计·详细设计·trae·skill应用
AiNightVision6 小时前
电力巡检夜视方案选型指南——无人机/机器人/固定监测三种场景怎么选
人工智能·科技·车载系统·机器人·无人机·边缘计算·视频
涛声依旧-底层原理研究所6 小时前
拆解 AI Agent 的四个内核:Loop、Tools、Memory 与 Harness
人工智能·架构
m0_639906946 小时前
MySQL 锁机制详解|表锁、行锁、意向锁,死锁成因与解决方案
数据库·mysql
田里的水稻6 小时前
FA_CNN卷积神经网络十八---感知机到多层感知机PyTorch
人工智能·pytorch·python
进击的荆棘6 小时前
MySQL——在ubuntu环境下安装MySQL
数据库·mysql·ubuntu