当前位置: 首页 > news >正文

datawhale RAG技术全栈指南 202509 第3次作业

目录

Task03:索引构建(第三章)

第一节 向量嵌入vector embedding

给AI装上一副“语义眼镜”:走进向量嵌入的神奇世界

一、Embedding是什么?AI的“语义翻译官”

二、Embedding如何助力RAG?扮演“最强大脑图书管理员”

三、Embedding技术的进化之旅:从“死记硬背”到“融会贯通”

四、如何为你的AI项目挑选“最佳翻译官”?

总结

第二节 多模态嵌入(Multimodal Embedding)

打破模态墙:当AI学会“融会贯通”

一、为什么要“多模态”?打破信息的“巴别塔”

二、CLIP模型:图文理解的“跨界大师”

三、新一代多模态模型:更强大、更全面(以BGE-M3为例)

代码示例

1 环境准备

手动下载方案(推荐)

作业1:

🔍 结果详细分析

第三节 向量数据库

向量数据库:AI的“超级记忆宫殿”

一、为什么需要它?从“小书柜”到“国家图书馆”的挑战

二、它如何工作?建造宫殿的“智能地图”

三、主流产品介绍:不同特色的“记忆宫殿”

作业2:

第四节 Milvus介绍及多模态检索实践

认识Milvus:AI时代的“超级图书馆管理员”

一、快速体验:用Docker一键启动你的“迷你图书馆”

二、核心概念:理解“图书馆”的运作方式

三、核心技术:“超级检索”的魔法背后

四、高级检索技巧:让搜索更智能

✅ 解决方案:在本地 Windows 安装 Docker Desktop

第五节 索引优化

让RAG更聪明:两种索引优化策略

一、句子窗口检索:精准定位+完整语境

二、结构化索引:先筛选再搜索

为什么理解原理比死记工具更重要?


Task03:索引构建(第三章)

第一节 向量嵌入vector embedding

给AI装上一副“语义眼镜”:走进向量嵌入的神奇世界

嘿,同学们!想象一下,如果AI能真正“读懂”我们的话,而不是仅仅匹配关键词,那该多酷?比如,你问“怎么照顾一只宠物猫?”,它能精准地找出讲“猫咪饲养指南”的文章,而不是给你一堆关于“猫科动物分类”的论文。这背后的魔法,就来自于一项叫做向量嵌入(Embedding) 的核心技术。今天,我们就来揭开它的神秘面纱!

一、Embedding是什么?AI的“语义翻译官”

简单来说,Embedding就是一位超级“翻译官”,它的任务是把人类世界复杂的信息(文字、图片、声音),翻译成AI能理解的“数学语言”——也就是一串数字组成的向量

  • 原始信息:比如“猫”这个词,或者一张猫咪的图片。
  • Embedding翻译官:一个训练有素的AI模型。
  • 输出结果:一个向量,就像一组独一无二的“坐标”,比如 [0.16, 0.29, -0.88, ...]。这个坐标定义了一个词或一张图在AI大脑这个“超级语义宇宙”中的位置。

这个“语义宇宙”的神奇法则:物以类聚!

Embedding最厉害的地方在于,它构建的“语义宇宙”是有逻辑的!意思相近的东西,它们的“坐标”在宇宙中就会离得很近;意思不相关的东西,坐标就会离得很远。

  • 猫”和“狗”(都是宠物)的坐标会靠得很近。
  • 猫”和“汽车” 的坐标就会非常遥远。
  • 我们通过计算余弦相似度(可以理解为比较两个坐标的“方向”是否一致)这样的数学工具,就能量化这种“语义亲密度”。
二、Embedding如何助力RAG?扮演“最强大脑图书管理员”

还记得我们之前聊过的RAG吗?它就是让AI在回答问题前,先从一个巨大的知识库(比如公司文档、百科全书)里查找相关资料。而Embedding,就是这个过程中的 最强大脑图书管理员”

它的工作流程超级高效:

  1. 整理图书(离线索引):知识库里的所有文章,都会被切分成小块。然后,Embedding翻译官为每一块内容生成一个唯一的“坐标”(向量),并存入一个特殊的“坐标图书馆”(向量数据库)。
  2. 理解问题(在线查询):当你提出一个问题时,同一位Embedding翻译官也会为你的问题生成一个“坐标”。
  3. 精准找书(语义检索):这位图书管理员会迅速在你的问题“坐标”和图书馆里所有内容的“坐标”之间进行计算,找出那些和你的问题“方向”最一致、位置最接近的几块内容。
  4. 递交资料(生成答案):找到的这些最相关的内容,会作为参考材料递给像ChatGPT这样的大语言模型,让它生成一个准确又靠谱的答案。

所以,Embedding的质量至关重要! 一个优秀的Embedding模型,就像是一个知识渊博、理解力超强的图书管理员,能精准把握你问题的深层含义。而一个差劲的模型,则可能给你找来回一堆不相关的“垃圾信息”,导致AI给出错误的答案。

三、Embedding技术的进化之旅:从“死记硬背”到“融会贯通”

这项技术也不是一天练成的,它经历了一场有趣的进化:

  • 第一代:静态词嵌入(像背字典)
    • 代表:Word2Vec(2013年)
    • 特点:每个词都有一个固定的向量,就像字典里每个词都有一个固定的解释。
    • 缺陷:无法理解一词多义!比如“苹果”这个词,无论是在“苹果手机”还是“吃苹果”里,它的向量都是一样的,AI无法区分差异。
  • 第二代:动态上下文嵌入(学会联系上下文)
    • 代表:BERT(2018年)
    • 革命:基于Transformer架构的BERT模型诞生了!它生成的向量是动态的,会根据一个词在句子中的具体含义来决定。
    • 效果:在“我想买苹果”和“这个苹果很甜”中,“苹果”会得到两个不同的向量,AI终于能分清你指的是公司还是水果了!
  • 第三代:为RAG量身定制(成为专业领域专家)
    • 新要求:为了在医疗、法律等专业领域也能表现出色,Embedding模型需要具备领域自适应能力。同时,还要能处理长文档、图片等多类型信息。
