常用检索方法介绍
常用方法对比:
| 对比维度 | similarity_search | similarity_search_with_score | as_retriever |
|---|---|---|---|
| 核心能力 | 基础语义相似检索,返回相似文档列表 | 基础检索 + 相似度得分(距离值) | 转换为LangChain标准检索器,支持多策略检索 |
| 返回信息 | 仅文档内容+元数据 | 文档内容+元数据+相似度得分(值越小越相似) | 可配置返回文档列表(同前两者),适配链调用 |
| 检索策略扩展 | 仅支持基础相似检索 | 仅支持基础相似检索 | 支持3类核心策略:<br>1. 基础相似检索<br>2. MMR多样性检索(避免结果重复)<br>3. 得分阈值过滤(仅保留高相似结果) |
| LangChain适配 | 需手动拼接结果到Prompt,适配性弱 | 需手动处理得分+拼接,适配性更弱 | 无缝对接RAG链/Agent/流水线,生态适配性满分 |
| 操作复杂度 | 极低(直接调用,结果直观) | 低(仅多处理得分字段) | 中等(需配置检索类型/参数) |
similarity_search 的场景
适用场景:
- 快速验证:比如确认向量库中是否有某类相关数据、测试元数据过滤是否生效;
- 极简检索需求:业务仅需“返回相似文档”,无需评估相似程度、无需接入LLM;
- 新手调试:刚接触向量检索,先看基础结果,不关注复杂指标。
❌ 不适用:
- 需要判断“文档到底有多相似”;
- 要接入LangChain RAG链实现问答。
similarity_search_with_score 的场景
适用场景:
- 检索质量调试:比如判断检索结果是否真的相关(得分>1.0大概率不相关);
- 策略优化:比如调整嵌入模型/分块规则后,对比得分分布评估效果;
- 业务规则过滤:比如仅保留得分
<0.8的结果,过滤低相似冗余内容; - 问题排查:比如用户反馈回答不准确时,通过得分定位“检索到低相似文档”的问题。
不适用:
- 生产环境直接对接LLM(得分无业务价值,且手动处理成本高);
- 仅需基础检索,无需评估相似程度。
as_retriever 的场景
适用场景:
- 生产级RAG开发:比如搭建智能问答系统、知识库助手等核心业务;
- 复杂检索需求:比如需要“多样性结果”(MMR)、“仅高相似结果”(阈值过滤);
- 流水线化开发:比如文档加载→分块→检索→问答的全流程封装;
- 多组件协同:比如检索结果需接入Agent、记忆模块、缓存系统等。
不适用:
- 仅做临时/一次性的检索验证(配置成本高于直接调用前两者);
- 完全脱离LangChain生态开发(检索器优势无法体现)。
选择原则
- 临时验证/极简检索 → similarity_search(省心);
- 调试/评估检索质量 → similarity_search_with_score(能看得分);
- 生产RAG/复杂检索 → as_retriever(适配生态、可扩展);
- 核心原则:非临时场景优先选
as_retriever,兼顾当前需求和未来扩展,是LangChain+ChromaDB开发的最佳实践。
similarity_search()简单检索
基于向量余弦相似度,根据查询文本,返回最相似的文档列表
语法
db.similarity_search(
query: str, # 【必选】检索问句/关键词
k: int = 4, # 【可选】返回top k条结果(默认4)
filter: Optional[Dict] = None, # 【可选】元数据过滤条件(如{"type": "数据库"})
**kwargs,
) -> List[Document]
例子
from langchain_chroma import Chroma
from langchain_community.embeddings import DashScopeEmbeddings
from dotenv import load_dotenv
# 加载环境变量(需配置 OPENAI_API_KEY)
load_dotenv()
# 初始化大模型
embeddings = DashScopeEmbeddings(model="text-embedding-v2")
# 创建数据库对象
db = Chroma(
embedding_function=embeddings,
persist_directory="./my_chroma_db",
collection_name="test_collection"
)
results = db.similarity_search(
query="ChromaDB", # 搜索内容
k=3)
# list 类型
print("results类型:", type(results))
# Document 类型
print("results 元素的类型:", type(results[0]))
print("结果数量:", len(results))
for item in results:
print(item.page_content)
similarity_search_with_score() 带相似度得分
返回相似文档 + 相似度得分(得分越低,相似度越高)
语法
db.similarity_search_with_score(
query: str, # 【必选】检索问句
k: int = 4, # 【可选】返回数量(默认4)
filter: Optional[Dict] = None, # 【可选】元数据过滤
) -> List[Tuple[Document, float]] # (文档对象, 相似度得分)
分数
| 属性 | 具体说明 |
|---|---|
| 取值范围 | 无严格上限(通常 0~2 为主),下限为 0(完全相同的文本) |
| 核心规律 | 分数越低,相似度越高;分数越高,相似度越低 |
| 计算方式 | ChromaDB 默认用「余弦距离」(也支持欧氏距离等),你无需手动配置,是内置逻辑 |
| 参考阈值 | 分数 ≤ 0.5:极高相似度(核心相关结果),0.5 < 分数 ≤ 1.0:中等相似度(相关但非核心),分数 > 1.0:低相似度(基本不相关) |
例子
from langchain_chroma import Chroma
from langchain_community.embeddings import DashScopeEmbeddings
from dotenv import load_dotenv
# 加载环境变量(需配置 OPENAI_API_KEY)
load_dotenv()
# 初始化大模型
embeddings = DashScopeEmbeddings(model="text-embedding-v2")
# 创建数据库对象
db = Chroma(
embedding_function=embeddings,
persist_directory="./my_chroma_db",
collection_name="test_collection"
)
results = db.similarity_search_with_score(
query="ChromaDB", # 搜索内容
k=3)
# list 类型
print("results类型:", type(results))
# 元素是 tuple 类型,第一个元素是 Document 对象,第二个元素是分数
print("results 元素的类型:", type(results[0]))
print("结果数量:", len(results))
for item in results:
doc = item[0]
score = item[1]
print(f"分数:{score} id:{doc.id},内容:{doc.page_content}")
as_retriever() RAG 检索
将 Chroma 对象转换成 LangChain 标准检索器,直接接入 RAG 链
db.as_retriever(
search_type: str = "similarity", # 【可选】检索类型:similarity/MMR(默认similarity)
search_kwargs: Dict = {}, # 【可选】检索参数(k/filter等)
) -> Retriever
参数详解:
search_type:见下面表格
| 类型 | 中文名称 | 核心作用 | 关键参数(search_kwargs) | 适用场景 |
|---|---|---|---|---|
"similarity" |
基础相似检索 | 等同于 similarity_search(),按向量余弦相似度,从高到低返回 top-K 结果(最常用) |
k(返回条数)、filter(元数据过滤) |
通用问答、精准匹配场景 |
"mmr" |
最大边缘相关性检索 | 兼顾相似度和多样性,避免结果重复,返回不同维度的相关文档 | k、lambda_mult(多样性权重)、filter |
开放式问答、多维度信息检索 |
"similarity_score_threshold" |
得分阈值过滤检索 | 仅返回「相似度得分 ≤ 阈值」的结果,过滤低相似/不相关内容 | k、score_threshold(得分阈值)、filter |
高精准度需求、过滤无关结果 |
search_kwargs:透传检索参数,如{"k": 3, "filter": {"type": "数据库"}}
similarity 例子
from langchain_chroma import Chroma
from langchain_community.embeddings import DashScopeEmbeddings
from dotenv import load_dotenv
# 加载环境变量(需配置 OPENAI_API_KEY)
load_dotenv()
# 初始化大模型
embeddings = DashScopeEmbeddings(model="text-embedding-v2")
# 创建数据库对象
db = Chroma(
embedding_function=embeddings,
persist_directory="./my_chroma_db",
collection_name="test_collection"
)
# 创建检索器(最简配置)
retriever = db.as_retriever(
search_type="similarity", # 基础相似检索(默认值,可省略)
search_kwargs={
"k": 3, # 返回top 2条最相似结果
})
# 用检索器(核心操作)
results = retriever.invoke("ChromaDB 是什么?")
# list 类型
print("results类型:", type(results))
# 元素是 tuple 类型,第一个元素是 Document 对象,第二个元素是分数
print("results 元素的类型:", type(results[0]))
print("结果数量:", len(results))
for item in results:
print(item.page_content)
执行结果:
results类型: <class 'list'>
results 元素的类型: <class 'langchain_core.documents.base.Document'>
结果数量: 3
ChromaDB是轻量级开源向量数据库,支持本地持久化
ChromaDB是轻量级开源向量数据库,支持本地持久化
ChromaDB轻量易用
similarity_score_threshold例子
from langchain_chroma import Chroma
from langchain_community.embeddings import DashScopeEmbeddings
from dotenv import load_dotenv
# 加载环境变量(需配置 OPENAI_API_KEY)
load_dotenv()
# 初始化大模型
embeddings = DashScopeEmbeddings(model="text-embedding-v2")
# 创建数据库对象
db = Chroma(
embedding_function=embeddings,
persist_directory="./my_chroma_db",
collection_name="test_collection"
)
# 创建检索器(最简配置)
retriever = db.as_retriever(
search_type="similarity_score_threshold", # 基础相似检索(默认值,可省略)
search_kwargs={
"k": 3, # 返回top 2条最相似结果
"score_threshold": 0.5, # 相似度得分 ≤ 阈值0.5 的结果
})
# 用检索器(核心操作)
results = retriever.invoke("ChromaDB 是什么?")
# list 类型
print("results类型:", type(results))
# 元素是 tuple 类型,第一个元素是 Document 对象,第二个元素是分数
print("results 元素的类型:", type(results[0]))
print("结果数量:", len(results))
for item in results:
print(item.page_content)
MMR用法
普通相似检索的缺点:只挑「和问题最像」的文档,哪怕这些文档内容几乎一样
MMR 检索:先挑 1条最相似的,再挑 既和问题相关,又和已选文档不重复 的文档,最终返回 相似且多样 的结果。
解决的问题
普通相似检索的痛点:
问题:ChromaDB 有哪些特性?
普通检索结果(重复):
1. ChromaDB 支持本地持久化存储
2. ChromaDB 可本地持久化保存数据
MMR 检索的优化:
MMR检索结果(多样):
1. ChromaDB 支持本地持久化存储
2. ChromaDB 支持MMR检索提升多样性
工作逻辑
- 先选出一批和问题「高相似」的候选文档(比如前20条);
- 从候选中选1条最相似的作为第一条结果;
- 选下一条时,优先选「和问题相似,但和已选文档差异大」的(既相关,又不重复);
- 重复步骤3,直到选够
k条结果。
关键参数
MMR 只有1个核心可调参数 lambda_mult(0~1):
lambda_mult=1:完全优先相似度(和普通相似检索一样,会重复);lambda_mult=0:完全优先多样性(可能选到不相关的文档);- 默认值=0.5:平衡相似度和多样性(通用场景够用)。
例子
from langchain_chroma import Chroma
from langchain_community.embeddings import DashScopeEmbeddings
from dotenv import load_dotenv
# 加载环境变量(需配置 OPENAI_API_KEY)
load_dotenv()
# 初始化大模型
embeddings = DashScopeEmbeddings(model="text-embedding-v2")
# 创建数据库对象
db = Chroma(
embedding_function=embeddings,
persist_directory="./my_chroma_db",
collection_name="test_collection"
)
# 创建检索器(最简配置)
retriever = db.as_retriever(
search_type="mmr", # 基础相似检索(默认值,可省略)
search_kwargs={
"k": 3, # 返回top 2条最相似结果
})
# 用检索器(核心操作)
results = retriever.invoke("ChromaDB 是什么?")
# list 类型
print("results类型:", type(results))
# 元素是 tuple 类型,第一个元素是 Document 对象,第二个元素是分数
print("results 元素的类型:", type(results[0]))
print("结果数量:", len(results))
for item in results:
print(item.page_content)
可能会搜索出不相关的答案
1. 向量层问题(最核心):文本转向量时“语义失真”
这是最常见的原因——嵌入模型没把文本的真实语义转换成准确的向量,导致“查询向量”和“不相关文档向量”被误判为相似:
嵌入模型不匹配:比如用英文模型(如 all-MiniLM-L6-v2)处理中文文本,语义理解差,容易把无关中文内容判为相似;
文本分块不合理:
- 分块太大(比如整篇文档一个块):块内包含多个无关主题,向量代表的是“混合语义”;
- 分块太小(比如一句话拆成多个块):语义不完整,向量无法准确表达核心含义;
- 查询词表达不精准:比如想查“ChromaDB 持久化配置”,却只搜“ChromaDB 设置”,查询向量太宽泛,容易匹配到无关内容。
2. 检索层问题:检索策略没过滤掉低相似结果
即使向量有轻微失真,合理的检索策略也能过滤掉不相关结果,反之则会放行:
- 未设置得分阈值:普通相似检索(similarity)会返回 top-K 结果,哪怕最后几条分数很高(相似度极低);
- k 值设置过大:比如 k=10,强制返回10条结果,系统会 “凑数”,把低相似的不相关文档也纳入;
- 元数据过滤缺失:比如库中有“技术文档”“营销文档”,却没过滤
filter={"type": "技术文档"},导致营销文档被检索出来。
3. 数据层问题:库中本身有低质量/无关数据
如果向量库中混入了和业务无关的文档,检索时自然可能命中:
- 数据清洗不彻底:入库前没剔除广告、重复、无效文本;
- 数据标注错误:元数据标错(比如把“营销文档”标成“技术文档”),过滤时无法精准筛选;
- 无业务边界的数据:库中混入了和当前查询无关的领域内容(比如查数据库问题,却有前端框架的文档)。
解决办法
1. 快速见效:优化检索策略
- 设置得分阈值过滤:改用
similarity_score_threshold检索类型,只保留分数≤0.8(中文场景)/0.6(英文场景)的结果:retriever = db.as_retriever( search_type="similarity_score_threshold", search_kwargs={"k": 3, "score_threshold": 0.8} ) - 缩小 k 值:把 k 从
5~10降到2~3,只保留最核心的相似结果; - 增加元数据过滤:入库时给文档打精准标签(如
type/domain/source),检索时过滤:retriever = db.as_retriever( search_kwargs={"k": 2, "filter": {"domain": "数据库", "type": "技术文档"}} )
2. 中期优化:修复向量层问题(核心)
- 换适配的嵌入模型:中文场景优先用 BGE 系列(如
BAAI/bge-small-zh-v1.5),不要用默认的英文模型:from langchain_huggingface import HuggingFaceEmbeddings embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5") - 优化文本分块:中文按“段落”分块(每块 200~500 字),保证块内语义完整且不混杂;
- 优化查询词:检索前对查询词做“语义增强”(比如“ChromaDB 设置”→“ChromaDB 本地持久化配置参数”)。
3. 长期保障:做好数据层治理
- 入库前清洗:剔除重复、无效、无关文本,只保留核心业务内容;
- 精准标注元数据:至少标注「领域(domain)」「文档类型(type)」「来源(source)」;
- 分库存储:不同领域的内容放在不同的 Chroma 集合(collection)中,检索时只查对应集合。
总结
- 检索类方法:
similarity_search()(基础)/similarity_search_with_score()(带得分)/as_retriever()(RAG适配),核心参数是k(返回数量)和filter(元数据过滤); - 过滤语法:支持
$eq/$in/$and等,是提升检索精准度的关键。
