Переписывание запросов и HyDE
Повышение полноты поиска
«Переписывание запросов и HyDE» — бесплатный урок AI Prompt Engineering на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Prompt Engineering, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Prompt Engineering содержит 4 уроков всего.
Запрос — слабое звено
Качество поиска ограничено запросом. Исходные пользовательские запросы часто коротки, неоднозначны, изобилуют местоимениями или сформулированы не так, как документы. Преобразование запроса изменяет запрос перед поиском, повышая полноту и точность.
Это одно из самых дешёвых и эффективных улучшений по сравнению с наивной RAG: исправьте запрос — и каждый следующий этап выиграет.
def transform_query(raw, history):
# Resolve references, expand, decompose, or hypothesize
# BEFORE embedding and retrieving.
return rewrite(raw, history)Переписывание запроса
Самое простое преобразование: LLM переписывает пользовательский запрос в более ясную, самостоятельную и удобную для поиска форму. Она исправляет опечатки, раскрывает сокращения и удаляет разговорный шум.
Это особенно важно в многоходовом диалоге, где последнее сообщение непонятно без контекста («А как насчёт второго?»).
def rewrite_query(raw):
prompt = (
'Rewrite the user question into a clear, standalone search '
'query optimized for document retrieval. Keep key entities.\n'
'Question: ' + raw
)
return llm(prompt, temperature=0).strip()Конденсация диалога
В диалоговой RAG объединяйте диалог и новый ход в один самостоятельный вопрос. Без этого местоимения и многоточия делают векторное представление бессмысленным, а поиск перестаёт работать.
Передавайте предыдущие ходы, чтобы модуль переписывания мог заменить «это», «то» и «предыдущий» явными сущностями, с которыми сможет сопоставить их система поиска.
def condense(history, follow_up):
prompt = (
'Given the conversation, rewrite the follow-up as a standalone '
'question with all references resolved.\nConversation:\n' +
render(history) + '\nFollow-up: ' + follow_up
)
return llm(prompt, temperature=0).strip()Расширение запроса
Расширение создаёт синонимы, связанные термины или альтернативные формулировки, чтобы расширить лексическое и семантическое покрытие. Оно устраняет несоответствие словаря: в документе написано «invalidate», а пользователь говорит «revoke».
Расширяйте запрос для поиска, затем выполняйте поиск по объединённому списку; не показывайте пользователю расширенный вариант. Остерегайтесь чрезмерного расширения: оно может привлечь результаты не по теме.
def expand(query, n=3):
prompt = (
'List ' + str(n) + ' alternative phrasings of this query using '
'synonyms and domain terms, one per line.\n' + query
)
variants = parse_lines(llm(prompt, temperature=0.5))
return [query] + variantsПоиск по нескольким запросам
Создайте несколько разных переформулировок, выполните поиск по каждой из них и объедините списки результатов с помощью взаимного слияния рангов. Разные формулировки выявляют разные релевантные фрагменты; объединение сочетает их преимущества и стабилизирует полноту поиска.
За это приходится платить дополнительными вызовами поиска, но система становится устойчивее к неудачной формулировке отдельного запроса.
def multi_query(raw, n=4):
queries = expand(raw, n)
rankings = [dense_retrieve(q, 30) for q in queries]
fused = rrf(*rankings)
return dedup(fused)Декомпозиция запроса
Для сложных многошаговых вопросов требуется декомпозиция на подвопросы, поиск по каждому из них и последующее объединение результатов. На вопрос о том, какой CEO компании, приобретшей X, старше… нельзя ответить с помощью одного поиска.
Разложите вопрос на части, выполните поиск по каждому подвопросу и позвольте генератору объединить собранные свидетельства.
def decompose_and_retrieve(question):
subs = parse_lines(llm(
'Break this into independent sub-questions, one per line.\n' +
question, temperature=0))
evidence = {s: rerank(s, dense_retrieve(s, 30))[:3] for s in subs}
return evidence # generator synthesizes the final answerHyDE: основная идея
HyDE (гипотетические векторные представления документов, Гао и др., 2022) меняет саму постановку задачи. Вместо того чтобы создавать векторное представление короткого запроса, система просит LLM сгенерировать гипотетический документ с ответом, затем создаёт векторное представление этого документа и выполняет поиск по нему.
Гипотетический документ написан в том же стиле, что и реальные документы, поэтому его векторное представление оказывается ближе к настоящим ответам и устраняет несоответствие между запросом и документом.
def hyde(query):
hypo = llm(
'Write a short passage that would answer this question, as if '
'from a reference document.\nQuestion: ' + query,
temperature=0.3)
return dense_retrieve_by_vector(embed(hypo), k=30) # embed the answerПочему HyDE повышает полноту поиска
Вопрос и ответ обычно сформулированы по-разному, тогда как вопрос и вымышленный, но правдоподобный ответ похожи на настоящий ответ. HyDE использует генеративное априорное знание LLM, чтобы преодолеть этот разрыв, даже если гипотетический документ содержит фактические ошибки.
Точность гипотетического документа не особенно важна: ему достаточно правильных слов и структуры, чтобы оказаться рядом с настоящими документами в пространстве векторных представлений.
# Robustness: average several hypothetical docs to reduce variance
def hyde_avg(query, n=3):
vecs = [embed(llm(HYDE_PROMPT + query, temperature=0.5))
for _ in range(n)]
centroid = sum(vecs) / n
return dense_retrieve_by_vector(centroid, 30)Компромиссы и сценарии отказа HyDE
HyDE добавляет генерацию LLM перед поиском, увеличивая задержку и стоимость, и может галлюцинировать гипотетический документ, который уйдёт от темы. Это ухудшает полноту поиска для узкоспециализированных запросов или запросов вне распределения, о которых модель ничего не знает.
Смягчите проблему, сочетая векторный поиск HyDE с поиском по исходному запросу через объединение результатов, чтобы неудачный гипотетический документ не мог полностью снизить полноту поиска.
def hyde_hybrid(query):
a = dense_retrieve_by_vector(embed(hyde_doc(query)), 30)
b = dense_retrieve(query, 30) # raw-query fallback
return dedup(rrf(a, b)) # robust to bad hypotheticalsВыбор и сочетание методов
Эти преобразования дополняют друг друга. Используйте конденсацию для диалогов, расширение и поиск по нескольким запросам при несоответствии словаря, декомпозицию для многошаговых вопросов и HyDE при несоответствии стиля вопроса и документа. Во многих производственных системах выстраивают цепочку: condense, затем HyDE, затем объединение с исходным запросом и переранжирование.
Каждое дополнительное преобразование требует отдельного вызова LLM, поэтому включайте их в зависимости от типа запроса, а не запускайте всегда все сразу.
def route_transform(query, history, qtype):
q = condense(history, query) if history else query
if qtype == 'multi_hop': return decompose_and_retrieve(q)
if qtype == 'mismatch': return hyde_hybrid(q)
if qtype == 'vocab_gap': return multi_query(q)
return dense_retrieve(q, 30)Оценка преобразований
Оценивайте каждое преобразование по приросту полноты поиска при k результатах и точности итогового ответа по сравнению с исходным запросом на наборе без утечки данных. Отслеживайте добавленную задержку и стоимость LLM, чтобы оставлять только те преобразования, которые окупаются.
Будьте внимательны: преобразование, которое повышает полноту поиска, но добавляет отвлекающие результаты, может снизить точность ответа, если не сочетать его с переранжированием и сжатием.
def eval_transform(name, fn, eval_set):
return {
'recall@10': recall_at_k(eval_set, retriever=fn, k=10),
'answer_acc': answer_accuracy(eval_set, retriever=fn),
'extra_latency_ms': transform_latency(fn),
}Быстрая проверка
Объясните, почему HyDE работает, несмотря на несовершенство гипотетических ответов.
Итоги
Основные выводы:
- Поиск ограничен запросом; его преобразование — недорогое и очень эффективное улучшение RAG.
- Переписывание и конденсация превращают запросы в чате в самостоятельные; расширение и несколько запросов устраняют пробелы в словаре.
- Декомпозиция обрабатывает многошаговые вопросы, выполняя поиск для каждого подвопроса.
- HyDE встраивает гипотетический ответ, чтобы устранить стилистическое несоответствие между вопросом и документом; правильность гипотезы не требуется.
- Сочетайте преобразования с учётом типа запроса, объединяйте их с исходным запросом для повышения устойчивости и оценивайте полноту поиска, точность ответа, задержку и стоимость.
Изучай AI Prompt Engineering с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 53
- Уроки
- 199
Часто задаваемые вопросы
Урок «Переписывание запросов и HyDE» бесплатный?
Да — полный текст урока «Переписывание запросов и HyDE» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Prompt Engineering, подпишись на CoddyKit PRO. Курс AI Prompt Engineering содержит 4 уроков всего.
Чему я научусь в уроке «Переписывание запросов и HyDE»?
Повышение полноты поиска Ты практикуешь AI Prompt Engineering с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать AI Prompt Engineering?
Предыдущий опыт не требуется. AI Prompt Engineering на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Переписывание запросов и HyDE»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке AI Prompt Engineering?
Да. Каждый урок AI Prompt Engineering включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- За пределами наивного RAG
- Переранжирование найденных фрагментов
- Сжатие контекста
- Переписывание запросов и HyDE