游乐游手机版
首页/AI教程/文章详情

LangChain实战:向量嵌入与语义表示

时间:2026-06-01 06:33
向量嵌入将文本映射为数值向量,实现语义检索。LangChain提供统一接口,对接OpenAI、HuggingFace等模型,支持本地部署BGE、text2vec等中文模型。嵌入维度与余弦相似度是影响检索精度的关键参数,常用余弦相似度衡量向量距离。

在LangChain生态系统中,向量嵌入(Embedding)是所有语义检索与智能问答应用的基础设施。无论你是构建RAG系统、开发问答机器人,还是对文本进行分类管理,底层都依赖这项技术——它负责将人类语言转化为机器可计算的数值向量。本章将从最基础的概念入手,逐步带你掌握如何对接各类嵌入模型、在本地环境中部署运行、以及优化性能与评估质量。最后,我们会通过一个完整的实战案例,将技术文档转化为高质量的向量表示。所有代码均可直接复制运行,新手也能轻松跟上。

第8章 向量嵌入与语义表示(LangChain实战)

8.1 什么是 Embedding?为何用于检索?

8.1.1 核心定义:文本的“数值身份证”

Embedding(嵌入)技术的本质是一种“语义编码器”。它可以将任何文本——无论是单词、句子还是整篇文档——映射到一个密集的数值向量空间中。在这个向量空间中,语义越相似的文本,它们的向量距离就越近。

举个直观的例子:

  • “猫”的向量可能是 [0.82, -0.15, 0.33, ..., 0.21]

  • “狗”的向量可能是 [0.79, -0.18, 0.31, ..., 0.23]

  • “苹果”的向量可能是 [-0.22, 0.85, -0.17, ..., 0.09]

你可以看到,“猫”和“狗”这两个向量在空间中距离很近,因为它们语义相似(都是动物);而它们与“苹果”的向量则相隔很远,因为语义毫无关联。这就是Embedding的核心价值:将抽象的“语义”转化为可计算的数值。

8.1.2 为何用于检索?秒杀传统关键词检索

传统的关键词检索,比如MySQL中的like查询,存在一个明显缺陷:它只匹配字面相同的词,完全无法理解语义相似性。例如,当你搜索“如何用LangChain做RAG”时,它可能无法找到“LangChain搭建检索增强生成系统”这篇文章,因为字面不同。但Embedding检索可以,因为这两句话语义高度一致。

那么,Embedding是如何工作的呢?流程非常清晰:

  1. 提前将所有文档转换为嵌入向量,并存储在向量数据库中;

  2. 用户提交查询时,先将问题也转换成嵌入向量;

  3. 然后计算查询向量与数据库中所有文档向量的“距离”,最后返回距离最近的几篇文档作为结果。

这其实就是LangChain中RAG的核心流程之一。Embedding就像一个桥梁,连接了人类语言与机器的检索能力。

8.1.3 关键提醒

有一点需要先说明:LangChain本身不生产嵌入模型,它更像一个“集成平台”。它提供统一的接口,让你可以轻松对接OpenAI、Hugging Face、甚至是本地运行的各种模型。开发者无需关心不同模型的调用细节,更换模型通常只需修改一行代码。

8.2 使用 OpenAI、Hugging Face、Sentence-Transformers 生成嵌入

本节聚焦最常用的三种嵌入方式。代码精简到最少,可直接复制运行,依赖安装和参考来源也一并给出。

8.2.1 准备工作:安装核心依赖

无论使用哪种模型,先安装基础工具:

pip install langchain# 核心框架pip install python-dotenv# 管理环境变量(用于存储API密钥)

8.2.2 OpenAI Embeddings(最常用,精度高)

OpenAI的嵌入模型,例如text-embedding-ada-002,性价比很高,是生产环境中的热门选择。当然,你需要准备好OpenAI的API密钥。

代码示例(简短可运行)

from langchain.embeddings.openai import OpenAIEmbeddingsfrom dotenv import load_dotenvimport os

# 加载环境变量(.env文件中存OPENAI_API_KEY=你的密钥)load_dotenv()

