什么是 RAG 假设性文档嵌入( HyDE)?它的工作原理是什么?


一则或许对你有用的小广告

欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书

  • 《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于 Spring AI + Spring Boot 3.x + JDK 21...查看介绍

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...查看介绍;演示链接:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/

  • 新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍

截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观

面试考察点

  1. RAG 优化深度:面试官不是想听你背 RAG 流程,而是想知道你有没有踩过检索效果不行的坑、知不知道有哪些进阶优化手段。HyDE 就是一个挺有 "亮点感" 的技术。

  2. 原理理解:能不能讲清楚 HyDE 为什么有效,它背后解决的是查询和文档之间的 "语义鸿沟" 问题,而不是只会复述 "LLM 生成假答案再去检索"。

  3. 工程权衡:HyDE 多一次 LLM 调用,延迟和成本都会涨。面试官想看你是不是无脑用技术,还是知道什么场景该用、什么场景反而是负担。

核心答案

HyDE(Hypothetical Document Embeddings,假设性文档嵌入) 是 2022 年论文 《Precise Zero-Shot Dense Retrieval without Relevance Labels(arXiv:2212.10496) 》提出的一种查询改写技术。

说白了就是:别拿用户的原始问题直接去检索,先让 LLM "假装回答" 一遍,把这个假设答案向量化后再去检索真实文档

为什么这么干?因为用户问题和知识库文档之间存在 语义鸿沟(Semantic Gap)。问题是口语化、短语化的,文档是书面化、长篇的,两者在向量空间里可能隔得很远,直接用问题向量检索很容易擦肩而过。而 LLM 生成的假设答案,在风格、长度、用词上都更接近知识库文档,检索精度自然更高。

对比 传统 RAG HyDE 增强 RAG
检索输入 用户原始 Query LLM 生成的假设答案
解决的问题 查询-文档语义鸿沟
是否需要标注数据 否(Zero-shot)
额外开销 多一次 LLM 调用

深度解析

一、为什么需要 HyDE:语义鸿沟问题

先把 HyDE 解决的是什么问题讲清楚,你才能在面试里讲明白。

传统稠密检索依赖的是 Query 和 Document 在同一向量空间中的相似度。但现实是:

  • 用户问 "怎么提高 RAG 召回率",他脑子里想的是一件事,落到字面上又是另一回事
  • 知识库里那篇文档标题叫 "检索增强生成系统的检索质量优化实践",正文写的是 "通过引入 Rerank、Hybrid Search、查询改写等手段提升 Top-K 命中率"

你看,问题和文档在词汇上几乎没重合,但语义是一致的。Embedding 模型虽然能捕捉一定语义,但在短 Query vs 长 Document 这种不对称场景下,效果还是会打折。

HyDE 的思路:与其费力让 Embedding 模型跨越这道鸿沟,不如先把 Query "翻译" 成一段像文档的内容,再去做匹配。

二、HyDE 工作原理

HyDE 工作原理流程图
HyDE 工作原理流程图

上图就是 HyDE 增强后的 RAG 流程。和传统 RAG 的区别就在橙色那两步,多了 "LLM 假答" 和 "假答向量化" 这两个动作。下面拆开看每一步:

  • 第一步:用户提问。比如 "怎么提高 RAG 召回率?",短、口语化、关键词模糊。
  • 第二步:LLM 生成假设答案。拿这个问题去问 LLM(注意,这一步 LLM 是凭自己的预训练知识在 "瞎编" 答案,不需要真实知识库),让它生成一段看起来像答案的文字。比如它可能生成:"提高 RAG 召回率可以从优化 Chunk 切分策略、引入 Hybrid Search、使用 Rerank 重排序、改进 Embedding 模型等方面入手……",一段 200-300 字的 "假" 文档。
  • 第三步:假设文档向量化。把这段假答案用 Embedding 模型编码成向量。
  • 第四步:向量检索。用这个假答案向量去知识库里找 Top-K 个真实文档。因为假答案在风格、长度、用词上都更接近真实文档,匹配精度更高。
  • 第五步到第七步:和传统 RAG 一样,检索到的真实文档 + 用户问题 → Prompt → LLM 生成最终答案。

这里有个细节容易被忽略:第二步 LLM 生成的假设答案 不需要是真的,它只需要在语义空间里 "像" 真实答案就够了。哪怕 LLM 幻觉了几个细节,只要大方向对,向量化后还是能召回正确的真实文档。

