本期要点

  1. 初识向量数据库
  2. 案例引入,为什么需要有向量数据库
  3. 向量数据库的市场情况
  4. 向量数据库架构和实现
  5. 还有哪些应用场景
  6. 向量数据库的未来市场和技术展望

前置准备

什么是向量

类官方解释:向量是指在数学中具有一定大小和方向的量,文本、图片、音视频等非结构化数据, 通过机器学习/深度学习模型 Embedding 提取出来的“特征” 用数学中的向量来表示
与之相对应的,在机器学习领域,还有几个重要概念**(仅做对比了解)**

什么是特征向量

特征向量是包含事物重要特征的向量
例子1
大家比较熟知的一个特征向量是 RGB(红-绿-蓝)色彩,每种颜色都可以通过对红(R)、绿(G)、蓝(B)三种颜色的比例来得到,这样一个特征向量可以描述为:颜色 = [红,绿,蓝]。对于一个像素点,我们可以用数组 [255, 255, 255] 表示白色,用数组 [0, 0, 0] 表示黑色,这里 [255, 255, 255]、[0, 0, 0] 可以认为是该像素点的特征向量
例子2
如果我们想要区分小狗,很自然想到可以通过体型大小、毛发长度、鼻子长短等特征来区分。如下面这张照片按照体型排序,可以看到体型越大的狗越靠近坐标轴右边,这样就能得到一个体型特征的一维坐标和对应的数值,从 0 到 1 的数字中得到每只狗在坐标系中的位置

然而单靠一个体型大小的特征并不够,像照片中哈士奇、金毛和拉布拉多的体型就非常接近,我们无法区分。所以我们会继续观察其它的特征,例如毛发的长短

这样每只狗对应一个二维坐标点,我们就能轻易的将哈士奇、金毛和拉布拉多区分开来,如果这时仍然无法很好的区分德牧和罗威纳犬。我们就可以继续再从其它的特征区分,比如鼻子的长短,这样就能得到一个三维的坐标系和每只狗在三维坐标系中的位置

什么是Embedding

通过深度学习神经网络提取非结构化数据里的内容和语义,把图片、视频等变成特征向量,这个过程叫Embedding

LLM输出的向量化是怎样的

这里以豆包最新的Doubao-embedding/text-240715向量模型和OpenAI第三代嵌入式向量模型text-embedding-3-small为例:

相似度计算

相似性计算方法 方法说明
内积(IP) 全称为 Inner Product,是一种计算向量之间相似度的度量算法,它计算两个向量之间的点积(内积),所得值越大越与搜索值相似。
欧式距离(L2) 全称为 Euclidean distance,指欧几里得距离,它计算向量之间的直线距离,所得的值越小,越与搜索值相似。L2在低维空间中表现良好,但是在高维空间中,由于维度灾难的影响,L2的效果会逐渐变差。
余弦相似度(COSINE) 余弦相似度(Cosine Similarity)算法,是一种常用的文本相似度计算方法。它通过计算两个向量在多维空间中的夹角余弦值来衡量它们的相似程度。所得值越大越与搜索值相似

内积(IP)

比较适合处理未归一化的数据或关注数据的大小和方向时
其中,a = (a1, a2,..., an) 和 b = (b1, b2,..., bn) ,是 n 维空间中的两个点。计算所得值越大,越与搜索值相似

两个 Embedding 向量间的 IP 距离计算公式:

余弦相似度(COSINE)

余弦相似度使用两组向量之间的夹角余弦来衡量它们的相似程度。可以将这两组向量想象成从相同起点 ([0,0,...]) 开始但指向不同方向的两条线段

要计算两组向量 A = (a(0), a(1),..., a(n-1)) 和 B = (b(0), b(1),..., b(n-1)) 之间的余弦相似度,计算公式:

余弦相似度始终在区间 [-1, 1] 内。例如,两个成比例的向量的余弦相似度为 1,两个正交向量的相似度为 0,两个相反向量的相似度为 -1。余弦值越大,表示两个向量之间的夹角越小,表明这两个向量彼此更相似。

