使用假设文档嵌入 (HyDE) 改进检索

原文地址:Improving retrieval using Hypothetical Document Embeddings(HyDE)

2023 年 11 月 5 日

什么是HyDE?

HyDE 使用一个语言学习模型,比如 ChatGPT,在响应查询时创建一个理论文档,而不是使用查询及其计算出的向量直接在向量数据库中搜索。

它更进一步,通过对比方法学习无监督编码器。这个编码器将理论文档转换为一个嵌入向量,以便在向量数据库中找到相似的文档。

它不是寻求问题或查询的嵌入相似性,而是专注于答案到答案的嵌入相似性。

它的性能非常稳健,在各种任务(如网络搜索、问答和事实核查)中的表现与经过良好调整的检索器相匹配。

它的灵感来源于论文Precise Zero-Shot Dense Retrieval without Relevance Labels

为什么需要LLM生成假设性回答?

在面对缺乏具体性或缺乏易于识别的元素从给定上下文中推导答案的问题时,有时候会相当具有挑战性。

例如,考虑必胜客(Pizza Hut)连锁餐厅的情况,它通常以销售食物而闻名。然而,如果有人询问必胜客最好的菜品是什么,这个问题暗示了对食物的关注。这里的难点在于没有指定具体的食物项。因此,寻找洞察力变得有困难。为了解决这个问题,我们利用语言模型(LLM)的帮助来编写一个假设性的答案,然后将其转化为嵌入向量。这些嵌入向量然后在向量存储库中根据语义相似性进行检查,以帮助寻找相关信息。

HyDE 利用 LLM(GPT3)的帮助创建一个“假设性”答案,然后搜索嵌入向量以找到匹配项。在这里,我们进行比较的是答案到答案的嵌入相似性搜索,而不是传统 RAG 检索方法中的查询到答案的嵌入相似性搜索。

然而,这种方法有一个缺点,即它可能无法始终如一地产生良好的结果。例如,如果讨论的主题对语言模型来说完全陌生,这种方法就无效了,可能会导致生成错误信息的次数增加。

实现HyDE

安装所需的依赖项

!pip -q install langchain huggingface_hub openai chromadb tiktoken faiss-cpu
!pip -q install sentence_transformers
!pip -q install -U FlagEmbedding
!pip -q install -U cohere
!pip -q install -U pypdf

导入已安装的依赖项

from langchain.llms import OpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains import LLMChain, HypotheticalDocumentEmbedder
from langchain.prompts import PromptTemplate
from langchain.vectorstores import FAISS
from langchain.document_loaders.pdf import PyPDFDirectoryLoader
from langchain.document_loaders import TextLoader
from langchain.embeddings import HuggingFaceBgeEmbeddings
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
import langchain

设置所需的API密钥

from getpass import getpass
os.environ["COHERE_API_KEY"] = getpass("Cohere API Key:")
os.environ["OPENAI_API_KEY"] = getpass("OpenAI API Key:")

打印文档的辅助函数

def pretty_print_docs(docs):
    print(
        f"\n{'-' * 100}\n".join(
            [f"Document {i+1}:\n\n" + d.page_content for i, d in enumerate(docs)]
        )
    )

加载所需的文档

pdf_folder_path = "/content/Documenation"
loader = PyPDFDirectoryLoader(pdf_folder_path)
docs = loader.load()

检查加载文档的长度和内容

print(len(docs))
print(docs[0].page_content)

将文本拆分成块

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(docs)
print(len(texts))

设置嵌入模型 — BGE 嵌入

model_name = "BAAI/bge-small-en-v1.5"
encode_kwargs = {'normalize_embeddings': True} # set True to compute cosine similarity

bge_embeddings = HuggingFaceBgeEmbeddings(
    model_name=model_name,
    model_kwargs={'device': 'cuda'},
    encode_kwargs=encode_kwargs
)

设置 LLM

llm = OpenAI()

使用“web_search”提示加载

embeddings = HypotheticalDocumentEmbedder.from_llm(llm,
                                                   bge_embeddings,
                                                   prompt_key="web_search"
                                                   )
print(embeddings.llm_chain.prompt)
langchain.debug = True

# Now we can use it as any embedding class!
result = embeddings.embed_query("According to Kelly and Williams what is ethics?")

print(result)

设置基础向量存储检索器

vectorstore = FAISS.from_documents(texts, embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 20})

根据查询从向量存储中检索最相关的上下文

query = "According to Kelly and Williams what is ethics?"
docs = retriever.get_relevant_documents(query)
pretty_print_docs(docs)

RAG流水线的生成部分

llm = ChatOpenAI(model_name="gpt-3.5-turbo-16k",temperature=0.1)

qa = RetrievalQA.from_chain_type(llm=llm,
                                 chain_type="stuff",
                                 retriever=retriever)

生成响应

%%time

response = qa.run(query=query)
print(response)

Multiple generations

我们也可以生成多个文档,然后将这些文档的嵌入向量进行合并。默认情况下,我们是通过取平均值的方式来合并这些嵌入向量。我们可以通过改变用于生成文档的语言模型,使其返回多个内容,从而实现这一点。

multi_llm = OpenAI(n=4, best_of=4)
#
embeddings = HypotheticalDocumentEmbedder.from_llm(
    multi_llm, bge_embeddings, "web_search"
)
#
result = embeddings.embed_query("According to Kelly and Williams what is ethics?")

为多次文本生成设置向量存储 - 假设文档检索器

vectorstore = FAISS.from_documents(texts, embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 20})

query = "According to Kelly and Williams what is ethics?"
docs = retriever.get_relevant_documents(query)
pretty_print_docs(docs)

