收藏必备!大模型知识库索引构建指南:从向量嵌入到多模态嵌入详解
本文详细介绍了知识库索引构建的全过程,从向量嵌入到多模态嵌入,再到向量数据库选型与索引优化。文章解释了嵌入模型的基本概念、距离计算方法及在RAG中的应用,介绍了CLIP和多模态BGE模型的使用,并通过代码演示了Milvus的图文检索实现。最后提供了上下文扩展和结构化索引两种优化方法,帮助构建高效的知识库索引系统。
本文详细介绍了知识库索引构建的全过程,从向量嵌入到多模态嵌入,再到向量数据库选型与索引优化。文章解释了嵌入模型的基本概念、距离计算方法及在RAG中的应用,介绍了CLIP和多模态BGE模型的使用,并通过代码演示了Milvus的图文检索实现。最后提供了上下文扩展和结构化索引两种优化方法,帮助构建高效的知识库索引系统。
向量嵌入
基本概念
嵌入(也就是经常提到的embedding),可以把真实实际中的复杂对象,如一句话、一张图、一个视频转为数字化的编码的向量。
可以想象,在一个多维的空间里,一句话、一张图、一个视频都可以嵌入到这个多维空间,同时保留原有的关键信息。这个过程就是embedding。

如上的embedding model也就是嵌入模型,他就是将一句话(原始对象)转为了一个向量(向量空间的一个点),这个向量可以表示为[0.5, 1.2, -0.7, …],实际向量长度有512 768 1024甚至更长的。长度越长,可以表达的信息越丰富,当然存储与计算量也越大。
在这个向量空间中,语义相似的对象,他们在这个空间里的距离也是相近的。另一方面,语义越远的对象,在这个空间中距离应该也越远。这样就可以为我们检索相关内容提供基础支撑。
具体怎么判断两个向量的距离?一般有以下方法:
1)余弦相似度,计算两个向量夹角余弦值,值越接近1,说明语义越接近
2)欧氏距离,计算两个向量在空间中的距离,值越小,说明语义越接近
3)点积,计算两个向量的乘积和。在向量归一化后,点积等价于余弦相似度。
在RAG中的应用
1)知识库构建,文本分块,调用embedding模型,存入向量库
2)用户输入,转换为embedding向量
3)比较用户输入的embedding向量,与知识库embedding向量,搜索语义相似的向量的分块
4)取top k分块内容,作为上下文+用户输入,调用大模型生成最终回复
其中步骤1)2)3)都涉及了embedding,1)2)是对原始文档分块、用户输入embedding向量化。3)是进行向量化检索比较
embedding怎么就可以做到语义相似检索
embedding模型基于transformer架构,进行了语义相关的训练
1)类似BERT模型,针对一段话,遮掩其中一部分文字,然后让模型预测这些文字
2)将一段话分为上下两部分,用上半部分,预测下半部分 通过这些方式,让模型学习句子之间的逻辑性、连贯性和主题相关性
另外,针对embedding模型还会做增强训练
1)直接以相似度作为优化目标,比如以问题-答案,新闻标题-内容数据进行训练
2)对比学习,以三元组形式训练(a,b,c)其中a,b是相关的,c是不相关的
目的都是为了让相关的对象距离接近,不相关的距离远离
embedding模型选择
embedding的选择要结合多种因素:
1)参数量,参数越大,性能越好,但是推理需要的资源越多,成本越高
2)支持语言,这个需要和我们实际业务结合,是中文还是英文
3)输入token长度,和分块策略相关,分块长度不能超过最大token
4)维度,维度越高,可以编码的信息越丰富,但也会占用更多的存储和计算资源
5)得分与机构,一般选择得分高,发布机构比较出名的
5)成本,如果调用公有云api,则需要考虑api成本,如果是私有化部署,则如上参数量、维度都会影响需要的硬件成本
目前国内使用的比较多的embedding包括 bge-large-zh-v1.5:最大token512、1024维、支持中文 bge-m3:最大token8192、1024维,支持多语言 bce-embedding-base_v1:最大token512、768维,支持中英文,网易出品 如上3个模型可以在硅基流动免费调用,bge的相对更出名,使用更多。
Qwen3-Embedding-8B:最大token32k,最高4096维可自定义,支持多语言,这个是收费模型,但是性能上表现更好,也可以私有化部署。
具体使用哪个embedding模型好,除了以上因素,还需要结合实际业务,制定一个测评集,根据实际测试情况来做选择。 再一点,实际测试效果不理想,也不一定是模型问题,也需要检查RAG过程是否可以进行迭代优化
多模态嵌入
为什么需要多模态嵌入
上面我们讲的都是文本向量化的,但是现实时间是多模态的,包括文本、图像、音频、视频等。传统的文本向量无法去搜索“红色的汽车”、“橘色的猫”,因为文本、图像是处于两个隔离的空间中。
多模态嵌入,就是为了将彼此隔离的空间融合在一起,从而把文本和图像等相关联起来。也就是要把文本、图像映射到同一个向量空间中。通过“一只奔跑的马”,它的向量应该会接近一直实际在奔跑的马的图片。
CLIP模型
这里有必要提下OPenAI开源的CLIP模型,它有一个文本编码器和一个图像编码器,最终将文本和图像映射到同一个向量空间。
它通过对比学习训练模型,让正确的图文对相似距离接近,让不正确的图文对相似距离远离,从而实现在同一个向量空间文字和图片的语义相似性。