四、如何为你的AI项目挑选“最佳翻译官”?

面对成千上万个Embedding模型,该怎么选呢?别慌,这里有一份“选秀指南”:

  1. 查看“英雄榜”:MTEB排行榜
    这是一个权威的模型评测网站,就像“模型世界杯”的积分榜。你可以根据综合得分模型大小(越大通常越强,但也越吃硬件)、支持的语言(一定要选支持中文的!)和能处理的文本长度来快速筛选。
  2. 明确你的“选秀标准”
    • 核心任务:如果你是做RAG,重点看模型在“检索”这项任务上的排名。
    • 硬件条件:你的电脑或服务器能带动多大的模型?要量力而行。
    • 文本长度:你的文档通常有多长?要确保模型的“处理长度”上限够用。
  3. 组织“终极试镜”
    公开榜单只是参考,真正的考验在你的业务场景里。最好的方法是:
    • 准备考题:收集一些你们业务中真实的问题和标准答案。
    • 让候选模型实战:让几个初步选中的模型在你的“考题”上跑一跑,看谁找资料最准、最快。
    • 选出冠军:通过对比测试,最终选出最适合你项目的那个“最强翻译官”!
总结

看,Embedding这项技术就像是为AI戴上了一副神奇的“语义眼镜”,让它能真正“看见”语言的深层含义。从简单的“背字典”到复杂的“理解上下文”,它的进化推动着AI变得越来越智能。现在,无论是你手机里的语音助手,还是能和你畅聊的AI,背后都有这位无声的“翻译官”在默默工作。

第二节 多模态嵌入(Multimodal Embedding)

打破模态墙:当AI学会“融会贯通”

想象一下,如果AI能像我们人类一样,同时用眼睛看、用耳朵听、用大脑理解,那该多强大?现代AI的一项重要突破,正是让模型从只理解文字,进化到能统一理解图像、声音、视频等多种信息。这项技术就像教AI学会了“融会贯通”,而它的核心秘诀,就藏在多模态嵌入(Multimodal Embedding) 之中。

一、为什么要“多模态”?打破信息的“巴别塔”

我们之前学过,Embedding能把文字变成AI懂的向量坐标。但如果AI只懂文字,那它就像一个只能听广播、却不能看电视的人,理解的世界是不完整的。

现实世界的信息是多模态的:我们既看图片、视频,也听声音、读文字。问题来了:传统的文本Embedding和图像Embedding,是在两个完全不同的坐标系里工作的。这就像中文和摩斯密码,互不相通,中间隔着一堵厚厚的 模态墙”

  • 你问AI:“找一张红色汽车的照片。”
  • AI的困境:它有一个强大的“文本坐标系”来理解“红色汽车”这个词,也有一个强大的“图像坐标系”来识别图片内容。但它不知道这两个坐标系如何对应!它无法将文字世界的“红色汽车”与图片世界中的那辆红色汽车联系起来。

多模态嵌入的目标,就是担任一位“宇宙级的地图绘制师”,为所有不同类型的数据建立一個统一的、共享的语义坐标系! 在这张新地图上,“一只奔跑的狗”这段文字的坐标,会和一张真实小狗奔跑的图片的坐标紧紧挨在一起。这样,AI就能实现真正的跨模态检索和理解

二、CLIP模型:图文理解的“跨界大师”

在打破“模态墙”的征程中,OpenAI发布的CLIP模型是一个里程碑式的存在。它的设计非常巧妙。

CLIP的“双子星”架构

CLIP模型内部有两位“专家”:

  1. 图像编码器:专门负责“看”图片,将任何图像转换成一个向量。
  2. 文本编码器:专门负责“读”文字,将任何一段描述转换成一个向量。

最关键的是,CLIP通过训练,让这两位专家使用同一套坐标系统!它们输出的向量在同一个空间里可以直接比较。

CLIP的“拉郎配”学习法:对比学习

CLIP是如何学会给图文配对的呢?它使用了一种叫对比学习的方法。这个过程就像一个高效的“配对游戏”:

  1. 输入:一批(比如1万张)图片和它们对应的文字描述。
  2. 目标:模型的任务是,拉近正确图文对的向量距离(比如“猫的图片”和“一只猫”的描述),同时推远所有错误配对的向量距离(比如“猫的图片”和“一辆汽车”的描述)。
  3. 结果:经过在海量互联网数据上玩这个游戏,CLIP最终学会了将语义相关的图片和文字自动“拴”在一起。

CLIP的超级能力:“零样本”分类

这种训练方式给了CLIP一项酷炫的超能力——零样本识别。比如,你给它一张狗的图片,再给它几个选项的文字描述:“一张狗的照片”、“一张猫的照片”、“一辆汽车的照片”,它不需要事先学习过如何识别狗,就能通过计算图片向量与每个文本向量的相似度,选出最匹配的“一张狗的照片”。这为AI的通用性打开了新的大门。

三、新一代多模态模型:更强大、更全面(以BGE-M3为例)

在CLIP之后,科学家们不断推出更强大的模型。其中,由北京智源研究院推出的BGE-M3就是一个非常出色的“多面手”。它的名字里的“M3”就代表了它的三大核心本领:

  1. 多语言:天生就能理解超过100种语言。你用中文问“红色汽车”,它不仅能找到英文标注“red car”的图片,还能找到法文、德文标注的图片。
  2. 多功能:一个模型,多种用法。它既支持CLIP那样的密集检索(比较整个向量的相似度),也支持更精细的多向量检索(比较图像多个局部的向量),甚至还能同时进行传统的关键词匹配,适应各种复杂场景。
  3. 多粒度:既能处理短短的图片标题,也能处理长达几千字的长篇文档,胃口特别好。

BGE-M3的“火眼金睛”:网格嵌入