# 初始化OpenAI嵌入模型embeddings = OpenAIEmbeddings(model="text-embedding-ada-002",# 推荐模型,性价比最高openai_api_key=os.getenv("OPENAI_API_KEY"))

# 生成单句嵌入text = "LangChain向量嵌入实战"embedding = embeddings.embed_query(text)# 检索时用embed_query,文档用embed_documentsprint(f"嵌入向量维度:{len(embedding)}")# 输出1536(ada-002固定维度)print(f"嵌入向量前5位:{embedding[:5]}")

关键说明

  • embed_query 专门用于生成“用户查询”的嵌入,会针对检索精度做优化;

  • embed_documents 则用于生成“文档”的嵌入;

  • 需要额外安装 openai 包(pip install openai)。

8.2.3 Hugging Face Embeddings(开源免费)

Hugging Face上有大量免费的开源嵌入模型,例如all-MiniLM-L6-v2,无需API密钥,非常适合本地开发或预算有限的场景。

代码示例

from langchain.embeddings import HuggingFaceEmbeddings

# 初始化Hugging Face嵌入模型(会自动下载模型)embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2",# 轻量模型,速度快,适合入门model_kwargs={"device": "cpu"},# 如果有GPU,改成"cuda"encode_kwargs={"normalize_embeddings": True}# 归一化,提升检索精度)

# 批量生成文档嵌入texts = ["LangChain是一个大模型开发框架","Embedding用于将文本转为向量","Hugging Face提供开源嵌入模型"]embeddings_list = embeddings.embed_documents(texts)print(f"批量生成{len(embeddings_list)}个嵌入,每个维度:{len(embeddings_list[0])}")

关键说明

  • 需要先安装 sentence-transformers 包(pip install sentence-transformers);

  • model_name 可以换成其他模型,例如 all-MiniLM-L12-v2,精度更高但速度会稍慢。

8.2.4 Sentence-Transformers(专注句子嵌入)

Sentence-Transformers库专门用于句子或段落级别的嵌入。LangChain也提供了专门的接口,本质上是将Hugging Face的模型封装了一层,使用起来更简洁。

代码示例

from langchain.embeddings.sentence_transformer import SentenceTransformerEmbeddings

# 初始化Sentence-Transformers嵌入模型embeddings = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2")

# 生成单句嵌入text = "Sentence-Transformers专注于句子语义嵌入"embedding = embeddings.embed_query(text)print(f"嵌入向量维度:{len(embedding)}")

关键说明

与直接使用HuggingFaceEmbeddings相比,SentenceTransformerEmbeddings的接口更清爽,默认已做归一化,省去了额外设置。对于句子级嵌入任务,这是一个不错的选择。

8.3 本地嵌入模型部署(BGE、text2vec)

在某些场景下,数据非常敏感,不能传输到第三方API,或者需要离线运行,此时本地部署一个嵌入模型是最佳选择。这里重点介绍两个对中文特别友好的模型:BGE(中文检索效果公认优秀)和text2vec(轻量且高效),它们都可以通过LangChain在本地运行。

8.3.1 本地部署核心前提

  • 环境:Python 3.8及以上,建议安装PyTorch(CPU即可,有GPU会更快);

  • 依赖:一行命令搞定——pip install sentence-transformers torch

  • 模型获取:首次运行时会自动下载(几百MB到几个GB不等),也可以从Hugging Face手动下载后本地加载。

8.3.2 BGE模型部署(中文首选)

BGE(BAAI General Embedding)是由智源AI开发的开源嵌入模型,中文语义理解能力强,支持长文本(最长8192个token),在中文RAG场景中位列首选。推荐直接使用BGE-M3版本。

代码示例(本地加载)

from langchain.embeddings import HuggingFaceEmbeddings

# 本地部署BGE-M3(会自动下载,首次较慢)embeddings = HuggingFaceEmbeddings(model_name="FlagAI-Open/BGE-M3",model_kwargs={"device": "cpu",# 若有GPU,替换为"cuda""trust_remote_code": True# 必须为True,因为BGE包含自定义代码},encode_kwargs={"normalize_embeddings": True,# 记得归一化,否则相似度计算不准确"max_length": 8192# BGE-M3支持长文本,根据需要调整})

