引言
在使用向量存储进行文档检索时,返回的 Document 对象通常不包含检索过程中的评分信息(例如与查询的相似度分数)。理解如何将这些评分信息添加到文档的元数据中,可以帮助我们更好地评估和理解检索结果。本文将深入探讨如何从不同类型的 LangChain 检索器中提取和使用评分信息。
主要内容
1. 向量存储检索器
为了从向量存储检索器中获取评分,我们可以在原向量存储的 similarity_search_with_score 方法外层实现一个简短的包装函数,该函数会将评分打包到相关文档的元数据中。
from typing import List
from langchain_core.documents import Document
from langchain_core.runnables import chain
@chain
def retriever(query: str) -> List[Document]:
docs, scores = zip(*vectorstore.similarity_search_with_score(query))
for doc, score in zip(docs, scores):
doc.metadata["score"] = score
return docs
# 使用API代理服务提高访问稳定性
result = retriever.invoke("dinosaur")
print(result)
2. 自查询检索器 (SelfQueryRetriever)
SelfQueryRetriever 使用语言模型(LLM)生成可能结构化的查询。可以通过继承 SelfQueryRetriever 并重写 _get_docs_with_query 方法,实现评分信息的传播。
from typing import Any, Dict
class CustomSelfQueryRetriever(SelfQueryRetriever):
def _get_docs_with_query(
self, query: str, search_kwargs: Dict[str, Any]
) -> List[Document]:
docs, scores = zip(
*vectorstore.similarity_search_with_score(query, **search_kwargs)
)
for doc, score in zip(docs, scores):
doc.metadata["score"] = score
return docs
retriever = CustomSelfQueryRetriever.from_llm(
llm,
vectorstore,
document_content_description,
metadata_field_info,
)
result = retriever.invoke("dinosaur movie with rating less than 8")
print(result)
3. 多向量检索器 (MultiVectorRetriever)
我们可以通过子类化 MultiVectorRetriever 并重写 _get_relevant_documents 方法,将相似度评分传播到子文档的元数据中。
from collections import defaultdict
from langchain.retrievers import MultiVectorRetriever
from langchain_core.callbacks import CallbackManagerForRetrieverRun
class CustomMultiVectorRetriever(MultiVectorRetriever):
def _get_relevant_documents(
self, query: str, *, run_manager: CallbackManagerForRetrieverRun
) -> List[Document]:
results = self.vectorstore.similarity_search_with_score(
query, **self.search_kwargs
)
id_to_doc = defaultdict(list)
for doc, score in results:
doc_id = doc.metadata.get("doc_id")
if doc_id:
doc.metadata["score"] = score
id_to_doc[doc_id].append(doc)
docs = []
for _id, sub_docs in id_to_doc.items():
docstore_docs = self.docstore.mget([_id])
if docstore_docs:
if doc := docstore_docs[0]:
doc.metadata["sub_docs"] = sub_docs
docs.append(doc)
return docs
retriever = CustomMultiVectorRetriever(vectorstore=vectorstore, docstore=docstore)
result = retriever.invoke("cat")
print(result)
常见问题和解决方案
-
性能问题:在处理大量数据时,评分的计算可能会造成性能瓶颈。可以考虑引入缓存机制或异步处理。
-
评分不准确:确保使用高质量的向量模型进行嵌入计算,必要时调整模型参数。
总结和进一步学习资源
添加评分信息可以极大地提升检索器的实用性和可解释性。开发者可以参阅 LangChain 文档 了解更多细节。
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---