BGE-M3在“看图”的方式上也有创新。CLIP通常把一整张图片当作一个整体来理解。而BGE-M3采用了一种更精细的 网格嵌入” 法。

  • 它把一张图片像棋盘一样分成许多个小格子,然后对每个小格子进行独立编码。
  • 这样做的好处是,模型能更好地捕捉图片中的局部细节。比如,一张“草地上有只猫和一只狗”的图片,模型不仅能理解整张图,还能分别定位到猫和狗所在的位置,理解能力更上一层楼!

从CLIP到BGE-M3,多模态嵌入技术正朝着更统一、更智能的方向飞速发展,让AI离真正“理解”我们丰富多彩的世界越来越近。

代码示例

1 环境准备

步骤1:安装 visual_bge 模块

# 进入 visual_bge 目录
cd code/C3/visual_bge# 安装 visual_bge 模块及其依赖
pip install -e .# 返回上级目录
cd ..

步骤2:下载模型权重

# 运行模型下载脚本
python download_model.py

手动下载方案(推荐)

  1. 访问 Hugging Face 页面

    • 打开 https://huggingface.co/BAAI/bge-visualized/tree/main

    • 点击 Visualized_base_en_v1.5.pth 文件右侧的下载按钮

  2. 下载

pip install modelscope

下载完整模型库

modelscope download --model BAAI/bge-base-en-v1.5

修改程序如下:

# 01_bge_visualized.py
# 功能:使用本地加载的 Visualized_BGE 模型进行多模态嵌入与相似度计算
# 作者:Datawhale All-in-RAG
# 说明:所有模型均从本地加载,避免网络请求和 SSL 证书问题import torch
from visual_bge.visual_bge.modeling import Visualized_BGE# ==============================
# 📁 模型路径配置(全部使用相对路径)
# ==============================
# BGE 文本编码器:指向你复制到项目 models/ 下的 bge-base-en-v1.5
BGE_MODEL_PATH = "../../models/bge-base-en-v1.5"# 多模态适配权重:你已有的 Visualized_BGE 微调权重
VISUAL_BGE_WEIGHT_PATH = "../../models/bge/Visualized_base_en_v1.5.pth"# 初始化模型(完全离线)
model = Visualized_BGE(model_name_bge=BGE_MODEL_PATH,      # 本地 BGE 模型路径model_weight=VISUAL_BGE_WEIGHT_PATH  # 本地多模态权重路径
)
model.eval()# ==============================
# 🧪 编码测试:文本、图像、图文融合
# ==============================
with torch.no_grad():text_emb = model.encode(text="datawhale开源组织的logo")img_emb_1 = model.encode(image="../../data/C3/imgs/datawhale01.png")multi_emb_1 = model.encode(image="../../data/C3/imgs/datawhale01.png", text="datawhale开源组织的logo")img_emb_2 = model.encode(image="../../data/C3/imgs/datawhale02.png")multi_emb_2 = model.encode(image="../../data/C3/imgs/datawhale02.png", text="datawhale开源组织的logo")# ==============================
# 🔍 相似度计算(余弦相似度,因向量已归一化,直接点积)
# ==============================
sim_1 = img_emb_1 @ img_emb_2.T
sim_2 = img_emb_1 @ multi_emb_1.T
sim_3 = text_emb @ multi_emb_1.T
sim_4 = multi_emb_1 @ multi_emb_2.Tprint("=== 相似度计算结果 ===")
print(f"纯图像 vs 纯图像: {sim_1.item():.4f}")
print(f"图文结合1 vs 纯图像: {sim_2.item():.4f}")
print(f"图文结合1 vs 纯文本: {sim_3.item():.4f}")
print(f"图文结合1 vs 图文结合2: {sim_4.item():.4f}")# ==============================
# 📊 嵌入向量信息分析
# ==============================
print("\n=== 嵌入向量信息 ===")
print(f"多模态向量维度: {multi_emb_1.shape}")
print(f"图像向量维度: {img_emb_1.shape}")
print(f"多模态向量示例 (前10个元素): {multi_emb_1[0][:10].cpu().numpy()}")
print(f"图像向量示例 (前10个元素):   {img_emb_1[0][:10].cpu().numpy()}")

显示结果如下:

=== 相似度计算结果 ===
纯图像 vs 纯图像: 0.8318
图文结合1 vs 纯图像: 0.8291
图文结合1 vs 纯文本: 0.7627
图文结合1 vs 图文结合2: 0.9058

=== 嵌入向量信息 ===
多模态向量维度: torch.Size([1, 768])
图像向量维度: torch.Size([1, 768])
多模态向量示例 (前10个元素): [ 0.03599895 -0.00321014 -0.03766303  0.02401761  0.01403442  0.03398741
  0.01475963  0.0292121   0.00599695 -0.01447793]
图像向量示例 (前10个元素):   [ 0.04065671 -0.06057012 -0.00366566  0.00731354  0.03045561  0.03183692
  0.01319521  0.04422256 -0.03800168 -0.02704623]

作业1:

尝试把代码中的部分文本替换一下,比如将datawhale开源组织的logo替换为blue whale看看结果有什么不同。

