LangChainMiddleTechnical
Как работает HypotheticalDocumentEmbedder (HyDE) и когда его следует использовать?
HyDE: LLM генерирует гипотетический ответ на вопрос, затем эмбеддинг этого ответа используется для поиска вместо эмбеддинга вопроса — семантически ближе к реальным документам. Добавляет один LLM-вызов на запрос, помогает при стилистическом разрыве вопрос/документ.
Идея HyDE (Hypothetical Document Embedder)
Стандартный retrieval сравнивает эмбеддинг вопроса с эмбеддингами документов. Проблема: вопрос короткий («Как настроить Redis?»), а документы длинные и детальные — их эмбеддинги семантически далеки.
HyDE решает это: сначала LLM генерирует гипотетический ответ на вопрос (без обращения к реальным документам), затем эмбеддинг этого гипотетического ответа используется для поиска. Гипотетический ответ стилистически и семантически ближе к реальным документам, чем голый вопрос.
Пример реализации
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
# 1. Векторное хранилище с реальными документами
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_texts(
texts=[
"Redis настраивается через redis.conf. Параметр maxmemory задаёт лимит памяти.",
"PostgreSQL использует pg_hba.conf для управления доступом клиентов.",
"Nginx проксирует запросы через директиву proxy_pass в server block.",
],
embedding=embeddings,
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# 2. Генератор гипотетического документа
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
hyde_prompt = ChatPromptTemplate.from_template(
"""Напиши короткий технический параграф (3-5 предложений), который мог бы быть
ответом на следующий вопрос в документации. Пиши как документ, не как ответ на вопрос.
Вопрос: {question}"""
)
hyde_chain = hyde_prompt | llm | StrOutputParser()
# 3. HyDE retriever: генерируем гипотезу, ищем по ней
def hyde_retrieve(question: str):
hypothetical_doc = hyde_chain.invoke({"question": question})
print(f"Hypothetical doc: {hypothetical_doc[:100]}...")
return retriever.invoke(hypothetical_doc) # ищем по гипотезе, не по вопросу
# 4. RAG-цепочка с HyDE
final_prompt = ChatPromptTemplate.from_template(
"Контекст: {context}\n\nВопрос: {question}\n\nОтвет:"
)
chain = (
{
"context": lambda x: "\n".join(d.page_content for d in hyde_retrieve(x["question"])),
"question": RunnablePassthrough() | (lambda x: x["question"]),
}
| final_prompt
| llm
| StrOutputParser()
)
result = chain.invoke({"question": "Как ограничить память в Redis?"})
print(result)
Когда HyDE помогает
- Короткие фактические вопросы с длинными документами-ответами.
- Технические вопросы, где вопрос написан в разговорном стиле, а документы — в формальном.
- Специализированные домены, где bi-encoder плохо обучен на domain-specific терминологии.
Когда HyDE не нужен
- Документы и вопросы уже стилистически близки (оба в разговорном стиле или оба технические).
- Нет бюджета на дополнительный LLM-вызов на каждый запрос.
- Factual retrieval с точными датами/именами — гипотеза может галлюцинировать конкретику.
Подводные камни
- HyDE добавляет LLM-вызов на каждый запрос — latency возрастает на 200–800 мс, стоимость удваивается.
- Если LLM галлюцинирует в гипотетическом документе, эмбеддинг уведёт поиск в неправильную сторону — хуже, чем без HyDE.
- Кеширование гипотетических документов по хэшу вопроса снижает стоимость для повторяющихся запросов.
- HyDE не заменяет reranking — часто эффективнее комбинировать: HyDE для retrieval + Cohere Rerank для переоценки.
- Качество зависит от quality промпта для гипотезы — экспериментируйте с инструкцией («пиши как документация», «пиши как статья»).
- Метрика Context Recall может не вырасти, если проблема не в стиле запроса, а в плохом chunking или малом k.
Common mistakes
- Объяснять
hyde retrieverтолько синтаксисом без shape, dtype, состояния или режима выполнения. - Игнорировать leakage, воспроизводимость, пустые входы и скрытые копии данных.
- Не проверять production-симптомы: latency, память, ретраи, дрейф качества и несовпадение версий.
What the interviewer is testing
- Может ли связать
hyde retrieverс реальным контрактом входов и выходов. - Упоминает ли тесты, метрики, reproducibility и диагностику ошибок.
- Видит ли различие между demo-кодом в ноутбуке и production-пайплайном.