[{"data":1,"prerenderedAt":761},["ShallowReactive",2],{"blog-conversational-search-query-rewriting-en":3},{"slug":4,"published":5,"minutes":6,"category":7,"tags":8,"keywords":14,"about":25,"sources":35,"cover":69,"og":70,"expertise":71,"locales":72,"lang":73,"title":76,"description":77,"coverAlt":78,"metaTitle":79,"takeaways":80,"faq":86,"toc":105,"blocks":139,"others":509},"conversational-search-query-rewriting","2026-10-17",12,"rag",[9,10,11,12,13],"Conversational search","Query rewriting","RAG","HyDE","E-commerce",[15,16,17,18,19,20,21,22,23,24],"conversational search query rewriting","coreference resolution search query","HyDE hypothetical document embeddings","multi-query expansion RAG","LLM filter extraction","B2B product search assistant","conversational product search","query rewriting latency","recall@k evaluation","standalone query generation",[26,29,32],{"name":27,"url":28},"Query expansion","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FQuery_expansion",{"name":30,"url":31},"Coreference","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCoreference",{"name":33,"url":34},"Okapi BM25","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FOkapi_BM25",[36,39,42,45,48,51,54,57,60,63,66],{"title":37,"url":38},"Gao et al.: Precise Zero-Shot Dense Retrieval without Relevance Labels, ACL 2023","https:\u002F\u002Faclanthology.org\u002F2023.acl-long.99\u002F",{"title":40,"url":41},"UTokyo-Hitotsubashi at TREC 2025 RAG Track: HyDE-Enhanced Sparse-Dense Retrieval Fusion with LLM Reranking","https:\u002F\u002Ftrec.nist.gov\u002Fpubs\u002Ftrec34\u002Fpapers\u002FUTokyo.rag.pdf",{"title":43,"url":44},"Hypothetical Documents or Knowledge Leakage? Rethinking LLM-based Query Expansion","https:\u002F\u002Faclanthology.org\u002F2025.findings-acl.980.pdf",{"title":46,"url":47},"ConvSearch-R1: Enhancing Query Reformulation for Conversational Search with Reasoning via Reinforcement Learning","https:\u002F\u002Faclanthology.org\u002F2025.emnlp-main.1349\u002F",{"title":49,"url":50},"CFDA and CLIP at TREC iKAT 2025: Query Reformulation and Rank Fusion","https:\u002F\u002Farxiv.org\u002Fabs\u002F2509.15588",{"title":52,"url":53},"MiniELM: A Lightweight and Adaptive Query Rewriting Framework for E-Commerce Search Optimization","https:\u002F\u002Faclanthology.org\u002F2025.findings-acl.363\u002F",{"title":55,"url":56},"Microsoft Learn: Rewrite queries with semantic ranker in Azure AI Search (preview)","https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002Fsemantic-how-to-query-rewrite",{"title":58,"url":59},"Microsoft Learn: Agentic retrieval overview in Azure AI Search","https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002Fagentic-retrieval-overview",{"title":61,"url":62},"Microsoft Tech Community: Generative query rewriting and a new semantic ranker","https:\u002F\u002Ftechcommunity.microsoft.com\u002Fblog\u002Fazure-ai-services-blog\u002Fraising-the-bar-for-rag-excellence-query-rewriting-and-new-semantic-ranker\u002F4302729\u002F",{"title":64,"url":65},"Amazon Bedrock User Guide: Configure and customize queries and response generation","https:\u002F\u002Fdocs.aws.amazon.com\u002Fbedrock\u002Flatest\u002Fuserguide\u002Fkb-test-config.html",{"title":67,"url":68},"Ragas documentation: List of available metrics","https:\u002F\u002Fdocs.ragas.io\u002Fen\u002Fstable\u002Fconcepts\u002Fmetrics\u002Favailable_metrics\u002F","\u002Fimages\u002Fblog\u002Fconversational-search-query-rewriting\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fconversational-search-query-rewriting\u002Fog.jpg","ai-engineer",[73,74,75],"en","de","hu","Query rewriting for conversational search: context, HyDE and filters","How to rewrite follow-up questions in a B2B shop assistant: coreference, HyDE, multi-query expansion, filter extraction, latency and evaluation.","A speech bubble, then a rewritten card, then a funnel over results, linked by arrows.","Query rewriting for conversational search · Balázs Csorba",[81,82,83,84,85],"A conversational query needs a rewrite, not a longer prompt: pronouns, ellipses and changed constraints have to become explicit before retrieval.","HyDE helps when the model already knows the domain vocabulary; on niche catalogue terms it invents the wrong words, so keep the original query in the mix.","Multi-query expansion buys recall and pays with drift and latency: expand along different axes, fuse with RRF and cap the number of queries.","Filters are the riskiest output: entitlement filters come from the account, never from the model, and every generated filter needs schema validation.","Measure on sessions with recall@k and answer quality, not on how closely a rewrite matches a human reference.",[87,90,93,96,99,102],{"q":88,"a":89},"What is conversational query rewriting?","It turns a context-dependent follow-up, such as \"and the same one in 5 litres\", into a standalone query that contains the product, the attribute and the inherited constraints. The retriever then sees a query it can answer without the chat history.",{"q":91,"a":92},"Do I need HyDE for a shop assistant?","Usually not. HyDE is worth testing for vague use-case queries where catalogue descriptions are much longer than the question. It is a poor fit for part numbers, and a compliance risk when a wrong attribute could mislead a buyer.",{"q":94,"a":95},"How many rewrites should I generate per turn?","One by default, three when confidence is low. Azure AI Search can generate up to ten variants, but every extra query multiplies retrieval and rerank work, and paraphrases tend to drift away from the user intent.",{"q":97,"a":98},"Should the model extract filters?","Preference filters such as material, size or a price ceiling yes, with a schema and validation. Entitlement filters such as assortment, price list or delivery country must come from the session and the ERP, never from the model.",{"q":100,"a":101},"How do I evaluate query rewriting?","On sessions: recall@k and MRR per turn, nDCG@10 if you have graded relevance, plus answer faithfulness and relevancy. Track identifier preservation and the zero-result rate separately, and segment by turn index, query type and language.",{"q":103,"a":104},"Does query rewriting break exact part-number search?","It can. Microsoft warns that rewritten queries may drop exact terms that matter for unique identifiers and product codes. Extract identifiers before the model sees the query, re-attach them verbatim, and test that they survive every prompt change.",[106,109,112,115,118,121,124,127,130,133,136],{"id":107,"title":108},"why-rewrite","Why the second question is harder than the first",{"id":110,"title":111},"what-breaks","Four things a conversation does to a query",{"id":113,"title":114},"coreference","Coreference, ellipsis and the standalone query",{"id":116,"title":117},"hyde","HyDE: useful, but it cannot invent your catalogue",{"id":119,"title":120},"multi-query","Multi-query expansion: more recall, more drift",{"id":122,"title":123},"filters","Filter extraction: schema first, model second",{"id":125,"title":126},"exact-identifiers","Part numbers and units: the rewrite must not touch them",{"id":128,"title":129},"latency-cost","Latency and cost: what the extra call buys",{"id":131,"title":132},"evaluation","Evaluation: recall@k on sessions, not on the rewrite",{"id":134,"title":135},"design","The pipeline I would ship",{"id":137,"title":138},"sources","Sources",[140,144,147,150,153,156,157,181,184,185,188,245,248,251,252,255,258,261,262,265,274,277,278,281,290,297,298,301,309,310,313,368,371,379,380,383,386,428,431,439,440,443,450,463,466,469,472,473],{"type":141,"content":142},"paragraph",[143],"A search box receives one query. A chat receives a conversation. By the third turn the buyer writes \"and the same one in 5 litres\", and the retriever gets a sentence with no product, no material and no unit. A bigger context window does not fix that. A rewrite step does.",{"type":141,"content":145},[146],"This article is about that step in a B2B shop assistant: coreference and ellipsis, HyDE, multi-query expansion, filter extraction, the part-number exception, the latency of the extra call, and how to evaluate the result on sessions instead of on the rewritten text.",{"type":148,"level":149,"id":107,"text":108},"heading",2,{"type":141,"content":151},[152],"Single-turn query understanding is parsing. Multi-turn search is reference resolution on top of parsing. \"4711-32\" is easy for every retriever. \"Do you have it in 5 litres\" is easy for a human and impossible for an index, because the noun is missing.",{"type":141,"content":154},[155],"Two ways to close the gap. Conversational dense retrieval encodes the history with the query into one vector, but needs session-passage training data. Conversational query reformulation keeps the existing retriever and rewrites the follow-up into a standalone query; ConvSearch-R1 describes this split and argues that reformulation lets you use an off-the-shelf retriever. I default to reformulation in shops: the search engine and the synonyms already exist, and a rewrite step is a smaller change than a new retrieval stack.",{"type":148,"level":149,"id":110,"text":111},{"type":158,"items":159},"list",[160,166,171,176],[161,165],{"tag":162,"children":163},"strong",[164],"Coreference."," \"It\", \"that one\", \"the second one\" point at a product the assistant showed.",[167,170],{"tag":162,"children":168},[169],"Ellipsis."," \"And in 5 litres?\" omits the product and the attribute.",[172,175],{"tag":162,"children":173},[174],"Constraint change."," \"Cheaper\" or \"not the galvanised one\" adds or removes a condition.",[177,180],{"tag":162,"children":178},[179],"Topic shift."," \"When does it ship?\" must not inherit the product filter.",{"type":141,"content":182},[183],"Each one fails differently: a missed coreference retrieves a random product from the category, a missed constraint returns the right family with the wrong specification, a missed topic shift returns a product when the user asked about logistics. An over-eager rewrite is also a failure: it invents constraints or drops the part number. The target is the smallest query that retrieves the right candidates and keeps the constraints the user actually stated.",{"type":148,"level":149,"id":113,"text":114},{"type":141,"content":186},[187],"A good rewrite carries the product identity, the attribute under discussion, the filters inherited from earlier turns and the new constraint. The table shows the patterns I test first.",{"type":189,"head":190,"rows":199},"table",[191,193,195,197],[192],"Pattern",[194],"Turn 2",[196],"Must carry",[198],"If missed",[200,209,218,227,236],[201,203,205,207],[202],"Pronoun",[204],"\"And in 5 litres?\"",[206],"product id + pack size",[208],"unrelated 5-litre containers",[210,212,214,216],[211],"Ellipsis",[213],"\"The stainless one\"",[215],"material from the last answer",[217],"the wrong material",[219,221,223,225],[220],"Ordinal",[222],"\"The second one\"",[224],"id from the assistant's list",[226],"the first product",[228,230,232,234],[229],"Constraint change",[231],"\"Cheaper than that\"",[233],"price ceiling + price list",[235],"list prices above budget",[237,239,241,243],[238],"Topic shift",[240],"\"When does it ship?\"",[242],"drop product filters, keep country",[244],"a product page instead of an answer",{"type":141,"content":246},[247],"The ordinal case is the one teams forget: resolving \"the second one\" needs the assistant's previous answer, including the order of the products it displayed. Flippi, a 2025 e-commerce assistant, maps \"second product\" to the name from the last bot output before retrieval. A rewriter that only sees user messages cannot do that.",{"type":141,"content":249},[250],"So the input is not the transcript but a compact state: the last turns, the ids and names shown, the active filters, and the account context (currency, price list, delivery country). Structured state is cheaper than twenty messages and makes the rewrite testable.",{"type":148,"level":149,"id":116,"text":117},{"type":141,"content":253},[254],"HyDE, from the 2023 ACL paper by Gao and colleagues, has a model write a hypothetical answer to the query, embeds that answer instead of the query, and retrieves with the vector. The encoder filters the invented details; what survives is the shape of a relevant document. In a shop the shape matters: buyer queries are short, catalogue text is long and structured.",{"type":141,"content":256},[257],"The evidence is mixed in a useful way. In the TREC 2025 RAG track, the UTokyo-Hitotsubashi team wrote roughly 150-word hypothetical answers with GPT-4.1 and mixed the query vector with the hypothetical vector at 0.7. nDCG@10 rose from 0.493 to 0.564 for one embedding model, a 14.4% relative gain; HyDE alone lowered precision@100 from 0.444 to 0.401. Keep the user's own words in the vector.",{"type":141,"content":259},[260],"The bigger caveat is a 2025 ACL findings paper on knowledge leakage: across three fact-verification benchmarks and seven models, query expansion helped only when the generated documents contained sentences entailed by the gold evidence. HyDE works when the model already knows the answer. A niche parts catalogue is where it does not: the model writes a confident description with a plausible material and the wrong thread size, and retrieves products that look right and are not. My rule: no HyDE on identifier queries, none where a wrong attribute is a safety issue, and only for vague use-case queries.",{"type":148,"level":149,"id":119,"text":120},{"type":141,"content":263},[264],"The next lever is several queries instead of one. Azure AI Search generates up to ten variants and sends them to the first retrieval stage together; Microsoft reported a four-point nDCG@3 gain on term-based indexes and up to 22 points combined with its newer semantic ranker. TREC iKAT 2025 found Best-of-N rewriting plus reciprocal rank fusion the most robust configuration, with reranking essential on top.",{"type":266,"attrs":267,"inner":271,"caption":272},"diagram",{"viewBox":268,"role":269,"aria-labelledby":270},"0 0 720 250","img","csqr-fan-t csqr-fan-d","\u003Ctitle id=\"csqr-fan-t\">Three queries, one candidate list\u003C\u002Ftitle>\u003Cdesc id=\"csqr-fan-d\">A follow-up is rewritten into a part-number query, a synonym query and an attribute query. Each retrieves candidates; reciprocal rank fusion merges them, and a reranker keeps the top of the list.\u003C\u002Fdesc>\u003Cdefs>\u003Cmarker id=\"csqr-fan-ah\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\">\u003Cpath d=\"M0 0L10 5L0 10z\" class=\"d-head\" \u002F>\u003C\u002Fmarker>\u003C\u002Fdefs>\u003Crect x=\"20\" y=\"95\" width=\"110\" height=\"60\" rx=\"9\" class=\"d-box\" \u002F>\u003Ctext x=\"75\" y=\"121\" text-anchor=\"middle\" class=\"d-text\">Follow-up\u003C\u002Ftext>\u003Ctext x=\"75\" y=\"141\" text-anchor=\"middle\" class=\"d-small\">chat + account\u003C\u002Ftext>\u003Cpath d=\"M130 125H156\" class=\"d-line\" marker-end=\"url(#csqr-fan-ah)\" \u002F>\u003Crect x=\"158\" y=\"95\" width=\"110\" height=\"60\" rx=\"9\" class=\"d-sky\" \u002F>\u003Ctext x=\"213\" y=\"121\" text-anchor=\"middle\" class=\"d-text\">Rewriter\u003C\u002Ftext>\u003Ctext x=\"213\" y=\"141\" text-anchor=\"middle\" class=\"d-small\">SLM + JSON\u003C\u002Ftext>\u003Cpath d=\"M268 125L326 52\" class=\"d-line\" marker-end=\"url(#csqr-fan-ah)\" \u002F>\u003Cpath d=\"M268 125H326\" class=\"d-line\" marker-end=\"url(#csqr-fan-ah)\" \u002F>\u003Cpath d=\"M268 125L326 198\" class=\"d-line\" marker-end=\"url(#csqr-fan-ah)\" \u002F>\u003Crect x=\"328\" y=\"27\" width=\"150\" height=\"50\" rx=\"9\" class=\"d-box\" \u002F>\u003Ctext x=\"403\" y=\"57\" text-anchor=\"middle\" class=\"d-text\">Part number\u003C\u002Ftext>\u003Crect x=\"328\" y=\"100\" width=\"150\" height=\"50\" rx=\"9\" class=\"d-box\" \u002F>\u003Ctext x=\"403\" y=\"130\" text-anchor=\"middle\" class=\"d-text\">Synonym\u003C\u002Ftext>\u003Crect x=\"328\" y=\"173\" width=\"150\" height=\"50\" rx=\"9\" class=\"d-box\" \u002F>\u003Ctext x=\"403\" y=\"203\" text-anchor=\"middle\" class=\"d-text\">Attribute\u003C\u002Ftext>\u003Cpath d=\"M478 52L526 122\" class=\"d-line\" marker-end=\"url(#csqr-fan-ah)\" \u002F>\u003Cpath d=\"M478 125H526\" class=\"d-line\" marker-end=\"url(#csqr-fan-ah)\" \u002F>\u003Cpath d=\"M478 198L526 128\" class=\"d-line\" marker-end=\"url(#csqr-fan-ah)\" \u002F>\u003Crect x=\"528\" y=\"95\" width=\"80\" height=\"60\" rx=\"9\" class=\"d-gold\" \u002F>\u003Ctext x=\"568\" y=\"121\" text-anchor=\"middle\" class=\"d-text\">RRF\u003C\u002Ftext>\u003Ctext x=\"568\" y=\"141\" text-anchor=\"middle\" class=\"d-small\">top 50\u003C\u002Ftext>\u003Cpath d=\"M608 125H636\" class=\"d-line\" marker-end=\"url(#csqr-fan-ah)\" \u002F>\u003Crect x=\"638\" y=\"95\" width=\"62\" height=\"60\" rx=\"9\" class=\"d-mint\" \u002F>\u003Ctext x=\"669\" y=\"130\" text-anchor=\"middle\" class=\"d-text\">Top 10\u003C\u002Ftext>",[273],"Three queries are a budget, not a target: each extra branch adds retrieval work and another chance to drift.",{"type":141,"content":275},[276],"More is not automatically better. The same TREC RAG 2025 system that gained from HyDE found that paraphrasing consistently decreased retrieval accuracy, which the authors attribute to semantic drift. A paraphrase moves away from what the buyer meant; a synonym or an attribute moves sideways. Expand along different axes. My default is three queries: standalone, identifier, one attribute variant. Fuse with RRF, deduplicate by SKU, cap the pool before reranking.",{"type":148,"level":149,"id":122,"text":123},{"type":141,"content":279},[280],"Filters are where the assistant earns its keep and where it does the most damage. \"Under 500\" is a price filter, \"in stock\" an availability filter, \"the ones we ordered last time\" a lookup in order history. Amazon Bedrock Knowledge Bases exposes the pattern: describe metadata attributes (key, type, description) and a model, and the service generates a filter before retrieval, with types string, number, boolean and string list.",{"type":141,"content":282},[283,284,289],"The detail that matters is the split between preference filters, which come from the user's words (material, size, brand, a price ceiling), and entitlement filters, which come from the account (assortment, price list, warehouse, visible products). A model may propose the first class; it must never produce the second. If the rewrite can set the price list, a ",{"tag":285,"to":286,"children":287},"link","\u002Fblog\u002Fprompt-injection-lethal-trifecta-patterns",[288],"prompt injection"," in a review becomes a discount. Within the preference class, allowlist the fields, check types, clamp ranges, reject unknown fields. A filter that silently disappears is worse than a zero-result page, because the buyer believes it was applied.",{"type":291,"variant":292,"title":293,"body":294},"callout","warn","A filter is an authorization decision",[295],[296],"The rewrite may narrow a search to what the customer asked for; it may not widen it to what the customer is allowed to see. Assortment, contract price, delivery country and document visibility come from the session and the ERP, are applied before retrieval on every lane, and are never part of the JSON the model returns.",{"type":148,"level":149,"id":125,"text":126},{"type":141,"content":299},[300],"Microsoft's documentation for Azure query rewriting carries the warning that matters most here: rewritten queries might not contain all the exact terms the original had, which hurts unique identifiers and product codes. To an embedding, 4711-32 and 4711-33 are neighbours; to a buyer they are different parts.",{"type":141,"content":302},[303,304,308],"The fix is procedural. Extract identifier candidates before the model sees the query (digits with separators, supplier prefixes, EANs, drawing numbers), replace them with placeholders, rewrite the rest, then re-attach them verbatim as a must-keep list and as a separate lexical query. Normalise units for filters (5 l, 5L and 5000 ml are one pack size) but keep the typed form for the lexical lane. Add a regression fixture: fifty real identifiers, and a test that every one survives every prompt and model change. The wider architecture is in ",{"tag":285,"to":305,"children":306},"\u002Fblog\u002Fsemantic-product-search-b2b",[307],"semantic product search for B2B shops",".",{"type":148,"level":149,"id":128,"text":129},{"type":141,"content":311},[312],"A rewrite is an extra model call before retrieval, and retrieval may then run three times. The bill has three parts: rewrite tokens, extra retrieval and rerank work, and the tail latency of the slowest branch. Microsoft reports ten rewrites of a 32-token query in 147 ms and a semantic rerank of fifty 2,048-token documents in 158 ms for a specialised small model. A general chat model will be slower.",{"type":189,"head":314,"rows":323},[315,317,319,321],[316],"Lever",[318],"Adds",[320],"Costs",[322],"Default",[324,333,342,351,359],[325,327,329,331],[326],"No rewrite",[328],"nothing",[330],"broken follow-ups",[332],"turn 1 only",[334,336,338,340],[335],"One rewrite",[337],"one SLM call",[339],"about 150 ms in Azure's setup",[341],"yes",[343,345,347,349],[344],"Three queries + RRF",[346],"3x retrieval, fusion",[348],"latency, drift",[350],"low confidence",[352,353,355,357],[12],[354],"generation + embedding",[356],"extra inference, wrong vocabulary",[358],"not for identifiers",[360,362,364,366],[361],"Filter extraction",[363],"schema in the prompt",[365],"validation, entitlement risk",[367],"yes, validated",{"type":141,"content":369},[370],"Azure's agentic retrieval exposes the trade-off as a setting: minimal effort runs no LLM query planning, low runs one planning pass, medium can trigger one follow-up iteration, and each iteration adds latency and cost. Bedrock's decomposition has a similar multiplier: reranked results can be up to five times the retrieved results.",{"type":141,"content":372},[373,374,378],"So budget per turn. Rewrite only when the turn needs it: a pronoun, an ellipsis, a changed constraint, a topic shift. Keep a structured constraint state instead of the transcript, a stable system prompt and schema so ",{"tag":285,"to":375,"children":376},"\u002Fblog\u002Fllm-cost-latency-prompt-caching-routing",[377],"prompt caching"," works, a small model for the rewrite, and a hard timeout with a fallback to the original query plus inherited filters. A late rewrite should still leave a correct answer, just a less clever one.",{"type":148,"level":149,"id":131,"text":132},{"type":141,"content":381},[382],"The tempting metric is similarity to a human-written rewrite. It is the wrong target: MiniELM's authors point out that there is no definitive ground truth for an ideal rewrite, and should not be, because several rewrites can retrieve the same correct products. Grade the retrieval and the answer.",{"type":141,"content":384},[385],"Build the eval set from real sessions. Per turn, record the user message, the state the rewriter saw, and the product a human would accept. Replay offline under several arms: original query, single rewrite, rewrite plus HyDE, three queries fused. Report recall@k per turn index, because turn one and turn five fail for different reasons.",{"type":189,"head":387,"rows":394},[388,390,392],[389],"Metric",[391],"Question",[393],"Computed on",[395,402,408,415,421],[396,398,400],[397],"recall@k",[399],"is the right product in the candidate set?",[401],"retrieval, per turn",[403,405,407],[404],"nDCG@10",[406],"are the graded-relevant products near the top?",[401],[409,411,413],[410],"filter precision and recall",[412],"did the filters match the hand labels?",[414],"rewrite output",[416,418,420],[417],"identifier preservation",[419],"did every part number survive?",[414],[422,424,426],[423],"faithfulness, response relevancy",[425],"is the answer grounded and on topic?",[427],"generation",{"type":141,"content":429},[430],"The last row uses Ragas metric names. Faithfulness catches a model that fills gaps from memory; response relevancy catches one that answers a different question politely. Neither replaces a human pass on a hundred answers, especially where a wrong compatibility claim is a return.",{"type":141,"content":432},[433,434,438],"Log the counterfactual: original query, rewritten queries, filters, candidate ids, final answer id. Without it you cannot tell whether a bad answer came from the rewrite, the retriever or the generator. The metric design is the same as in ",{"tag":285,"to":435,"children":436},"\u002Fblog\u002Frag-evaluation-metrics",[437],"evaluating RAG","; the unit is a session, and the segments that matter are turn index, query type and language.",{"type":148,"level":149,"id":134,"text":135},{"type":141,"content":441},[442],"The version I would put in front of a shop, in request order:",{"type":266,"attrs":444,"inner":447,"caption":448},{"viewBox":445,"role":269,"aria-labelledby":446},"0 0 720 170","csqr-flow-t csqr-flow-d","\u003Ctitle id=\"csqr-flow-t\">The rewrite pipeline\u003C\u002Ftitle>\u003Cdesc id=\"csqr-flow-d\">A session state goes through a small rewriter, a validator, two retrieval lanes, rank fusion and a cited answer. Any validation failure falls back to the original query with the inherited filters.\u003C\u002Fdesc>\u003Cdefs>\u003Cmarker id=\"csqr-flow-ah\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\">\u003Cpath d=\"M0 0L10 5L0 10z\" class=\"d-head\" \u002F>\u003C\u002Fmarker>\u003C\u002Fdefs>\u003Crect x=\"20\" y=\"47\" width=\"95\" height=\"76\" rx=\"10\" class=\"d-box\" \u002F>\u003Ctext x=\"68\" y=\"81\" text-anchor=\"middle\" class=\"d-text\">Session\u003C\u002Ftext>\u003Ctext x=\"68\" y=\"103\" text-anchor=\"middle\" class=\"d-small\">state\u003C\u002Ftext>\u003Cpath d=\"M115 85H135\" class=\"d-line\" marker-end=\"url(#csqr-flow-ah)\" \u002F>\u003Crect x=\"137\" y=\"47\" width=\"95\" height=\"76\" rx=\"10\" class=\"d-sky\" \u002F>\u003Ctext x=\"184\" y=\"81\" text-anchor=\"middle\" class=\"d-text\">Rewrite\u003C\u002Ftext>\u003Ctext x=\"184\" y=\"103\" text-anchor=\"middle\" class=\"d-small\">SLM\u003C\u002Ftext>\u003Cpath d=\"M232 85H252\" class=\"d-line\" marker-end=\"url(#csqr-flow-ah)\" \u002F>\u003Crect x=\"254\" y=\"47\" width=\"95\" height=\"76\" rx=\"10\" class=\"d-gold\" \u002F>\u003Ctext x=\"302\" y=\"81\" text-anchor=\"middle\" class=\"d-text\">Validate\u003C\u002Ftext>\u003Ctext x=\"302\" y=\"103\" text-anchor=\"middle\" class=\"d-small\">schema\u003C\u002Ftext>\u003Cpath d=\"M349 85H369\" class=\"d-line\" marker-end=\"url(#csqr-flow-ah)\" \u002F>\u003Crect x=\"371\" y=\"47\" width=\"95\" height=\"76\" rx=\"10\" class=\"d-mint\" \u002F>\u003Ctext x=\"418\" y=\"81\" text-anchor=\"middle\" class=\"d-text\">Retrieve\u003C\u002Ftext>\u003Ctext x=\"418\" y=\"103\" text-anchor=\"middle\" class=\"d-small\">2 lanes\u003C\u002Ftext>\u003Cpath d=\"M466 85H486\" class=\"d-line\" marker-end=\"url(#csqr-flow-ah)\" \u002F>\u003Crect x=\"488\" y=\"47\" width=\"95\" height=\"76\" rx=\"10\" class=\"d-box\" \u002F>\u003Ctext x=\"536\" y=\"81\" text-anchor=\"middle\" class=\"d-text\">Fuse\u003C\u002Ftext>\u003Ctext x=\"536\" y=\"103\" text-anchor=\"middle\" class=\"d-small\">RRF\u003C\u002Ftext>\u003Cpath d=\"M583 85H603\" class=\"d-line\" marker-end=\"url(#csqr-flow-ah)\" \u002F>\u003Crect x=\"605\" y=\"47\" width=\"95\" height=\"76\" rx=\"10\" class=\"d-box\" \u002F>\u003Ctext x=\"652\" y=\"81\" text-anchor=\"middle\" class=\"d-text\">Answer\u003C\u002Ftext>\u003Ctext x=\"652\" y=\"103\" text-anchor=\"middle\" class=\"d-small\">cited\u003C\u002Ftext>",[449],"The validator keeps a fluent rewrite from becoming a wrong filter, a lost part number or a permission leak.",{"type":158,"ordered":451,"items":452},true,[453,455,457,459,461],[454],"Normalise and protect: detect the language, extract identifiers and units, keep the typed form.",[456],"Decide: rewrite only on a reference, ellipsis, changed constraint or topic shift; otherwise pass the query through.",[458],"Rewrite into a strict JSON contract: standalone query, must-keep terms, preference filters, confidence, optional clarification.",[460],"Validate schema, fields, types and identifiers; on failure fall back to the original query and inherited filters.",[462],"Retrieve identifier lane first, then hybrid, fuse with RRF, rerank, answer with citations and show the interpreted query.",{"type":464,"code":465},"code","\u002F\u002F The rewrite contract: the model returns this, nothing else.\ntype Rewrite = {\n  standalone: string        \u002F\u002F query for the retriever\n  must_keep: string[]       \u002F\u002F part numbers, units, model names\n  filters: { field: string; op: \"eq\" | \"gte\" | \"lte\" | \"in\"; value: string | number | string[] }[]\n  confidence: number\n  clarify?: { question: string; options: string[] }\n}\n\nconst PREFERENCE = new Set([\"material\", \"thread\", \"length_mm\", \"brand\", \"price_net\"])\nconst ENTITLEMENT = new Set([\"assortment_id\", \"price_list_id\", \"ship_country\"])\n\nfunction validate(r: Rewrite, identifiers: string[]) {\n  if (r.filters.some((f) => ENTITLEMENT.has(f.field))) throw new Error(\"entitlement filter from model\")\n  if (r.filters.some((f) => !PREFERENCE.has(f.field))) throw new Error(\"unknown filter field\")\n  if (!identifiers.every((id) => r.must_keep.includes(id))) throw new Error(\"identifier lost\")\n  return r\n}",{"type":141,"content":467},[468],"Showing \"Search: stainless screw A6, 5 l, price up to 500 EUR\" under the answer costs one line of UI and catches most rewrite errors before they become a ticket. The buyer is an expert; give them the correction handle.",{"type":141,"content":470},[471],"The hard parts are the boring ones: the identifier guard, the entitlement split, the session eval set, the fallback. The model is the easy component.",{"type":148,"level":149,"id":137,"text":138},{"type":158,"ordered":451,"items":474},[475,479,482,485,488,491,494,497,500,503,506],[476],{"tag":477,"href":38,"children":478},"a",[37],[480],{"tag":477,"href":41,"children":481},[40],[483],{"tag":477,"href":44,"children":484},[43],[486],{"tag":477,"href":47,"children":487},[46],[489],{"tag":477,"href":50,"children":490},[49],[492],{"tag":477,"href":53,"children":493},[52],[495],{"tag":477,"href":56,"children":496},[55],[498],{"tag":477,"href":59,"children":499},[58],[501],{"tag":477,"href":62,"children":502},[61],[504],{"tag":477,"href":65,"children":505},[64],[507],{"tag":477,"href":68,"children":508},[67],[510,584,642,700],{"slug":511,"published":5,"minutes":512,"category":7,"tags":513,"keywords":518,"about":531,"sources":541,"cover":578,"og":579,"expertise":71,"locales":580,"lang":73,"title":581,"description":582,"coverAlt":583},"embedding-model-selection-2026",9,[514,11,515,516,517],"Embeddings","MTEB","Vector search","Model selection",[519,520,521,522,523,524,525,526,527,528,529,530],"best embedding model 2026","how to choose an embedding model","embedding model comparison","MTEB leaderboard explained","RTEB benchmark","open source embedding model","multilingual embedding model","voyage-4 vs openai embeddings","Qwen3-Embedding","EmbeddingGemma","embedding model for RAG","switching embedding models re-embed",[532,535,538],{"name":533,"url":534},"Word embedding","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWord_embedding",{"name":536,"url":537},"Information retrieval","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FInformation_retrieval",{"name":539,"url":540},"Discounted cumulative gain","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDiscounted_cumulative_gain",[542,545,548,551,554,557,560,563,566,569,572,575],{"title":543,"url":544},"Enevoldsen et al.: MMTEB, Massive Multilingual Text Embedding Benchmark (2025)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2502.13595",{"title":546,"url":547},"Hugging Face: Introducing RTEB, a new standard for retrieval evaluation (Oct 2025)","https:\u002F\u002Fhuggingface.co\u002Fblog\u002Frteb",{"title":549,"url":550},"OpenAI: Vector embeddings guide","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fembeddings",{"title":552,"url":553},"OpenAI: API pricing","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fpricing",{"title":555,"url":556},"Voyage AI: The Voyage 4 model family, shared embedding space with MoE architecture (Jan 2026)","https:\u002F\u002Fblog.voyageai.com\u002F2026\u002F01\u002F15\u002Fvoyage-4\u002F",{"title":558,"url":559},"Voyage AI: Text embeddings documentation","https:\u002F\u002Fdocs.voyageai.com\u002Fdocs\u002Fembeddings",{"title":561,"url":562},"Voyage AI: Pricing","https:\u002F\u002Fdocs.voyageai.com\u002Fdocs\u002Fpricing",{"title":564,"url":565},"Google: Gemini API embeddings documentation","https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fembeddings",{"title":567,"url":568},"Google: Gemini API pricing","https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Fpricing",{"title":570,"url":571},"Cohere: Embed models documentation","https:\u002F\u002Fdocs.cohere.com\u002Fdocs\u002Fcohere-embed",{"title":573,"url":574},"Qwen: Qwen3-Embedding-8B model card","https:\u002F\u002Fhuggingface.co\u002FQwen\u002FQwen3-Embedding-8B",{"title":576,"url":577},"Google Developers Blog: Introducing EmbeddingGemma (Sep 2025)","https:\u002F\u002Fdevelopers.googleblog.com\u002Fen\u002Fintroducing-embeddinggemma\u002F","\u002Fimages\u002Fblog\u002Fembedding-model-selection-2026\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fembedding-model-selection-2026\u002Fog.jpg",[73,74,75],"Choosing an embedding model in 2026: leaderboards, costs and a bake-off on your own data","How to pick an embedding model for RAG in 2026: what MTEB and RTEB tell you, hosted vs open weights, prices, dimensions, and a one-week bake-off.","Three columns of stacked blocks, the middle tallest, each measured by a short bar and a wide bracket.",{"slug":585,"published":5,"minutes":586,"category":7,"tags":587,"keywords":591,"about":603,"sources":611,"cover":636,"og":637,"expertise":71,"locales":638,"lang":73,"title":639,"description":640,"coverAlt":641},"contextual-retrieval-late-chunking",10,[11,588,514,589,590],"Chunking","Contextual retrieval","Late chunking",[592,593,594,595,596,597,598,599,600,601,602],"contextual retrieval","anthropic contextual retrieval","late chunking","contextual chunk embeddings","contextual embeddings rag","contextual bm25","chunk context rag","voyage-context-3","voyage-context-4","late chunking vs contextual retrieval","rag chunking context loss",[604,607,608],{"name":605,"url":606},"Retrieval-augmented generation","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FRetrieval-augmented_generation",{"name":33,"url":34},{"name":609,"url":610},"Sentence embedding","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSentence_embedding",[612,615,618,621,624,627,630,633],{"title":613,"url":614},"Anthropic: Introducing Contextual Retrieval (Sep 2024)","https:\u002F\u002Fwww.anthropic.com\u002Fnews\u002Fcontextual-retrieval",{"title":616,"url":617},"Günther et al.: Late Chunking, Contextual Chunk Embeddings Using Long-Context Embedding Models (2024, rev. 2025)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2409.04701",{"title":619,"url":620},"Jina AI: Late Chunking in Long-Context Embedding Models (Aug 2024)","https:\u002F\u002Fjina.ai\u002Fnews\u002Flate-chunking-in-long-context-embedding-models\u002F",{"title":622,"url":623},"Voyage AI: Introducing voyage-context-3 (Jul 2025)","https:\u002F\u002Fblog.voyageai.com\u002F2025\u002F07\u002F23\u002Fvoyage-context-3\u002F",{"title":625,"url":626},"Voyage AI: voyage-context-4 (Jun 2026)","https:\u002F\u002Fblog.voyageai.com\u002F2026\u002F06\u002F29\u002Fvoyage-context-4\u002F",{"title":628,"url":629},"Voyage AI: Contextualized chunk embeddings documentation","https:\u002F\u002Fdocs.voyageai.com\u002Fdocs\u002Fcontextualized-chunk-embeddings",{"title":631,"url":632},"Anthropic: Claude API pricing","https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fabout-claude\u002Fpricing",{"title":634,"url":635},"Qu, Tu and Bao: Is Semantic Chunking Worth the Computational Cost? (2024)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2410.13070","\u002Fimages\u002Fblog\u002Fcontextual-retrieval-late-chunking\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fcontextual-retrieval-late-chunking\u002Fog.jpg",[73,74,75],"Contextual retrieval and late chunking: giving RAG chunks back their context","Chunks lose their document. How contextual retrieval, late chunking and contextualized embedding models fix that, what each costs, and when to skip it.","Four loose square pieces gathered by a wide bracket below, each joined upward to a large sheet.",{"slug":643,"published":5,"minutes":512,"category":7,"tags":644,"keywords":648,"about":661,"sources":669,"cover":694,"og":695,"expertise":71,"locales":696,"lang":73,"title":697,"description":698,"coverAlt":699},"rag-access-control-permissions",[11,645,646,647,516],"Access control","Security","Multi-tenancy",[649,650,651,652,653,654,655,656,657,658,659,660],"rag access control","permission aware rag","document level security rag","rag multi tenancy","vector database access control","pgvector row level security","security trimming azure ai search","openfga rag authorization","qdrant multitenancy","pinecone namespaces multitenancy","owasp llm08 vector and embedding weaknesses","rag data leakage",[662,665,668],{"name":663,"url":664},"Access-control list","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAccess-control_list",{"name":666,"url":667},"Multitenancy","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMultitenancy",{"name":605,"url":606},[670,673,676,679,682,685,688,691],{"title":671,"url":672},"OWASP GenAI Security Project: LLM08:2025 Vector and Embedding Weaknesses","https:\u002F\u002Fgenai.owasp.org\u002Fllmrisk\u002Fllm082025-vector-and-embedding-weaknesses\u002F",{"title":674,"url":675},"PostgreSQL documentation: Row Security Policies","https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fddl-rowsecurity.html",{"title":677,"url":678},"pgvector README: filtering and iterative index scans","https:\u002F\u002Fgithub.com\u002Fpgvector\u002Fpgvector",{"title":680,"url":681},"Qdrant: Multitenancy and partitions guide","https:\u002F\u002Fqdrant.tech\u002Fdocumentation\u002Fguides\u002Fmultiple-partitions\u002F",{"title":683,"url":684},"Pinecone: Implement multitenancy using namespaces","https:\u002F\u002Fdocs.pinecone.io\u002Fguides\u002Findex-data\u002Fimplement-multitenancy",{"title":686,"url":687},"Microsoft Learn: Document-level access control in Azure AI Search","https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002Fsearch-document-level-access-overview",{"title":689,"url":690},"OpenFGA: RAG authorization use case","https:\u002F\u002Fopenfga.dev\u002Fdocs\u002Fuse-cases\u002Frag-authorization",{"title":692,"url":693},"Morris et al.: Text Embeddings Reveal (Almost) As Much As Text (EMNLP 2023)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2310.06816","\u002Fimages\u002Fblog\u002Frag-access-control-permissions\u002Fcover.webp","\u002Fimages\u002Fblog\u002Frag-access-control-permissions\u002Fog.jpg",[73,74,75],"Access control for RAG: permission-aware retrieval without leaking documents","How RAG assistants leak documents and how to stop it: ACLs on every chunk, pre-filtering, row-level security in pgvector, permission sync and leak tests.","Seven cards in a row, six with a lock badge, one bare card sending an arrow outward.",{"slug":701,"published":5,"minutes":586,"category":7,"tags":702,"keywords":707,"about":719,"sources":727,"cover":754,"og":755,"expertise":756,"locales":757,"lang":73,"title":758,"description":759,"coverAlt":760},"rag-product-catalog-pim-data",[11,703,704,705,706],"PIM","Product data","B2B e-commerce","Metadata filtering",[708,709,710,711,712,713,714,715,716,717,718],"rag product catalog","rag pim data","llm product data","product catalog chatbot","akeneo rag","pimcore ai search","rag structured data","metadata filtering rag","product attributes embeddings","b2b product assistant","etim classification ai",[720,723,724],{"name":721,"url":722},"Product information management","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FProduct_information_management",{"name":605,"url":606},{"name":725,"url":726},"ETIM (standard)","https:\u002F\u002Fwww.etim-international.com\u002Fclassification\u002F",[728,731,734,737,739,742,745,748,751],{"title":729,"url":730},"Akeneo API: Products, product values, metric values and product models","https:\u002F\u002Fapi.akeneo.com\u002Fconcepts\u002Fproducts.html",{"title":732,"url":733},"Akeneo Help Center: What about products with variants?","https:\u002F\u002Fhelp.akeneo.com\u002Fserenity-take-the-power-over-your-products\u002Fserenity-what-about-products-with-variants",{"title":735,"url":736},"Pimcore documentation: Classification Store","https:\u002F\u002Fdocs.pimcore.com\u002Fplatform\u002FPimcore\u002FObjects\u002FObject_Classes\u002FData_Types\u002FClassification_Store\u002F",{"title":738,"url":726},"ETIM International: Classification",{"title":740,"url":741},"ETIM International: ETIM releases and the IXF format","https:\u002F\u002Fetim-international.com\u002F?p=754",{"title":743,"url":744},"Reddy et al.: Shopping Queries Dataset, a large-scale ESCI benchmark for improving product search (2022)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2206.06588",{"title":746,"url":747},"Amazon Science: esci-data repository","https:\u002F\u002Fgithub.com\u002Famazon-science\u002Fesci-data",{"title":749,"url":750},"Qdrant documentation: Filtering","https:\u002F\u002Fqdrant.tech\u002Fdocumentation\u002Fconcepts\u002Ffiltering\u002F",{"title":752,"url":753},"Sui et al.: Table Meets LLM, can large language models understand structured table data? (WSDM 2024)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2305.13062","\u002Fimages\u002Fblog\u002Frag-product-catalog-pim-data\u002Fcover.webp","\u002Fimages\u002Fblog\u002Frag-product-catalog-pim-data\u002Fog.jpg","b2b-ecommerce-developer",[73,74,75],"RAG over product catalogues: turning PIM data into answers that hold","Product data is structured, so chunking it like PDFs fails. How to serialize PIM attributes, route spec questions to filters and keep answers exact.","A frame of nine squares with tiny symbols, funnelling down to one card.",1792245345489]