Реалізація HyDE (Hypothetical Document Embeddings) для RAG

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1566 послуг
Реалізація HyDE (Hypothetical Document Embeddings) для RAG
Середній
від 1 дня до 3 днів
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    901
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1119
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    853

Впровадження HyDE (Hypothetical Document Embeddings) для RAG

HyDE — це техніка поліпшення retrieval, запропонована Gao et al. (2022). Замість пошуку документів за embedding запиту безпосередньо, LLM генерує гіпотетичну відповідь на питання, а пошук виконується за embedding цієї відповіді. Гіпотетична відповідь розташована у просторі "документів", а не "запитів", тому її embedding краще збігається з реальними документами.

Чому HyDE працює

Асиметрія embedding простору: запитання та відповіді — різні розподіли у векторному просторі. Embedding запиту "який строк позивної давності для трудових спорів" падає в область запитів, а не документів з відповідями. HyDE генерує текст, подібний до документів у корпусі.

Стандартний RAG:
Запит → Embedding(запит) → пошук → документи

HyDE:
Запит → LLM → Гіпотетична_відповідь → Embedding(відповідь) → пошук → документи

Впровадження HyDE

from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain.retrievers import ParentDocumentRetriever
import asyncio

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

hyde_prompt = ChatPromptTemplate.from_template("""
Напиши абзац для підтримки/відповіді на питання
Питання: {query}
Абзац:""")

async def hyde_retriever(query: str, base_retriever, top_k: int = 5):
    # Крок 1: Генеруємо гіпотетичний документ
    hypothetical_docs = await asyncio.gather(
        *[asyncio.to_thread(
            lambda: llm.invoke(hyde_prompt.format(query=query)).content
        ) for _ in range(3)]
    )
    
    # Крок 2: Вбудовуємо кожний гіпотетичний документ та витягуємо
    all_docs = []
    for hypo_doc in hypothetical_docs:
        docs = await asyncio.to_thread(
            lambda: base_retriever.invoke(hypo_doc)
        )
        all_docs.extend(docs)
    
    # Крок 3: Дедублюємо та повертаємо top-k
    seen = set()
    unique_docs = []
    for doc in all_docs:
        if doc.metadata.get("id") not in seen:
            unique_docs.append(doc)
            seen.add(doc.metadata.get("id"))
    
    return unique_docs[:top_k]

Multi-Query HyDE

Комбінуємо HyDE з підходом multi-query для кращого охоплення:

class MultiQueryHyDE:
    def __init__(self, llm, embeddings, base_retriever):
        self.llm = llm
        self.embeddings = embeddings
        self.retriever = base_retriever
    
    def generate_hypothetical_answers(self, query: str, num=3) -> list:
        """Генеруємо кілька гіпотетичних відповідей"""
        prompt = f"""Генеруй {num} правдоподібних гіпотетичних відповідей на: {query}
Кожна відповідь повинна бути повним, самостійним абзацом."""
        
        response = self.llm.invoke(prompt)
        answers = response.content.split("\n\n")
        return [a.strip() for a in answers if a.strip()]
    
    def retrieve(self, query: str, top_k: int = 5) -> list:
        hypothetical_answers = self.generate_hypothetical_answers(query)
        
        all_docs = []
        for answer in hypothetical_answers:
            docs = self.retriever.invoke(answer)
            all_docs.extend(docs)
        
        # Дедублюємо та повертаємо
        seen = set()
        result = []
        for doc in all_docs:
            doc_id = doc.metadata.get("id")
            if doc_id not in seen:
                result.append(doc)
                seen.add(doc_id)
        
        return result[:top_k]

Практичний кейс: пошук технічної документації

Завдання: асистент для 50 000 технічних статей (середня довжина 2500 слів).

Результати:

Метрика Стандартний RAG HyDE
Context Recall 0.62 0.81
MRR@5 0.58 0.74
P@1 0.34 0.52
Latency 800ms 1200ms (+HyDE генерація)

HyDE поліпшив recall на 31% з прийнятним збільшенням latency.

Терміни

  • Впровадження HyDE retriever: 2–3 дні
  • Тестування та підбір промпту: 2–3 дні
  • Порівняння з baseline: 1–2 дні
  • Всього: 1 тиждень