---
Description: ""
date: "2026-01-30"
lastmod: ""
tags: []
title: Retriever 使用说明
weight: 6
---

## **基本介绍**

Retriever 组件是一个用于从各种数据源检索文档的组件。它的主要作用是根据用户的查询（query）从文档库中检索出最相关的文档。这个组件在以下场景中特别有用：

- 基于向量相似度的文档检索
- 基于关键词的文档搜索
- 知识库问答系统 (rag)

## **组件定义**

### **接口定义**

> 代码位置：eino/components/retriever/interface.go

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

#### **Retrieve 方法**

- 功能：根据查询检索相关文档
- 参数：
  - ctx：上下文对象，用于传递请求级别的信息，同时也用于传递 Callback Manager
  - query：查询字符串
  - opts：检索选项，用于配置检索行为
- 返回值：
  - `[]*schema.Document`：检索到的文档列表
  - error：检索过程中的错误信息

### **Document 结构体**

```go
type Document struct {
    // ID 是文档的唯一标识符
    ID string
    // Content 是文档的内容
    Content string
    // MetaData 用于存储文档的元数据信息
    MetaData map[string]any
}
```

### **公共 Option**

Retriever 组件使用 RetrieverOption 来定义可选参数， 以下是 Retriever 组件需要实现的公共 option。另外，每个具体的实现可以定义自己的特定 Option，通过 WrapRetrieverImplSpecificOptFn 函数包装成统一的 RetrieverOption 类型。

```go
type Options struct {
    // Index 是检索器使用的索引，不同检索器中的索引可能有不同含义
    Index *string
    
    // SubIndex 是检索器使用的子索引，不同检索器中的子索引可能有不同含义
    SubIndex *string
    
    // TopK 是检索的文档数量上限
    TopK *int
    
    // ScoreThreshold 是文档相似度的阈值，例如 0.5 表示文档的相似度分数必须大于 0.5
    ScoreThreshold *float64
    
    // Embedding 是用于生成查询向量的组件
    Embedding embedding.Embedder
    
    // DSLInfo 是用于检索的 DSL 信息，仅在 viking 类型的检索器中使用
    DSLInfo map[string]interface{}
}
```

可以通过以下方式设置选项：

```go
// 设置索引
WithIndex(index string) Option

// 设置子索引
WithSubIndex(subIndex string) Option

// 设置检索文档数量上限
WithTopK(topK int) Option

// 设置相似度阈值
WithScoreThreshold(threshold float64) Option

// 设置向量生成组件
WithEmbedding(emb embedding.Embedder) Option

// 设置 DSL 信息（仅用于 viking 类型检索器）
WithDSLInfo(dsl map[string]any) Option
```

## **使用方式**

### **单独使用**

#### VikingDB 示例

> 代码位置：eino-ext/components/retriever/volc_vikingdb/examples/builtin_embedding

```go
import (
    "github.com/cloudwego/eino/components/retriever"
    "github.com/cloudwego/eino/compose"
    "github.com/cloudwego/eino/schema"

    "github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb"
)

collectionName := "eino_test"
indexName := "test_index_1"

/*
 * 下面示例中提前构建了一个名为 eino_test 的数据集 (collection)，并在此数据集上构建了一个名为 test_index_1 的 hnsw-hybrid 索引 (index)
 * 数据集字段配置为:
 * 字段名称       字段类型         向量维度
 * ID            string
 * vector         vector       1024
 * sparse_vector    sparse_vector
 * content        string
 * extra_field_1    string
 *
 * component 使用时注意:
 * 1. ID / vector / sparse_vector / content 的字段名称与类型与上方配置一致
 * 2. vector 向量维度需要与 ModelName 对应的模型所输出的向量维度一致
 * 3. 部分模型不输出稀疏向量，此时 UseSparse 需要设置为 false，collection 可以不设置 sparse_vector 字段
 */

cfg := &volc_vikingdb.RetrieverConfig{
    // https://api-vikingdb.volces.com （华北）
    // https://api-vikingdb.mlp.cn-shanghai.volces.com（华东）
    // https://api-vikingdb.mlp.ap-mya.byteplus.com（海外-柔佛）
    Host:              "api-vikingdb.volces.com",
    Region:            "cn-beijing",
    AK:                ak,
    SK:                sk,
    Scheme:            "https",
    ConnectionTimeout: 0,
    Collection:        collectionName,
    Index:             indexName,
    EmbeddingConfig: volc_vikingdb.EmbeddingConfig{
       UseBuiltin:  true,
       ModelName:   "bge-m3",
       UseSparse:   true,
       DenseWeight: 0.4,
    },
    Partition:      "", // 对应索引中的【子索引划分字段】, 未设置时至空即可
    TopK:           of(10),
    ScoreThreshold: of(0.1),
    FilterDSL:      nil, // 对应索引中的【标量过滤字段】，未设置时至空即可，表达式详见 https://www.volcengine.com/docs/84313/1254609
}

volcRetriever, _ := volc_vikingdb.NewRetriever(ctx, cfg)


query := "tourist attraction"
docs, _ := volcRetriever.Retrieve(ctx, query)

log.Printf("vikingDB retrieve success, query=%v, docs=%v", query, docs)
```