常用多模型嵌入模型
这里我们以bge-visualized-m3为例介绍。模型可以通过modelscope下载(链接:https://modelscope.cn/models/BAAI/bge-visualized)
接下来我们通过代码的方式实际调用下这个模型
import os
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
import torch
from visual_bge.visual_bge.modeling import Visualized_BGE
model = Visualized_BGE(model_name_bge="BAAI/bge-base-en-v1.5",
model_weight=r"D:\Models\bge\Visualized_base_en_v1.5.pth")
model.eval()
with torch.no_grad():
text_emb = model.encode(text="一只橘猫")
img_emb_1 = model.encode(image="data/C3/imgs/orange_cat.jpg")
multi_emb_1 = model.encode(image="data/C3/imgs/orange_cat.jpg", text="一只橘猫")
img_emb_2 = model.encode(image="data/C3/imgs/orange_cat_02.jpg")
multi_emb_2 = model.encode(image="data/C3/imgs/orange_cat_02.jpg", text="一只橘猫")
img_emb_3 = model.encode(image="data/C3/imgs/dog.jpg")
# 计算相似度
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.T
print("=== 相似度计算结果 ===")
print(f"纯图像 vs 纯图像: {sim_1}")
print(f"图文结合1 vs 纯图像: {sim_2}")
print(f"图文结合1 vs 纯文本: {sim_3}")
print(f"图文结合1 vs 图文结合2: {sim_4}")
sim_5 = img_emb_1 @ img_emb_3.T
print(f"猫猫 VS 狗狗:{sim_5}")
通过以上代码,可以看出来,这个bge多模态embedding模型支持输入文本、图像或文本+图像的组合。 具体到实际应用场景,可以支持纯文本、纯图像或图文混编的向量化处理,而且也可以检索文本、图像或文本图像组合的内容。
运行结果
=== 相似度计算结果 ===
纯图像 vs 纯图像: tensor([[0.8031]])
图文结合1 vs 纯图像: tensor([[0.8780]])
图文结合1 vs 纯文本: tensor([[0.6650]])
图文结合1 vs 图文结合2: tensor([[0.8610]])
猫猫 VS 狗狗:tensor([[0.5810]])
可知,猫和狗的距离是要远一些的。
向量数据库
当我们通过上面的各种embedding模型将分块转换为向量后,需要有个地方可以存储,这里就用到了向量数据库。
传统数据库,多数是关系型数据库,主要服务于交易型业务数据存储,主要提供精确数据查询,虽然也支持模糊查询、关键字查询,但是缺乏语义检索能力。
向量数据库的功能
1、高效的存储管理,支持增删改查功能
2、高效的向量检索,具备高效的语义相似性检索功能
3、丰富的查询功能,除了向量检索,还需要支持元数据检索,比如筛选某个年度的数据、某个分类的数据
4、具备高性能,可以在百万千万级数据上保持高性能与扩展能力
5、生态与集成能力,可以和相关AI开发框架快速集成
基本工作原理
向量数据库通常采用四层架构,来实现高效的语义检索功能
存储:存储向量和元数据,优化存储结构
索引:维护索引算法,优化索引存储与检索
查询:处理查询请求,支持混合查询,实现查询优化
服务:提供客户端的连接管理,提供健康和日志,实现安全管理
主流向量数据库: Chroma:轻量、开源,可以本地Client模式运行,适合小规模应用、原型开发
FAISS:同样适合本地部署运行,不同在于FAISS通过将索引保存为本地文件管理,而不是数据库服务
Milvus:开源、分布式、高性能,适合大规模应用开发、高性能场景
还有一些是传统数据库增加了向量数据库功能,如ES、PostgreSQL
milvus
milvus是一个高性能、分布式向量数据库,支持lite、docker、k8s等多种方式部署。
其中lite模式类似chroma,不过仅支持在linux、mac下使用,windows目前不支持(没有适配windows版本的milvus-lite类库)。
个人开发使用,可以部署docker 版,还有一个方法是使用在线版(https://cloud.zilliz.com/),有免费试用订阅。
接下来,我们就通过代码,完整实现简单的图片文本信息向量化、入库、检索的过程。
import os
from tqdm import tqdm
from glob import glob
import torch
from visual_bge.visual_bge.modeling import Visualized_BGE
from pymilvus import MilvusClient, FieldSchema, CollectionSchema, DataType
import numpy as np
import cv2
from PIL import Image
from dotenv import load_dotenv
load_dotenv()
# 1. 初始化设置
MODEL_NAME = "BAAI/bge-base-en-v1.5"
MODEL_PATH = r"D:\Models\bge\Visualized_base_en_v1.5.pth"
DATA_DIR = "data/C3"
COLLECTION_NAME = "multimodal_demo"
MILVUS_URI = "http://localhost:19530"
# MILVUS_URI = "https://in03-d116d206d7638fb.serverless.aws-eu-central-1.cloud.zilliz.com"
MILVUS_TOKEN = os.getenv("MILVUS_TOKEN")
# 2. 定义工具 (编码器和可视化函数)
class Encoder:
"""编码器类,用于将图像和文本编码为向量。"""
def __init__(self, model_name: str, model_path: str):
self.model = Visualized_BGE(model_name_bge=model_name, model_weight=model_path)
self.model.eval()
def encode_query(self, image_path: str, text: str) -> list[float]:
with torch.no_grad():
if image_path != Noneand image_path != "":
query_emb = self.model.encode(image=image_path, text=text)
else:
query_emb = self.model.encode(text=text)
return query_emb.tolist()[0]
def encode_image(self, image_path: str) -> list[float]:
with torch.no_grad():
query_emb = self.model.encode(image=image_path)
return query_emb.tolist()[0]
def visualize_results(
query_image_path: str,
retrieved_images: list,
img_height: int = 300,
img_width: int = 300,
row_count: int = 3,
) -> np.ndarray:
"""从检索到的图像列表创建一个全景图用于可视化。"""
panoramic_width = img_width * row_count
panoramic_height = img_height * row_count
panoramic_image = np.full(
(panoramic_height, panoramic_width, 3), 255, dtype=np.uint8
)
query_display_area = np.full((panoramic_height, img_width, 3), 255, dtype=np.uint8)
# 处理查询图像
if query_image_path:
query_pil = Image.open(query_image_path).convert("RGB")
else:
query_pil = Image.new("RGB", (img_width, img_height), color=(255, 255, 255))
query_cv = np.array(query_pil)[:, :, ::-1]
resized_query = cv2.resize(query_cv, (img_width, img_height))
bordered_query = cv2.copyMakeBorder(
resized_query, 10, 10, 10, 10, cv2.BORDER_CONSTANT, value=(255, 0, 0)
)
query_display_area[img_height * (row_count - 1) :, :] = cv2.resize(
bordered_query, (img_width, img_height)
)
cv2.putText(
query_display_area,
"Query",
(10, panoramic_height - 20),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(255, 0, 0),
2,
)
# 处理检索到的图像
for i, img_path in enumerate(retrieved_images):
row, col = i // row_count, i % row_count
start_row, start_col = row * img_height, col * img_width
retrieved_pil = Image.open(img_path).convert("RGB")
retrieved_cv = np.array(retrieved_pil)[:, :, ::-1]
resized_retrieved = cv2.resize(retrieved_cv, (img_width - 4, img_height - 4))
bordered_retrieved = cv2.copyMakeBorder(
resized_retrieved, 2, 2, 2, 2, cv2.BORDER_CONSTANT, value=(0, 0, 0)
)
panoramic_image[
start_row : start_row + img_height, start_col : start_col + img_width
] = bordered_retrieved
# 添加索引号
cv2.putText(
panoramic_image,
str(i),
(start_col + 10, start_row + 30),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(0, 0, 255),
2,
)
return np.hstack([query_display_area, panoramic_image])
# 3. 初始化客户端
print("--> 正在初始化编码器和Milvus客户端...")
encoder = Encoder(MODEL_NAME, MODEL_PATH)
milvus_client = MilvusClient(
uri=MILVUS_URI,
token=MILVUS_TOKEN,
)
# 4. 创建 Milvus Collection
print(f"\n--> 正在创建 Collection '{COLLECTION_NAME}'")
if milvus_client.has_collection(COLLECTION_NAME):
milvus_client.drop_collection(COLLECTION_NAME)
print(f"已删除已存在的 Collection: '{COLLECTION_NAME}'")
image_list = glob(os.path.join(DATA_DIR, "dragon", "*.png"))
ifnot image_list:
raise FileNotFoundError(f"在 {DATA_DIR}/dragon/ 中未找到任何 .png 图像。")
dim = len(encoder.encode_image(image_list[0]))
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=dim),
FieldSchema(name="image_path", dtype=DataType.VARCHAR, max_length=512),
]
# 创建集合 Schema
schema = CollectionSchema(fields, description="多模态图文检索")
print("Schema 结构:")
print(schema)
# 创建集合
milvus_client.create_collection(collection_name=COLLECTION_NAME, schema=schema)
print(f"成功创建 Collection: '{COLLECTION_NAME}'")
print("Collection 结构:")
print(milvus_client.describe_collection(collection_name=COLLECTION_NAME))
# 5. 准备并插入数据
print(f"\n--> 正在向 '{COLLECTION_NAME}' 插入数据")
data_to_insert = []
for image_path in tqdm(image_list, desc="生成图像嵌入"):
vector = encoder.encode_image(image_path)
data_to_insert.append({"vector": vector, "image_path": image_path})
if data_to_insert:
result = milvus_client.insert(collection_name=COLLECTION_NAME, data=data_to_insert)
print(f"成功插入 {result['insert_count']} 条数据。")
# 6. 创建索引
print(f"\n--> 正在为 '{COLLECTION_NAME}' 创建索引")
index_params = milvus_client.prepare_index_params()
index_params.add_index(
field_name="vector",
index_type="HNSW",
metric_type="COSINE",
params={"M": 16, "efConstruction": 256},
)
milvus_client.create_index(collection_name=COLLECTION_NAME, index_params=index_params)
print("成功为向量字段创建 HNSW 索引。")
print("索引详情:")
print(
milvus_client.describe_index(collection_name=COLLECTION_NAME, index_name="vector")
)
milvus_client.load_collection(collection_name=COLLECTION_NAME)
print("已加载 Collection 到内存中。")
# 7. 执行多模态检索
print(f"\n--> 正在 '{COLLECTION_NAME}' 中执行检索")
# query_image_path = os.path.join(DATA_DIR, "dragon", "query.png")
query_image_path = ""
query_text = "小奶龙"
query_vector = encoder.encode_query(image_path=query_image_path, text=query_text)
search_results = milvus_client.search(
collection_name=COLLECTION_NAME,
data=[query_vector],
output_fields=["image_path"],
limit=5,
search_params={"metric_type": "COSINE", "params": {"ef": 128}},
)[0]
retrieved_images = []
print("检索结果:")
for i, hit in enumerate(search_results):
print(
f" Top {i+1}: ID={hit['id']}, 距离={hit['distance']:.4f}, 路径='{hit['entity']['image_path']}'"
)
retrieved_images.append(hit["entity"]["image_path"])
# 8. 可视化与清理
print(f"\n--> 正在可视化结果并清理资源")
ifnot retrieved_images:
print("没有检索到任何图像。")
else:
panoramic_image = visualize_results(query_image_path, retrieved_images)
combined_image_path = os.path.join(DATA_DIR, "search_result.png")
cv2.imwrite(combined_image_path, panoramic_image)
print(f"结果图像已保存到: {combined_image_path}")
Image.open(combined_image_path).show()
# milvus_client.release_collection(collection_name=COLLECTION_NAME)
# print(f"已从内存中释放 Collection: '{COLLECTION_NAME}'")
# milvus_client.drop_collection(COLLECTION_NAME)
# print(f"已删除 Collection: '{COLLECTION_NAME}'")
如上代码,当我输入“小奶龙”,检索结果确实排名第一的图片是小奶龙的图片。
索引优化
在检索阶段存在一个略显纠结的问题,文本分块比较大的时候,语义信息会比分散或检索内容包含了无关内容,或者叫做上下文过载;文本分块比较小的时候,语义检索会比较精准,但是上下文关联信息可能会有缺失。
在这里提供了两种方式进行优化:上下文扩展、结构化索引
上下文扩展
主要思路就是,检索的时候按较小的分块 去检索精准内容,在生成之前再把检索内容的上下文带上,去调用大模型,从而可以满足精确检索与完整上下文的要求。
基本思路: 1、索引阶段,单个句子作为单个分块,然后再把上下N个句子进行关联。这样单个句子被索引,但是作为上下文的元数据不会被索引
2、检索阶段,按照单个句子的分块进行检索,可以很好的匹配语义相似度。
3、后处理阶段,在检索到相关单句后,读取该分块的上下文元数据,将上下文和单句进行拼接
4、将拼接的完整上下文,传递给大模型,进行最后的生成
结构化索引
当知识库下文档数量非常多的情况,有些文档内容可能还比较相似,这种情况下一个是数据量大,一个是存储相似内容干扰,检索效率就会大受影响
这个时候,可以采用结构化索引,比如存储文件名、作者可以进行分类的标签数据作为元数据,就可以按照这些分类进行范围筛选。
比如:查下2024年评分最高的电影 构建索引的时候,可以设置year元数据
这样检索的时候,可以先按year 2024筛选缩小范围,再去按向量检索2024下的电影数据。这种也适用于按年分库存储知识库数据的情况。
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线科技企业深耕十二载,见证过太多因技术卡位而跃迁的案例。那些率先拥抱 AI 的同事,早已在效率与薪资上形成代际优势,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在大模型的学习中的很多困惑。我们整理出这套 AI 大模型突围资料包:
- ✅ 从零到一的 AI 学习路径图
- ✅ 大模型调优实战手册(附医疗/金融等大厂真实案例)
- ✅ 百度/阿里专家闭门录播课
- ✅ 大模型当下最新行业报告
- ✅ 真实大厂面试真题
- ✅ 2025 最新岗位需求图谱
所有资料 ⚡️ ,朋友们如果有需要 《AI大模型入门+进阶学习资源包》,下方扫码获取~
① 全套AI大模型应用开发视频教程
(包含提示工程、RAG、LangChain、Agent、模型微调与部署、DeepSeek等技术点)
② 大模型系统化学习路线
作为学习AI大模型技术的新手,方向至关重要。 正确的学习路线可以为你节省时间,少走弯路;方向不对,努力白费。这里我给大家准备了一份最科学最系统的学习成长路线图和学习规划,带你从零基础入门到精通!
③ 大模型学习书籍&文档
学习AI大模型离不开书籍文档,我精选了一系列大模型技术的书籍和学习文档(电子版),它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。
④ AI大模型最新行业报告
2025最新行业报告,针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。
⑤ 大模型项目实战&配套源码
学以致用,在项目实战中检验和巩固你所学到的知识,同时为你找工作就业和职业发展打下坚实的基础。
⑥ 大模型大厂面试真题
面试不仅是技术的较量,更需要充分的准备。在你已经掌握了大模型技术之后,就需要开始准备面试,我精心整理了一份大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

以上资料如何领取?

为什么大家都在学大模型?
最近科技巨头英特尔宣布裁员2万人,传统岗位不断缩减,但AI相关技术岗疯狂扩招,有3-5年经验,大厂薪资就能给到50K*20薪!

不出1年,“有AI项目经验”将成为投递简历的门槛。
风口之下,与其像“温水煮青蛙”一样坐等被行业淘汰,不如先人一步,掌握AI大模型原理+应用技术+项目实操经验,“顺风”翻盘!

这些资料真的有用吗?
这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理,现任上海殷泊信息科技CEO,其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证,服务航天科工、国家电网等1000+企业,以第一作者在IEEE Transactions发表论文50+篇,获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。
资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的技术人员,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。

以上全套大模型资料如何领取?

更多推荐

所有评论(0)