反过来:通过将它们的余弦相似度从 1 中减去,也就可以得到两个向量之间的余弦距离

场景引入

prompt优化无法解决问题?

在LLM的深入使用后,发现在某些场景prompt无论再怎样优化调教,仍然无法很好解决我们的问题,主要表现在

  • 知识落后:涉及比较新的知识,或者是些特定专业领域的知识,大语言模型没有学习过,无法给到我们想要的答案,比如GPT-3.5的知识库截止日期是2021年9月
  • 幻觉问题:大模型对于不了解的知识边界,对于欠缺知识的领域仍然尝试回答,容易造成错误回答(主打1个已读乱回),当然这主要也受引入**“zero-shot”和本身的“Decoder-Only”**的Transformer架构

    因此在这个问题背景下,业界提出了RAG(检索增强生成)技术

检索增强技术(RAG)

Meta BLog: Streamlining the creation of intelligent natural language processing models
检索增强生成(RAG)是一种利用附加数据增强 LLM 知识的技术,使其能够在生成响应之前引用训练数据来源之外的权威知识库。相当于给大语言模型装上**“知识外挂”**。而其内部知识的修改方式也很高效,不需要对整个模型进行重新训练
业界表现:RAG 在 Natural Questions(opens in a new tab)WebQuestions(opens in a new tab) 和 CuratedTrec 等基准测试中表现抢眼。用 MS-MARCO 和 Jeopardy 问题进行测试时,RAG 生成的答案更符合事实、更具体、更多样。FEVER 事实验证使用 RAG 后也得到了更好的结果

核心流程

这里基于LangChain实现一套RAG为例,LangChain是基于LLMs用于构建端到端语言模型应用的框架

  • 加载:首先我们需要加载数据。这是通过 DocumentLoaders 完成的
  • 分割:文本分割器将大文档分成更小的块。这对于索引数据和将其传递到模型都很有用,因为大块更难搜索并且不适合模型的有限上下文窗口
  • 向量化:基于分割后的文本进行向量化处理,以便模型更好处理识别和召回
  • 存储:我们需要某个地方来存储和索引我们的分割,以便以后可以搜索它们。这通常是使用 VectorStore 和 Embeddings 模型来完成的
  • 检索:给定用户输入,使用检索器从存储中检索相关分割
  • 生成:ChatModel / LLM 使用包含问题和检索到的数据的提示生成答案

模块实现

模块实现基于OpenAI最新API,国内大模型流程差不多

数据加载

基于langchain的Loader加载外部文件,如txt,当然也支持更多文本类型Loader,比如web链接的WebBaseLoader

# 基于TextLoader加载外部文档,如.txt
from langchain_community.document_loaders import TextLoader

loader = TextLoader("./data/clue_faq.txt",encoding="utf8")
faq = loader.load()

其中clue_faq.txt为清洗后的知识文档内容,比如

...
Q: 组件类型“智能电话”和“团购留资”是什么
A: "智能电话"是在留资组件中配置的商家联系电话、通过这种方式获取的线索会归类为智能电话,同样的,“团购留资”是指在团购中配置了“需要顾客留手机号”的订单上获取的客户联系电话
...
文本分割

文档内容都比较长,类似ES分词,我们需要对文档进行切分后再向量化,存入向量数据库便于搜索
这里基于RecursiveCharacterTextSplitter进行文本分割

Embedding

切分文本片段后,即可通过向量模型对文本进行向量化,LLMs基本都会提供对应的向量模型

这里选用OpenAI最新的text-embedding-3-small

from langchain.embeddings.openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
数据存储(VectorDB)

文档转成向量后,需要作为向量存储至VectorDB,这样后续问题搜索时会将问题向量化后再从数据库中匹配相似向量的文本片段作为回答,以弥补LLM的知识盲区
这里以Meta提供的相似性搜索库FAISS为例:

from langchain_community.vectorstores.faiss import FAISS

vectors = FAISS.from_documents(documents, embeddings)
数据检索