# 测试中文嵌入text = "LangChain本地部署BGE嵌入模型"embedding = embeddings.embed_query(text)print(f"BGE-M3嵌入维度:{len(embedding)}")# 输出1024维print(f"嵌入向量前5位:{embedding[:5]}")

关键说明

  • 模型版本:BGE-M3是最新版本,推荐使用;还有BGE-base-zh,更轻量,适合算力有限的设备。

  • GPU加速:如果安装了PyTorch-GPU版本,将device改为"cuda",生成速度可提升5到10倍。

  • 本地加载:若想将模型下载到本地使用,可将model_name替换为本地路径(例如"./BGE-M3"),避免每次重新下载。

8.3.3 text2vec模型部署(轻量高效)

text2vec是专为中文设计的轻量级嵌入模型,体积小(约100MB),速度快,在笔记本CPU上也能流畅运行,日常开发完全够用。

代码示例

from langchain.embeddings import HuggingFaceEmbeddings

# 本地部署text2vec模型embeddings = HuggingFaceEmbeddings(model_name="shibing624/text2vec-base-chinese",model_kwargs={"device": "cpu"},encode_kwargs={"normalize_embeddings": True})

# 测试中文嵌入texts = ["text2vec轻量高效", "中文嵌入模型推荐"]embeddings_list = embeddings.embed_documents(texts)print(f"text2vec嵌入维度:{len(embeddings_list[0])}")# 输出768维

关键说明

  • 它的优势是体积小、速度快,在CPU上也能快速完成嵌入。
  • 特别适合中小规模的中文文档检索或本地Demo开发。

8.4 嵌入维度、距离度量(余弦相似度)

生成嵌入后,有两个概念必须理解:一个是“嵌入维度”(向量的长度),另一个是“距离度量”(如何判断两个向量相似)——这两者直接决定了最终的检索精度。

8.4.1 嵌入维度:向量的“长度”

核心定义

嵌入维度,即生成的向量中包含多少个数值。例如ada-002有1536维,BGE-M3有1024维。通常,维度越高,能够承载的语义信息越丰富,但计算和存储成本也相应增加。

主流模型维度对比(重点记)

模型名称嵌入维度特点
OpenAI text-embedding-ada-0021536通用、精度高、性价比高
BGE-M31024中文最优、支持长文本
all-MiniLM-L6-v2384轻量、速度快、适合入门
text2vec-base-chinese768中文轻量、平衡精度与速度

维度选择建议

  • 生产环境(通用场景):优先选1024到1536维,如BGE-M3或ada-002,精度足够。

  • 本地Demo、低算力设备:选384到768维,如all-MiniLM-L6-v2或text2vec。

  • 注意:维度并非越高越好,超出一定范围后,精度提升不明显,反而增加成本。

8.4.2 距离度量:判断语义相似的“标尺”

距离度量用于计算两个向量之间的“距离”,距离越近,语义越相似。在LangChain中,最常用且最推荐的是“余弦相似度”。此外还有欧氏距离、曼哈顿距离等。

余弦相似度(重点)

余弦相似度衡量的是两个向量之间的“夹角”。取值范围在-1到1之间。

  • 等于1:方向完全一致,可理解为语义完全相同;

  • 等于0:方向垂直,语义上毫无关系;

  • 等于-1:方向完全相反,语义上就是反义词。

在文本检索中,通常只关心正数。一般来说,相似度超过0.7,就可以认为两个文本语义高度相关。

LangChain中计算余弦相似度(代码示例)

from langchain.embeddings import HuggingFaceEmbeddingsfrom sklearn.metrics.pairwise import cosine_similarityimport numpy as np

# 初始化嵌入模型embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")

# 生成两个文本的嵌入向量text1 = "LangChain向量嵌入"text2 = "LangChain Embedding实战"vec1 = np.array(embeddings.embed_query(text1)).reshape(1, -1)vec2 = np.array(embeddings.embed_query(text2)).reshape(1, -1)

# 计算余弦相似度similarity = cosine_similarity(vec1, vec2)[0][0]print(f"两个文本的余弦相似度:{similarity:.4f}")# 输出约0.8+,高度相关

