Hypothetical Document Embeddings(简称HyDE,假设性文档嵌入) 是一种用于提升RAG检索效果的嵌入技术,核心是不直接对用户原始查询做向量化检索,而是先让大语言模型生成一篇能回答该问题的“假设性文档”,再将这篇文档向量化后用于检索真实知识库内容。
- 核心工作流程
- 接收用户的自然语言查询,这类查询通常简短、语义信息不足。
- 由大语言模型零样本生成一篇贴合查询语义的假设性回答文档,补充更多上下文细节。
- 将生成的假设文档向量化,用该向量从文档库中检索最匹配的真实内容,有效对齐查询和知识库的语义空间。
- 核心优势
- 无需人工标注数据,可实现零样本稠密检索,适配缺乏训练数据的场景。
- 解决短查询、口语化查询和长文档之间的语义鸿沟,大幅提升检索的准确率和召回率。
- 可直接集成到LangChain、LlamaIndex等主流框架中,无需对现有RAG系统做大规模改造。
- 适用场景
- 原有检索链路召回率不足,无法匹配到相关内容。
- 面向医疗、法律等特殊垂直领域,原有检索模型在该领域泛化效果差。
- 处理表述模糊、语义信息少的用户查询。
下面通过Lanchain对这个过程进行简单的介绍。
以下是基于主流 LangChain 版本(特别是 langchain-community 和 langchain-core)的两种核心实现方式。
需要注意的是,搜索结果中提到的 langchain app add hyde 或 HYDEChain 属于较旧或特定 CLI 工具的用法,目前在标准 Python 开发中,更推荐直接使用 HypotheticalDocumentEmbedder 类或手动构建链式逻辑。
方法一:使用 HypotheticalDocumentEmbedder(推荐,最简洁)
LangChain 提供了一个专门的包装器 HypotheticalDocumentEmbedder,它透明地处理“生成假设文档 -> 嵌入”的过程。你可以像使用普通 Embedding 模型一样使用它。
- 安装依赖
pip install langchain langchain-openai faiss-cpu
- 代码实现
import os
from langchain_openai import OpenAI, OpenAIEmbeddings
from langchain_community.embeddings import HypotheticalDocumentEmbedder
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
设置 API Key
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
1. 初始化基础 LLM 和 Embedding 模型
llm = OpenAI(temperature=0)
base_embeddings = OpenAIEmbeddings()
2. 创建 HyDE 嵌入器
mode 可以是 "web_search" (生成简短答案) 或 "contextual_compression" 等
prompt_name 指定使用的提示模板,LangChain 内置了多种模板
hyde_embeddings = HypotheticalDocumentEmbedder.from_llm(
llm=llm,
base_embeddings=base_embeddings,
prompt_name="web_search"
)
3. 准备示例文档库
texts = [
"PostgreSQL 是一个强大的开源对象关系数据库系统。",
"BM25 是一种用于信息检索的相关性评分函数。",
"HyDE 通过生成假设文档来提升向量检索的效果。"
]
documents = [Document(page_content=t) for t in texts]
4. 创建向量存储 (使用 HyDE 嵌入器进行索引)
注意:在实际生产中,通常只对查询使用 HyDE,或者对文档也使用 HyDE 生成假设内容后索引
这里演示对查询侧的应用,通常向量库是用普通 embedding 建立的,
但 HyDE 的核心在于查询时的转换。为了演示完整流程,我们假设向量库已建立。
vectorstore = FAISS.from_documents(documents, base_embeddings)
5. 执行检索
query = "怎么提高数据库搜索的相关性?"
关键步骤:使用 HyDE 嵌入器将查询转换为向量
内部流程:LLM 生成假设答案 -> 对假设答案进行 Embedding -> 在向量库中搜索
similar_docs = vectorstore.similarity_search_by_vector(
hyde_embeddings.embed_query(query)
)
print(f"用户查询: {query}")
print("-" * 20)
for doc in similar_docs:
print(f"匹配文档: {doc.page_content}")
print(f"相似度得分: {doc.metadata.get('score', 'N/A')}")
方法二:手动构建 HyDE 链(更灵活,可调试)
如果你需要自定义生成的假设文档格式,或者想观察中间生成的假设文本,可以手动构建链。
代码实现
from langchain_openai import OpenAI, OpenAIEmbeddings
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
import os
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
1. 初始化组件
llm = OpenAI(temperature=0)
embeddings = OpenAIEmbeddings()
2. 定义 HyDE 提示模板
这个提示词旨在让 LLM 生成一个看起来像真实文档片段的回答
hyde_prompt = PromptTemplate.from_template(
"""Please write a passage to answer the question.
Question: {question}
Passage:"""
)
3. 构建生成链
generate_hypothetical_doc = hyde_prompt | llm | StrOutputParser()
4. 准备向量库 (使用普通 Embedding)
texts = [
"PostgreSQL 支持 BM25 算法通过 pg_bm25 扩展。",
"向量检索通常使用余弦相似度或欧氏距离。",
"HyDE 解决了查询与文档之间的语义鸿沟问题。"
]
docs = [Document(page_content=t) for t in texts]
vectorstore = FAISS.from_documents(docs, embeddings)
5. 执行检索流程
query = "PostgreSQL 如何实现 BM25?"
第一步:生成假设文档
hypothetical_doc = generate_hypothetical_doc.invoke({"question": query})
print(f"生成的假设文档:\n{hypothetical_doc}\n")
第二步:对假设文档进行嵌入
query_vector = embeddings.embed_query(hypothetical_doc)
第三步:检索真实文档
results = vectorstore.similarity_search_by_vector(query_vector, k=2)
print("检索到的真实文档:")
for res in results:
print(f"- {res.page_content}")
核心注意事项
- 性能开销:HyDE 每次查询都需要调用一次 LLM 生成文本,然后再调用 Embedding API。这比直接嵌入查询要慢且贵。建议仅在检索效果不佳、查询语义模糊时使用。
- 提示词工程:
prompt_name的选择很重要。LangChain 内置了web_search、sci_fact、code等模板。如果默认效果不好,可以自定义提示词,要求 LLM 生成更详细、包含更多关键词的段落。 - 索引侧 vs 查询侧:
- 查询侧 HyDE(上述代码):只在对用户查询进行向量化时生成假设文档。这是最常见的用法,无需重新索引整个知识库。
- 索引侧 HyDE:对知识库中的每个文档也生成假设性问题或摘要,然后嵌入。这能进一步提升匹配度,但计算成本极高,通常只在静态知识库构建时做一次。
- 模型选择:生成假设文档时,可以使用较小、较快的 LLM(如
gpt-3.5-turbo或本地部署的 Llama3-8b),而 Embedding 模型保持高精度即可,以平衡成本和速度。
参考书籍:
《RAG实践权威指南 (宁星星) 》P112-
如果喜欢这篇文章或对您有帮助,可以:[☕] 请我喝杯咖啡 | [💓] 小额赞助