现在需要考虑如何将原先的问题与加载后的文档进行串联,这里会构造1个documents_chain

关于更多Chain使用 >>

from langchain_openai import ChatOpenAI
from langchain.chains.combine_documents import create_stuff_documents_chain

llm = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0.5
)

prompt_template = ChatPromptTemplate.from_template("""
基于以下相关资料回答我的问题.
## 相关资料
{context}

## 我的问题
问题:{input}
""")
document_chain = create_stuff_documents_chain(llm, prompt_template)

接下来的问题就是将向量数据库加入到检索流程

from langchain.chains import create_retrieval_chain

retriever = vectors.as_retriever()
# 创建新的调用链,为了将向量检索过程加入调用流中
rag_chain = create_retrieval_chain(retriever, document_chain)
result = rag_chain.invoke({"input": "在线索经营中,组件类型“团购留资”是什么."})
print(result["answer"])

最终,来看看加入向量模型后,模型回答后的结果

业内市场

市场产品

随着生成式人工智能(GAI)应用以及大语言模型(LLM)的快速发展,在向量数据库如火如荼的市场中,各个服务商纷纷也推出了各自的解决方案
数据库排名网站 DB-Engines 列出了常见的一些向量数据库,包括专用的向量数据库和基于传统数据库的扩展功能
而目前向量数据库本质上有三种形态:

  • 第一种是纯单机向量数据库,它不是分布式的(如上面提到的FAISS)
  • 第二种是在传统数据库上加上一个具备向量检索能力的插件(如postgreSQL、mongoDB等)
  • 第三种是独立的、专业的企业级向量数据库

各大厂商解决方案

腾讯云向量数据库自 2019 年开始内部研发,在今年不断升级和发展,多项核心性能得到提升,最高支持千亿级向量规模和 500 万 QPS 峰值能力,并与信通院一起联合 50 多家企业共同发布了国内首个向量数据库标准,推进向量数据库及大模型相关产业走向大规模应用。

阿里妈妈拥有自研的具有大规模、高性能、低成本且易开发优势的向量数据库 Dolphin VectorDB,在妈妈内容风控、营销知识问答、达摩盘人群 AI 圈人和 AI 经营分析师等场景中落地应用

|字节|产品概述--向量数据库VikingDB-火山引擎|
|亚马逊|什么是向量数据库_向量数据库解决方案 - 亚马逊云科技|
|阿里云|向量检索服务_向量搜索_大模型生成式检索_人工智能-阿里云|
|腾讯云|cloud.tencent.com|
|...|...|

Milvus介绍

目前主流的开源的向量数据库Chroma、Milvus、Qdrant、Weaviate,这里以Milvus(star:28.5k)的架构实现为例
未开源的推荐Pinecone,主打卖点:支持排名跟踪、复杂搜索、数据去重
还有更多选型也可参考:2024年精选推荐的16个向量数据库:提升你的AI应用性能 - 掘金
Milvus在机器学习和数据科学领域获得了很高的声誉,在向量索引和查询方面拥有出色的能力。同时也是 LF AI & Data 基金会 的毕业项目
利用功能强大的算法,Milvus提供闪电般的处理和数据检索速度以及GPU支持,即使在处理非常庞大的数据集时也是如此。
Milvus还可以与PyTorch和TensorFlow等其他流行的框架集成(当然也包括类似langChain这种LLM应用框架),从而允许将其添加到现有的机器学习工作流中

Milvus架构


Milvus 是一款云原生向量数据库,采用存储与计算分离的架构设计,所有组件均为无状态组件,极大地增强了系统弹性和灵活性。整个系统架构分为四个层面

  • 接入层(Access Layer)。系统的门面,由一组无状态 proxy 组成。对外提供用户连接的 endpoint,负责验证客户端请求并合并返回结果
  • 协调服务(Coordinator Service)。系统的大脑,负责分配任务给执行节点。协调服务共有四种角色,分别为 root coord、data coord、query coord 和 index coord
  • 执行节点(Worker Node)。系统的四肢,负责完成协调服务下发的指令和 proxy 发起的数据操作语言(DML)命令。执行节点分为三种角色,分别为 data node、query node 和 index node
  • 存储服务 (Storage)。系统的骨骼,负责 Milvus 数据的持久化,分为元数据存储(meta store)、消息存储(log broker)和对象存储(object storage)三个部分

