云计算百科
云计算领域专业知识百科平台

LangChain Embedding与向量数据库

摘要

文档切好了得存起来,还得能根据问题找出来。Embedding把文字转成向量,向量数据库负责存和查。本文讲本地中文Embedding模型的使用、Chroma/Milvus的基本操作,以及怎么用元数据过滤缩小检索范围。

一、为什么需要Embedding

用户问"公司怎么处理迟到",文档里写的是"员工应按时出勤,违者按制度处理"。关键词不一样,意思一样。

普通关键词搜不到,得靠语义检索。

Embedding的作用就是把文本转成一组数字(向量)。意思越接近的文本,向量距离越近。

python

# 伪代码示意
"人工智能" → [0.12, -0.35, 0.78, …]
"机器学习" → [0.11, -0.33, 0.80, …] # 距离近
"红烧肉" → [0.89, 0.45, -0.23, …] # 距离远

二、Embedding和聊天模型的区别

类型输出用途
聊天模型(DeepSeek) 文本 回答问题、生成内容
Embedding模型 向量(数字列表) 计算文本相似度

知识库项目中两者配合:Embedding找相关文档,聊天模型读文档后生成回答。

三、安装依赖

bash

pip install langchain-community chromadb pymilvus dashscope

使用本地中文Embedding模型(bge-small-zh),或者阿里云DashScope的text-embedding-v4。课堂用本地模型,不消耗API额度。

四、案例一:把文本转换成向量

python

from langchain_community.embeddings import HuggingFaceEmbeddings

embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh-v1.5",
model_kwargs={"device": "cpu"},
encode_kwargs={"normalize_embeddings": True}
)

texts = ["人工智能正在改变世界", "机器学习是AI的一个分支"]

# 批量生成文档向量
vectors = embeddings.embed_documents(texts)
print(len(vectors))
print(len(vectors[0])) # 向量维度

# 生成查询向量
query_vec = embeddings.embed_query("什么是AI")
print(len(query_vec))

embed_documents用于文档列表,embed_query用于用户问题。两者使用的模型必须一致。

五、案例二:批量生成文本向量

在model_factory.py中封装Embedding方法:

python

from langchain_community.embeddings import HuggingFaceEmbeddings

def get_embeddings(model_name="BAAI/bge-small-zh-v1.5"):
return HuggingFaceEmbeddings(
model_name=model_name,
model_kwargs={"device": "cpu"},
encode_kwargs={"normalize_embeddings": True}
)

使用:

python

from utils.model_factory import get_embeddings

embeddings = get_embeddings()

chunks = ["文档块1", "文档块2", "文档块3"]
vectors = embeddings.embed_documents(chunks)

query = "用户问题"
query_vector = embeddings.embed_query(query)

六、什么是向量数据库

文本转成向量后需要存起来,还要支持根据向量找相似内容。这就是向量数据库。

向量数据库保存三类数据:

文本内容(文档块正文)
向量(数字列表)
元数据(文件名、页码、分类等)

检索流程:

用户问题 → 转成查询向量 → 向量库搜索最相似的文档向量 → 返回对应的文本和元数据

七、向量数据库选型

类型产品适用场景
开源本地 Chroma 开发测试、轻量级RAG
开源分布式 Milvus 大规模生产环境
自建组件 FAISS 嵌入自建系统
云托管 Pinecone、阿里云向量服务 企业级托管方案

课程用Chroma做演示,Milvus做案例。

八、Chroma向量数据库

python

from langchain_chroma import Chroma
from utils.model_factory import get_embeddings

embeddings = get_embeddings()

# 从文档创建向量库
vector_store = Chroma.from_documents(
documents=chunks, # Document列表
embedding=embeddings,
persist_directory="./chroma_db" # 持久化目录
)

# 检索
results = vector_store.similarity_search("员工迟到怎么处理", k=3)
for doc in results:
print(doc.page_content)
print(doc.metadata)

persist_directory指定持久化目录,下次启动时可以从磁盘加载,不用重新建库。

加载已有向量库:

python

vector_store = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings
)

九、相似度分数

similarity_search只返回文档,不返回分数。用similarity_search_with_score查看相似度:

python

results = vector_store.similarity_search_with_score("员工迟到怎么处理", k=3)

for doc, score in results:
print(f"分数:{score}")
print(f"内容:{doc.page_content[:100]}")
print("-" * 40)

不同向量库的分数含义不同,不要只凭固定数字做判断。结合Top K结果、文档内容、测试集效果综合评估。

十、Milvus向量数据库

Milvus是开源分布式向量数据库,适合大规模生产环境。

安装:

bash

pip install pymilvus langchain-milvus

确保Milvus服务已启动(Docker或本地部署)。

python

from langchain_milvus import Milvus
from utils.model_factory import get_embeddings

embeddings = get_embeddings()

# 连接Milvus并写入
vector_store = Milvus.from_documents(
documents=chunks,
embedding=embeddings,
connection_args={"host": "localhost", "port": "19530"},
collection_name="knowledge_base",
drop_old=True,
auto_id=True,
index_params={
"index_type": "HNSW",
"metric_type": "COSINE",
"params": {"M": 16, "efConstruction": 128}
}
)