三、用 Java 实现 HyDE

Java 生态里 HyDE 没有现成的 "开箱即用" 类,但主流框架都留了扩展点。下面给两个主流框架的写法。

方式一:LangChain4j 自定义 QueryTransformer

LangChain4j 在 RAG 模块里提供了 QueryTransformer 接口,内置了 DefaultQueryTransformerCompressingQueryTransformerExpandingQueryTransformer 等实现,HyDE 需要自定义实现:

import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.rag.query.Query;
import dev.langchain4j.rag.query.transformer.QueryTransformer;

/**
 * HyDE 查询转换器:让 LLM 先生成一个假设性答案文档,
 * 再用这个假设文档作为新的 Query 去做向量检索。
 */
public class HyDEQueryTransformer implements QueryTransformer {

    private final ChatLanguageModel model;

    // HyDE 的核心 Prompt:让 LLM 给出一段 "看起来像答案" 的文档
    private static final String HYDE_PROMPT = """
            请根据下面的问题,写一段 200 字左右的假设性答案文档。
            这段文档将用于向量检索,所以请用正式、文档化的语言,
            不要说 "我不知道",直接给出你认为合理的答案内容。

            问题:%s
            """;

    public HyDEQueryTransformer(ChatLanguageModel model) {
        this.model = model;
    }

    @Override
    public Query transform(Query query) {
        String userQuery = query.text();

        // 1. 让 LLM 生成假设性文档
        String hypotheticalDoc = model.generate(
                UserMessage.from(String.format(HYDE_PROMPT, userQuery))
        ).content().text();

        // 2. 用假设文档替换原始 Query 作为检索输入
        return Query.from(hypotheticalDoc, query.metadata());
    }
}

然后把 HyDE 注入到 RAG 流程里:

import dev.langchain4j.rag.DefaultRetrievalAugmentor;
import dev.langchain4j.rag.RetrievalAugmentor;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;

ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .maxResults(5)
        .build();

// 把 HyDE 作为 QueryTransformer 注入到 augmentor
RetrievalAugmentor augmentor = DefaultRetrievalAugmentor.builder()
        .queryTransformer(new HyDEQueryTransformer(chatModel))  // HyDE 关键
        .contentRetriever(contentRetriever)
        .build();

// 应用到 AI Service
Assistant assistant = AiServices.builder(Assistant.class)
        .chatLanguageModel(chatModel)
        .retrievalAugmentor(augmentor)
        .build();

方式二:Spring AI 自定义 QueryTransformer

Spring AI 在 1.0 GA 后通过 RetrievalAugmentationAdvisor 提供查询改写扩展点,内置了 RewriteQueryTransformerCompressionQueryTransformerTranslationQueryTransformer,但同样没有 HyDE,需要自己实现 QueryTransformer

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.rag.Advisor;
import org.springframework.ai.rag.Query;
import org.springframework.ai.rag.RetrievalAugmentationAdvisor;
import org.springframework.ai.rag.query.transformer.QueryTransformer;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.retrieve.VectorStoreDocumentRetriever;
import reactor.core.publisher.Flux;

public class HyDEQueryTransformer implements QueryTransformer {

    private final ChatClient chatClient;

    // HyDE Prompt 模板:要求模型给出假设性答案文档
    private static final String HYDE_TEMPLATE = """
            请基于下面的问题,写一段 200 字左右的假设性答案文档。
            这段文档将用于向量检索,请用正式、文档化的语言,
            直接给出你认为合理的答案内容。

            问题:{question}
            """;