# hk1_compare.py
import torch
from visual_bge.visual_bge.modeling import Visualized_BGE# 模型路径(保持不变)
model = Visualized_BGE(model_name_bge="../../models/bge-base-en-v1.5",model_weight="../../models/bge/Visualized_base_en_v1.5.pth"
)
model.eval()# 图像路径
img1_path = "../../data/C3/imgs/datawhale01.png"
img2_path = "../../data/C3/imgs/datawhale02.png"# 两种文本描述
text_original = "datawhale开源组织的logo"
text_new = "blue whale"with torch.no_grad():# 原始文本text_emb_orig = model.encode(text=text_original)multi_emb_1_orig = model.encode(image=img1_path, text=text_original)multi_emb_2_orig = model.encode(image=img2_path, text=text_original)# 新文本text_emb_new = model.encode(text=text_new)multi_emb_1_new = model.encode(image=img1_path, text=text_new)multi_emb_2_new = model.encode(image=img2_path, text=text_new)# 纯图像(不变)img_emb_1 = model.encode(image=img1_path)img_emb_2 = model.encode(image=img2_path)# 计算相似度
def sim(a, b):return (a @ b.T).item()print("=== 使用文本: 'datawhale开源组织的logo' ===")
print(f"图文1 vs 图像1: {sim(multi_emb_1_orig, img_emb_1):.4f}")
print(f"图文1 vs 文本:  {sim(multi_emb_1_orig, text_emb_orig):.4f}")
print(f"图文1 vs 图文2: {sim(multi_emb_1_orig, multi_emb_2_orig):.4f}")print("\n=== 使用文本: 'blue whale' ===")
print(f"图文1 vs 图像1: {sim(multi_emb_1_new, img_emb_1):.4f}")
print(f"图文1 vs 文本:  {sim(multi_emb_1_new, text_emb_new):.4f}")
print(f"图文1 vs 图文2: {sim(multi_emb_1_new, multi_emb_2_new):.4f}")print("\n=== 跨文本对比(关键!)===")
print(f"用'blue whale'描述的图文1 vs 原始文本: {sim(multi_emb_1_new, text_emb_orig):.4f}")
print(f"用'blue whale'描述的图文1 vs 'blue whale'文本: {sim(multi_emb_1_new, text_emb_new):.4f}")

显示结果:

=== 使用文本: 'datawhale开源组织的logo' ===
图文1 vs 图像1: 0.8291
图文1 vs 文本:  0.7627
图文1 vs 图文2: 0.9058

=== 使用文本: 'blue whale' ===
图文1 vs 图像1: 0.9218
图文1 vs 文本:  0.7572
图文1 vs 图文2: 0.8719

=== 跨文本对比(关键!)===
用'blue whale'描述的图文1 vs 原始文本: 0.4644
用'blue whale'描述的图文1 vs 'blue whale'文本: 0.7572

🔍 结果详细分析

✅ 1. 图文1 vs 图像1:0.8291 → 0.9218(显著提升)

  • 现象:用 "blue whale" 作为文本提示时,融合向量(multi_emb)与原始图像向量(img_emb)的相似度大幅提高
  • 原因推测
    • “datawhale开源组织的logo” 是一个非常具体、抽象的描述,包含“开源组织”“logo”等非视觉语义,模型难以将其与像素内容对齐;
    • “blue whale” 是一个具象的、视觉相关的词,即使图像不是真实蓝鲸,模型也可能从 logo 的蓝色、鲸鱼形状中提取到相关特征;
    • 因此,“blue whale” 与图像的视觉语义更匹配,导致多模态融合时更“信任”图像,向量更靠近图像侧。

💡 这说明:文本提示的质量直接影响多模态对齐效果。越具象、越视觉化的文本,越容易与图像融合。


✅ 2. 图文1 vs 文本:0.7627 → 0.7572(基本不变)

  • 两种文本下,融合向量与对应文本的相似度都约在 0.75~0.76
  • 说明模型在两种情况下都较好地编码了文本语义,没有明显偏向。

✅ 3. 图文1 vs 图文2:0.9058 → 0.8719(略有下降)

  • 两张不同 logo 图像,在使用 "datawhale..." 时相似度更高(0.9058),因为文本强调了“同一个组织的 logo”,增强了语义一致性;
  • 而 "blue whale" 是通用描述,无法区分两张 logo 的“同源性”,所以相似度略降。

📌 这体现了文本在跨样本对齐中的作用:特定文本能拉近同类样本,通用文本则弱化这种关系。


✅ 4. 跨文本对比:0.4644 vs 0.7572(巨大差异)

  • 用 "blue whale" 生成的图文向量,与原始文本 "datawhale..." 的相似度只有 0.46(很低);
  • 但与 "blue whale" 文本的相似度是 0.7572(高)。
  • 结论:多模态向量强烈依赖输入文本,换文本就等于换语义空间!

🔑 关键洞见
Visualized_BGE 的多模态嵌入 = f(图像, 文本)
改变文本,就改变了整个嵌入的语义方向。


🧠 总结:文本提示(Prompt)的重要性

文本类型特点对多模态融合的影响
具体、抽象文本<br>(如 “datawhale开源组织的logo”)包含非视觉语义(“开源”“组织”)可能与图像对齐较差,但能增强同类样本一致性
具象、视觉化文本<br>(如 “blue whale”)描述颜色、形状、物体类别与图像特征更匹配,提升图文一致性,但泛化性强、区分度弱

💡 实践建议

  1. 如果你做图像检索

    • 使用视觉相关的关键词(如 “blue whale icon”, “blue whale logo”)效果可能更好;
    • 避免加入“开源组织”这类非视觉信息。
  2. 如果你做语义对齐

    • 确保文本与图像内容语义一致
    • 可尝试多种 prompt,选相似度最高的。

第三节 向量数据库

向量数据库:AI的“超级记忆宫殿”

想象一下,AI模型就像一个学识渊博的“大脑”,它通过Embedding技术,把书本里的每一段知识都变成了一个独特的“思维坐标”。但是,当这个大脑读完了整个图书馆,拥有了数亿个“思维坐标”时,一个新问题出现了:如何在眨眼间,从这数亿个坐标里,找到与你的问题最相关的几个?

这个难题,就需要向量数据库来解决。它就像为AI建造的一个 超级记忆宫殿” ,专门负责高效地存储和快速查找这些海量的向量坐标。

一、为什么需要它?从“小书柜”到“国家图书馆”的挑战

你可以把简单的向量存储想象成一个小书柜。当你的书(向量)只有几十本时,你一眼就能找到想要的那本。但当你的书多到像一座国家图书馆(数亿向量)时,你再一本一本地去找,恐怕一辈子都找不到。

传统数据库(如MySQL)就像一位严谨的“档案管理员”,它擅长的是:“请精确地找出编号为A-1024的档案”。这种精确匹配是它的强项。