样本多个生成的文本

  • “text”: “\nKelly and Williams define ethics as the principles of right and wrong that govern the behavior of individuals and the decisions they make. They believe that ethical behavior is based on moral values, such as honesty, respect, and fairness, and is guided by the moral code of a particular society. They also argue that the moral code of a society is based on a shared set of values and beliefs that guide individuals in making ethical decisions. Ultimately, Kelly and Williams believe that ethical behavior is based on individual responsibility and choice, and that it is essential for people to have a sense of right and wrong in order to live lives of integrity and meaningfulness.”,
  • ......

RAG流水线的生成部分 - HyDE

from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
#
llm = ChatOpenAI(model_name="gpt-3.5-turbo-16k",temperature=0.1)
#
qa = RetrievalQA.from_chain_type(llm=llm,
                                 chain_type="stuff",
                                 retriever=retriever)
%%time
#
response = qa.run(query=query)

print(response)

为HyDE使用自定义提示

除了使用预配置的提示外,我们还可以轻松构建自己的提示,并在生成文档的LLMChain中使用它们。如果我们知道查询将处于哪个领域,这可能会很有用,因为我们可以调整提示以生成更相似的文本。

prompt_template = """Please answer the user's question as a single food item
Question: {question}
Answer:"""

prompt = PromptTemplate(input_variables=["question"], template=prompt_template)

llm_chain = LLMChain(llm=llm, prompt=prompt)
# Hypthetical Document Retriever
embeddings = HypotheticalDocumentEmbedder(
    llm_chain=llm_chain,
    base_embeddings=bge_embeddings
)

result = embeddings.embed_query(
    "According to Kelly and Williams what is ethics?"
)

设置向量存储 - 例如 ChromaDB

# set up Vectorstore
docsearch = Chroma.from_documents(texts, embeddings)

检索相似文档

query = "What is the role of ethical manager?"
docs = docsearch.similarity_search(query)

print(docs[0].page_content)

RAG流水线的生成部分

llm = ChatOpenAI(model_name="gpt-3.5-turbo-16k",temperature=0.1)

retriever = docsearch.as_retriever(search_kwargs={"top_k": 2})

qa = RetrievalQA.from_chain_type(llm=llm,
                                 chain_type="stuff",
                                 retriever=retriever)

Response

%%time

response = qa.run(query=query)
print(response)

query = "What should be the qualities of a good ethical manager?"
docs = docsearch.similarity_search(query)

pretty_print_docs(docs)

RAG-Response Generated

%%time

response = qa.run(query=query)
print(response)

Conclusion

HyDE,或称假设性文档扩展,利用语言学习模型(LLMs)如 ChatGPT 生成理论文档,以提高搜索的准确性。它使用无监督编码器将理论文档转换为用于检索的向量。这种方法在网络搜索、问答和事实核查等任务中表现出色,其稳健的性能可与经过良好调整的检索器相媲美。然而,这种方法并非完美无缺;如果主题对LLM来说完全陌生,这种方法可能会产生不准确的信息。尽管如此,HyDE 在检索技术方面标志着重大进步,它提供了一种新颖的方法,专注于答案到答案的嵌入相似性。

虽然给定引用未提及使用HyDE优化RAG进行蒙汉机器翻译任务的实现方法,但可以推测其通用实现思路如下: ### 整体框架搭建 基于可快速组合业务的RAG六大模块,搭建蒙汉机器翻译的RAG框架,该框架各模块应高度可扩展,具有极大灵活性,以便后续融入HyDE进行优化 [^1]。 ### 传统RAG构建 先采用RR模式构建传统的Naive RAG,作为蒙汉机器翻译任务的基础模型,为后续优化提供基础 [^1]。 ### 引入HyDE HyDE(Hypothetical Document Embeddings)通过生成假设文档嵌入来增强检索效果。在蒙汉机器翻译任务中,当用户输入蒙古语句子时,HyDE可以生成与该句子可能相关的假设文档,这些文档可以是潜在的翻译候选、相关的上下文信息等。将这些假设文档嵌入RAG检索过程中,从而提高检索的准确性和相关性。 ### 高级RAG转换 将原本的传统RAG转换为Advanced RAG(如RRRR模式),在这个过程中增加复杂的检索前和检索后过程。在检索前,利用HyDE生成的假设文档对输入的蒙古语句子进行预处理,例如对句子进行语义扩展、上下文补充等;在检索后,对检索结果进行筛选和排序,结合HyDE生成的信息评估结果的可靠性 [^1][^2]。 ### 奖惩机制实现 实现基于检索结果和用户评价的奖惩机制。当用户对翻译结果满意时,强化检索器的行为;当用户不满意时,纠正检索器的行为,使检索器能够根据HyDE提供的信息和用户反馈不断优化 [^1]。 ### 代码示例(伪代码) ```python # 模拟RAG系统 class RAGSystem: def __init__(self): self.retriever = Retriever() self.generator = Generator() def translate(self, mongolian_text): # 使用HyDE生成假设文档 hyde_docs = hyde_generate(mongolian_text) # 检索相关信息 retrieved_info = self.retriever.retrieve(mongolian_text, hyde_docs) # 生成翻译结果 translation = self.generator.generate(retrieved_info) return translation # 模拟HyDE生成假设文档 def hyde_generate(mongolian_text): # 这里需要具体的HyDE算法实现 # 简单示例,返回一些假设文档 return ["相关假设文档1", "相关假设文档2"] # 模拟检索器 class Retriever: def retrieve(self, mongolian_text, hyde_docs): # 检索逻辑 return "检索到的相关信息" # 模拟生成器 class Generator: def generate(self, retrieved_info): # 生成翻译结果 return "生成的汉语翻译" # 使用示例 rag = RAGSystem() mongolian_input = "蒙古语输入句子" chinese_translation = rag.translate(mongolian_input) print(chinese_translation) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值