Przepisywanie zapytań i HyDE
Poprawa kompletności wyszukiwania
Przepisywanie zapytań i HyDE to bezpłatna lekcja AI Prompt Engineering na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Prompt Engineering, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.
Zapytanie jest najsłabszym ogniwem
Jakość wyszukiwania jest ograniczona przez zapytanie. Surowe zapytania użytkowników są często krótkie, niejednoznaczne, pełne zaimków lub sformułowane inaczej niż dokumenty. Transformacja zapytania zmienia zapytanie przed wyszukiwaniem, aby zwiększyć recall i precision.
To jedno z najtańszych ulepszeń o największym wpływie w porównaniu z naiwnym RAG: poprawa zapytania przynosi korzyści każdemu kolejnemu etapowi.
def transform_query(raw, history):
# Resolve references, expand, decompose, or hypothesize
# BEFORE embedding and retrieving.
return rewrite(raw, history)Przepisywanie zapytań
Najprostsza transformacja: LLM przepisuje zapytanie użytkownika na jaśniejszą, samodzielną i przyjazną wyszukiwaniu formę. Poprawia literówki, rozwija skróty i usuwa konwersacyjny szum.
Jest to szczególnie ważne w rozmowie wieloturowej, w której najnowsza wiadomość jest niezrozumiała bez kontekstu (A co z drugim?).
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()Kondensowanie rozmowy
W chatowym RAG należy skondensować dialog i nową turę do jednego samodzielnego pytania. Bez tego zaimki i wielokropki sprawiają, że embedding staje się bezwartościowy, a wyszukiwanie przestaje działać.
Należy przekazać poprzednie tury, aby moduł przepisujący mógł zamienić określenia „to”, „tamto” i „poprzedni” na jawne encje, które wyszukiwarka będzie mogła dopasować.
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()Rozszerzanie zapytań
Rozszerzanie generuje synonimy, powiązane terminy lub alternatywne sformułowania, aby poszerzyć pokrycie leksykalne i semantyczne. Pomaga przezwyciężyć niezgodność słownictwa: dokument mówi „invalidate”, a użytkownik „revoke”.
Zapytanie należy rozszerzać na potrzeby wyszukiwania, a następnie wyszukiwać na podstawie połączenia wyników; nie należy wyświetlać użytkownikowi rozszerzonej formy. Należy uważać na nadmierne rozszerzanie, które może przyciągać wyniki niezwiązane z tematem.
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] + variantsWyszukiwanie na podstawie wielu zapytań
Należy wygenerować kilka różnorodnych przeformułowań, wyszukać wyniki dla każdego z nich i połączyć listy wyników (reciprocal rank fusion). Różne sformułowania ujawniają różne trafne fragmenty; łączenie wyników wykorzystuje ich mocne strony i stabilizuje recall.
Rozwiązanie to wymaga dodatkowych wywołań wyszukiwania, ale zwiększa odporność na pojedyncze nieudane sformułowanie.
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)Dekompzycja zapytań
Złożone pytania wieloetapowe wymagają dekompozycji na pytania składowe, z których każde jest wyszukiwane osobno, a następnie całość jest składana. Na pytanie „Który dyrektor generalny firmy przejętej przez X jest starszy od...” nie można odpowiedzieć na podstawie jednego wyszukiwania.
Należy podzielić pytanie, wyszukać informacje dla każdego pytania składowego i pozwolić generatorowi połączyć zebrane dowody.
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: główna idea
HyDE (Hypothetical Document Embeddings, Gao et al., 2022) odwraca to podejście. Zamiast osadzać krótkie zapytanie, prosi LLM o wygenerowanie hipotetycznego dokumentu z odpowiedzią, a następnie osadza ten dokument i na jego podstawie wyszukuje wyniki.
Hipotetyczny dokument jest napisany w takim samym rejestrze jak rzeczywiste dokumenty, więc jego embedding znajduje się bliżej prawdziwych odpowiedzi, co naprawia niezgodność między zapytaniem a dokumentem.
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 answerDlaczego HyDE poprawia recall
Pytanie i jego odpowiedź są sformułowane inaczej, natomiast pytanie i fałszywa, lecz wiarygodna odpowiedź są sformułowane podobnie do rzeczywistej odpowiedzi. HyDE wykorzystuje prior generatywny LLM-a, aby wypełnić tę lukę, nawet jeśli hipotetyczny dokument zawiera błędy faktograficzne.
Poprawność hipotetycznego dokumentu nie ma większego znaczenia: musi on jedynie zawierać właściwe słownictwo i strukturę, aby znaleźć się blisko prawdziwych dokumentów w przestrzeni embeddingów.
# 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)Kompromisy i tryby awarii HyDE
HyDE dodaje generowanie przez LLM przed wyszukiwaniem, zwiększając opóźnienie i koszt, a także może halucynować hipotetyczny dokument odbiegający od tematu. Pogarsza to recall w przypadku niszowych zapytań lub zapytań spoza rozkładu danych, o których model nic nie wie.
Można temu przeciwdziałać, łącząc wyszukiwanie na podstawie wektora HyDE z wyszukiwaniem na podstawie surowego zapytania, tak aby błędny dokument hipotetyczny nie mógł całkowicie zniszczyć recall.
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 hypotheticalsWybór i łączenie technik
Te transformacje wzajemnie się uzupełniają. Należy używać kondensowania w rozmowach, rozszerzania/wielu zapytań w przypadku luk w słownictwie, dekompozycji w przypadku pytań wieloetapowych oraz HyDE w przypadku niezgodności rejestru pytania i dokumentu. Wiele produkcyjnych stosów najpierw kondensuje zapytanie, następnie stosuje HyDE, łączy wyniki z wynikami surowego zapytania, a na końcu wykonuje reranking.
Każda dodatkowa transformacja kosztuje jedno wywołanie LLM, dlatego należy uruchamiać je zależnie od typu zapytania, a nie zawsze stosować wszystkie.
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)Ocena transformacji
Należy ocenić każdą transformację na podstawie jej wpływu na recall@k w retrievalu i dokładność końcowej odpowiedzi w porównaniu z surowym zapytaniem, korzystając ze zbioru wolnego od wycieków danych. Należy śledzić dodatkowe opóźnienie i koszt LLM, aby zachować tylko te transformacje, których korzyści przewyższają koszty.
Uwaga: transformacja, która poprawia recall, ale dodaje rozpraszające wyniki, może obniżyć dokładność odpowiedzi, jeśli nie zostanie połączona z rerankingiem i kompresją.
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),
}Szybki test
Proszę przeanalizować, dlaczego HyDE działa mimo niedoskonałych hipotez.
Podsumowanie
Najważniejsze wnioski:
- Możliwości retrievalu ogranicza zapytanie; jego transformacja to niedrogie ulepszenie RAG o dużym wpływie.
- Przepisywanie/kondensacja sprawia, że zapytania czatowe stają się samodzielne, a ekspansja i multi-query uzupełniają braki w słownictwie.
- Dekompozycja obsługuje pytania wieloetapowe, pobierając dane dla każdego podzapytania.
- HyDE osadza hipotetyczną odpowiedź, aby zniwelować różnicę rejestru między pytaniem a dokumentem; poprawność hipotezy nie jest wymagana.
- Należy łączyć transformacje zależnie od typu zapytania, scalać je z surowym zapytaniem dla większej odporności oraz oceniać recall, dokładność odpowiedzi, opóźnienie i koszt.
Często zadawane pytania
Czy lekcja „Przepisywanie zapytań i HyDE” jest bezpłatna?
Tak — pełny tekst „Przepisywanie zapytań i HyDE” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Prompt Engineering, przejdź na CoddyKit PRO. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.
Co nauczysz się w „Przepisywanie zapytań i HyDE”?
Poprawa kompletności wyszukiwania Ćwiczysz AI Prompt Engineering z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Prompt Engineering?
Nie wymagamy żadnego doświadczenia. AI Prompt Engineering w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Przepisywanie zapytań i HyDE”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Prompt Engineering?
Tak. Każda lekcja AI Prompt Engineering zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Poza naiwnym RAG
- Ponowne szeregowanie pobranych fragmentów
- Kompresja kontekstu
- Przepisywanie zapytań i HyDE