但AI需要的是:请找出所有和‘宇宙探索’这个主题最相似的10本书。” 这是一个相似性搜索问题。让传统数据库去做这件事,就像让档案管理员用尺子去量所有书籍封面颜色与“蓝色”的相似度,效率极低,根本无法完成。

而向量数据库,就是一位专门训练出来的“最强大脑图书检索员”。它的核心价值就在于:能在数十亿的向量中,实现毫秒级的相似性搜索,快速为你找到最相关的信息。

超级记忆宫殿”的五大本领:

  1. 光速检索:利用特殊的“索引地图”(如HNSW算法),实现近似最近邻搜索,速度极快。
  2. 海量存储:专门为存储成百上千维的向量而优化,轻松管理千亿级别的“知识坐标”。
  3. 混合查询:不仅能按语义找,还能结合条件筛。例如:“找出与‘新能源汽车’相关,且是2023年之后的文档。”
  4. 弹性伸缩:采用分布式架构,就像宫殿可以随时加盖新的侧殿,数据量增大时只需增加服务器即可。
  5. 无缝集成:能轻松与LangChain、LlamaIndex等AI应用框架连接,方便开发者构建智能应用。
二、它如何工作?建造宫殿的“智能地图”

向量数据库能如此高效,关键在于它使用了特殊的“索引”技术。这就像给巨大的记忆宫殿绘制了一张智能地图,而不是一本死板的目录。

常见的几种“绘图术”包括:

  • 基于图的方法(如HNSW):像一张复杂的地铁线路图。站点就是向量,相似的向量之间有“线路”直连。搜索时,就像从某个站点出发,沿着最快线路迅速抵达目标站点群。这是目前最流行、性能最好的方法之一。
  • 基于量化的方法(如Faiss的PQ):像把世界地图按大洲、国家、省市进行分层分区。搜索时,先定位到大概区域(比如“北美洲”),再在这个区域里精细查找,大大缩小了搜索范围。
  • 基于哈希的方法(如LSH):像给向量发“会员卡”,相似的向量会得到相同或相似的“卡号”(哈希值)。搜索时,只需要比较“卡号”就能快速找到相似的群体。
三、主流产品介绍:不同特色的“记忆宫殿”

市场上有许多各具特色的向量数据库,你可以根据你的“藏书量”和“查找需求”来选择:

  1. Pinecone:五星级“托管式智慧图书馆”
    • 特点:完全托管,无需自己操心服务器和维护。高可用、低延迟,开箱即用。
    • 适合:追求稳定、省心、有企业级需求的大型应用。
  2. Milvus:可自由设计的“开源图书馆蓝图”
    • 特点:开源、功能强大、支持分布式部署,社区活跃。可以把它建成非常庞大的系统。
    • 适合:需要高度自定义、处理超大规模数据的技术团队。
  3. Qdrant:高性能的“Rust动力跑车”
    • 特点:用Rust语言编写,性能极佳,资源利用率高。
    • 适合:对性能和资源消耗非常敏感的应用。
  4. Weaviate:自带AI的“智能知识图谱库”
    • 特点:不仅存储向量,还内置了AI模块,原生支持多模态和GraphQL查询,更像一个智能知识库。
    • 适合:希望快速构建复杂AI应用,尤其是涉及知识图谱的场景。
  5. Chroma:轻量便捷的“个人书房”
    • 特点:极其轻量,安装简单,几行代码就能用。与LangChain等工具集成度极高。
    • 适合初学者、原型开发、小规模项目。如果你想快速体验RAG,这是最好的起点。

如何选择你的“宫殿”?

  • 如果你是学生或初学者,想快速搭建一个demo,强烈推荐从 Chroma 开始,它最简单。
  • 如果你要为公司构建一个严肃的、大规模的生产系统,那么应该评估 Pinecone(省心)或 Milvus(可控)。
  • 如果你对性能有极致要求,可以试试 Qdrant

总之,向量数据库是RAG系统中承上启下的关键一环,它将AI的“知识”妥善保管,并能随时响应我们的“召唤”,是让AI真正变得有用的强大基石。

第一步:确认环境已安装 faiss-cpu

python -c "import faiss; print(faiss.__version__)"

安装库:

modelscope download --model BAAI/bge-small-zh-v1.5

运行修改后的程序:

from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings   # 新路径
from langchain_core.documents import Document# 1. 准备文本
texts = ["张三是法外狂徒","FAISS是一个用于高效相似性搜索和密集向量聚类的库。","LangChain是一个用于开发由语言模型驱动的应用程序的框架。"
]
docs = [Document(page_content=t) for t in texts]# 2. 加载本地模型(注意路径分隔符)
local_model_path = r"E:\Datawhale\All in rag 202509\code\all-in-rag-main\models\bge-small-zh-v1___5"
embeddings = HuggingFaceEmbeddings(model_name=local_model_path)# 3. 构建并保存 FAISS 索引
vectorstore = FAISS.from_documents(docs, embeddings)
save_path = "./faiss_index_store"
vectorstore.save_local(save_path)
print(f"FAISS index has been saved to {save_path}")# 4. 加载索引并查询
loaded_vectorstore = FAISS.load_local(save_path,embeddings,allow_dangerous_deserialization=True
)query = "FAISS是做什么的?"
results = loaded_vectorstore.similarity_search(query, k=1)print(f"\n查询: '{query}'")
print("相似度最高的文档:")
for doc in results:print(f"- {doc.page_content}")

显示结果:

FAISS index has been saved to ./faiss_index_store

查询: 'FAISS是做什么的?'
相似度最高的文档:
- FAISS是一个用于高效相似性搜索和密集向量聚类的库。

索引创建实现细节

