码力全开 / 假设性文档嵌入

Created Sun, 12 Jul 2026 17:51:39 +0800 Modified Sun, 12 Jul 2026 17:57:30 +0800
1983 Words 2 min

Hypothetical Document Embeddings(简称HyDE,假设性文档嵌入) 是一种用于提升RAG检索效果的嵌入技术,核心是不直接对用户原始查询做向量化检索,而是先让大语言模型生成一篇能回答该问题的“假设性文档”,再将这篇文档向量化后用于检索真实知识库内容。

  1. 核心工作流程
    • 接收用户的自然语言查询,这类查询通常简短、语义信息不足。
    • 由大语言模型零样本生成一篇贴合查询语义的假设性回答文档,补充更多上下文细节。
    • 将生成的假设文档向量化,用该向量从文档库中检索最匹配的真实内容,有效对齐查询和知识库的语义空间。
  2. 核心优势
    • 无需人工标注数据,可实现零样本稠密检索,适配缺乏训练数据的场景。
    • 解决短查询、口语化查询和长文档之间的语义鸿沟,大幅提升检索的准确率和召回率。
    • 可直接集成到LangChain、LlamaIndex等主流框架中,无需对现有RAG系统做大规模改造。
  3. 适用场景
    • 原有检索链路召回率不足,无法匹配到相关内容。
    • 面向医疗、法律等特殊垂直领域,原有检索模型在该领域泛化效果差。
    • 处理表述模糊、语义信息少的用户查询。

下面通过Lanchain对这个过程进行简单的介绍。

以下是基于主流 LangChain 版本(特别是 langchain-communitylangchain-core)的两种核心实现方式。

需要注意的是,搜索结果中提到的 langchain app add hydeHYDEChain 属于较旧或特定 CLI 工具的用法,目前在标准 Python 开发中,更推荐直接使用 HypotheticalDocumentEmbedder 类或手动构建链式逻辑。

方法一:使用 HypotheticalDocumentEmbedder(推荐,最简洁)

LangChain 提供了一个专门的包装器 HypotheticalDocumentEmbedder,它透明地处理“生成假设文档 -> 嵌入”的过程。你可以像使用普通 Embedding 模型一样使用它。

  1. 安装依赖
pip install langchain langchain-openai faiss-cpu
  1. 代码实现
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}")

核心注意事项

  1. 性能开销:HyDE 每次查询都需要调用一次 LLM 生成文本,然后再调用 Embedding API。这比直接嵌入查询要慢且贵。建议仅在检索效果不佳、查询语义模糊时使用。
  2. 提示词工程:prompt_name 的选择很重要。LangChain 内置了 web_searchsci_factcode 等模板。如果默认效果不好,可以自定义提示词,要求 LLM 生成更详细、包含更多关键词的段落。
  3. 索引侧 vs 查询侧:
    • 查询侧 HyDE(上述代码):只在对用户查询进行向量化时生成假设文档。这是最常见的用法,无需重新索引整个知识库。
    • 索引侧 HyDE:对知识库中的每个文档也生成假设性问题或摘要,然后嵌入。这能进一步提升匹配度,但计算成本极高,通常只在静态知识库构建时做一次。
  4. 模型选择:生成假设文档时,可以使用较小、较快的 LLM(如 gpt-3.5-turbo 或本地部署的 Llama3-8b),而 Embedding 模型保持高精度即可,以平衡成本和速度。

参考书籍:

《RAG实践权威指南 (宁星星) 》P112-

如果喜欢这篇文章或对您有帮助,可以:[☕] 请我喝杯咖啡 | [💓] 小额赞助