# Query Understanding and Expansion **Last updated:** 2026-04 | Verified: MCP 2026-04 **Status:** GA **Category:** RAG Architecture & Semantic Search --- ## Introduksjon Query understanding er den kritiske fasen i en RAG-løsning som transformerer brukerens spørsmål til optimaliserte søkespørringer før retrieval-steget. Mens direkte bruk av brukerens originale spørsmål kan fungere for enkle queries, gir query understanding betydelig forbedring av retrieval-kvalitet gjennom teknikker som query expansion, intent classification, query rewriting og sub-query decomposition. Målet med query understanding er tredelt: (1) **forstå brukerens intensjon** gjennom kontekstuell analyse, (2) **reformulere spørringen** til å treffe den terminologien som faktisk brukes i dokumentene, og (3) **utvide søkerommet** gjennom synonymer, relaterte termer og hypoteser. Dette steget er spesielt viktig i multi-turn conversations hvor kontekst fra tidligere meldinger må integreres, og i domener med spesialisert terminologi hvor brukerens ordvalg ikke matcher dokumentenes språk. Microsoft-stakken tilbyr flere verktøy for å implementere query understanding: Azure OpenAI for LLM-basert reformulering, Azure AI Search med innebygd fuzzy search og synonym mapping, og Semantic Kernel for orchestration av multi-step query pipelines. Kostnaden varierer basert på tilnærming — regelbaserte transformasjoner er gratis, mens LLM-basert query expansion krever ekstra tokens per spørring (typisk 200-500 input tokens + 100-300 output tokens per reformulering). ## Kjernekomponenter Query understanding består av flere teknikker som kan kombineres i en pipeline: ### 1. Intent Classification Klassifisering av brukerens intensjon i forhåndsdefinerte kategorier for å velge riktig retrieval-strategi. | Kategori | Eksempel | Handling | |----------|----------|----------| | **Factual lookup** | "Hva er hovedstaden i Frankrike?" | Single-shot keyword search | | **Complex analysis** | "Sammenlign økonomiske effekter av X og Y" | Query decomposition + multi-source retrieval | | **Troubleshooting** | "Feilen ORA-12154 i produksjon" | Entity extraction → filter på feilkode | | **Conversational followup** | "Hva med kostnaden?" | Context integration fra chat history | **Implementering:** Bruk Azure OpenAI med strukturert output (JSON mode) for å klassifisere intent. Alternativt: lightweight classification model (fine-tuned BERT) for lavere latency. ### 2. Query Expansion Utviding av spørringen med synonymer, relaterte termer og alternative formuleringer for bredere coverage. **Teknikker:** - **Synonym mapping:** Azure AI Search støtter synonym maps — definer f.eks. `"AI, kunstig intelligens, maskinlæring"` for automatisk expansion ved indexing-tid - **LLM-basert expansion:** Be GPT om "generer 3-5 alternative formuleringer av dette spørsmålet" - **Domain-specific thesaurus:** Bruk bransjespesifikke ordbøker (f.eks. medisinsk terminologi) **Trade-off:** Økt recall (finner flere relevante dokumenter), men potensielt lavere precision (mer støy). Kombiner med reranking. ### 3. Query Rewriting Reformulering av spørringen for å adressere problemer som vaghet, manglende keywords, unødvendige ord eller uklar semantikk. **Anvendelser:** | Problem | Originalt spørsmål | Rewritten query | |---------|-------------------|-----------------| | **Vagueness** | "Vis meg skjemaet" | "Vis medarbeider onboarding request form" (fra chat context) | | **Stavefeil** | "Azur AI serch" | "Azure AI Search" | | **Missing context** | "Hva med kostnaden?" | "Hva er kostnaden for Azure OpenAI GPT-4 i Norge?" | | **Unnecessary words** | "Jeg lurer virkelig på om kanskje..." | "Hvilke lisenser trengs for Power Automate AI Builder?" | **Implementering:** Multi-turn chat med `create_history_aware_retriever` i LangChain/Semantic Kernel — dette genererer standalone queries fra conversation history. ### 4. Sub-query Decomposition Dekomponering av komplekse spørsmål i flere enkle sub-queries som kjøres uavhengig, deretter aggregering av resultater. **Eksempel:** ``` Original: "Hvordan fungerer elbiler, og hvordan sammenlignes de med fossile biler?" Sub-queries: 1. "Hvordan fungerer elektriske kjøretøy? Forklar motor og batteri." 2. "Hva er fordeler og ulemper med elbiler vs bensin/diesel?" 3. "Sammenlign total eierkostnad for elbil og fossil bil over 5 år" ``` **Decomposition-strategi:** 1. **Klassifiser** spørringen som "simple" eller "complex" (via LLM prompt) 2. **Dekomponér** komplekse spørsmål i ordered sub-queries (minst → mest avhengig) 3. **Kjør** hver sub-query parallelt mot vector store 4. **Aggregér** top-N resultater fra alle sub-queries som accumulated context 5. **Kjør** original query med accumulated context til LLM **Når bruke:** Multi-part questions, sammenligninger, "hvordan X og hva er effekten av Y"-spørsmål. ### 5. Filter Extraction Identifisering og ekstraksjon av strukturerte filtre fra naturlig språk for metadata-filtrering. **Eksempler:** | Spørring | Ekstraherte filtre | |----------|-------------------| | "Artikler om AI fra siste 6 måneder" | `date >= 2025-08-01` | | "Power Automate-dokumentasjon på norsk" | `language = 'no', product = 'Power Automate'` | | "Sikkerhetspolicyer for helsesektoren" | `sector = 'healthcare', category = 'security'` | **Krav:** Metadata må være tilgjengelig i search index (konfigureres ved indexing). Kombiner med Azure AI Search `$filter` parameter. ### 6. HyDE (Hypothetical Document Embeddings) Teknikk hvor LLM genererer hypotetiske svar på spørringen, deretter brukes embedding av disse svarene (ikke spørringen) til vector search. **Hvorfor fungerer det:** Answer-to-answer similarity er ofte høyere enn question-to-answer similarity i embedding space. **Implementering:** ```python # 1. Generer hypotetisk svar hypothetical_answer = llm.generate(f"Answer this: {user_query}") # 2. Embed svaret (ikke spørringen) answer_embedding = embedding_model.embed(hypothetical_answer) # 3. Søk mot vector store results = vector_store.similarity_search_by_vector(answer_embedding, k=5) ``` **Trade-off:** Ekstra LLM-kall (kostnad + latency), men potensielt bedre retrieval for ambiguous queries. ## Arkitekturmønstre ### Mønster 1: Single-LLM Query Rewriting **Beskrivelse:** Én LLM-prompt tar originalspørring + chat history → genererer optimalisert søkequery. **Fordeler:** - Enkel å implementere - Lavere latency (ett LLM-kall) - Kostnadseffektiv **Ulemper:** - Kan feile ved komplekse multi-step logic - Mindre kontroll over individuelle steg **Når bruke:** Simple chatbots, enkle FAQs, begrenset domene. ### Mønster 2: Multi-step Pipeline (Intent → Extract → Rewrite) **Beskrivelse:** Tre sekvensielle LLM-kall: (1) klassifiser intent, (2) ekstraher entities/filters, (3) rewrite basert på (1) og (2). **Fordeler:** - Finere kontroll over hvert steg - Bedre debugging (kan inspisere output fra hvert steg) - Høyere kvalitet for komplekse scenarios **Ulemper:** - Høyere latency (3x LLM-kall) - Høyere kostnad - Mer kompleks kode **Når bruke:** Support bots, komplekse B2B applications, multi-intent queries. ### Mønster 3: Hybrid (Rules + LLM) **Beskrivelse:** Regelbaserte transformasjoner for common cases, LLM for edge cases. ``` IF query matches regex "Hva er ?" THEN: Simple keyword search on ELSE IF query contains "sammenlign X og Y" THEN: Decompose into [query about X, query about Y] ELSE: THEN: LLM-based rewriting ``` **Fordeler:** - Optimalt cost/performance ratio - Raskere for common patterns (ingen LLM-kall) - Deterministisk oppførsel for kjente cases **Ulemper:** - Krever vedlikehold av rule set - Fallback til LLM kan gi inkonsistens **Når bruke:** High-volume production systems, kostnadsoptimalisering, deterministic requirements. ## Beslutningsveiledning ### Beslutningstabell: Hvilken teknikk når? | Scenario | Anbefalt teknikk | Hvorfor | |----------|-----------------|---------| | Multi-turn chat | Query rewriting med chat history | Kontekstualisering av "Hva med X?" | | Stavefeil og typos | Fuzzy search (Azure AI Search innebygd) | Ingen LLM-kostnad, rask | | Vage spørsmål | Query expansion + reranking | Bredere coverage → rerank for precision | | Komplekse sammenligninger | Sub-query decomposition | Parallell retrieval fra multiple sources | | Spesialisert terminologi | Domain-specific synonym maps | Fast, deterministisk | | Ambiguous queries | HyDE | Bedre embedding similarity | | Filter-baserte spørsmål | Filter extraction + metadata filtering | Direkte $filter på index | ### Vanlige feil 1. **Over-rewriting:** Endrer brukerens intensjon ved aggressiv reformulering - **Løsning:** Behold original query i parallel search, rerank combined results 2. **Expansion without reranking:** For bredt søk uten prioritering - **Løsning:** Alltid kombiner expansion med cross-encoder reranker 3. **Missing context in multi-turn:** Glemmer tidligere chat history - **Løsning:** Bruk `ConversationBufferMemory` (LangChain) eller Semantic Kernel chat history 4. **LLM hallucination i query rewriting:** Legger til fakta som ikke er i original query - **Løsning:** Instruer LLM eksplisitt: "Do NOT add facts not present in the original query" 5. **Sub-query decomposition for simple queries:** Unødvendig overhead - **Løsning:** Klassifiser query først (simple vs complex) før decomposition ### Røde flagg - 🚩 **Høy kostnad:** > 1000 tokens per query for rewriting (optimaliser prompts) - 🚩 **Latency > 2s:** For mange sekvensielle LLM-kalls (vurder parallelisering eller caching) - 🚩 **Retrieval precision < 60%:** Query understanding hjelper ikke hvis underliggende chunks er dårlige - 🚩 **User frustration:** Brukere reformulerer spørsmål 3+ ganger → query understanding feiler ## Integrasjon med Microsoft-stakken ### Azure OpenAI **Query rewriting med chat history:** ```python from langchain.chains import create_history_aware_retriever from langchain_openai import AzureChatOpenAI llm = AzureChatOpenAI( azure_deployment="gpt-4", temperature=0 ) retriever_chain = create_history_aware_retriever( llm=llm, retriever=vector_store.as_retriever(), prompt=ChatPromptTemplate.from_messages([ ("system", "Given chat history and latest user question, formulate a standalone question."), MessagesPlaceholder("chat_history"), ("human", "{input}") ]) ) ``` **Intent classification med structured output:** ```python completion = client.chat.completions.create( model="gpt-4", messages=[ {"role": "system", "content": "Classify user intent. Return JSON: {\"category\": \"factual|complex|troubleshooting\"}"}, {"role": "user", "content": user_query} ], response_format={"type": "json_object"} ) intent = json.loads(completion.choices[0].message.content)["category"] ``` ### Azure AI Search **Fuzzy search for typos (innebygd):** ```http POST https://{search-service}.search.windows.net/indexes/{index-name}/docs/search?api-version=2024-07-01 { "search": "Azur AI Serch~2", // ~2 = max 2 edit distance "queryType": "full" } ``` **Synonym mapping:** ```json { "name": "ai-synonyms", "format": "solr", "synonyms": [ "AI, kunstig intelligens, maskinlæring, machine learning", "RAG, retrieval augmented generation, retrieval-basert generering", "embedding, vektor, vector" ] } ``` Koble til index via `synonymMaps` property på searchable fields. ### Semantic Kernel **Multi-step query pipeline:** ```csharp var kernel = Kernel.CreateBuilder() .AddAzureOpenAIChatCompletion(deploymentName, endpoint, apiKey) .Build(); // Step 1: Intent classification var intentPlugin = kernel.ImportPluginFromPromptDirectory("IntentPlugin"); var intent = await kernel.InvokeAsync(intentPlugin["ClassifyIntent"], new() { ["query"] = userQuery }); // Step 2: Query rewriting based on intent var rewritePlugin = kernel.ImportPluginFromPromptDirectory("RewritePlugin"); var rewrittenQuery = await kernel.InvokeAsync(rewritePlugin[$"Rewrite{intent}"], new() { ["query"] = userQuery, ["history"] = chatHistory }); // Step 3: Execute search with rewritten query var results = await vectorStore.SearchAsync(rewrittenQuery.ToString()); ``` ### Copilot Studio **Bruk "Create search query" node:** Automatisk query rewriting med conversation history — no-code løsning. **Konfigurasjon:** 1. Legg til "Create search query" node i topic 2. Input: Current user message + conversation history 3. Output: Rewritten standalone query 4. Bruk output i "Search" eller "Custom connector" node ### Power Automate med AI Builder **GPT-vurdering for query classification:** Bruk "Create text with GPT" action til å klassifisere intent før conditional branching. ## Offentlig sektor (Norge) ### Flerspråklige spørsmål **Utfordring:** Brukere spør på norsk, nynorsk, samisk — dokumenter kan være på engelsk eller blandede språk. **Løsninger:** 1. **Query translation:** Oversett spørring til engelsk før vector search (hvis dokumenter primært engelsk) ```python translated_query = azure_translator.translate(user_query, to="en") ``` 2. **Multilingual embeddings:** Bruk `text-embedding-3-large` (støtter 100+ språk) — spørring og dokumenter i ulike språk matcher i samme vector space 3. **Language-specific indexes:** Separate indexes per språk med language-specific analyzers **Tilgjengelighet:** - **Klarspråk:** Query rewriting bør forenkle, ikke komplisere — sjekk WCAG 2.1 readability guidelines - **Voice input:** Håndter ASR-feil (stavefeil) via fuzzy search ### GDPR og personvern **Filter ut PII i queries:** Bruk Azure AI Language PII detection på user query FØR logging eller videre prosessering. ```python from azure.ai.textanalytics import TextAnalyticsClient pii_result = text_analytics_client.recognize_pii_entities([user_query]) redacted_query = pii_result[0].redacted_text # Bruk denne videre ``` ## Kostnad og lisensiering ### Prismodell **Query understanding kostnader (per 1000 queries):** | Tilnærming | Kostnad (NOK) | Latency | Kvalitet | |------------|---------------|---------|----------| | **Regelbasert (fuzzy, synonyms)** | 0 | ~50ms | Middels | | **Single LLM rewrite (GPT-4o-mini)** | ~2 NOK | ~300ms | Høy | | **Multi-step pipeline (3x GPT-4o-mini)** | ~6 NOK | ~800ms | Svært høy | | **HyDE (GPT-4 Turbo)** | ~15 NOK | ~1.5s | Variabel | **Antagelser:** - GPT-4o-mini: 0.45 NOK / 1M input tokens, 1.80 NOK / 1M output tokens - 250 input tokens + 150 output tokens per LLM-kall ### Optimaliseringstips 1. **Cache rewrites:** For common queries, cache rewritten version (Redis/Azure Cache) 2. **Batch processing:** Ved bulk-queries (f.eks. analytics), batch LLM-calls med `max_tokens` limit 3. **Fallback til billigere modeller:** GPT-4o-mini for simple rewrites, GPT-4 for complex decomposition 4. **Prompt optimization:** Reduser system prompt lengde — hver token repeteres per query ### Lisenser | Komponent | Lisens/SKU | |-----------|-----------| | **Azure OpenAI** | Pay-as-you-go eller Provisioned Throughput Units (PTU) | | **Azure AI Search** | Basic tier støtter synonym maps, Standard+ for semantic ranker | | **Semantic Kernel** | Open-source (MIT) — ingen lisenskostnad | | **Copilot Studio** | Per user/session (inkludert i M365 Copilot eller standalone) | **ROI-vurdering:** Query understanding øker retrieval precision med 15-30% (typisk) → færre irrelevante svar → høyere user satisfaction → lavere support cost. Bryt-even oftest ved 5000+ queries/måned. ## For arkitekten (Cosmo) ### Spørsmål å stille kunden 1. **"Hva er typiske brukerqueries i løsningen deres? Kan jeg få 20-50 eksempler?"** - Analysér for common patterns (multi-turn, typos, vage spørsmål) 2. **"Finnes det bransjespesifikk terminologi eller forkortelser brukerne bruker?"** - Vurdér domain-specific synonym maps eller custom entity extraction 3. **"Hvor lang chat history er relevant? 3 messages? 10 messages?"** - Påvirker context window size for query rewriting 4. **"Hva er budsjettet for retrieval per måned? Antall forventede queries?"** - Bestemmer LLM-taktikk (GPT-4 vs GPT-4o-mini vs regelbasert) 5. **"Hva er akseptabel latency for et søk? 500ms? 2s? 5s?"** - Single-step vs multi-step pipeline trade-off 6. **"Støtter løsningen kun norsk, eller multiple språk?"** - Multilingual embeddings vs translation-basert approach 7. **"Hva er konsekvensen av feil retrieval? Kritisk (medical) eller informasjonell?"** - Høy confidence threshold + decomposition for kritiske domener 8. **"Har dere eksisterende analytics på søkeadferd? Click-through rates?"** - Evaluer current baseline før implementering av query understanding ### Fallgruver - ❌ **Over-engineering:** Ikke bruk HyDE + decomposition + expansion for enkle FAQ-bots - ❌ **Ignoring baseline:** Implementer alltid A/B test: query understanding ON vs OFF - ❌ **LLM-avhengighet:** Regelbasert løser 60-70% av cases billigere - ❌ **No reranking:** Query expansion uten reranker gir mer støy, ikke bedre svar - ❌ **Context loss:** Å "reformulere" kan miste nyanser i original query - ❌ **Token bloat:** System prompts på 1000+ tokens repeteres per query — optimaliser - ❌ **Single evaluation metric:** Ikke kun precision — vurder recall, MRR, user satisfaction ### Anbefalinger per modenhetsnivå **Nivå 1 — Starter (MVP):** - Azure AI Search fuzzy search (innebygd, gratis) - Synonym maps for top 10-20 vanlige termer - Ingen LLM-basert query understanding (hold kostnad lav) **Nivå 2 — Etablert (Production):** - Single LLM rewrite med chat history (GPT-4o-mini) - Filter extraction for common metadata (dato, kategori) - A/B testing query understanding ON/OFF **Nivå 3 — Optimert (Enterprise):** - Multi-step pipeline: Intent → Extract → Rewrite - Sub-query decomposition for komplekse spørsmål - Cross-encoder reranking - Continuous evaluation med precision@k, recall@k, MRR **Nivå 4 — Avansert (Innovation):** - HyDE for ambiguous queries - Fine-tuned query classifier (BERT) for lavere latency - Custom embedding model fine-tuned på domain data - Real-time feedback loop (user clicks → retraining signal) ## Multi-Query RAG ### Konsept Multi-Query RAG genererer *multiple spørringsvariasjoner* fra én brukerquery og kjører dem parallelt mot søkeindeksen. Resultatene dedupliseres og fusjoneres via **Reciprocal Rank Fusion (RRF)** for å gi bredere dekning enn en enkelt query. ### Forskjell fra Query Expansion | Aspekt | Query Expansion | Multi-Query RAG | |--------|----------------|-----------------| | **Output** | Én beriket query | Multiple separate queries | | **Søk** | Ett søk med utvidet query | Parallelle søk per variant | | **Fusjon** | Ikke nødvendig | RRF / set union | | **Dekning** | Dypere på ett konsept | Bredere over flere konsepter | | **Kostnad** | 1 søk + 1 LLM-kall | N søk + 1 LLM-kall | ### Implementering i Azure **Steg 1: Generer query-variasjoner med LLM** ```python from openai import AzureOpenAI client = AzureOpenAI(...) def generate_query_variants(original_query: str, n: int = 3) -> list[str]: response = client.chat.completions.create( model="gpt-4o-mini", messages=[{ "role": "system", "content": f"""Generate {n} different search queries that capture different aspects of the user's question. Return one query per line. Original question: {original_query}""" }], temperature=0.7 ) variants = response.choices[0].message.content.strip().split("\n") return [original_query] + variants[:n] ``` **Steg 2: Parallelle søk + RRF-fusjon** ```python import asyncio from collections import defaultdict async def multi_query_search(queries: list[str], k: int = 5): # Kjør parallelle søk tasks = [search_async(q, top=k*2) for q in queries] all_results = await asyncio.gather(*tasks) # Reciprocal Rank Fusion rrf_scores = defaultdict(float) rrf_constant = 60 for results in all_results: for rank, doc in enumerate(results): rrf_scores[doc["id"]] += 1.0 / (rank + rrf_constant) # Sorter og returner top-k sorted_docs = sorted(rrf_scores.items(), key=lambda x: x[1], reverse=True) return sorted_docs[:k] ``` ### RRF-algoritmen Azure AI Search bruker allerede RRF internt for hybrid search (BM25 + vektor). Multi-Query RAG legger til et ekstra lag: ``` RRF_score(d) = Σ_i (1 / (rank_i(d) + k)) hvor: i = indeks over alle queries (original + varianter) rank_i(d) = dokumentets posisjon i query i k = konstant (typisk 60) ``` ### Når bruke Multi-Query RAG | Scenario | Bruk multi-query? | Begrunnelse | |----------|-------------------|-------------| | Brede, tematiske spørsmål | Ja | Dekker flere aspekter | | Presise, fakta-baserte queries | Nei | Single query er tilstrekkelig | | Tvetydig intent | Ja | Varianter fanger ulike tolkninger | | Høyt volum (>10K queries/dag) | Vurder kostnad | N×søk-kostnad | | Lav recall i eksisterende system | Ja | Øker sannsynlighet for relevante treff | ### Kostnad Multi-Query RAG med 3 varianter = ~3x søkekostnad + 1 LLM-kall for generering. - LLM-kall (gpt-4o-mini): ~0.01 NOK per query - Ekstra søk: ~0.03 NOK per ekstra søk - **Total ekstra kostnad:** ~0.10 NOK per query (for 3 varianter) --- ## Kilder og verifisering **Microsoft Learn (Verified — hentet via MCP 2026-02):** 1. [Azure Databricks: Improve RAG chain quality — Query understanding](https://learn.microsoft.com/en-us/azure/databricks/generative-ai/tutorials/ai-cookbook/quality-rag-chain#query-understanding) **Konfidens:** Verified — Multi-step query understanding (intent, entity extraction, rewriting) 2. [Azure Architecture: RAG Information retrieval — Query translation](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-information-retrieval#query-translation) **Konfidens:** Verified — Query augmentation, decomposition, rewriting, HyDE 3. [Azure AI Search: Fuzzy search to correct misspellings and typos](https://learn.microsoft.com/en-us/azure/search/search-query-fuzzy) **Konfidens:** Verified — Fuzzy query expansion med Damerau-Levenshtein distance 4. [Azure AI Search: Simple query syntax](https://learn.microsoft.com/en-us/azure/search/query-simple-syntax) **Konfidens:** Verified — Keyword search, phrase search, boolean operators 5. [Azure Arc Edge RAG: Search type parameters](https://learn.microsoft.com/en-us/azure/azure-arc/edge-rag/search-types#search-type-parameters) **Konfidens:** Verified — Query expansion, sub-query generation, hypothetical answer generation 6. [Copilot Studio: Create search query](https://learn.microsoft.com/en-us/microsoft-copilot-studio/authoring-create-search-query) **Konfidens:** Verified — No-code query rewriting med conversation history **RAG Experiment Accelerator (GitHub — Microsoft):** 7. [microsoft/rag-experiment-accelerator](https://github.com/microsoft/rag-experiment-accelerator) **Konfidens:** Verified — Query classification, decomposition, rewriting prompts (Python) **Seksjoner med baseline-kunnskap (modellkunnskap, ikke MCP-verifisert):** - **Semantic Kernel C# eksempel:** Baseline — ikke funnet i MCP-søk, basert på SK pattern library - **Token cost estimater:** Baseline — basert på Azure OpenAI pricing (januar 2026) - **ROI-tall (15-30% precision improvement):** Baseline — industry benchmarks, ikke Microsoft-spesifikk data **Totalt antall kilder:** 7 Microsoft Learn URLer (Verified) + 1 GitHub repo (Verified) = 8 kilder ### Simple Query Syntax for RAG (oppdatert 2026-04) Azure AI Search simple query syntax er default parser for full-text søk i RAG: **Boolske operatorer (tegn-basert):** - `+` — AND (påkrevd term) - `|` — OR (alternativ term) - `-` — NOT (ekskluder term) — `searchMode=all` anbefales for presis NOT-atferd **Prefix queries:** `lingui*` — matcher "linguistic", "linguini" etc. **Phrase search:** `"eksakt frase"` — krever eksakt ordrekkefølge **Begrensninger:** Ingen fuzzy search, ingen suffix/infix wildcard (bruk full Lucene syntax for det). **Bruk i RAG query expansion:** Simple syntax egner seg for keyword-delen av hybrid queries. For agentic RAG bruker LLM query planning til å generere fokuserte subqueries som kombinerer full-text + vector search parallelt.