通过深入 LangChain 源码,可以发现索引创建是一个分层、解耦的过程,主要涉及以下几个方法的嵌套调用:

  1. from_documents (封装层):

    • 这是我们直接调用的方法。它的职责很简单:从输入的 Document 对象列表中提取出纯文本内容 (page_content) 和元数据 (metadata)。
    • 然后,它将这些提取出的信息传递给核心的 from_texts 方法。
  2. from_texts (向量化入口):

    • 这个方法是面向用户的入口。它接收文本列表,并执行关键的第一步:调用 embedding.embed_documents(texts),将所有文本批量转换为向量。
    • 完成向量化后,它并不直接处理索引构建,而是将生成的向量和其他所有信息(文本、元数据等)传递给一个内部的辅助方法 __from
  3. __from (构建索引框架):

    • 一个内部方法,负责搭建 FAISS 向量存储的“空框架”。
    • 它会根据指定的距离策略(默认为 L2 欧氏距离)初始化一个空的 FAISS 索引结构(如 faiss.IndexFlatL2)。
    • 同时,它也准备好了用于存储文档原文的 docstore 和用于连接 FAISS 索引与文档的 index_to_docstore_id 映射。
    • 最后,它调用另一个内部方法 __add 来完成数据的填充。
  4. __add (填充数据):

    • 真正执行数据添加操作的核心。它接收到向量、文本和元数据后,执行以下关键操作:
      • 添加向量: 将向量列表转换为 FAISS 需要的 numpy 数组,并调用 self.index.add(vector) 将其批量添加到 FAISS 索引中。
      • 存储文档: 将文本和元数据打包成 Document 对象,存入 docstore
      • 建立映射: 更新 index_to_docstore_id 字典,建立起 FAISS 内部的整数 ID(如 0, 1, 2...)到我们文档唯一 ID 的映射关系。

作业2

  1. LlamaIndex默认会将数据存储为透明可读的JSON格式,运行03_llamaindex_vector.py文件,查看保存的json文件内容。
    修改程序如下:
    # 03_llamaindex_vector.py
    from llama_index.core import VectorStoreIndex, Document, Settings
    from llama_index.embeddings.huggingface import HuggingFaceEmbedding# 1. 配置全局嵌入模型(使用本地路径!)
    Settings.embed_model = HuggingFaceEmbedding(model_name="../../models/bge-small-zh-v1___5",  # ✅ 关键修改trust_remote_code=False,device="cpu"
    )# 2. 创建示例文档
    texts = ["张三是法外狂徒","LlamaIndex是一个用于构建和查询私有或领域特定数据的框架。","它提供了数据连接、索引和查询接口等工具。"
    ]
    docs = [Document(text=t) for t in texts]# 3. 创建索引并持久化到本地
    index = VectorStoreIndex.from_documents(docs)
    persist_path = "./llamaindex_index_store"
    index.storage_context.persist(persist_dir=persist_path)
    print(f"LlamaIndex 索引已保存至: {persist_path}")
    

显示如下:

LlamaIndex 索引已保存至: ./llamaindex_index_store

运行下面的程序 view_index1.py

import json
import os# 指定索引目录
persist_dir = "./llamaindex_index_store"# 查看所有 JSON 文件
for filename in os.listdir(persist_dir):if filename.endswith(".json"):print(f"\n=== {filename} ===")with open(os.path.join(persist_dir, filename), "r", encoding="utf-8") as f:data = json.load(f)print(json.dumps(data, indent=2, ensure_ascii=False))

显示结果:

第四节 Milvus介绍及多模态检索实践

认识Milvus:AI时代的“超级图书馆管理员”

想象一下,AI大脑里装着数亿本书的知识向量,怎样才能在瞬间找到最相关的答案?这就需要一位专业的“图书管理员”——Milvus。它不是一个普通的数据库,而是一个专门为海量向量数据打造的超级搜索引擎,能轻松处理十亿甚至百亿级别的向量检索。

一、快速体验:用Docker一键启动你的“迷你图书馆”

想快速体验Milvus?最简单的方式就是使用Docker。这就像在你的电脑上快速搭建一个“迷你图书馆”。

第一步:准备“地基”(安装Docker)
确保你的电脑已经安装了Docker和Docker Compose。它们就像是建造图书馆所需的工具和蓝图。

第二步:下载“施工图纸”
打开终端,执行以下命令,下载Milvus的配置文件(docker-compose.yml):

bash

# Mac/Linux 用户
wget https://github.com/milvus-io/milvus/releases/download/v2.5.14/milvus-standalone-docker-compose.yml -O docker-compose.yml# Windows 用户 (PowerShell)
Invoke-WebRequest -Uri "https://github.com/milvus-io/milvus/releases/download/v2.5.14/milvus-standalone-docker-compose.yml" -OutFile "docker-compose.yml"

第三步:“开工建造”
在配置文件所在目录,运行一句魔法般的命令:

bash

docker compose up -d

Docker会自动下载所需镜像并启动服务。稍等片刻,你的“迷你Milvus图书馆”就建好了!你可以通过 docker ps 命令查看运行中的服务。

二、核心概念:理解“图书馆”的运作方式

要用好Milvus,需要理解它的几个核心概念,它们就像一个现代化图书馆的管理体系:

  1. Collection(集合) = 整个图书馆

    • 这是最高级别的容器,相当于一个完整的图书馆,用于存放某一类数据的所有信息。

  2. Partition(分区) = 图书馆里的不同区域

    • 比如“科技区”、“文学区”、“历史区”。把书分门别类放在不同区域,找起来就快得多。Milvus也通过分区来提升检索效率。

  3. Schema(模式) = 图书的编目规则

    • 规定每本书需要登记哪些信息:书名(主键)、作者(元数据)、内容摘要(向量)等。一个好的Schema是高效检索的基础。

  4. Entity(实体) = 一本具体的书

    • 就是一条具体的数据,包含它的各种属性和对应的向量。

  5. Alias(别名) = 图书馆的“临时指示牌”

    • 这是一个非常聪明的设计!比如图书馆要装修升级,你可以悄悄把新书搬到“新馆”,然后把入口的“综合阅览室”指示牌(别名)从“旧馆”指向“新馆”。读者完全感觉不到变化,就能享受到更新的资源。这实现了数据的无缝平滑升级。

三、核心技术:“超级检索”的魔法背后

