Blog/Retrieval & Suche
Query Rewriting für die konversationelle Suche: Kontext, HyDE und Filter
Wie Follow-up-Fragen in einem B2B-Shop-Assistenten umgeschrieben werden: Koreferenz, HyDE, Multi-Query, Filter, Latenz und Evaluation.
Balázs Csorba··12 Min. Lesezeit
- Conversational search
- Query rewriting
- RAG
- HyDE
- E-commerce

Das Wichtigste in Kürze
- Eine konversationelle Anfrage braucht ein Rewrite, keinen längeren Prompt: Pronomen, Ellipsen und geänderte Bedingungen müssen vor dem Retrieval explizit werden.
- HyDE hilft, wenn das Modell das Domänenvokabular schon kennt; bei Nischenbegriffen aus dem Katalog erfindet es die falschen Wörter, also die Originalanfrage im Mix behalten.
- Multi-Query-Erweiterung bringt Recall und kostet Drift und Latenz: entlang verschiedener Achsen erweitern, mit RRF fusionieren und die Anzahl begrenzen.
- Filter sind die riskanteste Ausgabe: Berechtigungsfilter kommen aus dem Konto, nie aus dem Modell, und jeder generierte Filter braucht Schema-Validierung.
- Auf Sitzungen mit Recall@k und Antwortqualität messen, nicht darauf, wie ähnlich ein Rewrite einer menschlichen Referenz ist.
Eine Suchmaske bekommt eine Anfrage. Ein Chat bekommt ein Gespräch. In der dritten Runde schreibt der Einkäufer „und dasselbe in 5 Liter", und die Suche erhält einen Satz ohne Produkt, ohne Werkstoff und ohne Einheit. Ein größeres Kontextfenster löst das nicht. Ein Rewrite-Schritt schon.
Dieser Artikel handelt von diesem Schritt in einem B2B-Shop-Assistenten: Koreferenz und Ellipse, HyDE, Multi-Query-Erweiterung, Filterextraktion, die Ausnahme für Artikelnummern, die Latenz des zusätzlichen Aufrufs und die Frage, wie man das Ergebnis auf Sitzungen evaluiert statt auf dem umgeschriebenen Text.
Warum die zweite Frage schwerer ist als die erste
Query Understanding in einer Runde ist Parsen. Mehrrundensuche ist Referenzauflösung zusätzlich zum Parsen. „4711-32" ist für jeden Retriever einfach. „Habt ihr das in 5 Liter" ist für einen Menschen einfach und für einen Index unmöglich, weil das Substantiv fehlt.
Zwei Wege aus der Lücke. Conversational Dense Retrieval kodiert den Verlauf mit der Anfrage in einen Vektor, braucht aber Session-Passage-Trainingsdaten. Conversational Query Reformulation behält den Retriever und schreibt die Folgefrage in eine eigenständige Anfrage um; ConvSearch-R1 beschreibt diese Trennung und argumentiert, dass Reformulation einen Standard-Retriever nutzbar macht. In Shops setze ich auf Reformulation: Suchmaschine und Synonyme existieren, und ein Rewrite-Schritt ist die kleinere Änderung als ein neuer Retrieval-Stack.
Vier Dinge, die ein Gespräch mit einer Anfrage macht
- Koreferenz. „Es", „das da", „das zweite" zeigen auf ein Produkt, das der Assistent gezeigt hat.
- Ellipse. „Und in 5 Liter?" lässt Produkt und Attribut weg.
- Geänderte Bedingung. „Günstiger" oder „nicht das verzinkte" fügt eine Bedingung hinzu oder entfernt eine.
- Themenwechsel. „Wann wird geliefert?" darf den Produktfilter nicht erben.
Jeder Fall scheitert anders: eine verpasste Koreferenz liefert ein zufälliges Produkt der Kategorie, eine verpasste Bedingung die richtige Familie mit falscher Spezifikation, ein verpasster Themenwechsel ein Produkt, obwohl nach Logistik gefragt wurde. Auch ein übereifriges Rewrite scheitert: Es erfindet Bedingungen oder verliert die Artikelnummer. Das Ziel ist die kleinste Anfrage, die die richtigen Kandidaten holt und die tatsächlich genannten Bedingungen behält.
Koreferenz, Ellipse und die eigenständige Anfrage
Ein gutes Rewrite trägt die Produktidentität, das besprochene Attribut, die geerbten Filter und die neue Bedingung. Die Tabelle zeigt die Muster, die ich zuerst teste.
| Muster | Runde 2 | Muss tragen | Wenn es fehlt |
|---|---|---|---|
| Pronomen | „Und in 5 Liter?" | Produkt-ID + Gebinde | unpassende 5-Liter-Behälter |
| Ellipse | „Das aus Edelstahl" | Werkstoff aus der letzten Antwort | der falsche Werkstoff |
| Ordinalverweis | „Das zweite" | ID aus der Liste des Assistenten | das erste Produkt |
| Geänderte Bedingung | „Günstiger als das" | Preisgrenze + Preisliste | Listenpreise über dem Budget |
| Themenwechsel | „Wann wird geliefert?" | Produktfilter weg, Land behalten | Produktseite statt Antwort |
Der Ordinalfall wird oft vergessen: „das zweite" aufzulösen braucht die vorige Antwort des Assistenten, inklusive Reihenfolge der gezeigten Produkte. Flippi, ein E-Commerce-Assistent aus einem Paper von 2025, bildet „second product" auf den Namen aus der letzten Bot-Ausgabe ab, bevor das Retrieval startet. Ein Rewriter, der nur Nutzernachrichten sieht, kann das nicht.
Die Eingabe ist also nicht das Transkript, sondern ein kompakter Zustand: die letzten Runden, gezeigte IDs und Namen, aktive Filter und der Kontokontext (Währung, Preisliste, Lieferland). Strukturierter Zustand ist billiger als zwanzig Nachrichten und macht das Rewrite testbar.
HyDE: nützlich, aber es kann den Katalog nicht erfinden
HyDE, aus dem ACL-Paper von Gao und Kollegen von 2023, lässt ein Modell eine hypothetische Antwort schreiben, bettet diese Antwort statt der Anfrage ein und sucht mit dem Vektor. Der Encoder filtert die erfundenen Details; übrig bleibt die Form eines relevanten Dokuments. Im Shop zählt die Form: Einkäuferanfragen sind kurz, Katalogtexte lang und strukturiert.
Die Evidenz ist gemischt, und zwar nützlich. Im TREC-2025-RAG-Track schrieb das Team von UTokyo und Hitotsubashi rund 150 Wörter lange hypothetische Antworten mit GPT-4.1 und mischte den Query-Vektor mit Gewicht 0,7 bei. Bei einem Embedding-Modell stieg nDCG@10 von 0,493 auf 0,564, ein relativer Gewinn von 14,4 %; HyDE allein senkte Precision@100 von 0,444 auf 0,401. Die Wörter des Nutzers im Vektor behalten.
Der größere Vorbehalt kommt aus einem ACL-Findings-Paper von 2025 zu Knowledge Leakage: Über drei Fact-Verification-Benchmarks und sieben Modelle half Query Expansion nur, wenn die generierten Dokumente Sätze enthielten, die aus der Gold-Evidenz folgen. HyDE funktioniert, wenn das Modell die Antwort schon kennt. Ein Nischenkatalog ist der Fall, in dem es sie nicht kennt: Das Modell schreibt eine selbstsichere Beschreibung mit plausiblem Werkstoff und falscher Gewindegröße und holt Produkte, die richtig aussehen und es nicht sind. Meine Regel: kein HyDE bei Identifier-Anfragen, keines wo ein falsches Attribut Sicherheitsrelevanz hat, und nur bei vagen Anwendungsfragen.
Multi-Query-Erweiterung: mehr Recall, mehr Drift
Der nächste Hebel sind mehrere Anfragen statt einer. Azure AI Search erzeugt bis zu zehn Varianten und schickt sie gemeinsam in die erste Retrieval-Stufe; Microsoft berichtet vier Punkte nDCG@3 auf termbasierten Indizes und bis zu 22 Punkte mit dem neueren semantischen Ranker. TREC iKAT 2025 fand Best-of-N-Rewriting plus Reciprocal Rank Fusion als robusteste Konfiguration, mit Reranking darüber.
Mehr ist nicht automatisch besser. Dasselbe TREC-RAG-2025-System, das von HyDE profitierte, fand, dass Paraphrasen die Retrieval-Genauigkeit durchgängig senkten; die Autoren führen das auf semantische Drift zurück. Eine Paraphrase bewegt weg vom gemeinten Intent, ein Synonym oder Attribut seitlich. Also entlang verschiedener Achsen erweitern. Mein Standard sind drei Anfragen: eigenständig, Identifier, eine Attribut-Variante. Mit RRF fusionieren, nach SKU deduplizieren, Pool vor dem Reranking begrenzen.
Filterextraktion: zuerst das Schema, dann das Modell
Filter sind der Ort, an dem der Assistent Wert zeigt, und der, an dem er am meisten Schaden anrichtet. „Unter 500" ist ein Preisfilter, „auf Lager" ein Verfügbarkeitsfilter, „die vom letzten Mal" ein Lookup in der Bestellhistorie. Amazon Bedrock Knowledge Bases zeigt das Muster: Metadaten-Attribute (Key, Typ, Beschreibung) und ein Modell beschreiben, und der Dienst generiert vor dem Retrieval einen Filter, mit den Typen String, Number, Boolean und String List.
Entscheidend ist die Trennung zwischen Präferenzfiltern aus den Worten des Nutzers (Werkstoff, Größe, Marke, Preisgrenze) und Berechtigungsfiltern aus dem Konto (Sortiment, Preisliste, Lager, sichtbare Produkte). Die erste Klasse darf ein Modell vorschlagen, die zweite nie erzeugen. Wenn das Rewrite die Preisliste setzen kann, wird aus einer Prompt-Injection in einer Bewertung ein Rabatt. Innerhalb der Präferenzklasse: Felder allowlisten, Typen prüfen, Bereiche begrenzen, unbekannte Felder ablehnen. Ein still verschwindender Filter ist schlimmer als eine Nulltreffer-Seite, weil der Einkäufer glaubt, er sei angewandt.
Artikelnummern und Einheiten: das Rewrite darf sie nicht anfassen
Die Azure-Dokumentation zum Query Rewriting enthält die wichtigste Warnung: Umgeschriebene Anfragen enthalten möglicherweise nicht mehr alle exakten Begriffe der Originalanfrage, was eindeutige Identifier und Produktcodes verschlechtert. Für ein Embedding sind 4711-32 und 4711-33 Nachbarn; für einen Einkäufer sind es verschiedene Teile.
Die Lösung ist prozedural. Identifier-Kandidaten extrahieren, bevor das Modell die Anfrage sieht (Ziffern mit Trennern, Lieferantenpräfixe, EANs, Zeichnungsnummern), durch Platzhalter ersetzen, den Rest umschreiben lassen, dann unverändert anhängen, als Must-keep-Liste und als eigene lexikalische Anfrage. Einheiten für Filter normalisieren (5 l, 5L und 5000 ml sind ein Gebinde), die getippte Form für die lexikalische Spur behalten. Dazu eine Regressions-Fixture: fünfzig echte Identifier und ein Test, dass jeder jede Prompt- und Modelländerung überlebt. Die größere Architektur steht in semantische Produktsuche für B2B-Shops.
Latenz und Kosten: was der zusätzliche Aufruf bringt
Ein Rewrite ist ein zusätzlicher Modellaufruf vor dem Retrieval, und das Retrieval läuft danach vielleicht dreimal. Die Rechnung hat drei Teile: Rewrite-Tokens, zusätzliche Retrieval- und Rerank-Arbeit und die Tail-Latenz des langsamsten Zweigs. Microsoft nennt zehn Rewrites einer 32-Token-Anfrage in 147 ms und ein semantisches Rerank von fünfzig 2.048-Token-Dokumenten in 158 ms für ein spezialisiertes kleines Modell. Ein allgemeines Chat-Modell braucht länger.
| Hebel | Bringt | Kostet | Standard |
|---|---|---|---|
| Kein Rewrite | nichts | kaputte Folgefragen | nur Runde 1 |
| Ein Rewrite | ein SLM-Aufruf | etwa 150 ms in Azures Setup | ja |
| Drei Anfragen + RRF | 3-faches Retrieval, Fusion | Latenz, Drift | niedrige Confidence |
| HyDE | Generierung + Embedding | zusätzliche Inferenz, falsches Vokabular | nicht bei Identifiern |
| Filterextraktion | Schema im Prompt | Validierung, Berechtigungsrisiko | ja, validiert |
Azures Agentic Retrieval macht den Trade-off zu einer Einstellung: minimal Effort plant ohne LLM, low macht einen Planungslauf, medium kann eine Folgeiteration auslösen, und jede Iteration kostet Latenz und Geld. Bedrocks Dekomposition hat einen ähnlichen Multiplikator: Die rerankten Ergebnisse können bis zu fünfmal so viele sein wie die abgerufenen.
Also pro Runde budgetieren. Nur rewriten, wenn die Runde es braucht: Pronomen, Ellipse, geänderte Bedingung, Themenwechsel. Einen strukturierten Constraint-State statt des Transkripts halten, System-Prompt und Schema stabil für Prompt-Caching, ein kleines Modell fürs Rewrite und ein hartes Timeout mit Fallback auf Originalanfrage plus geerbte Filter. Ein spätes Rewrite soll noch eine korrekte Antwort lassen, nur eine weniger kluge.
Evaluation: Recall@k auf Sitzungen, nicht auf dem Rewrite
Die naheliegende Metrik ist die Ähnlichkeit zu einem menschlichen Rewrite. Das falsche Ziel: Die MiniELM-Autoren sagen, es gibt keine eindeutige Ground Truth für ein ideales Rewrite, und sollte sie nicht geben, weil mehrere Rewrites dieselben richtigen Produkte finden können. Bewerte das Retrieval und die Antwort.
Den Eval-Set aus echten Sitzungen bauen. Pro Runde Nutzernachricht, den Zustand des Rewriters und das akzeptable Produkt festhalten. Offline unter mehreren Armen replayen: Originalanfrage, einzelnes Rewrite, Rewrite plus HyDE, drei fusionierte Anfragen. Recall@k pro Turn-Index berichten, weil Runde eins und fünf anders scheitern.
| Metrik | Frage | Berechnet auf |
|---|---|---|
| Recall@k | ist das richtige Produkt im Kandidatensatz? | Retrieval, pro Runde |
| nDCG@10 | stehen relevante Produkte weit oben? | Retrieval, pro Runde |
| Filter-Precision und -Recall | entsprechen die Filter den Handlabels? | Rewrite-Ausgabe |
| Identifier-Erhalt | ist jede Artikelnummer erhalten? | Rewrite-Ausgabe |
| Faithfulness, Response Relevancy | ist die Antwort belegt und passend? | Generierung |
Die letzte Zeile nutzt Ragas-Metriknamen. Faithfulness erwischt ein Modell, das Lücken aus dem Gedächtnis füllt; Response Relevancy eines, das höflich eine andere Frage beantwortet. Keine ersetzt einen menschlichen Durchgang über hundert Antworten, besonders wo eine falsche Kompatibilitätsaussage eine Retoure ist.
Das Gegenfaktische mitloggen: Originalanfrage, umgeschriebene Anfragen, Filter, Kandidaten-IDs, ID der finalen Antwort. Ohne das ist nicht erkennbar, ob eine schlechte Antwort vom Rewrite, vom Retriever oder vom Generator kam. Das Metrik-Design ist dasselbe wie in RAG evaluieren; die Einheit ist die Sitzung, und die relevanten Segmente sind Turn-Index, Query-Typ und Sprache.
Die Pipeline, die ich ausliefern würde
Die Version, die ich vor einen Shop setzen würde, in Request-Reihenfolge:
- Normalisieren und schützen: Sprache erkennen, Identifier und Einheiten extrahieren, getippte Form behalten.
- Entscheiden: nur bei Referenz, Ellipse, geänderter Bedingung oder Themenwechsel rewriten; sonst durchreichen.
- In einen strikten JSON-Vertrag rewriten: eigenständige Anfrage, Must-keep-Begriffe, Präferenzfilter, Confidence, optionale Klärung.
- Schema, Felder, Typen und Identifier validieren; bei Fehler auf Originalanfrage und geerbte Filter zurückfallen.
- Zuerst Identifier-Spur, dann hybrid, mit RRF fusionieren, reranken, mit Belegen antworten und die interpretierte Anfrage zeigen.
// The rewrite contract: the model returns this, nothing else.
type Rewrite = {
standalone: string // query for the retriever
must_keep: string[] // part numbers, units, model names
filters: { field: string; op: "eq" | "gte" | "lte" | "in"; value: string | number | string[] }[]
confidence: number
clarify?: { question: string; options: string[] }
}
const PREFERENCE = new Set(["material", "thread", "length_mm", "brand", "price_net"])
const ENTITLEMENT = new Set(["assortment_id", "price_list_id", "ship_country"])
function validate(r: Rewrite, identifiers: string[]) {
if (r.filters.some((f) => ENTITLEMENT.has(f.field))) throw new Error("entitlement filter from model")
if (r.filters.some((f) => !PREFERENCE.has(f.field))) throw new Error("unknown filter field")
if (!identifiers.every((id) => r.must_keep.includes(id))) throw new Error("identifier lost")
return r
}Unter der Antwort „Suche: Edelstahlschraube A6, 5 l, Preis bis 500 EUR" anzuzeigen kostet eine Zeile UI und fängt die meisten Rewrite-Fehler ab, bevor sie ein Ticket werden. Der Einkäufer ist Experte; gib ihm den Korrekturhebel.
Die schweren Teile sind die langweiligen: Identifier-Guard, Berechtigungstrennung, Session-Eval-Set, Fallback. Das Modell ist die leichte Komponente.
Quellen
- Gao et al.: Precise Zero-Shot Dense Retrieval without Relevance Labels, ACL 2023
- UTokyo-Hitotsubashi at TREC 2025 RAG Track: HyDE-Enhanced Sparse-Dense Retrieval Fusion with LLM Reranking
- Hypothetical Documents or Knowledge Leakage? Rethinking LLM-based Query Expansion
- ConvSearch-R1: Enhancing Query Reformulation for Conversational Search with Reasoning via Reinforcement Learning
- CFDA and CLIP at TREC iKAT 2025: Query Reformulation and Rank Fusion
- MiniELM: A Lightweight and Adaptive Query Rewriting Framework for E-Commerce Search Optimization
- Microsoft Learn: Rewrite queries with semantic ranker in Azure AI Search (preview)
- Microsoft Learn: Agentic retrieval overview in Azure AI Search
- Microsoft Tech Community: Generative query rewriting and a new semantic ranker
- Amazon Bedrock User Guide: Configure and customize queries and response generation
- Ragas documentation: List of available metrics
Häufige Fragen
Was ist konversationelles Query Rewriting?
Es macht aus einer kontextabhängigen Folgefrage wie „und dasselbe in 5 Liter" eine eigenständige Anfrage mit Produkt, Attribut und geerbten Bedingungen. Der Retriever sieht dann eine Anfrage, die er ohne den Chatverlauf beantworten kann.
Brauche ich HyDE für einen Shop-Assistenten?
Meistens nicht. HyDE lohnt einen Test bei vagen Anwendungsfragen, wenn die Katalogtexte viel länger sind als die Frage. Für Artikelnummern ist es ungeeignet, und bei Attributen mit Sicherheits- oder Compliance-Relevanz riskant.
Wie viele Rewrites soll ich pro Turn erzeugen?
Eines als Standard, drei bei niedriger Confidence. Azure AI Search kann bis zu zehn Varianten erzeugen, aber jede weitere Anfrage vervielfacht Retrieval und Reranking, und Paraphrasen driften vom gemeinten Intent weg.
Soll das Modell Filter extrahieren?
Präferenzfilter wie Werkstoff, Größe oder Preisgrenze ja, mit Schema und Validierung. Berechtigungsfilter wie Sortiment, Preisliste oder Lieferland müssen aus der Sitzung und dem ERP kommen, nie aus dem Modell.
Wie evaluiere ich Query Rewriting?
Auf Sitzungen: Recall@k und MRR pro Turn, nDCG@10 bei abgestufter Relevanz, dazu Faithfulness und Relevanz der Antwort. Identifier-Erhalt und Nulltrefferquote separat verfolgen und nach Turn-Index, Query-Typ und Sprache segmentieren.
Bricht Query Rewriting die exakte Artikelnummernsuche?
Es kann. Microsoft warnt, dass umgeschriebene Anfragen exakte Begriffe verlieren können, die für eindeutige Identifier und Produktcodes nötig sind. Identifier vor dem Modell extrahieren, unverändert anhängen und testen, dass sie jede Prompt-Änderung überleben.