    public HyDEQueryTransformer(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    @Override
    public Flux<Query> apply(Query query) {
        String userQuery = query.text();

        // 1. 调用 LLM 生成假设性文档
        String hypotheticalDoc = chatClient.prompt()
                .user(spec -> spec.text(HYDE_TEMPLATE).param("question", userQuery))
                .call()
                .content();

        // 2. 用假设文档构造新的 Query 用于后续检索
        return Flux.just(Query.builder()
                .text(hypotheticalDoc)
                .metadata(query.metadata())
                .build());
    }
}

把 Advisor 组装起来:

@Bean
public Advisor ragAdvisor(VectorStore vectorStore, ChatClient.Builder chatClientBuilder) {
    return RetrievalAugmentationAdvisor.builder()
            .queryTransformers(new HyDEQueryTransformer(chatClientBuilder))  // HyDE
            .documentRetriever(VectorStoreDocumentRetriever.builder()
                    .vectorStore(vectorStore)
                    .topK(5)
                    .build())
            .build();
}

提醒:Spring AI 1.0 GA 之后 QueryTransformer 接口在不同小版本间还有微调,正式项目里建议以官方文档为准,参考 Spring AI RAG Reference

四、HyDE 的优势与代价

维度 优势 劣势
检索精度 显著缓解查询-文档语义鸿沟,尤其短查询、口语化查询场景
数据需求 Zero-shot,不需要标注数据
性能开销 多一次 LLM 调用,延迟和成本上升
鲁棒性 LLM 幻觉方向错误时,反而误导检索
适用范围 适合开放性、语义模糊的问题 对事实性、关键词明确的问题画蛇添足

五、什么场景适合用 HyDE

不是所有 RAG 都该上 HyDE。我个人的踩坑经验:

  • 适合:用户查询短、口语化、和专业文档措辞差距大(典型如客服、问答助手、聊天机器人)
  • 适合:跨语言检索,比如用中文问题检索英文文档,LLM 翻译生成的假答案能拉齐语言差异
  • 不适合:查询本身已经包含精确关键词(产品编号、订单号、专有名词这种),用 BM25 或直接向量检索就够了,HyDE 反而引入噪声
  • 不适合:对延迟敏感的在线场景,多一次 LLM 调用,P99 延迟会很难看

生产环境建议把 HyDE 当作 可选策略,配合其他查询改写手段一起用。比如先用规则判断查询类型,再决定要不要启用 HyDE。

六、HyDE 的演进方向(2025-2026)

HyDE 这两年有不少改进方向,面试时提一嘴能加分:

  • Multi-HyDE:让 LLM 一次生成多个假设文档(3-5 个),分别向量化后取平均或加权,降低单次幻觉风险
  • Adaptive HyDE:先用一个小模型判断当前查询是否需要 HyDE,避免无谓的 LLM 调用(2025 年 arXiv 上有相关论文)
  • HyDE + Rerank 组合:HyDE 负责 "粗召回",Cross-Encoder Rerank 负责 "精排序",这套组合目前在 RAG 检索优化里效果不错
  • 结合 Agentic RAG:在 Agent 架构里把 HyDE 作为检索工具的一个内部步骤,由 Agent 自己决定要不要调用

面试高频追问

  1. HyDE 会不会因为 LLM 幻觉反而检索错?

    会。但 HyDE 的精髓在于:假设文档不需要事实正确,语义方向对就行。即便 LLM 编错了细节,只要主题、用词、领域对了,向量化后照样能召回正确的真实文档。真正怕的是 LLM 把问题方向都理解错了,那就是 Prompt 设计的锅了。

  2. HyDE 和 Query Rewriting 有什么区别?

    Query Rewriting 是把原查询改写成更规范的查询(改完还是一个 query);HyDE 是把查询 "升级" 成一段文档(从 query 变成 document),形态都不一样了。两者可以叠加使用。

  3. HyDE 增加了延迟,怎么优化?

    • 用小模型(比如 7B 级别)做假设文档生成,没必要用最强的大模型
    • 对历史查询做缓存,相似查询复用假设文档
    • Adaptive HyDE:只对需要改写的查询启用

常见面试变体

  • "RAG 检索效果不好怎么办?除了 Rerank 还有哪些手段?"(HyDE 是其中之一)
  • "什么是查询改写?常见的方法有哪些?"(HyDE / Rewrite / Expansion / Decomposition)
  • "HyDE 的假设文档为什么要用 LLM 生成,不能直接用关键词扩展吗?"

记忆口诀

HyDE 三步走:LLM 假答 → 假答向量化 → 拿假答检索真文档。核心是 "用文档找文档,比用问题找文档更准"

总结

HyDE 的本质是用 LLM 把短查询 "翻译" 成文档形态再做向量检索,解决的是查询和文档之间的语义鸿沟。原理不复杂,但要讲清楚它为什么有效、什么时候用、有什么代价,才能在面试里真正拿分。生产环境里,HyDE + Rerank + Hybrid Search 配合起来用,效果通常都不错。