关键说明

  • 需要安装 scikit-learn 包(pip install scikit-learn)。

  • 实际使用中,像Chroma、FAISS这样的向量数据库会自动计算余弦相似度,无需手动编写。

  • 选择余弦相似度的原因是它不受向量“长度”影响,只关注方向。这对文本语义匹配非常合适,例如长句子和短句子,只要语义相似,相似度就会很高。

8.5 缓存嵌入结果避免重复计算

生成嵌入,尤其是调用API或在本地大型模型上推理,非常耗费时间和资源。如果同一文本反复生成,会造成极大浪费。LangChain提供了内置的缓存机制,可以有效避免重复劳动,提升效率。

8.5.1 两种常用缓存方式

LangChain支持多种缓存,这里重点介绍两种:内存缓存,适合临时开发;SQLite缓存,可持久化,程序重启后缓存仍在,适合长期项目。

方式1:内存缓存(InMemoryCache)

缓存存储在内存中,程序重启即消失。适合临时测试或短期开发。

from langchain.embeddings import OpenAIEmbeddingsfrom langchain.cache import InMemoryCacheimport langchainfrom dotenv import load_dotenv

load_dotenv()

# 启用内存缓存langchain.llm_cache = InMemoryCache()

# 初始化OpenAI嵌入模型embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")

# 第一次生成(会调用API)text = "LangChain缓存嵌入实战"emb1 = embeddings.embed_query(text)print("第一次生成:完成")

# 第二次生成同样的文本(从缓存读,不调API了)emb2 = embeddings.embed_query(text)print("第二次生成:完成(从缓存读取)")

# 看看两次结果是否一样print(f"两次嵌入是否相同:{emb1 == emb2}")# 输出True

方式2:SQLite缓存(SQLiteCache)

缓存存储在本地SQLite数据库文件中,程序重启后依然存在。适合长期开发或生产环境使用。

from langchain.embeddings import OpenAIEmbeddingsfrom langchain.cache import SQLiteCacheimport langchainfrom dotenv import load_dotenv

load_dotenv()

# 启用SQLite缓存(缓存文件放在当前目录下的langchain_cache.db)langchain.llm_cache = SQLiteCache(database_path="./langchain_cache.db")

# 初始化嵌入模型embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")

# 第二次同样从缓存读取text = "LangChain SQLite缓存"emb1 = embeddings.embed_query(text)emb2 = embeddings.embed_query(text)print(f"两次嵌入是否相同:{emb1 == emb2}")# 输出True

8.5.2 关键提醒

  • 缓存生效的条件:文本必须完全一致,包括空格和大小写,否则会被视为新文本重新生成。

  • 除了以上两种,LangChain还支持Redis缓存,适用于分布式系统,用法类似。

8.6 批量嵌入与性能优化

当需要处理大量文本(例如成千上万篇文档)时,逐篇生成嵌入显然效率低下。LangChain支持批量嵌入,结合一些性能优化技巧,可以大幅提升处理效率。这是大型文档检索场景的必备技能。

8.6.1 批量嵌入(核心操作)

所有LangChain嵌入模型都支持embed_documents方法,只需传入一批文本,即可一次性批量生成嵌入。这比逐条处理快5到10倍。

from langchain.embeddings import HuggingFaceEmbeddings

# 初始化嵌入模型embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")

# 模拟100条文本,批量处理texts = [f"LangChain批量嵌入测试{i}" for i in range(100)]

# 一次调用,搞定所有batch_embeddings = embeddings.embed_documents(texts)print(f"批量生成{len(batch_embeddings)}个嵌入,每个维度:{len(batch_embeddings[0])}")

8.6.2 性能优化技巧(实战必备)

技巧1:控制批量大小

批量大小并非越大越好,需根据模型和硬件调整:

  • API模型(OpenAI):建议一次10到100条,避免被限流。

  • 本地模型(BGE、text2vec):CPU上建议32到64条;GPU上可到64到128条,具体看显存和内存。

技巧2:异步调用(提升并发效率)

