什么是向量数据库?
向量数据库是专门用于存储、管理和检索高维向量数据的数据库系统。
基础:
①向量(Vector):将非结构化数据(文本、图像、音频、视频等)通过 Embedding 模型转换后的高维数值数组(例如 768 维、1536 维),每个维度代表数据的一个语义 / 特征属性。更通俗的说法,向量就是一个数字列表,例如:[12, 13, 19, 8, 9]。这些数字表示维度空间中的一个位置,代表在这个维度上的特征。量的距离越近,代表数据语义越相似。
②向量的数据表示: 由ID(唯一标识)、向量(数值表示)、有效负载(元数据)组成。
检索:
向量数据库使用专门的近似最近邻搜索算法来建立索引,极大地提高了搜索速度,同时牺牲一点精度以换取性能。
常见的索引算法有:
HNSW:一种基于图结构的、性能优异的流行算法。
IVF:通过聚类思想来缩小搜索范围。
PQ:通过量化技术压缩向量,减少内存占用和计算量。
相似度计算,衡量两个向量之间相似度的度量方法:
常见的包括:
余弦相似度:最常用,衡量向量方向上的差异,对向量的绝对大小不敏感。
欧氏距离:衡量向量在空间中的实际直线距离。
点积:也用于衡量相似性。
常见的检索应用场景:
语义搜索:用户不再需要输入精确的关键词。例如,搜索"会飞的哺乳动物",即使文章中没有这个词,数据库也能通过向量相似度找到关于"蝙蝠"的文章。
多模态检索:可以用一种类型的数据去搜索另一种类型的数据。例如,用一张狗的图片去搜索所有关于狗的文本描述。
推荐系统:找到与用户喜欢的内容在向量空间上最接近的其他物品。
异常检测:在金融或网络安全领域,异常行为的向量表示会与正常行为的向量集群相距甚远。
大语言模型的"记忆体":这是目前最火热的场景。LLM本身的知识有局限性且不会实时更新。通过向量数据库,可以为LLM提供外部的、私有的知识库。当用户提问时,先从向量数据库中检索出最相关的信息,再将这些信息作为上下文提供给LLM,从而得到更精准、可靠的回答。
向量数据库的工作流程:
入库流程 :
①非结构化数据分段
为什么要分段:
1. 大模型上下文窗口限制,太长无法处理
2. 大模型对长文本中边缘信息理解能力会下降(注意力分散)
3. 提升精度,长文本会存在语义模糊的问题,检索时匹配度更高(减少「答非所问」)
4. 降低嵌入模型的计算成本
②使用嵌入模型转换
嵌入式模型会影响什么
1. 精度,通常同系列嵌入模型,维度越高,精度越高,但过高的精度容易过拟合,维度灾难(距离饱和)
2. 存储空间,维度越高,所需的存储空间越大
3. 任务类型适配问题,不同的嵌入模型擅长方向有所差别
如何选择嵌入式模型
短文本检索(如商品、客服问答): 优先考虑轻量快速模型,如 MiniLM、DistilBERT
长文档处理(论文、法律文书):选择大上下文窗口模型,如 BGE-M3 (支持 8K tokens)
实时响应系统:必须选择推理速度快的模型 (如 bge-small 系列),牺牲部分精度换取性能
单语言中文: BGE-zh、ERNIE 等中文优化模型效果优于通用英文模型
多语言混合: BGE-M3 (支持 100 + 语言)、OpenAI text-embedding-3 多语言版是首选,词汇量需≥50k
混合数据(文本 + 结构化属性): BGE-M3 等支持结构化数据融合的模型更优
图像 / 音频: 必须选择 CLIP、MagicLens 等多模态模型
同时还要考虑 设备资源,有没有GPU
通用场景用 768 维,专业场景可升至 1024/1536 维(需优化 Milvus)
③ 将向量和元数据(内容,标题,页码等)一块存到向量数据库中
查询流程:
① 使用同样的嵌入模型将查询数据转化为向量
② 向量数据库进行相似度检索
③ 返回Top K相识向量数据(向量+元数据 相似度等)
向量数据库使用案例:
chromadb 增 删 改 查
import chromadb
import os
from langchain_huggingface import HuggingFaceEmbeddings
from chromadb.utils.embedding_functions import HuggingFaceEmbeddingFunction,SentenceTransformerEmbeddingFunction
embedding_model = HuggingFaceEmbeddings(
model_name=r"D:\MyWork\GitProject\LLM\my_llm\.model\embedding\bge-small-zh-v1.5",
model_kwargs={
"device": "cpu",
"trust_remote_code": True,
},
encode_kwargs={"normalize_embeddings": True},
)
custom_hf_ef = SentenceTransformerEmbeddingFunction(
model_name=r"D:\MyWork\GitProject\LLM\my_llm\.model\embedding\bge-small-zh-v1.5"
)
def chroma_demo():
chroma_client = chromadb.PersistentClient(
path="./.temp/chroma" # 数据会保存在当前目录的 chroma_memory_data 文件夹中
)
# chroma_client.delete_collection(name="my_collection")
collection_clent = chroma_client.get_or_create_collection(name="my_collection2",embedding_function=custom_hf_ef)
# embedding_function 指定嵌入函数,可以是自定义的函数,也可以是 HuggingFaceEmbeddings 实例
# 增
# 文档加载
list_documents = [
"中国大唐集团有限公司成立于2002年12月29日,是中央直接管理的国有特大型能源企业,承担着"三北"地区近9.3亿平方米供热任务。",
"在用户遵守本文件的前提下,海康威视授予用户关于本网站的有限的、不可转让的、非独占的、可撤销的、仅为合法及非商业性目的使用的权利。在任何情形下,本网站内容及服务仅被许可由用户本人使用而不得被出售或转让。",
"海康威视不能保证于本网站下向用户提供的服务是连续的、即时的、准确的,不能保证缺陷一定会被及时纠正,。"
]
metadatas =[{"type":"公司简介"},{"type":"海康威视"},{"type":"服务条款"}]
ids = ["id1", "id2","id3"]
embedding_results = embedding_model.embed_documents(list_documents)
add_result = collection_clent.add(
ids=ids, # 每条数据的「唯一标识」,可以是数字、字符串或其他类型
# embeddings = embedding_model.embed_documents(list_documents), # 向量数据. 如果创建集合时指定了 embedding_function,向量可以自动生成
metadatas = metadatas, # 元数据,元数据就是"描述数据的数据", 描述documents或uris
documents = list_documents # 向量对应的「原始文本」
# images = None, #向量对应的 图片数据 base64
# uris = None, # 向量对应的 链接列表,可选 本地路径或者二网络路径
)
# print(f'共添加{len(add_result)}条数据')
print(collection_clent.count())
pass
# 注意事项 如果填写embeddings 向量来源必须唯一 documents images uris 只能填一个,或者由embedding_function生成
# 如果创建集合时指定了 embedding_function,向量可以自动生成, 则不需要填写embeddings
'''********************************************************************************************************************'''
# 查
results = collection_clent.query(
query_embeddings=embedding_model.embed_documents(["海康威视"]), # 文本/图片等数据 向量化后
# query_texts
# query_images # query_embeddings/query_texts/query_images/query_uris 必须四选一
# query_uris # 非嵌入向量 需指定embedding_function
ids =["id2","id3"], # 精确查找 限定仅在指定 ID 集合中搜索(快速缩小查询范围)
n_results=2 , # 最多返回几条结果,默认10条
where={'type': '海康威视'}, # 按元数据过滤 过滤metadatas中, 大于小于等于,类似MongoDB 语法
where_document={'$contains': '不利影响'}, # 按文档内容过滤,documents, 全文搜索, 类似MongoDB 语法
# include # 包含哪些字段的元数据, 默认["metadatas", "documents", "distances"],可以包含向量
)
print(results)
'''********************************************************************************************************************'''
# 删
delete_result = collection_clent.delete(
ids=["id1", "id2"],
where ={"type": "公司简介"}, # 按元数据过滤 过滤metadatas中的数据,类似MongoDB 语法 {"$and": [{"tag": "test"}, {"score": {"$lt": 3}}]}
where_document ={"$contains": "废弃"},
# 至少填一个
)
'''********************************************************************************************************************'''
# 改
update_result = collection_clent.update(
ids=["id1", "id2"], # 必选
# embeddings 更新后的嵌入向量
# documents 更新后的原始文本
# images 更新后的图片数据 base64
# uris 更新后的链接列表
)
'''*'''
#获取全部
all_results = collection_clent.get
if __name__ == "__main__":
chroma_demo()