语义搜索实战:用 ChromaDB 构建向量检索系统

Published by rcdfrd on 2026-02-09

语义搜索实战:用 ChromaDB 构建向量检索系统

搜索这件事,关键词匹配能做,但做不好。你搜「高效训练」,传统搜索只会找包含这四个字的文档,语义搜索却能找到讨论「加速模型收敛」的段落。这就是向量检索的价值。

索引:把文档变成向量

语义搜索的前置步骤是索引,分四步走:读文档、切片、向量化、存进向量库。

from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma

# 读 PDF
loader = PyPDFLoader("data/paper.pdf")
documents = loader.load()

# 切片
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200
)
all_splits = text_splitter.split_documents(documents)

# 向量化并存储
embedding_model = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma(
    collection_name="demo",
    embedding_function=embedding_model,
    persist_directory="./chroma_db",
)
vector_store.add_documents(all_splits)

chunk_size=1000 是每个文本块的字符上限,chunk_overlap=200 让相邻块有重叠,避免语义在切割处断裂。

查询:多种检索方式

存好之后,查询就很直观了:

# 基本相似度搜索
results = vector_store.similarity_search("如何实现高效推理?")

# 带分数的搜索
results = vector_store.similarity_search_with_score(
    "如何实现高效推理?", k=3
)
for doc, score in results:
    print(f"分数: {score}, 内容: {doc.page_content[:100]}")

你也可以把查询封装成 LangChain 的 chain,方便后续和 Agent 串联:

from langchain_core.runnables import chain

@chain
def retriever(query: str):
    return vector_store.similarity_search(query, k=1)

result = retriever.invoke("高效推理的方法")

评分方式的选择

ChromaDB 支持多种距离计算方式:L2(欧氏距离)、余弦相似度、内积。默认用 L2。

vector_store = Chroma(
    collection_name="cosine_demo",
    embedding_function=embedding_model,
    collection_metadata={"hnsw:space": "cosine"},
)

不同场景适合不同度量。文本语义搜索一般用余弦相似度效果最好,因为它只关注方向不关注长度。L2 对向量的绝对大小敏感,内积则介于两者之间。

ChromaDB 的管理

实际开发中你会需要查看和清理向量库:

import chromadb

client = chromadb.PersistentClient(path="./chroma_db")
collections = client.list_collections()
for col in collections:
    print(f"{col.name}: {col.count()} 条记录")

小结

语义搜索的核心流程就是:文档切片、向量化、存储、查询。ChromaDB 轻量好用,本地开发首选。理解了这套流程,后面做 RAG 就有了基础。