#### Milvus 示例

```go
import (
        "github.com/cloudwego/eino-ext/components/retriever/milvus2"
        "github.com/cloudwego/eino-ext/components/retriever/milvus2/search_mode"
)

// 创建 retriever
retriever, err := milvus2.NewRetriever(ctx, &milvus2.RetrieverConfig{
        ClientConfig: &milvusclient.ClientConfig{
                Address:  addr,
                Username: username,
                Password: password,
        },
        Collection: "my_collection",
        TopK:       10,
        SearchMode: search_mode.NewApproximate(milvus2.COSINE),
        Embedding:  emb,
})

// 检索文档
documents, err := retriever.Retrieve(ctx, "search query")
```

#### ElasticSearch 7 示例

```go
import (
        "github.com/cloudwego/eino/schema"
        elasticsearch "github.com/elastic/go-elasticsearch/v7"

        "github.com/cloudwego/eino-ext/components/retriever/es7"
        "github.com/cloudwego/eino-ext/components/retriever/es7/search_mode"
)

client, _ := elasticsearch.NewClient(elasticsearch.Config{
        Addresses: []string{"http://localhost:9200"},
        Username:  username,
        Password:  password,
})

// 创建带有稠密向量相似度搜索的检索器
retriever, _ := es7.NewRetriever(ctx, &es7.RetrieverConfig{
        Client:     client,
        Index:      "my_index",
        TopK:       10,
        SearchMode: search_mode.DenseVectorSimilarity(search_mode.DenseVectorSimilarityTypeCosineSimilarity, "content_vector"),
        Embedding:  emb,
})

// 检索文档
docs, _ := retriever.Retrieve(ctx, "search query")
```

#### OpenSearch 2 示例

```go
package main

import (
        "github.com/cloudwego/eino/schema"
        opensearch "github.com/opensearch-project/opensearch-go/v2"

        "github.com/cloudwego/eino-ext/components/retriever/opensearch2"
        "github.com/cloudwego/eino-ext/components/retriever/opensearch2/search_mode"
)

client, err := opensearch.NewClient(opensearch.Config{
        Addresses: []string{"http://localhost:9200"},
})

// 创建检索器组件
retriever, _ := opensearch2.NewRetriever(ctx, &opensearch2.RetrieverConfig{
        Client: client,
        Index:  "your_index_name",
        TopK:   5,
        // 选择搜索模式
        SearchMode: search_mode.Approximate(&search_mode.ApproximateConfig{
                VectorField: "content_vector",
                K:           5,
        }),
        ResultParser: func(ctx context.Context, hit map[string]interface{}) (*schema.Document, error) {
                // 解析 hit map 为 Document
                id, _ := hit["_id"].(string)
                source := hit["_source"].(map[string]interface{})
                content, _ := source["content"].(string)
                return &schema.Document{ID: id, Content: content}, nil
        },
        Embedding: emb,
})

// 检索文档
docs, err := retriever.Retrieve(ctx, "search query")
```

### **在编排中使用**

```go
// 在 Chain 中使用
chain := compose.NewChain[string, []*schema.Document]()
chain.AppendRetriever(retriever)

// 在 Graph 中使用
graph := compose.NewGraph[string, []*schema.Document]()
graph.AddRetrieverNode("retriever_node", retriever)
```

## **Option 和 Callback 使用**

### **Callback 使用示例**

> 代码位置：eino-ext/components/retriever/volc_vikingdb/examples/builtin_embedding

```go
import (
    "github.com/cloudwego/eino/callbacks"
    "github.com/cloudwego/eino/components/retriever"
    "github.com/cloudwego/eino/compose"
    "github.com/cloudwego/eino/schema"
    callbacksHelper "github.com/cloudwego/eino/utils/callbacks"
    "github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb"
)

// 创建 callback handler
handler := &callbacksHelper.RetrieverCallbackHandler{
    OnStart: func(ctx context.Context, info *callbacks.RunInfo, input *retriever.CallbackInput) context.Context {
       log.Printf("input access, content: %s\n", input.Query)
       return ctx
    },
    OnEnd: func(ctx context.Context, info *callbacks.RunInfo, output *retriever.CallbackOutput) context.Context {
       log.Printf("output finished, len: %v\n", len(output.Docs))
       return ctx
    },
    // OnError
}

// 使用 callback handler
helper := callbacksHelper.NewHandlerHelper().
    Retriever(handler).
    Handler()

chain := compose.NewChain[string, []*schema.Document]()
chain.AppendRetriever(volcRetriever)

// 在运行时使用
run, _ := chain.Compile(ctx)

outDocs, _ := run.Invoke(ctx, query, compose.WithCallbacks(helper))

log.Printf("vikingDB retrieve success, query=%v, docs=%v", query, outDocs)
```