LangChain的嵌入模型支持异步调用(ainvoke)。处理大量文本时,可以在等待I/O的同时执行其他任务,大幅提高并发效率,特别适用于Web服务等场景。

from langchain.embeddings import OpenAIEmbeddingsimport asynciofrom dotenv import load_dotenv

load_dotenv()

# 初始化嵌入模型embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")

# 定义一个异步函数来批量生成async def async_batch_embed():texts = [f"异步嵌入测试{i}" for i in range(50)]# 注意是aembed_documentsbatch_embeddings = await embeddings.aembed_documents(texts)return batch_embeddings

# 运行它if __name__ == "__main__":embeddings_list = asyncio.run(async_batch_embed())print(f"异步批量生成{len(embeddings_list)}个嵌入")

技巧3:GPU加速(本地模型首选)

本地部署模型时,若使用GPU加速,生成速度可提升5到10倍。只需将model_kwargs中的device改为"cuda"即可。前提是已安装PyTorch-GPU版本。

embeddings = HuggingFaceEmbeddings(model_name="FlagAI-Open/BGE-M3",model_kwargs={"device": "cuda"},# GPU加速就这么简单encode_kwargs={"normalize_embeddings": True})

技巧4:文本预处理(减少无效计算)

在生成嵌入之前,先对文本进行清理。去除多余空白、换行、重复内容甚至无效字符。文本变短后,计算成本自然降低。

def preprocess_text(text):# 去除首尾空白,替换换行和多余空格text = text.strip().replace("n", "").replace("", " ")# 太短的就直接丢掉return text if len(text) >= 3 else ""

# 先批量预处理,再生成嵌入texts = [preprocess_text(t) for t in texts if preprocess_text(t)]batch_embeddings = embeddings.embed_documents(texts)

8.7 嵌入质量评估方法

生成嵌入后,如何判断其质量?许多开发者会跳过这一步,导致后续检索精度不佳。这里介绍三种实用的评估方法,从简单到复杂,适合不同场景。无需深奥的学术知识,可直接上手。

8.7.1 方法1:人工评估(最简单,适合小批量)

思路简单:挑选几对文本,凭直觉判断语义相似度,然后计算它们嵌入向量的余弦相似度,对比结果是否一致。

from langchain.embeddings import HuggingFaceEmbeddingsfrom sklearn.metrics.pairwise import cosine_similarityimport numpy as np

embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")

# 自己标注的文本对(后面标的是“相似”还是“不相似”)text_pairs = [("LangChain向量嵌入", "LangChain Embedding", "相似"),("猫", "狗", "相似"),("猫", "苹果", "不相似"),("Python编程", "Ja va编程", "相似"),("雨天", "晴天", "不相似")]

# 开始评估correct = 0for text1, text2, label in text_pairs:vec1 = np.array(embeddings.embed_query(text1)).reshape(1, -1)vec2 = np.array(embeddings.embed_query(text2)).reshape(1, -1)sim = cosine_similarity(vec1, vec2)[0][0]# 设定一个阈值,比如0.7,大于等于就算相似pred = "相似" if sim >= 0.7 else "不相似"if pred == label:correct += 1print(f"{text1} vs {text2}:相似度{sim:.4f},预测{pred},实际{label}")

accuracy = correct / len(text_pairs)print(f"n评估准确率:{accuracy:.2f}")# 准确率到0.8以上就说明嵌入质量还不错了

8.7.2 方法2:聚类评估(看语义簇是否清晰)

该方法的逻辑是:将同一类文本的嵌入向量放在一起,观察它们是否能自然聚成一团,而不同类文本能否分开。聚类效果越好,嵌入质量越高。常用工具是K-Means聚类加上UMAP或t-SNE降维可视化。

from langchain.embeddings import HuggingFaceEmbeddingsfrom sklearn.cluster import KMeansfrom sklearn.manifold import TSNEimport matplotlib.pyplot as plt

embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")

# 构造几类不同的文本texts = ["LangChain向量嵌入", "LangChain RAG实战", "LangChain文档加载","BGE嵌入模型", "text2vec模型", "OpenAI Embeddings","Python编程", "Ja va开发", "Ja vaScript入门"]

embeddings_list = embeddings.embed_documents(texts)

# 用t-SNE把高维向量降到2维,好画图tsne = TSNE(n_components=2, random_state=42)embeddings_2d = tsne.fit_transform(embeddings_list)

# 用K-Means分成3类kmeans = KMeans(n_clusters=3, random_state=42)clusters = kmeans.fit_predict(embeddings_list)

# 画出来看看plt.scatter(embeddings_2d[:, 0], embeddings_2d[:, 1], c=clusters, cmap="viridis")for i, text in enumerate(texts):plt.annotate(text, (embeddings_2d[i, 0], embeddings_2d[i, 1]), fontsize=8)plt.title("嵌入向量聚类可视化")plt.show()

评估标准

如果图中“LangChain”、“嵌入模型”、“编程语言”三类文本各自聚成一团,界限分明,说明嵌入质量不错;如果几类文本混乱地混在一起,则可能需要考虑更换模型。

8.7.3 方法3:下游任务评估(最实用,生产环境首选)

最后一种也是最实在的:嵌入最终用于实际任务(如检索或问答),其质量直接体现在这些下游任务的表现上。例如检索的“召回率”或问答的“准确率”。

示例:用检索召回率来评估

from langchain.embeddings import HuggingFaceEmbeddingsfrom langchain.vectorstores import Chromafrom langchain.document_loaders import TextLoader

# 1. 加载文档(假设文档里分别讲了LangChain、BGE、Python)loader = TextLoader("test_doc.txt")documents = loader.load()

# 2. 生成嵌入并构建向量库embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")db = Chroma.from_documents(documents, embeddings)

# 3. 测试一下,看查询能不能命中正确的文档queries = ["LangChain是什么", "BGE模型怎么用", "Python入门教程"]recall = 0for query in queries:similar_docs = db.similarity_search(query, k=1)# 简单判断下,看查询里的关键词是否出现在结果文档里if query.split(" ")[0] in similar_docs[0].page_content:recall += 1

print(f"检索召回率:{recall / len(queries):.2f}")# 召回率超过0.9,说明嵌入质量合格

8.7.4 评估总结

  • 小批量文本:用人工评估,简单高效。

  • 大规模文本:用聚类评估,能直观看到语义分布。

  • 生产环境:用下游任务评估,最贴合实际用途。

8.8 【实战】为技术文档生成高质量向量表示

本节将前面所有知识点串联起来,完成一个完整的实战:加载技术文档(以LangChain官方文档片段为例),进行文本预处理、生成嵌入、使用缓存优化、评估质量,最后将文档向量存入向量数据库,为后续检索做好准备。

8.8.1 实战目标

  • 加载本地技术文档(.txt格式);

  • 对文本进行预处理和分割,防止超出模型输入长度;

  • 使用本地部署的BGE-M3模型生成高质量嵌入;

  • 启用缓存,避免重复计算;

  • 评估嵌入质量;

  • 将嵌入向量存入Chroma向量数据库(支持持久化)。

8.8.2 实战步骤(完整代码,可直接运行)

步骤1:准备工作(依赖+文档)

  1. 安装依赖:

    pip install langchain sentence-transformers torch chromadb scikit-learn matplotlib

  2. 准备技术文档:创建一个langchain_docs.txt文件,写入如下内容(LangChain相关介绍):

    LangChain是一个用于构建大语言模型应用的框架,它提供了一系列工具和组件,帮助开发者快速搭建RAG、聊天机器人等应用。LangChain的核心组件包括:文档加载器(Document Loaders)、文本分割器(Text Splitters)、嵌入模型(Embeddings)、向量数据库(Vector Stores)、大语言模型(LLMs)等。向量嵌入(Embedding)是LangChain RAG的核心,它能将文本转化为数值向量,实现语义检索。常用的嵌入模型有OpenAI Embeddings、BGE、text2vec等。BGE-M3是智源AI推出的开源嵌入模型,中文语义理解能力强,支持长文本,适合本地部署,是中文RAG场景的首选模型。Chroma是一个轻量级向量数据库,适合本地开发和小规模数据存储,可与LangChain无缝集成,支持相似性检索。

步骤2:完整实战代码

from langchain.embeddings import HuggingFaceEmbeddingsfrom langchain.document_loaders import TextLoaderfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain.vectorstores import Chromafrom langchain.cache import SQLiteCacheimport langchainfrom sklearn.metrics.pairwise import cosine_similarityimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.manifold import TSNE

# ---------------------- 1. 启用缓存(避免重复计算) ----------------------langchain.llm_cache = SQLiteCache(database_path="./embedding_cache.db")

# ---------------------- 2. 加载并预处理技术文档 ----------------------loader = TextLoader("langchain_docs.txt")documents = loader.load()

# 文本预处理函数def preprocess_text(text):text = text.strip().replace("n", " ").replace("", " ")return text if len(text) >= 5 else ""

# 预处理一下内容for doc in documents:doc.page_content = preprocess_text(doc.page_content)

# 分割文本(防止文本太长,也为了保留上下文)text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20)split_docs = text_splitter.split_documents(documents)print(f"文档分割后共{len(split_docs)}个文本块")

# ---------------------- 3. 本地部署BGE-M3模型,生成嵌入 ----------------------embeddings = HuggingFaceEmbeddings(model_name="FlagAI-Open/BGE-M3",model_kwargs={"device": "cpu", "trust_remote_code": True},encode_kwargs={"normalize_embeddings": True, "max_length": 8192})

# 批量生成嵌入(相同的文本会从缓存读取)doc_embeddings = embeddings.embed_documents([doc.page_content for doc in split_docs])print(f"生成{len(doc_embeddings)}个文档嵌入,维度:{len(doc_embeddings[0])}")

# ---------------------- 4. 嵌入质量评估(聚类可视化) ----------------------tsne = TSNE(n_components=2, random_state=42)embeddings_2d = tsne.fit_transform(doc_embeddings)

plt.scatter(embeddings_2d[:, 0], embeddings_2d[:, 1], c="blue", alpha=0.7)for i, doc in enumerate(split_docs):plt.annotate(doc.page_content[:20] + "...", (embeddings_2d[i, 0], embeddings_2d[i, 1]), fontsize=8)plt.title("技术文档嵌入向量聚类可视化")plt.show()

# 再抽几个文本人工评估一下sample_texts = [split_docs[0].page_content, split_docs[2].page_content, split_docs[3].page_content]sample_embeddings = embeddings.embed_documents(sample_texts)

sim1 = cosine_similarity([sample_embeddings[0]], [sample_embeddings[1]])[0][0]sim2 = cosine_similarity([sample_embeddings[0]], [sample_embeddings[2]])[0][0]sim3 = cosine_similarity([sample_embeddings[1]], [sample_embeddings[2]])[0][0]print(f"n相似度评估:")print(f"LangChain框架 vs 向量嵌入:{sim1:.4f}")print(f"LangChain框架 vs BGE-M3:{sim2:.4f}")print(f"向量嵌入 vs BGE-M3:{sim3:.4f}")# 向量嵌入和BGE-M3应该最像,因为它们都跟嵌入相关

# ---------------------- 5. 将嵌入存入Chroma向量数据库(持久化) ----------------------vector_db = Chroma.from_documents(documents=split_docs,embedding=embeddings,persist_directory="./langchain_embedding_db")vector_db.persist()print(f"n向量数据库已持久化,存储路径:./langchain_embedding_db")

# 测试一下检索效果query = "BGE-M3模型适合什么场景"similar_docs = vector_db.similarity_search(query, k=2)print(f"n检索结果(与'{query}'最相关的2个文本块):")for i, doc in enumerate(similar_docs):print(f"n--- 结果{i+1} ---")print(doc.page_content)

8.8.3 实战结果说明

  1. 文档分割:将一篇长文档切分成多个短块,既满足模型输入限制,又通过重叠部分保留上下文信息。

  2. 嵌入生成:使用BGE-M3本地模型,同时开启缓存,重复文本不再重复计算。

  3. 质量评估:聚类图显示语义相关的文本自然聚在一起。人工抽查结果符合预期,例如“向量嵌入”与“BGE-M3”相似度最高,因为它们都属于嵌入主题。

  4. 向量存储:最终将向量存入Chroma数据库并持久化。下次程序启动可直接加载,无需重新生成。

8.8.4 实战拓展

  • 换模型:若想换成OpenAI模型,只需修改embeddings的初始化代码。

  • 加载其他格式:可使用PyPDFLoader加载PDF文件,使用WebBaseLoader抓取网页。

  • 处理大规模文档:结合前面介绍的批量嵌入和GPU加速,可大幅提升效率。

本章总结

这一章从Embedding的基础概念出发,一直讲到动手实战,覆盖了嵌入的核心原理、多种模型的调用方式、本地部署方案、性能优化以及效果评估。最后通过一个完整的例子,将技术文档成功转化为向量表示。

关键要点梳理:

  • Embedding的本质:将文本转换为机器可计算的向量,这是语义检索的基石。

  • 模型选择:通用高精度选OpenAI,中文场景首选BGE,轻量需求用text2vec,按需选用。

  • 性能提升:批量处理、开启缓存、使用GPU加速,可让效率成倍增长。

  • 质量评估:人工评估、聚类评估、下游任务评估三种方法,确保嵌入可靠有效。

  • 实战闭环:文本预处理→生成嵌入→质量评估→存入数据库,掌握完整流程。

下一章将重点讲解向量数据库的使用,届时可以基于本章生成的文档向量,构建一个完整的LangChain RAG检索功能。

来源:https://juejin.cn/post/7624444910117765160
上一篇大语言模型的致命弱点阿喀琉斯之踵解析 下一篇Claude Code 3.7 Hooks实战:让AI编程助手学会自律
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Synthesia零基础教程:客户端安装与工作区权限设置
AI教程 · 2026-06-07

Synthesia零基础教程:客户端安装与工作区权限设置

本文介绍了AI视频生成工具Synthesia的入门流程。内容涵盖从官网下载客户端、完成账户注册与登录,到软件安装与启动的完整步骤。详细说明了如何初始化工作区,包括创建首个AI视频项目、选择模板与AI主播。最后,指导用户理解并设置团队协作中的不同权限角色,以便安全高效地共同管理项目。

FramePack新手入门指南:安装启动报错修复导出全流程
AI教程 · 2026-06-07

FramePack新手入门指南:安装启动报错修复导出全流程

本文详细介绍了FramePack工具从下载安装到项目导出的完整流程。内容涵盖软件安装步骤、首次启动设置、常见报错解决方案以及项目打包导出方法。指南旨在帮助用户快速掌握工具核心操作,解决使用过程中可能遇到的技术问题,确保顺利完成AI视频帧处理任务。

FLUX.1保姆级教程:环境安装、显存优化与首次出图测试
AI教程 · 2026-06-07

FLUX.1保姆级教程:环境安装、显存优化与首次出图测试

本文详细介绍了FLUX 1的安装与初步使用流程。内容涵盖从Python环境配置、代码仓库克隆、依赖包安装,到关键的显存优化设置,最后指导用户完成首次文生图测试。教程旨在帮助用户顺利搭建运行环境,解决常见安装问题,并实现基础图像生成功能。

AnythingLLM新手实战:本地大模型部署后知识库接入设置
AI教程 · 2026-06-07

AnythingLLM新手实战:本地大模型部署后知识库接入设置

本文介绍了在本地部署大模型后,如何为AnythingLLM设置知识库。内容涵盖知识库的基本概念、创建与配置步骤、文档上传与处理技巧,以及如何通过问答测试其效果。旨在帮助用户有效整合本地文档资源,构建个性化的AI知识助手,提升信息检索与利用效率。

Aider安装失败排查:扩展冲突与登录异常全解析
AI教程 · 2026-06-07

Aider安装失败排查:扩展冲突与登录异常全解析

本文针对Aider安装过程中常见的扩展冲突与登录异常问题,提供了系统的排查思路与解决方案。内容涵盖如何识别并处理与其他AI工具的兼容性问题,解决因网络或账户设置导致的登录失败,以及通过环境检查、依赖更新等步骤彻底排除安装障碍,帮助用户顺利完成安装与配置。