微信扫码
添加专属顾问
我要投稿
掌握Golang和Redis,构建高效的文档向量索引与检索系统。 核心内容: 1. 使用Redis实现文档向量检索,构建RAG知识库 2. Eino框架介绍与大语言模型结合的技术栈 3. 系统架构详解与项目运行测试指南
大家好,这里是白泽。这篇文章将讲解如何使用 Redis 的向量检索与 LLM 构建一个 RAG 知识库,知识库存储内容是 Eino 框架的介绍。每次尝试从 Redis 向量索引中获取 top k 条相关信息,并使用 LLM 进行总结回复;当没有相关知识,则提示未查找到文档,限制大模型自由发挥。
使用到的技术栈如下:
语言:go1.22
工作流框架:Eino(字节开源的大模型工作流开发框架)
向量存储与检索:Redis
大语言模型:doubao-pro-32k-241215
向量化模型:doubao-embedding-large-text-240915
?项目已经开源,地址如下:https://github.com/BaiZe1998/go-learning
这里说明一下,当前案例中,索引构建阶段的代码取自:https://github.com/cloudwego/eino-examples
系统架构回答生成阶段查询检索阶段索引构建阶段Markdown文件文件加载器文档分割器嵌入模型文档向量Redis向量数据库用户问题嵌入模型查询向量KNN向量搜索TopK相关文档提示构建增强提示大语言模型生成回答检索器\nRetrieverRAG系统生成器\nGenerator参数配置\ntopK等
cd eino_assistant
docker-compose up -d
# 通过这种方式启动的 redis 内置了一部分已经完成向量化的 Eino 文档数据
# 在知识库构建阶段,需要使用到文档向量化的模型
# 在检索增强阶段,需要使用语言大模型进行总结回复
cd eino_assistant
source .env
# 使用 redis 作为文档数据库,同时每次检索3条
go run eino/rag/cmd/main.go --redis=true --topk=3
问题> Agent 是什么
===== 检索到 3 个相关文档 =====
文档[1] 相似度: 0.7705 标题: 无标题
----------------------------------------
## **Agent 是什么**
Agent(智能代理)是一个能够感知环境并采取行动以实现特定目标的系统。在 AI 应用中,Agent 通过结合大语言模型的理解能力和预定义工具的执行能力,可以自主地完成复杂的任务。是未来 AI 应用到生活生产中...
文档[2] 相似度: 0.7606 标题: 无标题
----------------------------------------
## **总结**
介绍了使用 Eino 框架构建 Agent 的基本方法。通过 Chain、Tool Calling 和 ReAct 等不同方式,我们可以根据实际需求灵活地构建 AI Agent。
Agent 是 AI 技术发展的重要方向。它不仅能够理解用户意图,还能主动采取行动,通过�...
文档[3] 相似度: 0.7603 标题: 无标题
----------------------------------------
## **Agent 是什么**
Agent(智能代理)是一个能够感知环境并采取行动以实现特定目标的系统。在 AI 应用中,Agent 通过结合大语言模型的理解能力和预定义工具的执行能力,可以自主地完成复杂的任务。是未来 AI 应用到生活生产中...
==============================
回答:
Agent(智能代理)是一个能够感知环境并采取行动以实现特定目标的系统。在 AI 应用中,Agent 通过结合大语言模型的理解能力和预定义工具的执行能力,可以自主地完成复杂的任务。是未来 AI 应用到生活生产中主要的形态。
本文中示例的代码片段详见:[eino-examples/quickstart/taskagent](https://github.com/cloudwego/eino-examples/blob/master/quickstart/taskagent/main.go)
问题> 什么是大数据
===== 检索到 3 个相关文档 =====
文档[1] 相似度: 0.7647 标题: 无标题
----------------------------------------
---
Description: ""
date: "2025-01-07"
lastmod: ""
tags: []
title: Tool
weight: 0
---
文档[2] 相似度: 0.7488 标题: 无标题
----------------------------------------
---
Description: ""
date: "2025-01-06"
lastmod: ""
tags: []
title: Document
weight: 0
---
文档[3] 相似度: 0.7419 标题: 无标题
----------------------------------------
---
Description: ""
date: "2025-01-06"
lastmod: ""
tags: []
title: Embedding
weight: 0
---
==============================
回答:
很抱歉,我不知道什么是大数据,文档中没有提供相关信息。
# 在 cmd/knowledgeindexing 目录下新建一个 big_data.md 文档,内容如下:
# 大数据
大数据(Big Data)是指规模庞大、结构复杂且无法通过传统数据处理工具在合理时间内进行有效捕捉、管理和处理的数据集合。其核心价值在于通过专业化分析挖掘数据中蕴含的信息,从而提升决策力、优化流程并创造新价值。
yucong@yucongdeMacBook-Air eino_assistant % cd cmd/knowledgeindexing
yucong@yucongdeMacBook-Air knowledgeindexing % go run ./
[start] indexing file: eino-docs/_index.md
[done] indexing file: eino-docs/_index.md, len of parts: 4
[start] indexing file: eino-docs/agent_llm_with_tools.md
[done] indexing file: eino-docs/agent_llm_with_tools.md, len of parts: 1
[start] indexing file: eino-docs/big_data.md
[done] indexing file: eino-docs/big_data.md, len of parts: 1 # 可以看到被切分了
index success
问题> 什么是大数据
===== 检索到 3 个相关文档 =====
文档[1] 相似度: 0.8913 标题: 大数据
----------------------------------------
# 大数据
大数据(Big Data)是指规模庞大、结构复杂且无法通过传统数据处理工具在合理时间内进行有效捕捉、管理和处理的数据集合。其核心价值在于通过专业化分析挖掘数据中蕴含的信息,从而提升决策力、优化流程并创造�...
文档[2] 相似度: 0.7647 标题: 无标题
----------------------------------------
---
Description: ""
date: "2025-01-07"
lastmod: ""
tags: []
title: Tool
weight: 0
---
文档[3] 相似度: 0.7488 标题: 无标题
----------------------------------------
---
Description: ""
date: "2025-01-06"
lastmod: ""
tags: []
title: Document
weight: 0
---
==============================
回答:
大数据(Big Data)是指规模庞大、结构复杂且无法通过传统数据处理工具在合理时间内进行有效捕捉、管理和处理的数据集合。其核心价值在于通过专业化分析挖掘数据中蕴含的信息,从而提升决策力、优化流程并创造新价值。
这一部分参见:eino_assistant/eino/knowledgeindexing 目录代码
流程图:
索引的构建阶段,本质也是一个工作流,因此可以通过 Goland 的 Eino Dev 插件进行可视化绘制,完成之后点击生成流程框架代码,然后填充一些业务实现即可:
参见:eino_assistant/eino/rag/retriver.go
// Retrieve 检索与查询最相关的文档
func (r *RedisRetriever) Retrieve(ctx context.Context, query string, topK int) ([]*schema.Document, error) {
// 生成查询向量
queryVectors, err := r.embedder.EmbedStrings(ctx, []string{query})
if err != nil {
returnnil, fmt.Errorf("生成查询向量失败: %w", err)
}
iflen(queryVectors) == 0 || len(queryVectors[0]) == 0 {
returnnil, fmt.Errorf("嵌入模型返回空向量")
}
queryVector := queryVectors[0]
// 构建向量搜索查询
searchQuery := fmt.Sprintf("(*)=>[KNN %d @%s $query_vector AS %s]",
topK,
redispkg.VectorField,
redispkg.DistanceField)
// 执行向量搜索
res, err := r.client.Do(ctx,
"FT.SEARCH", r.indexName, // 执行搜索的索引名称
searchQuery, // 向量搜索查询语句
"PARAMS", "2", // 参数声明,后面有2个参数
"query_vector", vectorToBytes(queryVector), // 查询向量的二进制表示
"DIALECT", "2", // 查询方言版本
"SORTBY", redispkg.DistanceField, // 结果排序字段
"RETURN", "3", redispkg.ContentField, redispkg.MetadataField, redispkg.DistanceField, // 返回字段
).Result()
if err != nil {
returnnil, fmt.Errorf("执行向量搜索失败: %w", err)
}
// 将Redis结果转换为Document对象
return r.parseSearchResults(res)
}
参见:eino_assistant/eino/rag/generator.go
// Generate 生成回答
func (g *ArkGenerator) Generate(ctx context.Context, query string, documents []*schema.Document) (string, error) {
// 组合上下文信息
context := ""
iflen(documents) > 0 {
contextParts := make([]string, len(documents))
for i, doc := range documents {
// 如果元数据中有标题,添加标题信息
titleInfo := ""
if title, ok := doc.MetaData["title"].(string); ok && title != "" {
titleInfo = fmt.Sprintf("标题: %s\n", title)
}
contextParts[i] = fmt.Sprintf("文档片段[%d]:\n%s%s\n", i+1, titleInfo, doc.Content)
}
context = strings.Join(contextParts, "\n---\n")
}
// 构建提示
systemPrompt := "你是一个知识助手。基于提供的文档回答用户问题。如果文档中没有相关信息,请诚实地表明你不知道,不要编造答案。"
userPrompt := query
if context != "" {
userPrompt = fmt.Sprintf("基于以下信息回答我的问题:\n\n%s\n\n问题:%s", context, query)
}
// 构建请求
messages := []chatMessage{
{Role: "system", Content: systemPrompt},
{Role: "user", Content: userPrompt},
}
reqBody := chatRequest{
Model: g.modelName,
Messages: messages,
}
// 序列化请求体
jsonData, err := json.Marshal(reqBody)
if err != nil {
return"", fmt.Errorf("序列化请求失败: %w", err)
}
// 创建HTTP请求
endpoint := fmt.Sprintf("%s/chat/completions", g.baseURL)
req, err := http.NewRequestWithContext(ctx, "POST", endpoint, bytes.NewBuffer(jsonData))
if err != nil {
return"", fmt.Errorf("创建HTTP请求失败: %w", err)
}
// 添加头信息
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", g.apiKey))
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return"", fmt.Errorf("发送请求失败: %w", err)
}
defer resp.Body.Close()
// 读取响应
body, err := io.ReadAll(resp.Body)
if err != nil {
return"", fmt.Errorf("读取响应失败: %w", err)
}
// 检查响应状态
if resp.StatusCode != http.StatusOK {
return"", fmt.Errorf("API返回错误: %s, 状态码: %d", string(body), resp.StatusCode)
}
// 解析响应
var chatResp chatResponse
if err := json.Unmarshal(body, &chatResp); err != nil {
return"", fmt.Errorf("解析响应失败: %w", err)
}
// 提取回答
iflen(chatResp.Choices) > 0 {
return chatResp.Choices[0].Message.Content, nil
}
return"", fmt.Errorf("API没有返回有效回答")
}
func main() {
// 定义命令行参数
useRedis := flag.Bool("redis", true, "是否使用Redis进行检索增强")
topK := flag.Int("topk", 3, "检索的文档数量")
flag.Parse()
// 检查环境变量
env.MustHasEnvs("ARK_API_KEY")
// 构建RAG系统
ctx := context.Background()
ragSystem, err := rag.BuildRAG(ctx, *useRedis, *topK)
if err != nil {
fmt.Fprintf(os.Stderr, "构建RAG系统失败: %v\n", err)
os.Exit(1)
}
// 显示启动信息
if *useRedis {
fmt.Println("启动RAG系统 (使用Redis检索)")
} else {
fmt.Println("启动RAG系统 (不使用检索)")
}
fmt.Println("输入问题或输入'exit'退出")
// 创建输入扫描器
scanner := bufio.NewScanner(os.Stdin)
// 主循环
for {
fmt.Print("\n问题> ")
// 读取用户输入
if !scanner.Scan() {
break
}
input := strings.TrimSpace(scanner.Text())
if input == "" {
continue
}
// 检查退出命令
if strings.ToLower(input) == "exit" {
break
}
// 处理问题
answer, err := ragSystem.Answer(ctx, input)
if err != nil {
fmt.Fprintf(os.Stderr, "处理问题时出错: %v\n", err)
continue
}
// 显示回答
fmt.Println("\n回答:")
fmt.Println(answer)
}
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "读取输入时出错: %v\n", err)
}
fmt.Println("再见!")
}
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2025-05-07
精|RAG与推理协同全面综述:背景、目的、模式、实现、评估、实践、趋势
2025-05-07
图像也能通过 RAG 加入知识库啦
2025-05-07
RAGflow分片策略与文档解析器
2025-05-07
从RAG到QA-RAG:整合生成式AI以用于药品监管合规流程
2025-05-07
RAG 中的语义分块:实现更优的上下文检索
2025-05-07
从复杂文档到AI秒懂的高质量数据:EasyDoc解析实战指南
2025-05-07
使用Ragas自动化评测RAG知识问答系统的各项表现
2025-05-07
Social RAG群助手AI , Matrix虚拟社交网络AI评论点赞
2024-10-27
2024-09-04
2024-05-05
2024-07-18
2024-06-20
2024-06-13
2024-07-09
2024-07-09
2024-05-19
2024-07-07
2025-05-05
2025-04-30
2025-04-29
2025-04-29
2025-04-26
2025-04-25
2025-04-22
2025-04-22