大模型学习系列-Embedding与向量数据库

前言

作者:小蜗牛向前冲

名言:我可以接受失败,但我不能接受放弃

如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正

目录

一、Embedding

1、什么是Embedding

[2、从 N-Gram 到 TF-IDF](#2、从 N-Gram 到 TF-IDF)

[3、Gensim 工具](#3、Gensim 工具)

4、Embedding模型的选择

二、向量数据库

1、向量数据量

2、导入向量数据库


一、Embedding

1、什么是Embedding

在计算机的世界中,可以通过特定的编码将文字进行影视,知道了苹果,香蕉怎么去表示,但是对于计算机来说,不能理解苹果和香蕉是什么关系,是属于水果吗?为了表示这种关系,人们将苹果和香蕉,转换为向量,在通过计算余弦相似度,来确认二者的相似度,这种将代码,图片,文字转换为向量的过程称为Embedding。

其中A和B计算的结果越是接近于1,那么就关系越相近。

2、从 N-Gram 到 TF-IDF

N-Gram

n表示n个词,gram表示单词的意思,他是给一个句子,进行分词,通过分词找到规律,从而理解语句,进行预测。

比如:

它通过观察一段文本中连续出现的 N个词来预测下一个词。

  • Unigram (1-gram): 单个词,比如 ["我", "喜欢", "吃", "苹果"]。

  • Bigram (2-gram): 两个连续词,比如 ["我喜欢", "喜欢吃", "吃苹果"]。

  • Trigram (3-gram): 三个连续词,比如 ["我喜欢吃", "喜欢吃苹果"]。

逻辑很简单: 如果语料库里,"我喜欢吃"后面紧跟着"苹果"的频率远高于"手机",那么模型就会认为,"我喜欢吃"后面接"苹果"的概率更大。

CountVectorizer:词频统计

他将文本中的词语转换为词频矩阵,通过fit_transform: 计算各个词语出现的次数。简单来说就是在一个词表中统计,某个词出现的次数

TF-IDF:加了"过滤算法"的统计

为了解决 CountVectorizer 偏向于"高频词"的问题,TF-IDF 应运而生。它的名字直接揭示了它的逻辑:

TF:指这个词在词库中出现多少次数

IDF:指这个词出现的频率是怎么样的

一个词出现的次数多,TF就高,但是IDF就低

TF-IDF 的目的是通过调低那些到处都有的虚词的权重,极大地突出了文章的"核心特征词"

3、Gensim 工具

在python中Gensim 能把大量的文本数据"翻译"成计算机能理解的数学向量,并从中挖掘出隐藏的主题或语义关系。

bash 复制代码
//安装
pip install gensim

他支持TF-IDF, LDA, LSA, word2vec等多种主题模型算法

这里我们以word2vec模型的训练为例子

python 复制代码
# 先运行 word_seg进行中文分词,然后再进行word_similarity计算
# 将Word转换成Vec,然后计算相似度 
from gensim.models import word2vec
import multiprocessing

# 如果目录中有多个文件,可以使用PathLineSentences
segment_folder = './journey_to_the_west/segment'
# 切分之后的句子合集
sentences = word2vec.PathLineSentences(segment_folder)

# 设置模型参数,进行训练
model = word2vec.Word2Vec(sentences, vector_size=100, window=3, min_count=1)
#print(model.wv['孙悟空'])
print(model.wv.similarity('孙悟空', '猪八戒'))
print(model.wv.similarity('孙悟空', '孙行者'))
print(model.wv.most_similar(positive=['孙悟空', '唐僧'], negative=['孙行者']))
# 设置模型参数,进行训练
model2 = word2vec.Word2Vec(sentences, vector_size=128, window=5, min_count=5, workers=multiprocessing.cpu_count())
# 保存模型
model2.save('./models/word2Vec.model')
print(model2.wv.similarity('孙悟空', '猪八戒'))
print(model2.wv.similarity('孙悟空', '孙行者'))
print(model2.wv.most_similar(positive=['孙悟空', '唐僧'], negative=['孙行者']))

这里先给一个文件里面有大量语句,对这些语句进行分词,在将分好的给模型word2vcv训练,这样我们就能计算小说中的人物相似度, 比如孙悟空与猪八戒, 孙悟空与孙行者

相似度越是接近1就认为关系越相近。

4、Embedding模型的选择

Embedding模型将文本等离散数据转换为低维、稠密的向量,捕捉其语义信息。在训练的模型进行分词的时候,我们不需要自己去训练Embedding模型,可以直接在MTEB榜单中选择自己合适的模型。

MTEB (Massive Text Embedding Benchmark) 是一个全面的评测基准,它涵盖了分类、聚类、检索、排序等8大类任务和58个数据集。可以清晰地看到不同模型(如 BGE系列, GTE, Jina 等)在不同任务类型上的性能表现。

型选型是一个系统的过程,不能仅依赖于公开榜单。包括以下关键步骤:

• 明确业务场景与评估指标: 首先定义核心任务是检索、分类还是聚类?并确定衡量业务成功的关键指标,如

搜索召回率 (Recall@K)、准确率 (Accuracy) 或 NDCG。

• 构建"黄金"测试集: 准备一套能真实反映您业务场景和数据分布的高质量小规模测试集。

比如,构建一系列"问题-标准答案"对 => 评估模型好坏的"金标准"。

• 小范围对比测试 (Benchmark): 从MTEB榜单中挑选几款排名靠前且符合需求(如语言、维度)的候选模型。使用 "黄金"测试集,对这些模型进行评测

二、向量数据库

1、向量数据量

对于大模型,前面的Emdedding模型解决,让模型理解文字,图片,代码的能力,但是理解这些的基础,是自己有足够的知识库,那这些知识是怎么存储,这些都是非结构化的,不能像一些结构化的数据可以存入MYSQL等数据库,于是就有了向量数据库。
向量数据库用于存储和查询 由非结构化数据(如文本、图片、音视频)转化而来 的高维向量嵌入(Embeddings )。 这些向量在多维空间中的距离代表了原始数据的语义相似度。
常见的向量数据库

1. FAISS
特点:由 Facebook 开发,专注于高性能的相似性搜索,
适合大规模静态数据集。
优势:检索速度快,支持多种索引类型。
局限性:主要用于静态数据,更新和删除操作较复杂。
2. Elasticsearch
特点: 强大的分布式搜索和分析引擎,将向量搜索
( k-NN )作为其众多功能之一。
优势:具备业界领先的混合搜索能力,可以无缝结合
传统的关键词搜索和向量语义搜索。
3. Milvus
特点:开源,支持分布式架构和动态数据更新。
优势:具备强大的扩展性和灵活的数据管理功能。
4. Pinecone
特点:托管的云原生向量数据库,支持高性能的向量搜索。
优势:完全托管,易于部署,适合大规模生产环境。

2、导入向量数据库

那如何将Emdedding处理好的高纬度向量导入到向量数据库中呢?直接像传统数据库调用insert的接口吗?

1、数据清洗与准备
确保原始数据(如文本文档、图片)的质量,进行必要的预处理。
2、 数据向量化(Embedding)
使用预训练的 Embedding Model 将原始数据转换成向量。
文本: 可使用 bge-m, Qwen3-Embedding, Jina-Embedding 等模型。
图片: 可使用 CLIP, ResNet 等模型。
选择合适的模型至关重要, 它直接决定了向量的质量和后续检索的效果。
3、 数据与元数据一同导入
在存放向量数据库的时候,不仅仅要把Embedding生成向量导入。还要将元数据一起导入
唯一iD: 用于唯一标识每个数据点,方便后续的更新或删除。
**元数据:**描述向量的附加信息,是实现高级检索的关键。
例如:
文本来源的文件名、章节、 URL
商品的类别、品牌、价格
图片的创建日期、作者

这里先用embedding计算文字的向量

python 复制代码
import os
from openai import OpenAI

client = OpenAI(
    api_key="sk-1253a03c92644575a6c5d158353ba312",  # 如果您没有配置环境变量,请在此处用您的API Key进行替换
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"  # 百炼服务的base_url
)

completion = client.embeddings.create(
    model="text-embedding-v4",
    input='我想知道迪士尼的退票政策',
    dimensions=1024, # 指定向量维度(仅 text-embedding-v3及 text-embedding-v4支持该参数)
    encoding_format="float"
)

print(completion.model_dump_json())

这里演示通过导入FAISS

但是对于FAISS数据库本身只提供存储和检索向量,所以我们需要在在 FAISS 之外维护一个元数据的"查找表",并通过向量在 FAISS 中的唯一ID将两者关联起来。
最直接有效的方法是使用 FAISS 的 IndexIDMap => 允许我们为每个向量指定一个自定义的、唯一的 64 位整数 ID 。 然后,可以用这个ID 作为元数据存储的键。

python 复制代码
import os
import numpy as np
import faiss
from openai import OpenAI

# Step1. 初始化 API 客户端
try:
    client = OpenAI(
        api_key="sk-1253a03c92644575a6c5d158353ba312",
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
    )
except Exception as e:
    print("初始化OpenAI客户端失败,请检查环境变量'DASHSCOPE_API_KEY'是否已设置。")
    print(f"错误信息: {e}")
    exit()

# Step2. 准备示例文本和元数据
# 在实际应用中,这些数据可能来自数据库、文件等
documents = [
    {
        "id": "doc1",
        "text": "迪士尼乐园的门票一经售出,原则上不予退换。但在特殊情况下,如恶劣天气导致园区关闭,可在官方指引下进行改期或退款。",
        "metadata": {"source": "official_faq_v1.pdf", "category": "退票政策", "author": "Admin"}
    },
    {
        "id": "doc2",
        "text": "购买"奇妙年卡"的用户,可以享受一年内多次入园的特权,并且在餐饮和购物时有折扣。",
        "metadata": {"source": "annual_pass_rules.docx", "category": "会员权益", "author": "MarketingDept"}
    },
    {
        "id": "doc3",
        "text": "对于在线购买的迪士尼门票,如果需要退票,必须在票面日期前48小时通过原购买渠道提交申请,并可能收取手续费。",
        "metadata": {"source": "online_policy.html", "category": "退票政策", "author": "E-commerceTeam"}
    },
    {
        "id": "doc4",
        "text": "园区内的"加勒比海盗"项目因年度维护,将于下周暂停开放。",
        "metadata": {"source": "maintenance_notice.txt", "category": "园区公告", "author": "OpsDept"}
    }
]

# Step3. 创建元数据存储和向量列表
# 我们使用一个简单的列表来存储元数据。列表的索引将作为FAISS的ID。
# 这种方式简单直接,适用于中小型数据集。
# 对于大型数据集,可以考虑使用字典或数据库(如Redis, SQLite)
metadata_store = []
vectors_list = []
vector_ids = []

print("正在为文档生成向量...")
for i, doc in enumerate(documents):
    try:
        # 调用API生成向量
        completion = client.embeddings.create(
            model="text-embedding-v4",
            input=doc["text"],
            dimensions=1024,
            encoding_format="float"
        )
        
        # 获取向量
        vector = completion.data[0].embedding
        vectors_list.append(vector)
        
        # 存储元数据,并使用列表索引作为唯一ID
        metadata_store.append(doc)
        vector_ids.append(i) # 自定义ID与列表索引一致
        
        print(f"  - 已处理文档 {i+1}/{len(documents)}")

    except Exception as e:
        print(f"处理文档 '{doc['id']}' 时出错: {e}")
        continue

# 将向量列表转换为NumPy数组,FAISS需要这种格式
vectors_np = np.array(vectors_list).astype('float32')
vector_ids_np = np.array(vector_ids)

# Step4. 构建并填充 FAISS 索引
dimension = 1024  # 向量维度
k = 3             # 查找最近的3个邻居

# 创建一个基础的L2距离索引
index_flat_l2 = faiss.IndexFlatL2(dimension)

# 使用IndexIDMap来包装基础索引,能够映射我们自定义的ID
# 这就是关联向量和元数据的关键!
index = faiss.IndexIDMap(index_flat_l2)

# 将向量和它们对应的ID添加到索引中
index.add_with_ids(vectors_np, vector_ids_np)

print(f"\nFAISS 索引已成功创建,共包含 {index.ntotal} 个向量。")


# Step5. 执行搜索并检索元数据
query_text = "我想了解一下迪士尼门票的退款流程"
print(f"\n正在为查询文本生成向量: '{query_text}'")

try:
    # 为查询文本生成向量
    query_completion = client.embeddings.create(
        model="text-embedding-v4",
        input=query_text,
        dimensions=1024,
        encoding_format="float"
    )
    query_vector = np.array([query_completion.data[0].embedding]).astype('float32')

    # 在FAISS索引中执行搜索
    # search方法返回两个NumPy数组:
    # D: 距离 (distances)
    # I: 索引/ID (indices/IDs)
    distances, retrieved_ids = index.search(query_vector, k)

    # Step6. 展示结果
    print("\n--- 搜索结果 ---")
    # `retrieved_ids[0]` 包含与查询最相似的k个向量的ID
    for i in range(k):
        doc_id = retrieved_ids[0][i]
        
        # 检查ID是否有效
        if doc_id == -1:
            print(f"\n排名 {i+1}: 未找到更多结果。")
            continue

        # 使用ID从我们的元数据存储中检索信息
        retrieved_doc = metadata_store[doc_id]
        
        print(f"\n--- 排名 {i+1} (相似度得分/距离: {distances[0][i]:.4f}) ---")
        print(f"ID: {doc_id}")
        print(f"原始文本: {retrieved_doc['text']}")
        print(f"元数据: {retrieved_doc['metadata']}")

except Exception as e:
    print(f"执行搜索时发生错误: {e}")

导入总结:

1、准备好数据,文本,元数据

2、把数据生成向量

3、创建元数据存储,Python中可以用列表,列表的索引当做唯一ID。在某些场景一下,可以将列表换为键值数据库(如 Redis)或者关系型数据库(如 PostgreSQL)或者文档数据库(如 MongoDB)。

4、创建FAISSS索引:
•用faiss.indexFlatL2创建一个基础的索引 => 这里使用L2距离(欧氏距离)进行精确搜索.
• 用 faiss.IndexIDMap 将基础索引包装起来 => 这样就可以添加带有自定义ID的向量了.
5、添加数据到索引:将生成的向量和对应的ID(即元数据列表的索引)添加到 IndexIDMap 中。
6、执行搜索:
• 对一个新的查询文本生成向量。
• 在 FAISS 索引中搜索最相似的向量。
• FAISS 会返回最相似向量的ID。
7、检索元数据:使用返回的ID,从元数据存储中查找到原始文本和元数据。

相关推荐
MediaTea2 小时前
Python:词频统计流程及综合示例
开发语言·python
敬业小码哥2 小时前
记一次:clion使用rust插件配置环境并开发
学习·rust
未来之窗软件服务2 小时前
vosk-ASR php调用[AI人工智能(四十九)]—东方仙盟
人工智能·仙盟创梦ide·东方仙盟
LucianaiB2 小时前
从基础配置到架构设计:JiuwenClaw 日报生成器开发实践
人工智能·ai·腾讯云·保姆级·opencalw
华科易迅2 小时前
SQL学习
java·sql·学习
Wu_Dylan2 小时前
液态神经网络系列(七) | 事件驱动与可变步长:把“稀疏计算”做到极致
人工智能·深度学习·神经网络
Swift社区2 小时前
AI 时代,ArkUI 的设计模式会改变吗?
人工智能·设计模式
心疼你的一切2 小时前
【Unity-MCP完全指南:从零开始构建AI游戏开发助手】
人工智能·unity·ai·游戏引擎·aigc·mcp
_李小白2 小时前
【AI大模型学习笔记之平台篇】第三篇:Minimax
人工智能·笔记·学习