HyDE
混合策略
在前面的文章中,学习的优化策略都是将对应的 查询 生成 新查询,通过 新查询 来执行相应的检索,但是在数据库中存储的数据一般都是 文档 层面上的,数据会远远比 查询 要大很多,所以 query
和 doc
之间是不对称检索,能找到的相似性文档相对来说也比较少。
例如:**今天回家的路上看到了美丽的风景,非常开心!想学习 python
该怎么办?**这个请求中,前面的风景、开心等词语均为无关信息。会对真实的请求学习 python
产生干扰。如果直接搜索用户的请求,可能会产生不正确或无法回答的 LLM
响应。因此,有必要使得用户查询的语义空间与文档的语义空间保持一致。
资料推荐
- 💡大模型中转API推荐
- ✨中转使用教程
- ✨模型优惠查询
特别是 query
和对应的相关内容(答案)可能只存在弱相关性,导致难以找到最相关的文档内容。
在这篇论文《Precise Zero-Shot Dense Retrieval without Relevance Labels
》中提出了一个 HyDE
混合策略 的概念,首先利用 LLM
将问题转换为回答问题的假设性文档/假回答,然后使用嵌入的 假设性文档 去检索真实文档,前提是因为 doc-doc
这个模式执行相似性搜索可以尝试更多的匹配项。
论文地址:https://arxiv.org/pdf/2212.10496
假回答和真回答虽然可能存在事实错误,但是会比较像,因此能更容易找到相关内容。
简单来说,就是先根据 query
生成一个 doc
,然后根据 doc
生成对应的 embedding
,再执行相应的检索,运行流程如下:
在 LangChain
中,并没有封装基于 HyDE
混合策略 的检索器,所以需要自定义一个检索器,并实现 _get_relevant_documents()
方法,具象化代码如下:
from typing import Listimport dotenv
import weaviate
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from langchain_core.documents import Document
from langchain_core.language_models import BaseLanguageModel
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.retrievers import BaseRetriever
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_weaviate import WeaviateVectorStore
from weaviate.auth import AuthApiKeydotenv.load_dotenv()class HyDERetriever(BaseRetriever):"""HyDE混合策略检索器"""retriever: BaseRetrieverllm: BaseLanguageModeldef _get_relevant_documents(self, query: str, *, run_manager: CallbackManagerForRetrieverRun) -> List[Document]:"""传递检索query实现HyDE混合策略检索"""# 1.构建生成假设性文档的promptprompt = ChatPromptTemplate.from_template("请写一篇科学论文来回答这个问题。\n""问题: {question}\n""文章: ")# 2.构建链应用chain = ({"question": RunnablePassthrough()}| prompt| self.llm| StrOutputParser()| self.retriever)return chain.invoke(query)# 1.构建向量数据库与检索器
db = WeaviateVectorStore(client=weaviate.connect_to_wcs(cluster_url="https://mbakeruerziae6psyex7ng.c0.us-west3.gcp.weaviate.cloud",auth_credentials=AuthApiKey("ZltPVa9ZSOxUcfafelsggGyyH6tnTYQYJvBx"),),index_name="DatasetDemo",text_key="text",embedding=OpenAIEmbeddings(model="text-embedding-3-small"),
)
retriever = db.as_retriever(search_type="mmr")# 2.创建HyDE检索器
hyde_retriever = HyDERetriever(retriever=retriever,llm=ChatOpenAI(model="gpt-3.5-turbo-16k", temperature=0),
)# 3.检索文档
documents = hyde_retriever.invoke("关于LLMOps应用配置的文档有哪些?")
print(documents)
print(len(documents))
输出内容:
[Document(metadata={'source': './项目API文档.md', 'start_index': 0.0}, page_content='LLMOps 项目 API 文档\n\n应用 API 接口统一以 JSON 格式返回,并且包含 3 个字段:code、data 和 message,分别代表业务状态码、业务数据和接口附加信息。\n\n业务状态码共有 6 种,其中只有 success(成功) 代表业务操作成功,其他 5 种状态均代表失败,并且失败时会附加相关的信息:fail(通用失败)、not_found(未找到)、unauthorized(未授权)、forbidden(无权限)和validate_error(数据验证失败)。\n\n接口示例:\n\njson { "code": "success", "data": { "redirect_url": "https://github.com/login/oauth/authorize?client_id=f69102c6b97d90d69768&redirect_uri=http%3A%2F%2Flocalhost%3A5001%2Foauth%2Fauthorize%2Fgithub&scope=user%3Aemail" }, "message": "" }'), Document(metadata={'source': './项目API文档.md', 'start_index': 1621.0}, page_content='id -> uuid:应用 id,类型为 uuid。\n\nname -> string:应用名称。\n\nicon -> string:应用图标。\n\ndescription -> string:应用描述。\n\npublished_app_config_id -> uuid:已发布应用配置 id,如果不存在则为 null。\n\ndrafted_app_config_id -> uuid:草稿应用配置 id,如果不存在则为 null。\n\ndebug_conversation_id -> uuid:调试会话记录 id,如果不存在则为 null。\n\npublished_app_config/drafted_app_config -> json:应用配置信息,涵盖草稿配置、已发布配置,如果没有则为 null,两个配置的变量信息一致。\n\nid -> uuid:应用配置 id。\n\nmodel_config -> json:模型配置,类型为 json。\n\ndialog_round -> int:携带上下文轮数,类型为非负整型。'), Document(metadata={'source': './项目API文档.md', 'start_index': 5818.0}, page_content='json { "code": "success", "data": { "list": [ { "id": "1550b71a-1444-47ed-a59d-c2f080fbae94", "conversation_id": "2d7d3e3f-95c9-4d9d-ba9c-9daaf09cc8a8", "query": "能详细讲解下LLM是什么吗?", "answer": "LLM 即 Large Language Model,大语言模型,是一种基于深度学习的自然语言处理模型,具有很高的语言理解和生成能力,能够处理各式各样的自然语言任务,例如文本生成、问答、翻译、摘要等。它通过在大量的文本数据上进行训练,学习到语言的模式、结构和语义知识'), Document(metadata={'source': './项目API文档.md', 'start_index': 490.0}, page_content='带有分页数据的接口会在 data 内固定传递 list 和 paginator 字段,其中 list 代表分页后的列表数据,paginator 代表分页的数据。\n\npaginator 内存在 4 个字段:current_page(当前页数) 、page_size(每页数据条数)、total_page(总页数)、total_record(总记录条数),示例数据如下:')]
4
资料推荐
- 💡大模型中转API推荐
- ✨中转使用教程
- ✨模型优惠查询