操作对象

Database

与传统数据库引擎类似,可以在Milvus中创建数据库,并向某些用户分配权限来管理它们。其中一个 Milvus 集群最多支持 64 个数据库

from pymilvus import connections, db

conn = connections.connect(host="127.0.0.1", port=19530)

database = db.create_database("business_db")

Schema

字段模式是字段的逻辑定义。因此在定义集合模式和管理集合之前需要先给定各字段的逻辑定义

from pymilvus import FieldSchema

id_field = FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, description="primary id")
age_field = FieldSchema(name="age", dtype=DataType.INT64, description="age")
embedding_field = FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=128, description="vector")

position_field = FieldSchema(name="position", dtype=DataType.VARCHAR, max_length=256, is_partition_key=True)

定义完成字段模式后,接下来需要定义集合模式collection schema(类似Create Table DML)

from pymilvus import FieldSchema, CollectionSchema

...
# 设置collection schema 
schema = CollectionSchema(fields=[id_field, age_field, embedding_field], auto_id=False, enable_dynamic_field=True, description="desc of a collection")

Collections

生成的vector会嵌入存储在集合中。集合中的所有vector嵌入共享相同的维度和距离度量,从而用于测量相似性
在很多情况下大多数开发者没有过多的定制化诉求,只需要一个简单而动态的集合来开始,因此提供两种创建方式

  • 通过官方包 MilvusClient 创建。
  • 定制设置,也就是基于上面指定schema的方式
