📷 [图片 token=CB09bMdC5oFLi6xqxnucL7Xinmf(未能下载,见飞书原文)]
📷 [图片 token=NuHhbFYeuoW8PExUYK9ctiNRnN2(未能下载,见飞书原文)]
注意,运行程序之前请先看:
[环境准备教程](/oncall/智能 OnCall Agent 项目/第八章 _ 实战演练与运行项目/环境准备教程/)
[运行项目教程](/oncall/智能 OnCall Agent 项目/第八章 _ 实战演练与运行项目/运行项目教程(Go)/)
前言
上一节我们实现了知识库Agent的上半部分,这一节我们来实现知识库的召回功能。
核心代码:SuperBizAgent/internal/ai/cmd/recall_cmd/main.go
📷 [图片 token=NQ6zblccCoZOQOxomXkc6H2bnbg(未能下载,见飞书原文)]
实战
观察代码,首先创建retriever组件,然后调用它的Retrieve方法进行查询,最后打印召回的内容。
我们直接先运行代码,来看看执行后的效果。
func main() {
ctx := context.Background()
r, err := retriever2.NewMilvusRetriever(ctx)
if err != nil {
panic(err)
}
query := "服务下线是什么原因"
docs, err := r.Retrieve(ctx, query)
if err != nil {
panic(err)
}
fmt.Println("Q:", query)
for _, doc := range docs {
fmt.Println("A:", doc.Content)
}
}
代码路径:SuperBizAgent/internal/ai/cmd/recall_cmd/main.go
通过输出可以看到,确实召回了我们上一节上传的文件内容。下面我们就来看看核心组件Retrieve到底做了什么。
(base) ➜ recall_cmd git:(main) ✗ go run main.go
Q: 服务下线是什么原因
A: # 服务下线
告警解释:服务下线可能因为服务panic,导致pod重启造成的
解决方案:
1. 根据关键字"panic"进行最近1小时的日志搜索
2. 根据panic日志内容分析是什么bug导致的panic
召回-Retriever组件
我们之前是将文档存储到了Milvus向量数据库里面,所以召回的时候也是从这个数据库去查询。
首先我们对Milvus客户端进行一些配置,指定向量字段为vector,需要返回的字段有id、content、metadata。
func NewMilvusRetriever(ctx context.Context) (rtr retriever.Retriever, err error) {
r, err := milvus.NewRetriever(ctx, &milvus.RetrieverConfig{
Client: client.NewMilvusClient(ctx),
Collection: common.MilvusCollectionName,
VectorField: "vector",
OutputFields: []string{
"id",
"content",
"metadata",
},
TopK: 10,
Embedding: embedder.DoubaoEmbedding(ctx),
})
if err != nil {
return nil, err
}
return r, nil
}
在Eino框架里面,Retriever组件是用来实现召回的,所以我们来看看Retriever这个接口。可以看到返回值是一个Retriever接口,需要实现这个接口的Retrieve方法:
对输入的问题进行向量化,计算出向量
调用Milvus数据库sdk的相似度查询接口
构造返回结构体,返回
func (r *Retriever) Retrieve(ctx context.Context, query string, opts ...retriever.Option) (docs []*schema.Document, err error) {
// 1. 首先对输入的问题进行向量化
// embedding the query
vectors, err := emb.EmbedStrings(r.makeEmbeddingCtx(ctx, emb), []string{query})
// 2. 调用Milvus的相似度查询接口
results, err = r.config.Client.Search(
r.config.OutputFields,
// 查询的向量
vectors,
// 向量字段
r.config.VectorField,
// 查询相似度前多少个
*co.TopK,
)
// convert the search result to schema.Document
documents := make([]*schema.Document, 0, len(results))
for _, result := range results {
// 3. 构造结构体
document, err := r.config.DocumentConverter(ctx, result)
documents = append(documents, document...)
}
// 4. 返回
return documents, nil
}
type Retriever interface {
Retrieve(ctx context.Context, query string, opts ...Option) ([]*schema.Document, error)
}
总结:对问题先进行向量化,然后根据向量,调用数据库的向量查询接口进行查询。
总结
至此,RAG的分片、索引、召回功能我们都实现完了。后续会介绍其他Agent是怎么使用知识库,怎么结合召回来与大模型进行交互的。