Milvus之所以能如此快地找到信息,关键在于它使用了特殊的“索引”技术。这就像给图书馆绘制了不同的“智能检索地图”。

1. FLAT索引:最“老实”的检索员

  • 工作方式:拿到一本书的查询请求后,会跑遍图书馆的每一个书架,逐一对比,确保找到最匹配的那本。

  • 优点:结果100%准确。

  • 缺点:速度太慢,只适合藏书量很少的小书吧。

2. IVF系列索引:聪明的“分区管理员”

  • 工作方式:先把所有书按主题分成几百个区域(比如“人工智能区”、“科幻小说区”)。当你来找书时,它先判断你的书属于哪个主题区,然后只在这个区域内进行精细查找。

  • 优点:大大缩小搜索范围,速度和精度的平衡之选。

  • 适用:大多数通用场景。

3. HNSW索引:拥有“空间跳跃”能力的超能力者

  • 工作方式:它建立了一个多层的“快速通道网络”。最顶层是稀疏的骨干网,用于快速定位到大区域;越往下,网络越密集,用于精确定位。检索时从上至下,快速逼近目标。

  • 优点:速度极快,尤其擅长高维数据。

  • 缺点:占用的“脑容量”(内存)很大。

  • 适用:对速度要求极高的实时应用,如聊天机器人。

4. DiskANN索引:管理“超大型图书馆”的专家

  • 工作方式:当图书馆太大,无法把所有书的信息都放在手边(内存)时,DiskANN擅长利用高速书架(SSD硬盘)来组织图书,虽然单次取书稍慢一点,但能管理远超内存容量的海量藏书。

  • 适用:数据量达到百亿级别的超大规模场景。

四、高级检索技巧:让搜索更智能

除了基本的找相似,Milvus这位“超级管理员”还有很多高级技能:

  • 过滤检索:“请帮我找与这幅画风格相似的作品,但只要文艺复兴时期的。”——先按条件过滤,再找相似。

  • 范围检索:“请找出所有与标准样本相似度超过90% 的产品。”——用于质检、人脸门禁等场景。

  • 多向量混合检索:同时根据“文章语义向量”和“关键词向量”进行搜索,然后智能合并结果,让检索既准确又全面。

  • 分组检索:搜索“机器学习”时,确保前10个结果来自10本不同的书籍,避免结果都集中在某一本书里,保证答案的多样性。

通过这些强大的功能组合,Milvus让我们能够构建出真正智能、高效的AI应用,是处理海量向量数据时不可或缺的利器。

✅ 解决方案:在本地 Windows 安装 Docker Desktop

步骤 1:下载并安装 Docker Desktop

  1. 访问官网:https://www.docker.com/products/docker-desktop/
  2. 下载 Docker Desktop for Windows
  3. 安装时勾选:
    • ✅ Use WSL 2 instead of Hyper-V(推荐)
    • ✅ Install required Windows components for WSL 2
  4. 安装完成后重启电脑

💡 需要 Windows 10/11 64位,且启用 WSL2(Docker Desktop 会自动配置)。

由于windows系统不支持,待做。

第五节 索引优化

让RAG更聪明:两种索引优化策略

想象一下,你的AI助手就像一个正在写论文的学生。如果参考资料太零碎(比如只有孤立的句子),它可能无法理解整体语境;但如果资料太冗长(比如整章内容),它又可能抓不住重点。如何解决这个矛盾?本节介绍两种让RAG系统变聪明的索引优化方法。

一、句子窗口检索:精准定位+完整语境

1. 核心思路:小而精的检索,大而全的生成

这就像查字典时的聪明做法:

  • 检索时​:先快速找到包含目标单词的那一行(精准定位)
  • 理解时​:再看这个单词所在的整个例句段落(完整语境)

具体实现步骤:

步骤1:建立"句子级"索引库

  • 将文档拆分成单个句子,每个句子作为一个独立单元存入向量数据库
  • 同时,为每个句子记录它的"上下文窗口"(前后各3个句子),作为隐藏的参考资料

步骤2:智能检索与扩展

  • 用户提问时,系统先找出最相关的单个句子
  • 然后自动将该句子的上下文窗口(前后各3句)一起送给AI生成答案

效果对比:
当询问"大西洋环流有什么风险?"时:

  • 普通方法​:可能找到一段泛泛而谈的气候变化内容
  • 句子窗口法​:精准定位到讨论AMOC的具体段落,给出详细、专业的回答

这种方法确保了答案既准确又丰富,就像让AI先找到靶心再看清整个靶子。

二、结构化索引:先筛选再搜索

当知识库变得很大(比如几百个PDF)时,新问题出现了:如何快速找到真正相关的资料?

传统方法的局限:
在整个知识库中搜索,就像在杂乱的大仓库里找一颗特定螺丝——效率低下且容易找错。

解决方案:给资料贴"智能标签"

1. 元数据过滤:先缩小范围

  • 为每个文档块添加标签:文件名、日期、章节、作者等
  • 检索时先按标签筛选,再在筛选结果中搜索

示例场景:
问:"2023年第二季度财报中关于AI的内容"
系统先筛选:年份=2023 + 类型=财报 + 季度=Q2
然后在筛选出的少量文档中精准搜索

2. 递归检索:智能路由查询

对于更复杂的情况(如包含多个表格的Excel文件),可以使用"递归检索":

python

# 简化示例:智能路由到正确的数据表
1. 顶层索引:包含各表格的摘要描述
2. 用户提问:"1994年哪部电影评分人数最少?"
3. 系统先判断:这个问题应该由"1994年电影表"回答
4. 然后将问题路由到对应的表格查询引擎
5. 最终得到精准答案:"《燃情岁月》"

安全提示: 虽然有些工具能自动生成代码查询表格,但存在安全风险。更稳妥的做法是使用元数据过滤等安全方法。

为什么理解原理比死记工具更重要?

学习这些技术时,有人可能会问:为什么不只学一个现成框架?

这好比学做菜:

  • 只学框架 = 死记菜谱,食材一变就不会做了
  • 理解原理 = 掌握烹饪逻辑,有什么食材都能做出美味