from pymilvus import MilvusClient, DataType

 # 实例化客户端,连接 Milvus 服务
 client = MilvusClient(
     uri="http://localhost:19530"
 )
 
 # 方式一:快速创建1个collection
 client.create_collection(
     collection_name="demo_v2",
     dimension=5
 )
 
 # 方式二: 定制设置
 # 1. 创建schema
 schema = MilvusClient.create_schema(
    auto_id=False,
    enable_dynamic_field=True,
)
# 2. 定义schema中的字段
schema.add_field(field_name="my_id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=5)
# 3. 创建集合
client.create_collection(
     collection_name="consult_faq",
     schema=schema,
     index_params=index_params
 )

Index

Milvus 提供多种索引类型来对字段值进行排序,以实现高效的相似性搜索。同时它还提供三种度量类型:余弦相似度 (COSINE)、欧几里得距离 (L2) 和内积 (IP)来测量向量嵌入之间的距离

索引类型
如何选型
索引类型 使用场景 适用向量规模 召回率 检索速度 写入速度
FLAT 暴力检索,召回率100%,但检索效率低。 10万以内 最高,可保证100%召回率
HNSW 基于图算法构建索引,可通过调整检索参数提升召回率。具体信息,请参见 配置索引参数。检索效率高,但数据量大后写入效率会变低 10万-1亿 95%+,可根据参数调整
IVF系列 基于聚类算法构建的索引,可通过参数调整召回率,适用于上亿规模的数据集,检索效率高,内存占用低,写入效率高。 1亿以上 95%+,可根据参数调整 快(批量写入后统一构建索引)
索引使用

索引参数决定 Milvus 如何组织集合中的数据。我们可以通过调整特定字段的 metric_typeindex_type 来设置特定字段的索引过程。对于矢量,可以灵活选择COSINEL2IP作为metric_type

# 1. 设置索引的参数
index_params = MilvusClient.prepare_index_params()

# 创建schema & collection(同Collection)
schema = MilvusClient.create_schema(
     auto_id=False,
     enable_dynamic_field=True,
)
schema.add_field(field_name="my_id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=5)
client.create_collection(
     collection_name="consult_faq",
     schema=schema,
     index_params=index_params
)
 
 # 2. 在向量字段 vector 上面添加一个索引
index_params.add_index(
    field_name="my_vector",
    metric_type="COSINE",
    index_type="IVF_FLAT",
    index_name="vector_index",
    params={ "nlist": 128 }
)
# 3. 为集合添加索引(类似向表加索引)
client.create_index(
    collection_name="consult_faq",
    index_params=index_params
)
# 4. 查看collection索引信息
 index_info = client.list_indexes(
     collection_name="consult_faq"
 )
变量索引分类
  • auto-index: Milvus 根据标量字段的数据类型自动决定索引类型。这适用于不需要控制具体索引类型的情况
    • 变量字段就是除 vector 字段,id 字段之外的字段。在 Milvus 中,标量索引用于加速特定非向量字段值的元过滤,可以理解为传统的数据库索引
  • custom-index: 可以指定明确的索引类型,比如倒排索引。这就提供了对索引的类型的更多选择
# 这里以自定义索引类型为例
index_params = client.create_index_params() 

#  准备一个 IndexParams 对象  
index_params.add_index(    
     field_name="scalar_1", # 标量字段名称     
     index_type="INVERTED", # 明确索引类型     
     index_name="inverted_index" # 索引的名称 
)  

client.create_index(   
    collection_name="consult_faq", # 将索引添加到集合中   
    index_params=index_params 
 )

Partitions

Milvus中的分区代表集合的子分区。此功能允许将集合的物理存储分为多个部分,通过将焦点缩小到较小的数据子集而不是整个集合,有助于提高查询性能。

创建集合后,至少会自动创建一个名为**_default的默认分区。您可以在一个集合中最多创建4,096**个分区

向量搜索

更多向量搜索api,参考官方文档: Search、Query&Get
结合以上操作对象,写入一批量数据后,就可以基于创建好的索引进行向量搜索
Milvus 支持两种类型的搜索,具体取决于集合中向量字段的数量

  • 单向量搜索:如果您的集合只有一个向量字段,请使用search()方法查找最相似的实体。此方法将您的查询向量与集合中的现有向量进行比较,并返回最接近匹配的 ID 以及它们之间的距离。或者,它还可以返回结果的向量值和元数据。
  • 多向量搜索:对于具有两个或多个向量场的集合,请使用hybrid_search()方法。此方法执行多个近似最近邻 (ANN) 搜索请求,并组合结果以在重新排名后返回最相关的匹配项
    这样可以实现应用场景中最常用的搜索诉求
  • 基本搜索:包括单向量搜索、批量向量搜索、分区搜索和指定输出字段搜索
  • 过滤搜索: 应用基于标量字段的过滤条件来细化搜索结果
  • 范围搜索: 查找距查询向量特定距离范围内的向量
  • 分组搜索: 根据特定字段对搜索结果进行分组,以确保结果的多样性
# 分区搜索:指定返回和过滤标量
res = client.search(    
        collection_name="consult_faq",        # 集合名称
        data=[[0.02174828545444263, 0.058611125483182924, 0.6168633415965343, -0.7944160935612321, 0.5554828317581426]],    # 关键字的vector,比如"灰色夹克"
        limit=5,                              # 返回的搜索结果最大数量,top5
        search_params={"metric_type": "IP", "params": {}},  # 相似性搜索的度量类型:IP(内积)
        partition_names=["partition_1"]       # 这里指定搜索的分区以缩小集合分区
        output_fields=["name_field"]          # 返回定义的字段
        filter='color like "gree%"'           # 模糊搜索过滤
)

应用场景

模型知识库

这个场景其实就是上面「场景引入」的经典应用场景,目前很多LLM的知识库应用无不都是基于VectorDB来实现RAG的,这里推荐几个github比较受欢迎的基于 LLM 大语言模型的开源知识库问答系统

名称 项目地址 star数
dify https://github.com/langgenius/dify (LLM应用开发平台,类似字节的扣子) 39.2k
FastGPT https://github.com/labring/FastGPT 15.8k
MaxKB https://github.com/1Panel-dev/MaxKB?tab=readme-ov-file 8.5k

推荐系统


得益于企业级向量数据库的快速发展,在系统推荐场景下主要应有

  • 搜索场景:试想下,在抖音搜索“灰色夹克”,得到的搜索结果基本都是与之相关的商品,结合向量的相似性搜索,推荐系统可以更好更准确地做信息推荐,这种比较适合推荐系统的冷启动阶段
    • 大致的实现方式,可以参考我以前实现的demo:colab地址
  • 用户推荐:将用户行为特征向量化存储在向量数据库。比如用户经常浏览数码产品,这种行为特征就可以作为特征向量。当发起推荐请求时,系统会基于用户特征进行相似度计算,最终筛选用户可能感兴趣的物品推荐给用户

文本图像检索

向量数据库可以存储大量的图像向量数据,并通过向量索引技术实现高效相似度计算,返回与检索图像最相似的图像结果

未来展望

** 现状 **
在国内,随着数字化转型的加速和人工智能应用的普及,对于高质量、高效率数据处理工具的需求日益旺盛。众多企业纷纷加大在人工智能领域的投入,加速推动了向量数据库在国内市场的发展。
融资规模

  • 23年4月,向量数据库平台 Pinecone 获得 1 亿美元 B 轮融资,估值达到 7.5 亿美元
  • 继 2023 年 4 月完成 750 万美元种子轮融资后,开源向量数据库公司 Qdrant 24年初完成 2800 万美元的 A 轮融资
  • Chroma 在23年4月宣布获得1800万美元的种子轮融资

市场展望

东北证券预测,到 2030 年,全球向量数据库市场规模有望达到 500 亿美元,国内向量数据库市场规模有望超 600 亿人民币
以 ChatGPT 为代表的生成式人工智能的快速发展,而模型的训练效果与数据源的质量和数量相关性愈发明显,因此数据成为 AIGC 应用产品的核心竞争壁垒之一和兵家必争之地
而向量数据库作为专门处理高维向量数据的重要工具,使得对于高效处理和存储大规模向量数据的需求急剧增加。各种新兴的应用场景,如计算机视觉、自然语言处理等领域,都对向量数据库的性能和功能提出了更高的要求,从而推动了市场规模的持续扩大

技术展望

随着AI技术的不断发展和大数据时代的来临,向量数据库将会迎来更多的应用场景和挑战(当然也是机会),这其中就包括

  • 扩展性:大模型的兴起,对嵌入(embedding)和向量化这些能力的需求急剧增加。大模型的普及也让向量数据的规模不断增大,从百万级别的数据体量已经变为千万级别,甚至更大。这就需要数据库能够有效地支持大规模向量数据的存储和检索,这对硬件资源提出了更高的要求,特别是在云上部署时成本可能成为一个重要问题
  • 成本问题:在向量搜索中,索引的大小和存储是关键因素,而向量索引的成本通常较高。以前在数据量较小的情况下,可能只需要几台机器就足够了,成本并不是关键问题。但随着数据规模的增大,需要更多的资源来支持,这就涉及到成本的考虑
  • 易用性问题:与传统的关系型数据库不同,向量搜索涉及到更多维度的考量,包括性能和召回率等。为了平衡性能和召回率,需要调整各种参数,但这可能对用户来说不太友好。因此,简化参数选择,优化用户体验是一个重要的挑战
    就以上问题,讨论比较多的优化方向
  • 边缘计算的支持:随着云计算和边缘计算的兴起,向量数据库也将会更加注重分布式处理和边缘计算的支持
  • 一体化趋势:特别在“降本增效”的大环境下,目前,出现了单机分布式一体化、在离线一体化、多模态一体化。一体化技术使得数据库具备更强的适应性,并且能极大地降低用户使用和运维管理的复杂度。尤其在多模态技术方向上,通过对非结构数据向量化,也实现了多样性的数据检索管理能力。还有就是通过整合不同的数据库技术,实现一体化管理,也可以提高数据得处理效率