## **已有实现**

- Volc VikingDB Retriever: 基于火山引擎 VikingDB 的检索实现 [Retriever - VikingDB](/zh/docs/eino/ecosystem_integration/retriever/retriever_volc_vikingdb)
- Milvus v2.5+ Retriever: 基于 Milvus 实现的向量数据库检索器 [Retriever - Milvus 2 (v2.5+) ](/zh/docs/eino/ecosystem_integration/retriever/retriever_milvusv2)
- Milvus v2.4- Retriever: 基于 Milvus 实现的向量数据库检索器 [Retriever - Milvus (v2.4-)](/zh/docs/eino/ecosystem_integration/retriever/retriever_milvus)
- Elasticsearch 8 Retriever: 基于 ES8 实现的通用搜索引擎检索器 [Retriever - Elasticsearch 8](/zh/docs/eino/ecosystem_integration/retriever/retriever_es8)
- ElasticSearch 7 Retriever: 基于 ES7 实现的通用搜索引擎检索器 [Retriever - Elasticsearch 7](/zh/docs/eino/ecosystem_integration/retriever/retriever_elasticsearch7)
- OpenSearch 3 Retriever: 基于 OpenSearch 3 实现的通用搜索引擎检索器 [Retriever - OpenSearch 3](/zh/docs/eino/ecosystem_integration/retriever/retriever_opensearch3)
- OpenSearch 2 Retriever: 基于 OpenSearch 2 实现的通用搜索引擎检索器 [Retriever - OpenSearch 2](/zh/docs/eino/ecosystem_integration/retriever/retriever_opensearch2)

## **自行实现参考**

实现自定义的 Retriever 组件时，需要注意以下几点：

1. 注意 option 机制的处理，及处理公共的 option.
2. 注意处理 callback
3. 注意需要注入特定的 metadata，以便后续节点使用

### **option 机制**

Retriever 组件提供了一组公共选项，实现时需要正确处理这些选项：

```go
// 使用 GetCommonOptions 处理公共 option
func (r *MyRetriever) Retrieve(ctx context.Context, query string, opts ...retriever.Option) ([]*schema.Document, error) {
    // 1. 初始化及读取 option
    options := &retriever.Options{ // 可设置default值
        Index: &r.index,
        TopK: &r.topK,
        Embedding: r.embedder,
    }
    options = retriever.GetCommonOptions(options, opts...)
    
    // ...
}
```

### **Callback 处理**

Retriever 实现需要在适当的时机触发回调，以下结构体是 retriever 组件定义好的结构：

```go
// 定义回调输入输出
type CallbackInput struct {
    Query string
    TopK int
    Filter string
    ScoreThreshold *float64
    Extra map[string]any
}

type CallbackOutput struct {
    Docs []*schema.Document
    Extra map[string]any
}
```

### **完整实现示例**

```go
type MyRetriever struct {
    embedder embedding.Embedder
    index string
    topK int
}

func NewMyRetriever(config *MyRetrieverConfig) (*MyRetriever, error) {
    return &MyRetriever{
        embedder: config.Embedder,
        index: config.Index,
        topK: config.DefaultTopK,
    }, nil
}

func (r *MyRetriever) Retrieve(ctx context.Context, query string, opts ...retriever.Option) ([]*schema.Document, error) {
    // 1. 处理选项
    options := &retriever.Options{
        Index: &r.index,
        TopK: &r.topK,
        Embedding: r.embedder,
    }
    options = retriever.GetCommonOptions(options, opts...)
    
    // 2. 获取 callback manager
    cm := callbacks.ManagerFromContext(ctx)
    
    // 3. 开始检索前的回调
    ctx = cm.OnStart(ctx, info, &retriever.CallbackInput{
        Query: query,
        TopK: *options.TopK,
    })
    
    // 4. 执行检索逻辑
    docs, err := r.doRetrieve(ctx, query, options)
    
    // 5. 处理错误和完成回调
    if err != nil {
        ctx = cm.OnError(ctx, info, err)
        return nil, err
    }
    
    ctx = cm.OnEnd(ctx, info, &retriever.CallbackOutput{
        Docs: docs,
    })
    
    return docs, nil
}

func (r *MyRetriever) doRetrieve(ctx context.Context, query string, opts *retriever.Options) ([]*schema.Document, error) {
    // 1. 如果设置了 Embedding，生成查询的向量表示 (注意公共option的逻辑处理)
    var queryVector []float64
    if opts.Embedding != nil {
        vectors, err := opts.Embedding.EmbedStrings(ctx, []string{query})
        if err != nil {
            return nil, err
        }
        queryVector = vectors[0]
    }
    
    // 2. 其他逻辑
    return docs, nil
}
```