我们的学习哲学:

  1. 原理优先​:理解"为什么"比记住"怎么用"更重要
  2. 灵活应变​:真实业务千变万化,原理让你能随机应变
  3. 安全第一​:知道工具的风险,才能选择更安全的方案

当你真正理解了RAG的工作原理,无论遇到什么新工具、新场景,你都能快速掌握并做出明智的选择。

记住:好的AI助手不是死记硬背的"书呆子",而是懂得如何高效查找、智能理解的"聪明学生"。通过这些优化策略,你的RAG系统就能变得更加精准和可靠。

修改程序如下:

import os
import pandas as pd
from dotenv import load_dotenv
from llama_index.core import VectorStoreIndex, Document, Settings
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.vector_stores import MetadataFilters, ExactMatchFilter
from llama_index.llms.deepseek import DeepSeek
from llama_index.embeddings.huggingface import HuggingFaceEmbeddingload_dotenv()# ---------------- 模型配置(完全离线) ----------------
Settings.llm = DeepSeek(model="deepseek-chat", api_key=os.getenv("DEEPSEEK_API_KEY"))
Settings.embed_model = HuggingFaceEmbedding(model_name=r"E:\Datawhale\All in rag 202509\code\all-in-rag-main\models\bge-base-en-v1.5"
)# ---------------- 1. 加载与预处理数据 ----------------
excel_file = r"E:\Datawhale\All in rag 202509\code\all-in-rag-main\data\C3\excel\movie.xlsx"
xls = pd.ExcelFile(excel_file)summary_docs, content_docs = [], []
print("开始加载和处理 Excel 文件...")
for sheet_name in xls.sheet_names:df = pd.read_excel(xls, sheet_name=sheet_name)# 清洗:把“1234人评价”→1234if '评分人数' in df.columns:df['评分人数'] = df['评分人数'].astype(str).str.replace('人评价', '').str.strip()df['评分人数'] = pd.to_numeric(df['评分人数'], errors='coerce').fillna(0).astype(int)year = sheet_name.replace('年份_', '')summary_docs.append(Document(text=f"This sheet contains movie information for the year {year}, including title, director, rating, number of reviewers, etc.",metadata={"sheet_name": sheet_name}))content_docs.append(Document(text=df.to_string(index=False),metadata={"sheet_name": sheet_name}))print("数据加载和处理完成。\n")# ---------------- 2. 构建索引 ----------------
summary_index = VectorStoreIndex(summary_docs)
content_index  = VectorStoreIndex(content_docs)
print("摘要索引和内容索引构建完成。\n")# ---------------- 3. 查询函数 ----------------
def query_safe_recursive(query_str: str):print("--- 开始执行查询 ---")print(f"查询: {query_str}")# 路由:找最相关年份表print("\n第一步:在摘要索引中进行路由...")summary_retriever = VectorIndexRetriever(index=summary_index, similarity_top_k=1)nodes = summary_retriever.retrieve(query_str)if not nodes:return "抱歉,未能找到相关的电影年份信息。"matched_sheet = nodes[0].node.metadata['sheet_name']print(f"路由结果:匹配到工作表 -> {matched_sheet}")# 检索:在该年份表内精确匹配print("\n第二步:在内容索引中检索具体信息...")content_retriever = VectorIndexRetriever(index=content_index,similarity_top_k=1,filters=MetadataFilters(filters=[ExactMatchFilter(key="sheet_name", value=matched_sheet)]))response = RetrieverQueryEngine.from_args(content_retriever).query(query_str)print("--- 查询执行结束 ---\n")return response# ---------------- 4. 执行查询 ----------------
if __name__ == "__main__":query = "1994年评分人数最少的电影是哪一部?"answer = query_safe_recursive(query)print(f"最终回答: {answer}")

显示结果如下:

开始加载和处理 Excel 文件...
数据加载和处理完成。

摘要索引和内容索引构建完成。

--- 开始执行查询 ---
查询: 1994年评分人数最少的电影是哪一部?

第一步:在摘要索引中进行路由...
路由结果:匹配到工作表 -> 年份_1994

第二步:在内容索引中检索具体信息...
--- 查询执行结束 ---

最终回答: 1994年评分人数最少的电影是《燃情岁月》,评分人数为176801。

http://www.dtcms.com/a/407807.html

相关文章:

  • 网站建设软件做淘宝一样的网站
  • 网页前端模板网站家里装修
  • 怎么避免网站开发后门上海怎么建设网站
  • 牛客算法题_查找
  • 数据结构算法学习:LeetCode热题100-子串篇(和为 K 的子数组、滑动窗口最大值、最小覆盖子串)
  • 投资网站模板太原做网站哪家好
  • 营销网站开发isuos常州seo外包
  • 网站的基础建设项目网站平台建设的作用
  • 【EE初阶 - 网络原理】Socket 套接字
  • 2025 9月25 最近两周的问题
  • golang做网站企业年金办法
  • 南京网站建设王道下拉??智能网站建设报价
  • 网站建设色系搭配企业简介介绍
  • 国内做网站的公司有哪些如何在局域网中做网站
  • wordpress仿站教程WordPress拍卖模板
  • app开发和网站开发的区别做同行的旅游网站
  • 做网站网站赚怎么买到精准客户的电话
  • 操作系统进程同步与互斥核心知识点复习
  • 网站推广方案中网站图片模板
  • 网站建设好处网络营销渠道
  • 网页模板免费资源整站优化包年
  • 网站图片动态换名一对一专属定制方案
  • 网站建设销售实习建筑网官网查证
  • Express路由设计最佳实践
  • 如何成为一名合格的Java架构师
  • 亚马逊seo是什么意思seo策略分析
  • 网站优化年报告seo整站优化费用
  • 【系统分析师】2025年上半年真题:综合知识-答案及详解(回忆版)
  • 0、计算机硬件 —— 主板
  • 做网站需要的流程东莞网站关键词优化收费