Rag向量化是怎么实现的
核心实现原理:Embedding模型
向量化的实现,完全依赖于一个预训练好的深度学习模型,我们称之为Embedding模型。
这些模型通常是基于Transformer架构构建的,比如BERT、RoBERTa,以及现在更流行的专门为文本嵌入优化的模型,如Sentence-BERT、all-MiniLM、BGE (BAAI General Embedding) 等。
一个Embedding模型的内部工作原理可以简化为以下几个步骤:
-
文本预处理与分词 (Tokenization):
- 首先,输入的文本段落(Chunk)会被进行一些预处理,如转为小写、去除特殊符号等。
- 然后,通过一个分词器(Tokenizer),将文本切分成一个个的词元(Token)。这些词元可以是单词、子词(subword)甚至是字符。例如,“unbelievable”可能会被切分成“un”、“believ”和“able”。
-
输入表示 (Input Representation):
- 每个词元会被映射到一个固定维度的向量,这称为词嵌入(Word Embedding)。
- 除了词嵌入,模型还会加入位置嵌入(Positional Embedding)来表示每个词元在句子中的位置信息,以及段落嵌入(Segment Embedding)来区分不同的句子。
- 这些嵌入向量相加,构成了模型最终的输入表示。
-
编码器处理 (Encoder):
- 将准备好的输入表示,喂给一个深度神经网络编码器(通常是多层的Transformer Block)。
- 在编码器内部,通过自注意力机制(Self-Attention),模型能够捕捉到文本中词与词之间的复杂依赖关系和上下文信息。每个词元的表示会不断地与其他词元的表示进行交互和融合。
-
池化操作 (Pooling):
- 编码器会为输入序列中的每一个词元都生成一个上下文相关的向量表示。但我们需要的是一个能够代表整个文本段落的、固定大小的向量。
- 池化操作就是用来实现这个目的的。最常用的方法是平均池化(Mean Pooling),即将所有输出词元向量的对应维度取平均值,得到一个最终的句向量(Sentence Embedding)。
- 另一种方法是取
[CLS]这个特殊词元的输出向量作为整个句子的表示。
-
输出向量:
- 经过池化操作后,我们就得到了一个固定维度的、能够捕捉输入文本段落丰富语义信息的向量。这个向量,就是我们向量化的最终结果。这个向量的维度通常是几百到上千,比如384、768、1024等。
在RAG中的具体应用流程
在RAG系统中,向量化的实现流程通常如下:
-
选择Embedding模型: 首先,我们需要根据业务需求(语言、领域、性能要求)选择一个合适的Embedding模型。现在有很多开源的模型可供选择,比如Hugging Face上的
sentence-transformers/all-MiniLM-L6-v2(通用,速度快)或BAAI/bge-large-zh(中文效果好)。 -
对文档库进行离线向量化(Indexing):
- 我们将之前分好段的每一个文本块(Chunk)作为输入,批量地送入Embedding模型。
- 模型为每一个Chunk生成一个向量。
- 我们将每一个Chunk的原文、它的向量,以及一些元数据(如来源文件名、段落ID等),一起存储到一个专门的数据库中。这个数据库就是向量数据库(Vector Database),如FAISS, Milvus, Pinecone, ChromaDB等。
- 向量数据库会对这些向量构建高效的索引(如IVF-PQ、HNSW等),以支持后续的快速近似最近邻搜索。
-
对用户查询进行在线向量化(Querying):
- 当用户发起一个查询时,我们使用同一个Embedding模型,对用户的查询语句进行实时地向量化,得到一个查询向量(Query Vector)。
- 使用同一个模型至关重要,这保证了文档向量和查询向量是在同一个语义空间中,它们的相似度计算才有意义。
-
向量检索:
- 我们拿着这个查询向量,去向量数据库中进行搜索。
- 向量数据库会高效地计算查询向量与数据库中所有文档向量的相似度(通常是余弦相似度),并返回与查询向量最相似的Top-K个文档块。
这个过程,就是RAG中“检索(Retrieval)”环节的核心。通过向量化,我们将语义理解的问题,巧妙地转换成了一个在高维空间中寻找最近邻的几何问题,从而实现了高效、精准的语义检索。