# 检索
results = vector_store.similarity_search("员工迟到怎么处理", k=3)

index_params参数说明:

index_type="HNSW":分层导航小世界图,检索速度快,适合百万级以内向量。
metric_type="COSINE":余弦相似度,中文Embedding首选。
M=16:每个节点最大连接邻居数,越大内存占用越高。
efConstruction=128:构建时候选邻居数,越大索引质量越好。

带分数的检索:

python

results = vector_store.similarity_search_with_score("员工迟到怎么处理", k=3)

返回的score是距离值,越小表示越相似。

十一、元数据过滤

知识库可能有多个分类,检索时可以按元数据过滤。

python

# 只检索人事制度
results = vector_store.similarity_search(
"迟到怎么处理",
k=3,
expr='file_name == "employee_handbook.txt"'
)

# 只检索PDF文件
results = vector_store.similarity_search(
"产品参数",
k=3,
expr='file_type == "pdf"'
)

注意Milvus使用expr表达式语法,不是filter参数。

元数据过滤适合:只检索某个部门的资料、只检索某个产品线的手册、只检索某个文件来源。

十二、企业案例:知识库检索索引

项目结构:

text

knowledge_base/
├── hr/
│ └── employee_handbook.txt
├── customer_service/
│ └── refund_policy.md
└── product/
└── product_manual.pdf

build_index.py
search_knowledge.py
document_loader.py
embedding_factory.py

embedding_factory.py:

python

from langchain_community.embeddings import HuggingFaceEmbeddings

def get_embeddings():
return HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh-v1.5",
model_kwargs={"device": "cpu"},
encode_kwargs={"normalize_embeddings": True}
)

document_loader.py:

python

from pathlib import Path
from langchain_community.document_loaders import TextLoader, PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

def load_and_split(directory_path, chunk_size=500, chunk_overlap=50):
docs = []
directory = Path(directory_path)

for file_path in sorted(directory.rglob("*")):
if not file_path.is_file():
continue
suffix = file_path.suffix.lower()
try:
if suffix == ".txt":
loader = TextLoader(str(file_path), encoding="utf-8")
elif suffix == ".md":
loader = TextLoader(str(file_path), encoding="utf-8")
elif suffix == ".pdf":
loader = PyPDFLoader(str(file_path))
else:
continue
loaded = loader.load()
for doc in loaded:
doc.metadata["file_name"] = file_path.name
doc.metadata["file_type"] = suffix[1:]
doc.metadata["category"] = file_path.parent.name
docs.extend(loaded)
except Exception as e:
print(f"加载失败:{file_path.name},错误:{e}")

splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap
)
return splitter.split_documents(docs)

build_index.py:

python

from langchain_milvus import Milvus
from embedding_factory import get_embeddings
from document_loader import load_and_split

print("加载并切分文档…")
chunks = load_and_split("knowledge_base")
print(f"生成{len(chunks)}个文档块")

print("写入Milvus…")
embeddings = get_embeddings()

vector_store = Milvus.from_documents(
documents=chunks,
embedding=embeddings,
connection_args={"host": "localhost", "port": "19530"},
collection_name="knowledge_base",
drop_old=True,
index_params={
"index_type": "HNSW",
"metric_type": "COSINE",
"params": {"M": 16, "efConstruction": 128}
}
)

print("索引构建完成")

search_knowledge.py:

python

from langchain_milvus import Milvus
from embedding_factory import get_embeddings

embeddings = get_embeddings()

vector_store = Milvus(
embedding_function=embeddings,
connection_args={"host": "localhost", "port": "19530"},
collection_name="knowledge_base"
)

while True:
question = input("\\n请输入问题(输入q退出):")
if question.lower() == "q":
break

results = vector_store.similarity_search_with_score(question, k=3)

print(f"\\n相关文档块:")
for i, (doc, score) in enumerate(results, 1):
print(f"{i}. 来源:{doc.metadata.get('file_name')}")
print(f" 分类:{doc.metadata.get('category')}")
print(f" 相似度:{score:.4f}")
print(f" 内容:{doc.page_content[:150]}…")
print()

十三、检索效果调优

不准的话检查这些:

文档块太短或太长:调整chunk_size
上下文被切断:增大chunk_overlap
标题和正文分离:调整分隔符
查询和文档表达差异大:增加同义表达
Embedding模型不适合中文:换模型

准备一组测试问题,逐个观察Top 3结果是否相关。这是最早期的评估方式。

常见问题

DeepSeek能做Embedding吗

DeepSeek是聊天模型,不做Embedding。本课程用本地中文模型,不消耗API额度。

为什么要用同一个Embedding模型

建库和查询必须用同一个模型,否则向量空间不一致,检索效果差。

相似度分数阈值设多少合适

不要写死。不同模型、不同向量库的分数含义不同。先观察真实问题结果再定。

第一次运行慢

首次运行会下载模型文件到本地缓存,后续就快了。

赞(0)
未经允许不得转载:网硕互联帮助中心 » LangChain Embedding与向量数据库
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!