中间数据迷失:长上下文的问题
无论您的模型架构如何,当您包含10个以上的检索文档时,性能会显著下降。简而言之:当模型必须在长上下文的中间访问相关信息时,它们往往会忽略提供的文档。详见:https://arxiv.org/abs/2307.03172
为了避免这个问题,您可以在检索后重新排序文档以避免性能下降。
import os
import chromadb
from langchain.vectorstores import Chroma
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.document_transformers import (
LongContextReorder,
)
from langchain.chains import StuffDocumentsChain, LLMChain
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
# 获取嵌入
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
texts = [
"篮球是一项伟大的运动。",
"带我去月球是我最喜欢的歌曲之一。",
"凯尔特人队是我最喜欢的球队。",
"这是一篇关于波士顿凯尔特人队的文档。",
"我非常喜欢去电影院。",
"波士顿凯尔特人队以20分的优势赢得了比赛。",
"这只是一段随机的文本。",
"《埃尔登之环》是过去15年中最好的游戏之一。",
"L·科内特是最好的凯尔特人队球员之一。",
"拉里·伯德是一位标志性的NBA球员。",
]
# 创建一个检索器
retriever = Chroma.from_texts(texts, embedding=embeddings).as_retriever(
search_kwargs={"k": 10}
)
query = "你能告诉我关于凯尔特人队的信息吗?"
# 按相关性得分获取相关文档的顺序
docs = retriever.get_relevant_documents(query)
docs
API 参考:
- Chroma 来自
langchain.vectorstores
- HuggingFaceEmbeddings 来自
langchain.embeddings
- LongContextReorder 来自
langchain.document_transformers
- StuffDocumentsChain 来自
langchain.chains
- LLMChain 来自
langchain.chains
- PromptTemplate 来自
langchain.prompts
- OpenAI 来自
langchain.llms
[Document(page_content='这是一篇关于波士顿凯尔特人队的文档', metadata={}),
Document(page_content='凯尔特人队是我最喜欢的球队。', metadata={}),
Document(page_content='L·科内特是最好的凯尔特人队球员之一。', metadata={}),
Document(page_content='波士顿凯尔特人队以20分的优势赢得了比赛。', metadata={}),
Document(page_content='拉里·伯德是一位标志性的NBA球员。', metadata={}),
Document(page_content='《埃尔登之环》是过去15年中最好的游戏之一。', metadata={}),
Document(page_content='篮球是一项伟大的运动。', metadata={}),
Document(page_content='我非常喜欢去电影院。', metadata={}),
Document(page_content='带我去月球是我最喜欢的歌曲之一。', metadata={}),
Document(page_content='这只是一段随机的文本。', metadata={})]
# 重新排序文档:
# 不相关的文档将位于列表的中间,相关性更高的文档将位于开头/结尾。
reordering = LongContextReorder()
reordered_docs = reordering.transform_documents(docs)
# 确认4个相关文档位于开头和结尾。
reordered_docs
[Document(page_content='凯尔特人队是我最喜欢的球队。', metadata={}),
Document(page_content='波士顿凯尔特人队以20分的优势赢得了比赛。', metadata={}),
Document(page_content='《埃尔登之环》是过去15年中最好的游戏之一。', metadata={}),
Document(page_content='我非常喜欢去电影院。', metadata={}),
Document(page_content='这只是一段随机的文本。', metadata={}),
Document(page_content='带我去月球是我最喜欢的歌曲之一。', metadata={}),
Document(page_content='篮球是一项伟大的运动。', metadata={}),
Document(page_content='拉里·伯德是一位标志性的NBA球员。', metadata={}),
Document(page_content='L·科内特是最好的凯尔特人队球员之一。', metadata={}),
Document(page_content='这是一篇关于波士顿凯尔特人队的文档', metadata={})]
# 我们准备并运行一个自定义的 Stuff 链,使用重新排序的文档作为上下文。
# 覆盖提示
document_prompt = PromptTemplate(
input_variables=["page_content"], template="{page_content}"
)
document_variable_name = "context"
llm = OpenAI()
stuff_prompt_override = """给定这些文本摘录:
-----
{context}
-----
请回答以下问题:
{query}"""
prompt = PromptTemplate(
template=stuff_prompt_override, input_variables=["context", "query"]
)
# 实例化链
llm_chain = LLMChain(llm=llm, prompt=prompt)
chain = StuffDocumentsChain(
llm_chain=llm_chain,
document_prompt=document_prompt,
document_variable_name=document_variable_name,
)
chain.run(input_documents=reordered_docs, query=query)