feat(ms-ai-architect): add plugin to open marketplace (v1.5.0 baseline)

Initial addition of ms-ai-architect plugin to the open-source marketplace.
Private content excluded: orchestrator/ (Linear tooling), docs/utredning/
(client investigation), generated test reports and PDF export script.
skill-gen tooling moved from orchestrator/ to scripts/skill-gen/.

Security scan: WARNING (risk 20/100) — no secrets, no injection found.
False positive fixed: added gitleaks:allow to Python variable reference
in output-validation-grounding-verification.md line 109.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-04-07 17:17:17 +02:00
commit 6a7632146e
490 changed files with 213249 additions and 2 deletions

View file

@ -0,0 +1,287 @@
# Agentic RAG Patterns — Agent-styrt retrieval
**Last updated:** 2026-02
**Status:** GA (Semantic Kernel), Preview (Azure AI Search agentic retrieval)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Agentic RAG representerer et paradigmeskifte fra statisk til autonom retrieval. I tradisjonell RAG er retrieval-flyten hardkodet: embed query → søk → generer svar. I agentic RAG bestemmer LLM-en selv *om*, *når* og *hvilke* kilder den henter fra, basert på dynamisk vurdering av informasjonsbehov.
Microsoft tilbyr tre primære implementeringsveier: **Semantic Kernel** (code-first RAG med TextSearchProvider), **Microsoft Agent Framework** (produksjonsklart, merged fra AutoGen + SK), og **Azure AI Search agentic retrieval** (managed service med automatisk query decomposition).
Agentic RAG gir dokumentert 34% bedre accuracy og 28% reduksjon i hallusinasjoner sammenlignet med single-query RAG, fordi agenter kan reformulere spørsmål, velge optimal kilde, og iterere til svaret er tilfredsstillende.
---
## Kjernekomponenter
### Agentic retrieval loop
```
Loop:
Agent vurderer informasjonsbehov
├─ Tilstrekkelig info? → Generer svar
└─ Utilstrekkelig? → Velg verktøy → Hent data → Vurder → Fortsett
```
### Semantic Kernel — Retrieval timing
| Modus | Beskrivelse | Brukstilfelle |
|-------|-------------|---------------|
| **BeforeAIInvoke** (default) | Automatisk søk før hver agent-invokasjon | Enkel RAG, konsistent kontekst |
| **OnDemandFunctionCalling** | Agent bestemmer selv når den søker | Agentic RAG, selektiv retrieval |
### Azure AI Search agentic retrieval — 4-stegs prosess
1. **Workflow initiation:** App sender query + konversasjonshistorikk til knowledge base
2. **Query planning:** LLM dekomponerer kompleks query i fokuserte subqueries
3. **Query execution:** Subqueries kjøres parallelt med semantic reranking per subquery
4. **Result synthesis:** 3-delt respons: Grounding Data + Reference Data + Activity Plan
### Sammenligning: Klassisk RAG vs. Agentic Retrieval
| Aspekt | Klassisk single-query | Agentic multi-query |
|--------|----------------------|---------------------|
| Query-tilnærming | Én «catch-all» query | Multiple fokuserte subqueries |
| Kontekstbruk | Begrenset | Full chat history |
| Dekomponering | Manuell/statisk | LLM-driven, automatisert |
| Eksekvering | Sekvensiell | Parallell |
| Reranking | Standard L2 | Semantisk reranking per subquery |
| Prismodell | Per query (1 000 queries) | Token-basert (1M tokens) |
---
## Arkitekturmønstre
### Mønster 1: Semantic Kernel RAG med TextSearchProvider
**Arkitektur:** Semantic Kernel Agent → TextSearchProvider → Azure AI Search VectorStore → Embedding
**Implementering (C#):**
```csharp
var embeddingGenerator = new AzureOpenAIClient(
new Uri("<endpoint>"), new AzureCliCredential())
.GetEmbeddingClient("<deployment>")
.AsIEmbeddingGenerator(1536);
var vectorStore = new InMemoryVectorStore(
new() { EmbeddingGenerator = embeddingGenerator });
using var textSearchStore = new TextSearchStore<string>(
vectorStore, "KnowledgeBase", vectorDimensions: 1536);
ChatCompletionAgent agent = new()
{
Name = "Assistant",
Instructions = "Use search to find relevant information",
Kernel = kernel,
UseImmutableKernel = true // Kreves for OnDemandFunctionCalling
};
ChatHistoryAgentThread agentThread = new();
agentThread.AIContextProviders.Add(
new TextSearchProvider(textSearchStore));
```
**Fordeler:**
- Full kontroll over retrieval-logikk
- Støtter Azure AI Search, Qdrant, Pinecone, Redis
- Namespace-filtrering for multi-tenant
**Status:** Eksperimentell (subject to change).
### Mønster 2: Tool-basert RAG med multiple retrieval-backends
**Arkitektur:** Agent → [Tool 1: Product Search] + [Tool 2: Policy Search] + [Tool 3: SQL Query] → Fusjonert svar
**Implementering (Python, Microsoft Agent Framework):**
```python
product_search = product_collection.create_search_function(
function_name="search_products",
description="Search for product information and specs.",
search_type="semantic_hybrid",
).as_agent_framework_tool()
policy_search = policy_collection.create_search_function(
function_name="search_policies",
description="Search for company policies and procedures.",
search_type="keyword_hybrid",
).as_agent_framework_tool()
agent = chat_client.as_agent(
instructions="Use appropriate search tool before answering. Cite sources.",
tools=[product_search, policy_search]
)
```
**Nøkkel:** Agenten analyserer query og velger riktig tool basert på description — ingen hardkodet routing.
**Fordeler:**
- Skalerbar: legg til nye kilder som tools
- LLM-drevet routing (ikke regelbasert)
- Kan kombinere resultater fra flere backends
**Anbefalt for:** Enterprise med multiple kunnskapskilder.
### Mønster 3: Azure AI Search managed agentic retrieval
**Arkitektur:** App → Azure AI Search Knowledge Agent → Automatisk query decomposition → Parallelle subqueries → Reranked results
**Fordeler:**
- Fully managed — ingen custom orchestration-kode
- Automatisk query planning basert på chat history
- Built-in semantic reranking per subquery
- 3-delt response med grounding + citations + activity plan
**Begrensninger:**
- Kun single index per agentic retrieval instance
- Krever semantic ranker (S1+ tier)
- Preview status (API 2025-11-01-preview)
**Prising:**
- Free tier: 50M agentic reasoning tokens/mnd
- Standard: Token-basert ($0.022/token)
**Anbefalt for:** Teams som vil ha agentic RAG uten custom infrastruktur.
### Mønster 4: Multi-agent RAG orchestration
**Arkitektur:** Orchestrator Agent → [Specialist Agent 1] + [Specialist Agent 2] + ... → Aggregert svar
**Orchestration patterns (Semantic Kernel):**
| Pattern | Beskrivelse | Brukstilfelle |
|---------|-------------|---------------|
| **Sequential** | Pipeline — agents i rekkefølge | Draft → Review → Polish |
| **Concurrent** | Parallell analyse | Finans fra ulike perspektiver |
| **Handoff** | Dynamisk delegering | Kundeservice triage |
| **Group Chat** | Collaborative diskusjon | Kvalitetsvalidering |
**Anbefalt for:** Komplekse use cases der ulike domeneeksperter trengs.
---
## Beslutningsveiledning
### Beslutningstabell
| Scenario | Query-kompleksitet | Anbefalt mønster |
|----------|-------------------|------------------|
| Enkel Q&A | Lav | Mønster 1 (BeforeAIInvoke) |
| Multiple kilder | Middels | Mønster 2 (tool-basert) |
| Konversasjonell AI | Høy | Mønster 3 (managed agentic) |
| Domene-ekspertise | Høy | Mønster 4 (multi-agent) |
| Budsjett-begrenset | Alle | Mønster 1 (BeforeAIInvoke) |
### Vanlige feil
| Feil | Konsekvens | Løsning |
|------|------------|---------|
| Multi-agent uten behov | Økt kompleksitet og kostnad | Vurder single agent med multiple tools først |
| Glemmer `UseImmutableKernel = true` | OnDemandFunctionCalling feiler | Alltid sett dette for agentic RAG i SK |
| Ingen timeout/retry | Agent henger ved LLM-feil | Implementer circuit breaker og retry logic |
| For mange agents i group chat | Infinite loops | Begrens til 3 agenter |
### Røde flagg
- Agentic RAG for enkle lookup-queries (overkill)
- Ingen observability/logging av agent-beslutninger
- Preview-tjenester i produksjon uten fallback-plan
- Multi-agent uten tydelig spesialisering per agent
---
## Integrasjon med Microsoft-stakken
| Tjeneste | Integrasjonspunkt |
|----------|-------------------|
| **Azure AI Search** | Agentic retrieval (preview), vector store, hybrid search |
| **Semantic Kernel** | TextSearchProvider, agent orchestration patterns |
| **Microsoft Agent Framework** | VectorStore bridge, tool-basert RAG |
| **Azure AI Foundry** | Prompt Flow for visual DAG orchestration |
| **Azure OpenAI** | GPT-4o for query planning, function calling |
| **Application Insights** | Agent decision logging, token tracking |
---
## Offentlig sektor (Norge)
### Dataplassering
- **Azure AI Search agentic retrieval:** Sjekk regional tilgjengelighet (endres)
- **Semantic Kernel:** Kjøres i egen infrastruktur — full kontroll
- **Azure OpenAI (function calling):** Sweden Central — data i EU/EØS
### Relevante vurderinger
| Krav | Implikasjon |
|------|-------------|
| **AI Act** | Agent-beslutninger må logges og forklares |
| **Forvaltningsloven** | Automatiserte avgjørelser krever human oversight |
| **GDPR** | Agent-logger som inneholder persondata krever databehandleravtale |
| **NSM** | Gradert info → on-premises agent-infrastruktur |
---
## Kostnad og lisensiering
### Kostnadssammenligning
| Mønster | Kostnad per query | Notat |
|---------|-------------------|-------|
| Klassisk RAG (single query) | ~1 NOK | Embedding + search + LLM |
| Agentic retrieval (managed) | ~2-5 NOK | Token-basert, query decomposition |
| Tool-basert RAG (2-3 tools) | ~3-8 NOK | Multiple search + LLM calls |
| Multi-agent (3 agents) | ~5-15 NOK | Flere LLM-kall per query |
### Optimaliseringstips
1. **Bruk gpt-4o-mini for query planning** (raskere, billigere)
2. **Implementer semantic caching** for gjentatte queries
3. **BeforeAIInvoke for enkle queries** (sparer tool-calling overhead)
4. **Monitor token usage** via Application Insights
---
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **"Hvor komplekse er typiske bruker-spørsmål?"** — Enkle lookup → klassisk RAG, komplekse → agentic
2. **"Har dere multiple kunnskapskilder?"** — >2 kilder → tool-basert RAG
3. **"Er konversasjonshistorikk viktig?"** — Ja → agentic retrieval med chat history
4. **"Hva er akseptabel kostnad per query?"** — Agentic = 2-15x dyrere
5. **"Trenger dere forklarbare agent-beslutninger?"** — Compliance → logging av activity plan
### Fallgruver
- **Agentic for alt:** Single-query RAG dekker 70% av use cases — start der
- **Preview-avhengighet:** Azure AI Search agentic retrieval er preview — ha fallback
- **Agent-explosion:** For mange spesialist-agenter = uforutsigbar oppførsel
### Anbefalinger per modenhetsnivå
| Modenhet | Anbefaling |
|----------|------------|
| **Prototyp** | Klassisk RAG med hybrid search + semantic ranker. |
| **Pilot** | Semantic Kernel med BeforeAIInvoke + single tool. |
| **Produksjon** | Tool-basert RAG med 2-3 backends. OnDemandFunctionCalling. |
| **Enterprise** | Azure AI Search agentic retrieval + multi-agent for komplekse workflows. |
---
## Kilder og verifisering
| Kilde | Konfidens | URL |
|-------|-----------|-----|
| Adding RAG to Semantic Kernel Agents | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-rag) |
| Agentic Retrieval (Azure AI Search) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/agentic-retrieval-overview) |
| Agent RAG (Microsoft Agent Framework) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/agent-framework/user-guide/agents/agent-rag) |
| AI Agent Design Patterns | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/ai-agent-design-patterns) |
| Semantic Kernel Agent Orchestration | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-orchestration/) |
| Multi-agent performance (34% accuracy) | **Baseline** | Community source (ragaboutit.com) |

View file

@ -0,0 +1,464 @@
# Azure AI Search - Configuration and Deployment
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Azure AI Search (tidligere Azure Cognitive Search) er Microsofts managed search-plattform for å bygge enterprise-ready søkeløsninger med AI-beriket innhold. For RAG-arkitektur er den det dominerende valget i Microsoft-stakken — den støtter hybrid search (full-text + vector), semantic ranker, og integrerer direkte med Azure OpenAI, AI Foundry, og Copilot Studio.
Korrekt konfigurasjon av Azure AI Search avgjør om RAG-systemet ditt er kostnadseffektivt, performant, og skalerbart. Feilvalg av SKU, indekseringsstrategi, eller replika-konfigurasjon kan føre til unødvendig høye kostnader eller dårlig brukeropplevelse. Denne referansen dekker de kritiske valgene arkitekten må ta: SKU-seleksjon, indekseringsstrategier, skalering, og prisingmodeller.
For offentlig sektor er Azure AI Search spesielt relevant fordi den støtter data residency (Norway East/West regioner), GDPR-compliance, og kan konfigureres med Private Link for å holde trafikk innenfor Azure-nettverket. Den er en nøkkelkomponent i norske AI-løsninger som må følge Schrems II og Forvaltningslovens krav til informasjonssikkerhet.
## Kjernekomponenter
### Azure AI Search Service Tiers
| Tier | Bruksområde | Maks dokumenter | Maks indekser | Semantic Ranker | Vector Search | Estimert kostnad (NOK/mnd) |
|------|-------------|-----------------|---------------|-----------------|---------------|----------------------------|
| **Free** | Prototyping | 10 000 | 3 | Nei | Begrenset | Gratis (0) |
| **Basic** | Små prod-miljøer | 15M | 15 | Nei | Ja | ~800 |
| **Standard (S1)** | Mid-tier prod | 60M per partition | 50 | Ja | Ja | ~4 000 |
| **Standard (S2)** | Høy-volum prod | 120M per partition | 200 | Ja | Ja | ~8 000 |
| **Standard (S3)** | Enterprise-scale | 240M per partition | 200 | Ja | Ja | ~16 000 |
| **Storage Optimized (L1/L2)** | Arkivering, cold search | 120M/240M per partition | 10 | Nei | Ja | ~11 000 / ~22 000 |
**Viktige egenskaper:**
- **Partitions:** Øker lagringskapasitet og parallellitet (horizontal scaling)
- **Replicas:** Øker throughput og tilgjengelighet (query load balancing)
- **SLA:** 99.9% for 2+ replicas (query), 99.9% for 3+ replicas (indexing + query)
- **Semantic Ranker:** Kun Standard og høyere (S1+)
- **Private Link:** Standard (S1+), Storage Optimized
### Indekseringsstrategier
Azure AI Search støtter tre indekseringsmodeller:
1. **Push API** — Applikasjonen sender dokumenter direkte til indexing API
- Best for: Real-time updates, custom pipelines, event-driven indexing
- Kompleksitet: Høy (må bygge egen orchestration)
- Use case: Chat-applikasjoner som krever øyeblikkelig synkronisering
2. **Pull (Indexers)** — Azure AI Search henter data fra datakilde på schedule
- Best for: Bulk indexing, batch processing, scheduled updates
- Støttede kilder: Azure Blob Storage, Cosmos DB, SQL Database, SharePoint Online
- Use case: Bulk-indeksering av SharePoint-dokumenter, nightly sync
3. **Hybrid (Debug Sessions + Skillsets)** — Indexer + AI enrichment pipeline
- Best for: OCR, entity extraction, key phrase extraction før indexing
- Koster: Både AI Search indexer-tid OG Azure AI Services API-kall
- Use case: Søk i scannede PDF-er, bildeanalyse, custom skills
### Search Service Configuration
**Kritiske konfigurasjonsparametre:**
```json
{
"name": "search-service-name",
"location": "norwayeast",
"sku": {
"name": "standard"
},
"replicaCount": 2,
"partitionCount": 1,
"hostingMode": "default",
"publicNetworkAccess": "disabled",
"privateEndpointConnections": [...],
"semanticSearch": "standard"
}
```
**Replica vs Partition trade-offs:**
| Scenario | Replicas | Partitions | Begrunnelse |
|----------|----------|------------|-------------|
| Høy query load, moderat data | 3+ | 1 | Prioriter throughput, unngå partition-overhead |
| Stor datamengde, lav trafikk | 1-2 | 3+ | Prioriter lagring, spar på replica-kostnad |
| Enterprise prod (SLA) | 3+ | 2+ | SLA krever 3 replicas, partitions for skalering |
| Dev/test | 1 | 1 | Minimal kostnad |
## Arkitekturmønstre
### Mønster 1: Single-Index RAG (enkleste)
```
[Azure OpenAI] --> [AI Search (1 index)] --> [Storage Account]
[Indexer pipeline]
```
**Når bruke:**
- Én domene/datakilde (f.eks. kun produktdokumentasjon)
- Homogene dokumenter (samme format, metadata)
- Enkelt RBAC-krav (alle brukere ser alt)
**Fordeler:**
- Lavest kompleksitet
- Enkleste kostnadsmodell
- Best latency (én søkeoperasjon)
**Ulemper:**
- Kan ikke skille tilgang per bruker uten custom filtering
- Blander alle dokumenttyper i samme index
- Vanskelig å optimere for ulike query-mønstre
### Mønster 2: Multi-Index Federation (enterprise)
```
[Azure OpenAI] --> [Search Client Logic]
┌─────────────────┼─────────────────┐
↓ ↓ ↓
[Index: HR] [Index: Legal] [Index: Public]
↑ ↑ ↑
[Indexer 1] [Indexer 2] [Indexer 3]
```
**Når bruke:**
- Multi-tenant scenarios (per kunde/avdeling)
- Ulike RBAC-krav per datasett
- Ulike refresh-frekvenser (HR daglig, Legal hourly)
**Fordeler:**
- Granulær sikkerhetskontroll
- Optimert per use case (ulike analyzers, scoring profiles)
- Isolert feilhåndtering (én index nede påvirker ikke andre)
**Ulemper:**
- Høyere kostnad (multiple indexes)
- Kompleks query-orchestration (må merge resultater)
- Vanskelig å ranke på tvers
### Mønster 3: Hybrid Search + Semantic Ranker (anbefalt for RAG)
```
[User Query] --> [AI Search]
┌──────────┴──────────┐
↓ ↓
[BM25 Full-Text] [Vector Search]
↓ ↓
└──────────┬──────────┘
[Semantic Ranker] (rerank top 50)
[Top K til LLM]
```
**Når bruke:**
- RAG-arkitektur med Azure OpenAI
- Trenger både keyword precision og semantic recall
- Budsjett for Standard tier (S1+)
**Fordeler:**
- Best relevance for RAG (kombinerer begge verdener)
- Semantic Ranker forbedrer top-K dramatisk
- Støtter både "exact match" og "conceptual match"
**Ulemper:**
- Krever S1+ tier (dyrere)
- Semantic Ranker koster ekstra per 1000 queries
- Høyere latency (3 steg: BM25, vector, rerank)
## Beslutningsveiledning
### Velg SKU basert på bruksområde
| Krav | Anbefalt SKU | Begrunnelse |
|------|--------------|-------------|
| Prototype, POC, demo | Free eller Basic | Gratis/billig, tilstrekkelig for <15M docs |
| Prod, <10M docs, moderate queries | S1 | Best value, semantic ranker inkludert |
| Prod, 10-50M docs | S1 (multi-partition) eller S2 | Øk partitions etter behov |
| Prod, >50M docs | S2 eller S3 | S3 for høy throughput + stor data |
| Compliance: Private Link | S1+ | Free/Basic støtter ikke Private Link |
| Arkivering, cold storage | L1 eller L2 | Billigere per GB, men tregere queries |
### Vanlige feil og misforståelser
| Feil | Konsekvens | Riktig tilnærming |
|------|------------|-------------------|
| "Vi trenger S3 for å være sikre" | 4x kostnad vs. S1 uten reell gevinst | Start med S1, skaler opp ved faktisk behov |
| Bruke 1 replica i prod | Ingen SLA, downtime ved maintenance | Alltid 2+ replicas for prod (query SLA) |
| Bruke Basic tier for RAG | Ingen semantic ranker → dårlig relevance | S1 minimum for RAG med semantic ranker |
| Ignorere partition-grense | Query-timeout ved >60M docs på S1 | Øk partitions, ikke bare replicas |
| Push API uten rate limiting | Throttling (429 errors) | Bruk batch indexing eller indexer-pipeline |
### Røde flagg arkitekten bør se etter
1. **Kunden krever <100ms latency for RAG:** Urealistisk med hybrid search + semantic ranker (typisk 200-500ms). Vurder caching eller pre-retrieval.
2. **"Vi skal indeksere 500M dokumenter":** S3 HD (high density) eller vurder sharding til flere services.
3. **"Vi vil ha vector search uten full-text":** Mulig, men dårlig idé — hybrid search er nesten alltid bedre.
4. **"Vi trenger real-time sync (<1 sek)":** Push API mulig, men komplekst. Vurder om eventual consistency (5-10 sek) er akseptabelt.
5. **"Kan vi bruke Free tier i prod?":** Nei. Ingen SLA, maksimalt 10K docs, ingen semantic ranker.
## Integrasjon med Microsoft-stakken
### Azure OpenAI + AI Search (RAG)
```python
from azure.search.documents import SearchClient
from openai import AzureOpenAI
# 1. Retrieve via AI Search
search_client = SearchClient(endpoint, index_name, credential)
results = search_client.search(
search_text=user_query,
vector_queries=[VectorizedQuery(vector=query_embedding, k_nearest_neighbors=5)],
select=["content", "title", "url"],
top=5
)
# 2. Ground OpenAI with retrieved context
context = "\n\n".join([doc["content"] for doc in results])
openai_client = AzureOpenAI(...)
response = openai_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": f"Use this context: {context}"},
{"role": "user", "content": user_query}
]
)
```
### Copilot Studio + AI Search (Declarative Agent)
Copilot Studio kan bruke AI Search som "knowledge base" via **Declarative Agent**-manifest:
```json
{
"capabilities": [
{
"name": "OneDriveAndSharePoint",
"items_by_url": [
{
"url": "https://search-service.search.windows.net/indexes/my-index"
}
]
}
]
}
```
**Krav:**
- AI Search må ha Public Network Access eller Managed Identity-konfigurasjon
- Index må ha semantic configuration
- Copilot Studio kjører automatisk hybrid search + semantic ranker
### AI Foundry + AI Search (Prompt Flow)
AI Foundry (tidligere AI Studio) har innebygget **Vector Index**-node i Prompt Flow:
```yaml
inputs:
query: ${inputs.question}
index_type: "Azure AI Search"
endpoint: "https://search-service.search.windows.net"
index_name: "my-index"
top_k: 5
```
**Best practice:**
- Bruk Managed Identity (ikke API keys) mellom AI Foundry og AI Search
- Konfigurer Private Link hvis begge er i samme VNET
### Power Platform + AI Search (Custom Connector)
Power Automate/Power Apps kan kalle AI Search via **Custom Connector**:
- Bruk OpenAPI-spec for Azure AI Search REST API
- Bruk Service Principal for autentisering
- Typisk use case: "Search company docs" action i Power Virtual Agents
## Offentlig sektor (Norge)
### GDPR og data residency
Azure AI Search støtter **Norway East** og **Norway West** regioner:
- Data lagres kun i Norge (ingen geo-replication utenfor EU/EEA)
- Metadata (index schema, konfiguration) lagres i Azure Control Plane (EU)
- Oppfyller GDPR Article 28 (processor agreement)
### Schrems II og Forvaltningsloven
**Schrems II-relevans:**
- Microsoft er amerikansk selskap → potensielt CLOUD Act-scope
- **Mitigerende tiltak:**
- Bruk Norway regions (ikke US/Global)
- Konfigurer Private Link (ingen trafikk over internet)
- Krypter data med Customer Managed Keys (CMK) i Azure Key Vault
**Forvaltningsloven § 13b (informasjonssikkerhet):**
- Krav om tilgangskontroll: Bruk Azure RBAC + document-level security filters
- Krav om logging: Aktiver Diagnostic Settings (Log Analytics)
- Krav om risikovurdering: Dokumenter SKU-valg, encryption, network isolation
### AI Act (fra 2026)
**Relevans for AI Search:**
- Ikke en "høyrisiko AI-system" i seg selv (er infrastruktur)
- Men hvis brukt i RAG for høyrisiko use case (f.eks. saksbehandling), må systemet dokumentere:
- Data provenance (hvor kom dokumentene fra?)
- Citation tracking (hvilke dokumenter ble brukt i svar?)
- Bias testing (er søkeresultater skjeve?)
**Anbefaling:** Implementer metadata-tagging for data lineage (kilde, dato, versjon).
## Kostnad og lisensiering
### Prismodell (2026)
Azure AI Search prises per **search unit** (SU = 1 partition × 1 replica).
| Tier | Kostnad per SU (NOK/mnd) | Ekstrakostnader |
|------|---------------------------|-----------------|
| Basic | ~800 | N/A |
| S1 | ~2 000 | Semantic Ranker: ~70 NOK per 1000 queries |
| S2 | ~4 000 | Semantic Ranker: ~70 NOK per 1000 queries |
| S3 | ~8 000 | Semantic Ranker: ~70 NOK per 1000 queries |
| L1 | ~5 500 | N/A |
**Eksempel:**
- S1 med 2 replicas, 1 partition = 2 SU = 4 000 NOK/mnd
- S1 med 3 replicas, 2 partitions = 6 SU = 12 000 NOK/mnd
- Semantic Ranker: 100 000 queries/mnd = ~7 000 NOK ekstra
### Kostnadsoptimaliseringstips
1. **Start med 1 partition, 2 replicas (ikke omvendt):**
- 2 replicas gir SLA og throughput
- Legg til partitions kun når du treffer lagringsgrense
2. **Bruk indexer-schedule, ikke continuous:**
- Continuous indexing koster mer (konstant polling)
- Scheduled indexing (f.eks. hver 6. time) er billigere
3. **Deaktiver semantic ranker i dev/test:**
- Semantic ranker koster per query
- Aktiver kun i prod-miljø
4. **Bruk Free tier for prototyping:**
- Gratis, men maks 10K docs og 3 indekser
- Bytt til Basic/S1 kun når du deployer til prod
5. **Vurder Storage Optimized (L1/L2) for arkivering:**
- Hvis <100 queries/dag, men stor datamengde (100M+ docs)
- 50% billigere per GB vs. Standard
6. **Unngå over-replication:**
- 2 replicas er nok for de fleste use cases
- 3+ replicas kun hvis >1000 queries per sekund eller 99.9% SLA-krav
### Sammenligning med alternativer
| Løsning | Kostnad (NOK/mnd) | Når bruke |
|---------|-------------------|-----------|
| Azure AI Search (S1, 2 replicas) | ~4 000 | Standard for RAG i Microsoft-stakk |
| Pinecone (1M vectors, standard) | ~6 000 | Kun vector search, ingen hybrid |
| Weaviate (self-hosted, Azure VM) | ~3 000 (VM) | Open source, full kontroll, men ops-kostnad |
| Azure Cosmos DB (vector search) | ~8 000+ | Hvis du allerede bruker Cosmos, ellers overkill |
**Anbefaling:** Azure AI Search er best value for RAG i Microsoft-stakken pga. native integrasjon og semantic ranker.
## For arkitekten (Cosmo)
### Nøkkelspørsmål å stille kunden
1. **"Hvor mange dokumenter skal indekseres totalt? Hvor stor er gjennomsnitts-dokumentet?"**
- Avgjør om Basic/S1/S2/S3 er tilstrekkelig (partition-sizing)
2. **"Hvor ofte må dataene oppdateres? Real-time, hourly, eller daily?"**
- Real-time → Push API (komplekst, dyrt)
- Hourly/daily → Indexer (enklere, billigere)
3. **"Hva er forventet query-volum? Queries per sekund i peak?"**
- <10 QPS: 2 replicas
- 10-50 QPS: 3 replicas
- >50 QPS: 4+ replicas eller vurder caching
4. **"Trenger dere document-level security (RBAC per dokument)?"**
- Ja → Implementer security filters (øker query-kompleksitet)
- Nei → Enklere, men alle brukere ser alt
5. **"Er dette et POC, pilot, eller prod-deployment?"**
- POC: Free/Basic
- Pilot: S1 (1 partition, 2 replicas)
- Prod: S1+ (3 replicas for SLA)
6. **"Hva er compliance-kravene? Schrems II, GDPR, AI Act?"**
- Schrems II → Norway regions + Private Link + CMK
- AI Act → Metadata tagging, citation tracking
7. **"Trenger dere hybrid search (keyword + vector) eller kun vector?"**
- Hybrid → S1+ (anbefalt for RAG)
- Kun vector → Vurder alternativer (Pinecone, Qdrant)
8. **"Hva er budsjettet for search-infrastruktur per måned?"**
- <5 000 NOK: Basic eller S1 (1 partition, 2 replicas)
- 5 000-15 000 NOK: S1 (multi-partition) eller S2
- >15 000 NOK: S2/S3 eller multi-index architecture
### Vanlige fallgruver
1. **Over-provisioning fra dag 1:**
- Kunder ber ofte om S3 "for å være sikre"
- Start med S1, skaler opp basert på faktisk bruk
2. **Glemme SLA-krav:**
- 1 replica = ingen SLA (maintenance = downtime)
- Prod krever minimum 2 replicas (query) eller 3 replicas (indexing + query)
3. **Bruke Basic tier med semantic ranker-forventning:**
- Basic støtter ikke semantic ranker
- S1 er minimum for RAG med god relevance
4. **Push API uten retry logic:**
- AI Search throttler ved >1000 docs/batch
- Implementer exponential backoff
5. **Ignorere partition-grense:**
- S1 = 60M docs per partition
- Hvis du har 100M docs, trenger du 2 partitions (ikke 10 replicas)
### Anbefalinger per modenhetsnivå
| Modenhetsnivå | Anbefaling |
|---------------|------------|
| **Pilot (ingen prod-bruk)** | Free eller Basic tier, 1 partition, 1 replica. Bruk Indexer med Azure Blob Storage. Ingen Private Link. |
| **Prod (lav trafikk, <1000 users)** | S1, 1 partition, 2 replicas. Aktiver semantic ranker. Vurder Private Link hvis sensitive data. |
| **Prod (moderat trafikk, enterprise)** | S1 eller S2, 2 partitions, 3 replicas. Private Link, Diagnostic Logging, Managed Identity. |
| **Prod (høy trafikk, >10 000 users)** | S2 eller S3, 3+ partitions, 4+ replicas. Multi-index architecture, caching-lag (Redis), CDN for static content. |
## Kilder og verifisering
### Microsoft Learn-referanser
- [Azure AI Search pricing](https://azure.microsoft.com/en-us/pricing/details/search/)
- [Choose a tier for Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-sku-tier)
- [Scale for performance in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-performance-optimization)
- [Semantic ranking in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/semantic-search-overview)
- [Indexers in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-indexer-overview)
- [Hybrid search in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/hybrid-search-overview)
### Konfidensnivå
**Verified (90%+ confidence):**
- SKU-pricing, partition/replica limits, semantic ranker availability
- Norway region support, Private Link requirements
- Hybrid search architecture, indexer support
**Baseline (70-89% confidence):**
- Semantic Ranker pricing per query (varierer noe per region)
- Exact QPS limits per tier (Microsoft dokumenterer ikke eksakte tall)
- AI Act-implikasjoner (ennå ikke fullt enforceret)
**Assumed (<70% confidence):**
- Kostnadssammenligning med Pinecone/Weaviate (priser endres ofte)
- Optimal chunk size for RAG (avhenger av use case)
---
**For Cosmo:** Denne referansen brukes når kunden snakker om "RAG-implementasjon", "søkeløsning", "Azure AI Search setup", eller spør om SKU-valg. Kombiner med **RAG Core Patterns** for arkitekturveiledning og **Hybrid Search - Full-Text and Vector Combined** for query-optimalisering.

View file

@ -0,0 +1,329 @@
# Document Chunking — Strategies and Implementation
**Last updated:** 2026-02
**Status:** GA (core features), Preview (token chunking)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Chunking er prosessen med å dele opp dokumenter i mindre segmenter som kan indekseres og hentes uavhengig i en RAG-pipeline. Kvaliteten på chunking har direkte innvirkning på retrieval-kvalitet, svar-nøyaktighet og kostnader — og er ofte den viktigste faktoren for om en RAG-løsning oppleves som nyttig eller frustrerende.
Azure AI Search tilbyr fem innebygde chunking-strategier gjennom integrated vectorization: fixed-size (Text Split skill), variable-size (sentence mode), document layout-basert (Document Intelligence), semantisk (Azure Content Understanding), og document parsing (native formatstøtte). I tillegg støttes custom skills for egendefinert logikk via Azure Functions eller eksterne biblioteker som LangChain og Semantic Kernel.
Valg av chunking-strategi avhenger av dokumenttype, bruksmønster, kvalitetskrav og kostnadsrammer. Det finnes ingen universell "beste" strategi — men det finnes gode utgangspunkt og kjente fallgruver.
## Kjernekomponenter
### Chunking-strategier i Azure AI Search
| Strategi | Skill / Metode | Status | Kostnad | Best for |
|----------|---------------|--------|---------|----------|
| Fixed-size | Text Split skill (`pages` mode) | GA | Inkludert i AI Search | Generell RAG, rask oppsett |
| Sentence-basert | Text Split skill (`sentences` mode) | GA | Inkludert | Finkornet søk (bruk forsiktig) |
| Document Layout | Document Intelligence Layout skill | GA | Per side (DI-prising) | Strukturerte dokumenter (PDF, DOCX) |
| Semantisk | Azure Content Understanding skill | GA | Per dokument (CU-prising) | Komplekse dokumenter, kryssende sider |
| Document parsing | Indexer parsing modes (Markdown, JSON) | GA | Inkludert | Pre-strukturert innhold |
| Custom | Custom Web API skill | GA | Egen infrastruktur | Domenespesifikk logikk |
### Konfigurasjonsparametere (Text Split skill)
| Parameter | Default | Anbefalt start | Beskrivelse |
|-----------|---------|----------------|-------------|
| `textSplitMode` | `pages` | `pages` | `pages` = multi-sentence chunks, `sentences` = enkeltsetninger |
| `maximumPageLength` | 2000 | 2000 (tegn) | Maks tegn per chunk (~512 tokens) |
| `pageOverlapLength` | 0 | 500 (25%) | Overlapp mellom chunks |
| `defaultLanguageCode` | `en` | `no` (for norsk) | Språkspesifikk setningsdeteksjon |
| `maximumPagesToTake` | 0 | 0 | Begrens antall chunks (0 = alle) |
### Skillset-definisjon (Text Split)
```json
{
"@odata.type": "#Microsoft.Skills.Text.SplitSkill",
"textSplitMode": "pages",
"maximumPageLength": 2000,
"pageOverlapLength": 500,
"defaultLanguageCode": "no",
"context": "/document/content",
"inputs": [{"name": "text", "source": "/document/content"}],
"outputs": [{"name": "textItems", "targetName": "pages"}]
}
```
### Document Layout skill (strukturert chunking)
```json
{
"@odata.type": "#Microsoft.Skills.Util.DocumentIntelligenceLayoutSkill",
"context": "/document",
"outputMode": "oneToMany",
"markdownHeaderDepth": "h3",
"inputs": [{"name": "file_data", "source": "/document/file_data"}],
"outputs": [{"name": "markdown_document", "targetName": "markdownDocument"}]
}
```
## Arkitekturmønstre
### Mønster 1: Standard fixed-size chunking
**Arkitektur:** Data source → Indexer → Text Split skill → Embedding skill → Index
**Fordeler:**
- Enklest å sette opp og forstå
- Forutsigbar chunk-størrelse og kostnad
- Ingen ekstra API-kostnader (inkludert i AI Search)
- God nok for de fleste generelle brukstilfeller
**Ulemper:**
- Kan bryte semantisk sammenheng midt i avsnitt
- Ingen bevissthet om dokumentstruktur
- Overlap er eneste mekanisme for kontekstbevaring
**Anbefalt for:** Rask prototyping, generell RAG, homogent tekstinnhold.
### Mønster 2: Strukturbasert chunking med Document Intelligence
**Arkitektur:** Data source → Indexer → Document Layout skill → Text Split skill (om nødvendig) → Embedding skill → Index
**Fordeler:**
- Bevarer overskrifter, avsnitt og dokumentstruktur
- Markdown-output med hierarkiske headings
- Metadata om posisjon (sidenummer, bounding boxes)
- Kan kombineres med Text Split for størrelsesbegrensning
**Ulemper:**
- Ekstra kostnad per side (Document Intelligence-prising)
- Begrenset portalstøtte (East US, West Europe, North Central US)
- Krever filbasert datakilde (PDF, DOCX, PPTX, etc.)
**Anbefalt for:** Offentlig sektor (policy-dokumenter, regelverk), strukturerte rapporter, juridiske tekster.
### Mønster 3: Parent-child med index projections
**Arkitektur:** Data source → Indexer → Chunking skill → Index projections → Parent index + Child index
**Fordeler:**
- Sporbarhet: chunk → kildedokument via `text_parent_id`
- Muliggjør "zoom ut" fra chunk til fullt dokument
- Automatisk felt-mapping uten `outputFieldMappings`
- Viktig for citation tracking og audit
**Ulemper:**
- Mer kompleks indeksstruktur
- Krever forståelse av index projections
- Noe mer lagringskostnad
**Anbefalt for:** Enterprise RAG med krav til kildehenvisning, compliance-systemer, revisjonsklare løsninger.
### Mønster 4: Semantisk/kontekst-bevisst chunking
**Arkitektur:** Data source → Indexer → Azure Content Understanding skill → Semantiske enheter → Embedding skill → Index
**Konsept:** I stedet for å dele dokumenter etter fast størrelse eller setningsgrenser, identifiserer semantisk chunking meningsfulle tematiske enheter som kan spenne over sider. Azure Content Understanding (GA nov 2025) analyserer dokumentstruktur og semantikk for å produsere chunks som bevarer sammenhengende konsepter.
**Fordeler:**
- Chunks bryter ikke midt i et konsept eller argument
- Støtter kryss-side-enheter (tabeller, avsnitt som fortsetter)
- Markdown-output med LaTeX, HTML-tabeller og headings
- Bedre retrieval-kvalitet for komplekse dokumenter
**Ulemper:**
- Høyere kostnad enn Text Split (Content Understanding-prising)
- Regional tilgjengelighet begrenset
- Mindre forutsigbar chunk-størrelse
**Sammenligning med andre strategier:**
| Aspekt | Fixed-size | Document Layout | Semantisk (CU) |
|--------|-----------|-----------------|-----------------|
| Chunk-grenser | Tegntelling | Headings/avsnitt | Semantiske enheter |
| Kryss-side | Nei | Nei | Ja |
| Tabellhåndtering | Brytes | Delvis | Full støtte |
| Kostnad | Gratis | Per side (DI) | Per dokument (CU) |
| Forutsigbarhet | Høy | Middels | Lav |
**Custom semantic chunking via Azure Functions:**
For domenespesifikke krav kan du implementere egen semantisk chunking via custom skill:
```python
# Custom skill: Semantisk chunking med embedding-likhet
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer("all-MiniLM-L6-v2")
def semantic_split(text, threshold=0.5):
sentences = text.split(". ")
embeddings = model.encode(sentences)
chunks, current = [], [sentences[0]]
for i in range(1, len(sentences)):
sim = np.dot(embeddings[i], embeddings[i-1]) / (
np.linalg.norm(embeddings[i]) * np.linalg.norm(embeddings[i-1]))
if sim < threshold:
chunks.append(". ".join(current))
current = [sentences[i]]
else:
current.append(sentences[i])
chunks.append(". ".join(current))
return chunks
```
**Anbefalt for:** Komplekse dokumenter med tabeller, kryssende seksjoner, og semantisk rike avsnitt.
## Beslutningsveiledning
### Beslutningstabell
| Dokumenttype | Volumkrav | Budsjett | → Anbefalt strategi |
|-------------|-----------|----------|---------------------|
| Ren tekst (artikler, e-post) | Alle | Lavt | Text Split (fixed-size) |
| Strukturerte PDF-er (rapporter) | Alle | Moderat | Document Layout skill |
| Komplekse dokumenter (tabeller over sider) | Lavt-moderat | Høyere | Content Understanding |
| Pre-strukturert (Markdown, JSON) | Alle | Lavt | Document parsing modes |
| Domenespesifikke krav | Alle | Varierer | Custom skill |
| Blanding av formater | Høyt | Moderat | Document Layout + fallback til Text Split |
### Vanlige feil
| Feil | Konsekvens | Løsning |
|------|------------|---------|
| `sentences` mode i produksjon | 200-siders PDF → 13 000+ chunks, enorm kostnad | Bruk `pages` mode |
| Overlap > 50% av chunk size | Gir faktisk ingen overlapp (Azure-begrensning) | Hold overlap ≤ 25-30% |
| Ignorerer token-grenser | Embedding-modellen trunkerer, kvalitetstap | Sjekk med tiktoken, hold under 8191 tokens |
| Ingen parent-child tracking | Kan ikke spore tilbake til kildedokument | Bruk index projections |
| Hardkodet chunk-størrelse | Suboptimal for ulike dokumenttyper | Test og iterer basert på kvalitetsmetrikker |
| Glemmer språkparameter | Feil setningsoppdeling for norsk tekst | Sett `defaultLanguageCode: "no"` |
### Røde flagg
- Chunk-størrelse valgt uten testing med faktiske spørringer
- Ingen overlapp i chunks med narrativt innhold
- Bruker `sentences` mode for annet enn analyse/forskning
- Ingen evaluering av retrieval-kvalitet etter chunking-endring
- Blander chunking-strategi og embedding-modell uten å re-evaluere
## Integrasjon med Microsoft-stakken
| Tjeneste | Integrasjonspunkt |
|----------|-------------------|
| **Azure AI Search** | Integrated vectorization pipeline (indexer → skillset → index) |
| **Azure OpenAI** | Embedding-generering (text-embedding-3-small/large) |
| **Document Intelligence** | Document Layout skill for strukturbasert chunking |
| **Azure Content Understanding** | Semantisk chunking med kryssende sider |
| **Azure Functions** | Custom chunking skills via Web API |
| **Microsoft Fabric / Databricks** | Pre-processing pipeline for stor-skala dokumentbehandling |
| **Semantic Kernel** | TextChunker-klasse for kode-basert chunking |
| **LangChain** | RecursiveCharacterTextSplitter for fleksibel chunking |
### Integrated vectorization pipeline
```
Blob Storage → Indexer → Skillset:
1. Document Layout / Text Split (chunking)
2. AzureOpenAIEmbedding (vektorisering)
→ Index (med index projections for parent-child)
→ Query (med semantic ranker + vectorizer)
```
## Offentlig sektor (Norge)
### Dataplassering og suverenitet
- **Azure AI Search:** Tilgjengelig i Norway East — data forblir i Norge
- **Document Intelligence:** Tilgjengelig i West Europe — data i EU, men ikke Norge spesifikt
- **Content Understanding:** Sjekk regional tilgjengelighet (endres hyppig)
- **GDPR:** Chunking-prosessen behandler potensielt personopplysninger — databehandleravtale påkrevd
### Relevante vurderinger
| Krav | Implikasjon for chunking |
|------|-------------------------|
| **Forvaltningsloven** | Chunks må kunne spores tilbake til kildedokument (bruk parent-child) |
| **GDPR Art. 17** | Sletting av kildedokument må kaskadere til chunks (index projections) |
| **AI Act** | Dokumentasjon av chunking-strategi som del av AI-systemdokumentasjon |
| **Schrems II** | Unngå tjenester som sender data utenfor EU/EØS under chunking |
| **Sikkerhetsloven** | Gradert informasjon krever on-premises chunking (custom skill) |
### Norsk språkstøtte
- Text Split skill: `defaultLanguageCode: "no"` for korrekt norsk setningsoppdeling
- Document Intelligence Layout: Støtter norsk tekst i OCR og strukturgjenkjenning
- Embedding-modeller (text-embedding-3): Støtter norsk, men tren/evaluer med norske testdata
## Kostnad og lisensiering
### Kostnadskomponenter
| Komponent | Prismodell | Estimat (liten skala) |
|-----------|------------|----------------------|
| Text Split skill | Inkludert i AI Search | $0 ekstra |
| Document Layout skill | DI Standard per side | ~$0.01-0.05/side |
| Content Understanding | Per dokument/side | Varierer |
| Embedding (text-embedding-3-small) | Per 1M tokens | ~$0.02/1M tokens |
| Vektorlagring | Per GB i indeksen | Avhenger av tier |
| Custom skill | Azure Functions compute | ~$0.20/million invocations |
### Optimaliseringstips
1. **Start med Text Split:** $0 ekstra kostnad, god nok for 70% av brukstilfeller
2. **Bruk Document Layout selektivt:** Kun for dokumenter som har viktig struktur
3. **Optimaliser chunk-størrelse:** Færre, større chunks = lavere embedding- og lagringskostnad
4. **Sett `stored: false` på vektorfelt:** Sparer lagring hvis du ikke trenger rå-vektorer i søkeresultater
5. **Batch-indeksering:** Kjør under off-peak for lavere compute-kostnad
6. **Monitor med Azure Cost Management:** Tag AI Search-ressurser for sporbarhet
### Kostnadseffekt av overlapp
Overlapp øker antall chunks proporsjonalt:
- 0% overlapp: N chunks
- 25% overlapp: ~1.33N chunks (+33% lagring og embedding-kostnad)
- 50% overlapp: ~2N chunks (+100% kostnad)
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **"Hva slags dokumenter skal indekseres?"** — Strukturerte PDF-er krever Document Layout, ren tekst klarer seg med Text Split
2. **"Hvor viktig er kildehenvisning i svarene?"** — Hvis viktig, krev parent-child med index projections
3. **"Hva er typisk spørringslengde og -type?"** — Korte, presise spørringer → mindre chunks. Brede tematiske → større chunks
4. **"Finnes det gradert eller sensitiv informasjon?"** — Kan kreve on-premises chunking med custom skill
5. **"Hva er akseptabel latency?"** — Flere chunks = mer søketid, men potensielt bedre kvalitet
6. **"Har dere norskspråklige dokumenter?"** — Sett `defaultLanguageCode: "no"`, test embedding-kvalitet
7. **"Hva er volumet?"** — Høyt volum + Document Intelligence = betydelig kostnad per side
8. **"Hvordan håndterer dere dokumentoppdateringer?"** — Inkrementell oppdatering vs. full re-indeksering påvirker arkitekturen
### Fallgruver
- **Over-engineering fra dag 1:** Start med Text Split, mål kvaliteten, iterer. Ikke begynn med Content Understanding før du har bevist at det trengs.
- **Chunk-størrelse som dogme:** "512 tokens" er et utgangspunkt, ikke et fasitsvar. Evaluer med faktiske spørringer og dokumenter.
- **Glemmer overlapp:** Uten overlapp mistes kontekst ved chunk-grenser. 25% er en god start.
- **Sentences-fellen:** `textSplitMode: sentences` ser logisk ut men genererer tusenvis av chunks per dokument. Bruk `pages`.
### Anbefalinger per modenhetsnivå
| Modenhet | Anbefaling |
|----------|------------|
| **Prototyp** | Text Split, 2000 tegn, 25% overlapp. Evaluer med 5-10 testspørringer. |
| **Pilot** | Legg til Document Layout for strukturerte dokumenter. Implementer parent-child med index projections. |
| **Produksjon** | Differensiert strategi per dokumenttype. Automatisert kvalitetsevaluering. Kostnadsmonitorering. |
| **Enterprise** | Custom skills for domenespesifikke krav. Token chunking (preview). A/B-testing av chunk-strategier. |
## Kilder og verifisering
| Kilde | Konfidens | URL |
|-------|-----------|-----|
| Chunk large documents for RAG (Azure AI Search) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/vector-search-how-to-chunk-documents) |
| Chunk and vectorize by document layout | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/search-how-to-semantic-chunking) |
| Integrated vectorization overview | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/vector-search-integrated-vectorization) |
| Set up integrated vectorization (REST) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/search-how-to-integrated-vectorization) |
| RAG chunking phase (Architecture Guide) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-chunking-phase) |
| RAG with Document Intelligence | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/ai-services/document-intelligence/concept/retrieval-augmented-generation) |
| Azure Search Vector Samples (GitHub) | **Verified** | [github.com/Azure](https://github.com/Azure/azure-search-vector-samples) |
| Token chunking (preview) | **Baseline** | Annonsert i 2025-11-01-preview API |
| Prisinformasjon | **Baseline** | Basert på offentlige prislister, sjekk Azure-kalkulator for oppdaterte priser |

View file

@ -0,0 +1,294 @@
# Citation Tracking and Source Attribution
**Last updated:** 2026-02
**Status:** GA (classic RAG), Preview (agentic retrieval)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Citation tracking er en kritisk komponent i enterprise RAG-systemer. Det handler om å spore og eksponere kildene som ligger til grunn for AI-genererte svar, slik at brukere kan verifisere informasjonen. I Azure-økosystemet støttes citation tracking gjennom to hovedmønstre: **Classic RAG** (GA) med Azure AI Search og Azure OpenAI, og **Agentic Retrieval** (Preview) med strukturerte grounding data.
God citation tracking reduserer hallusinering ved å tvinge LLM-en til å basere seg på hentet kontekst, gir brukerne tillit til svarene, og oppfyller compliance-krav i offentlig sektor der sporbarhet er lovpålagt. Azure AI Search returnerer automatisk kildemetadata med søkeresultater, og Azure OpenAI "On Your Data"-mønsteret inkluderer citation annotations i responser.
Agentic Retrieval (preview 2025/2026) representerer neste evolusjon med LLM-assistert query planning, parallelle subqueries, og strukturerte citation-responser med full provenance tracking.
## Kjernekomponenter
### Citation-formater
#### URL Citation Annotations (Azure OpenAI)
```python
for event in stream_response:
if event.type == "response.output_item.done":
if event.item.type == "message":
text_content = event.item.content[-1]
for annotation in text_content.annotations:
if annotation.type == "url_citation":
print(f"URL: {annotation.url}")
print(f"Start: {annotation.start_index}")
print(f"End: {annotation.end_index}")
```
#### File Citation Annotations (Assistants API)
```python
message_content = message.content[0].text
annotations = message_content.annotations
citations = []
for index, annotation in enumerate(annotations):
message_content.value = message_content.value.replace(
annotation.text, f' [{index}]'
)
if file_citation := getattr(annotation, 'file_citation', None):
cited_file = client.files.retrieve(file_citation.file_id)
citations.append(
f'[{index}] {file_citation.quote} from {cited_file.filename}'
)
message_content.value += '\n' + '\n'.join(citations)
```
### Citation Metadata-elementer
| Element | Beskrivelse | Eksempel |
|---------|-------------|---------|
| `title` | Dokument- eller kildetittel | "Veileder for offentlige anskaffelser" |
| `url` | URL til kildedokument | `https://docs.example.com/guide` |
| `file_id` | Referanse til opplastet fil | `file-abc123` |
| `snippet` | Relevant utdrag fra kilden | "I henhold til §4..." |
| `doc_uri` | Dokumentlokasjon | `docs/mlflow/guide.md` |
| `chunk_id` | Spesifikk chunk-identifikator | `chunk_001` |
| `relevance_score` | Konfidensverdi | 0.95 |
| `start_index` / `end_index` | Tekstregion som er grounded | 142 / 287 |
### Grounding Data (Agentic Retrieval)
```json
{
"grounding_data": "Ekstraherte relevante passasjer...",
"references": [
{
"title": "Dokumenttittel",
"url": "https://...",
"chunk_id": "chunk_001",
"relevance_score": 0.95
}
],
"activity": [
{
"operation": "subquery_1",
"tokens_used": 150,
"latency_ms": 245
}
]
}
```
## Arkitekturmønstre
### Mønster 1: Classic RAG med automatisk citation
**Flyt:** Query → Azure AI Search → Top-k dokumenter med metadata → LLM med citation-instruks → Svar med fotnoter
**Implementering:**
```python
template = """
Answer the following question using only the context below.
Include citations [1], [2] etc. for each fact.
Only include information specifically discussed in the context.
Question: {question}
Context: {context}
"""
```
**Fordeler:**
- Enkel implementering via Azure OpenAI "On Your Data"
- Automatisk citation-generering
- GA-funksjonalitet, produksjonsklart
**Ulemper:**
- LLM kan fremdeles hallusinere citations
- Krever post-validering av citation-nøyaktighet
- Begrenset til kontekstvindu-størrelse
### Mønster 2: Agentic Retrieval med provenance
**Flyt:** Query → LLM query planning → Subqueries → Parallel retrieval → Grounding data + references → LLM → Svar med strukturerte citations
**Fordeler:**
- Full provenance tracking (hvilke subqueries hentet hvilke dokumenter)
- Strukturert output med references array
- Activity log for audit og debugging
- LLM planlegger optimale søk for bedre dekning
**Ulemper:**
- Preview-funksjon, ikke GA ennå
- Høyere kompleksitet og token-kostnad
- Ranking tokens gratis kun under initial preview-fase
### Mønster 3: Fakta-verifisering med LLM-judge
**Flyt:** RAG-svar med citations → Fakta-verifikasjon-agent → Krysssjekk mot kildedokumenter → Verifisert svar
```python
from azure.ai.evaluation import GroundednessProEvaluator
groundedness_eval = GroundednessProEvaluator(
azure_ai_project=project,
credential=credential,
threshold=2
)
result = groundedness_eval(
query="Hva er reglene for offentlige anskaffelser?",
response="I henhold til anskaffelsesloven §4...",
context="Anskaffelsesloven §4 sier at..."
)
```
**Fordeler:**
- Automatisk validering av citation-nøyaktighet
- Kan flagge hallusinerte fakta
- Skalerbar QA-pipeline
**Ulemper:**
- Ekstra LLM-kall = ekstra kostnad
- LLM-judges er ikke ufeilbarlige
- Økt latency
## Beslutningsveiledning
### Når bruke hvilket mønster
| Scenario | Anbefaling | Begrunnelse |
|----------|------------|-------------|
| Intern kunnskapsbase | Classic RAG med citations | GA, tilstrekkelig for de fleste behov |
| Publikumstjenester (høy tillit) | Agentic + fakta-verifisering | Sporbarhet og kvalitetssikring er kritisk |
| Juridisk/medisinsk rådgivning | Alle tre mønstre | Maksimal grounding og verifisering |
| Intern chatbot | Classic RAG | Enklest og billigst |
| Compliance-rapportering | Agentic med full audit log | Activity-loggen dokumenterer hele søkeprosessen |
### Vanlige feil
1. **Ikke validere citations post-generering** — LLM-er kan generere plausible men feilaktige kildereferanser
2. **Mangle chunk-til-dokument-mapping** — Brukere trenger å navigere til kilden, ikke bare se en chunk-ID
3. **Ignorere konfidensscoring** — Vis ikke citations med lav relevance_score som primærkilde
4. **Glemme tilgangskontroll** — Citations til dokumenter brukeren ikke har tilgang til er en sikkerhetsfeil
### Røde flagg
- Citations som peker til ikke-eksisterende dokumenter → Hallusinering i citation-genereringen
- Høy andel scores under 0.5 → Dårlig retrieval-kvalitet, ikke kun citation-problem
- Brukere som rapporterer at citations ikke stemmer → Trenger fakta-verifiseringslagret
## Konfidensscoring
### Tilgjengelige scoring-mekanismer
| Mekanisme | Skala | Kilde |
|-----------|-------|-------|
| Semantic Ranking | 0.04.0 | Azure AI Search |
| Vector Similarity (Cosine) | 0.3331.0 | Azure AI Search |
| Groundedness Pro | Threshold-basert | Azure AI Content Safety |
| Semantic Answer Confidence | 70% terskel | Azure AI Search |
| Custom relevance_score | 0.01.0 | Applikasjonskode |
### Anbefalte terskelverdier for RAG
| Terskelverdi | Handling |
|-------------|---------|
| rerankerScore ≥ 3.0 | Vis citation med høy konfidensindikator |
| rerankerScore 2.03.0 | Vis citation med moderat konfidensindikator |
| rerankerScore < 2.0 | Utelat fra primærcitations, men behold i "Se også" |
| relevance_score < 0.5 | Ikke vis som citation |
## Integrasjon med Microsoft-stakken
| Tjeneste | Rolle i citation tracking |
|----------|--------------------------|
| **Azure AI Search** | Primær retrieval med metadata og scores |
| **Azure OpenAI** | LLM-generering med citation annotations |
| **Azure AI Foundry** | Evaluering av groundedness og citation-kvalitet |
| **MLflow** | Tracing og observerbarhet for citation pipeline |
| **Azure AI Content Safety** | Groundedness-deteksjon med korreksjonsfunksjon |
| **Copilot Studio** | Automatisk citation i Copilot-svar |
## Offentlig sektor (Norge)
### Lovmessige krav
- **Forvaltningsloven:** Vedtak skal begrunnes med referanse til relevant regelverk
- **Offentleglova:** Innsynsrett krever sporbar saksbehandling
- **AI Act:** Transparenskrav for AI-systemer i offentlig forvaltning
- **Arkivloven:** Dokumentasjon av beslutningsgrunnlag
### Praktiske implikasjoner
- Citations er ikke bare "nice to have" — de er juridisk nødvendige i mange offentlige kontekster
- Audit trail (agentic retrieval activity log) kan brukes som dokumentasjon for tilsyn
- Brukere i offentlig sektor forventer å kunne klikke seg gjennom til kildedokumentet
### Sikkerhet
- Dokumentnivå-sikkerhet (RBAC) må filtrere citations basert på brukeridentitet
- Sensitive dokumenter skal ikke siteres til brukere uten tilgang
- Implement security trimming i Azure AI Search før citations eksponeres
## Kostnad og lisensiering
### Komponenter som påvirker kostnad
| Komponent | Kostnadsdriver |
|-----------|---------------|
| Azure AI Search | Standard spørringskostnad (ingen ekstra for metadata) |
| Semantic Ranker | Per 1000 requests (1000 gratis/mnd) |
| Azure OpenAI | Token-kostnad for citation-generering i LLM-respons |
| Agentic Retrieval | Ranking tokens (gratis under preview), Azure OpenAI for query planning |
| Groundedness Pro | Per evaluerings-kall (Azure AI Content Safety) |
### Kostnadsoptimering
- Returner kun citation-relevante felt via `select` for å redusere token-bruk
- Bruk caching for gjentatte queries med samme citations
- Evaluer groundedness kun for brukervendte svar, ikke interne prosesser
- Begrens antall citations per svar (35 er typisk tilstrekkelig)
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. Har dere lovmessige krav til sporbarhet og kildehenvisning?
2. Skal brukerne kunne navigere direkte til kildedokumentene?
3. Hvilken grad av konfidensindikasjon trenger brukerne?
4. Er det behov for audit trail av hele retrieval-prosessen?
5. Har dokumentene ulik sikkerhetsgraddering som påvirker citation-eksponering?
6. Hva er akseptabel feilrate for citations (hallusinerte kilder)?
7. Trengs fakta-verifisering, eller er standard citation tilstrekkelig?
8. Hvordan chunkes dokumentene — trengs chunk-til-dokument navigering?
### Fallgruver
- Å anta at LLM-genererte citations alltid er korrekte — de er ikke det
- Å eksponere chunk-IDer i brukergrensesnittet uten å mappe dem til lesbare dokumentreferanser
- Å bruke agentic retrieval i produksjon uten å forstå at det er preview
- Å ignorere tilgangskontroll i citation-laget — dette er et vanlig sikkerhetshull
### Anbefalinger per modenhetsnivå
| Nivå | Anbefaling |
|------|------------|
| **Starter** | Classic RAG med Azure OpenAI "On Your Data" citation |
| **Intermediær** | Custom citation-formatering, konfidensscoring, chunk-til-dokument mapping |
| **Avansert** | Agentic retrieval med provenance, fakta-verifisering, audit logging |
## Kilder og verifisering
### Verified (MCP-research)
- [RAG overview in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview)
- [Agentic retrieval overview](https://learn.microsoft.com/en-us/azure/search/agentic-retrieval-overview)
- [Transparency note for Azure AI Search](https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/search/transparency-note)
- [Grounding data design](https://learn.microsoft.com/en-us/azure/well-architected/ai/grounding-data-design)
- [Azure AI Foundry agents - AI Search tools](https://learn.microsoft.com/en-us/azure/ai-foundry/agents/how-to/tools/ai-search)
### Baseline (modellkunnskap)
- Norsk lovgivning (Forvaltningsloven, Offentleglova, Arkivloven)
- Kostnadsoptimerings-anbefalinger
- Modenhetsnivå-tabellen

View file

@ -0,0 +1,284 @@
# Contextual Retrieval — Kontekstuell berikelse av chunks
**Last updated:** 2026-02
**Status:** GA (custom skill pattern), Preview (agentic retrieval)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Contextual Retrieval er en teknikk der hvert dokumentsegment (chunk) berikes med en LLM-generert kontekstbeskrivelse *før* embedding og indeksering. I tradisjonell RAG mister chunks kontekst når de løsrives fra kildedokumentet — pronomener, forkortelser og referanser blir tvetydige. Contextual Retrieval løser dette ved å prepende en 2-3-setningers forklaring som beskriver segmentets plass i dokumentet.
Anthropic dokumenterte teknikken i 2024 og viste at den reduserer retrieval failures med opptil 67% når den kombineres med BM25 og reranking. Microsoft Tech Community har validert tilnærmingen i Azure AI Search med 80-85% reduksjon i token-bruk per query og 31% forbedring i retrieval precision.
I Azure-stakken implementeres contextual retrieval via en **Custom Web API Skill** (Azure Functions) som genererer kontekstuell prefiks via Azure OpenAI GPT-4o, integrert i skillset-pipelinen mellom chunking og embedding.
---
## Kjernekomponenter
### Kontekstuell prefiks-generering
| Komponent | Beskrivelse |
|-----------|-------------|
| **Custom Web API Skill** | Azure Function som mottar chunk + metadata, returnerer kontekstuell prefiks |
| **LLM (GPT-4o)** | Genererer 2-3 setninger som forklarer chunkens plass i dokumentet |
| **Text Merge Skill** | Konkatenerer kontekstuell prefiks + original chunk |
| **Embedding Skill** | Embedder den berikede teksten (prefiks + chunk) |
### Eksempel
```
Original chunk: "Forskningen understreket AI"
→ Problematisk: Hvem, når, hvilken AI?
Contextual chunk: "Fra Statens vegvesen sin 2025-rapport om autonome
kjøretøy. Dette avsnittet diskuterer AI-teknologier for selvkjørende biler.
Forskningen understreket AI"
→ Tydelig: LLM kan nå forstå konteksten
```
### Custom Skill-konfigurasjon
```json
{
"@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
"name": "context-generation-skill",
"uri": "https://<function-app>.azurewebsites.net/api/generate-context",
"httpMethod": "POST",
"timeout": "PT90S",
"context": "/document/pages/*",
"inputs": [
{ "name": "chunk", "source": "/document/pages/*" },
{ "name": "documentTitle", "source": "/document/metadata_storage_name" },
{ "name": "documentMetadata", "source": "/document/metadata" }
],
"outputs": [
{ "name": "contextualPrefix", "targetName": "context" }
]
}
```
### Azure Function (Python)
```python
import azure.functions as func
from openai import AzureOpenAI
import json, os
client = AzureOpenAI(
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
api_key=os.getenv("AZURE_OPENAI_KEY"),
api_version="2024-10-01-preview"
)
def main(req: func.HttpRequest) -> func.HttpResponse:
values = req.get_json()['values']
results = []
for record in values:
chunk = record['data']['chunk']
doc_title = record['data']['documentTitle']
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": f"""Generate a 2-3 sentence
contextual summary for this chunk.
Document: {doc_title}
Chunk: {chunk}
Include: document source/type, section/topic, temporal context."""}],
max_tokens=100,
temperature=0.3
)
context = response.choices[0].message.content
results.append({
"recordId": record['recordId'],
"data": {"contextualPrefix": context},
"errors": [], "warnings": []
})
return func.HttpResponse(
json.dumps({"values": results}),
mimetype="application/json"
)
```
---
## Arkitekturmønstre
### Mønster 1: Post-chunking context enrichment (anbefalt)
**Arkitektur:** Data source → Indexer → Document Layout/Text Split → Custom Context Skill → Text Merge → Embedding → Index
**Fordeler:**
- Enklest å integrere i eksisterende pipelines
- Bruker standard Azure AI Search skillset-mekanismer
- Kompatibel med alle chunking-strategier
**Ulemper:**
- Ekstra LLM-kall per chunk (GPT-4o kostnad)
- Økt indekseringstid (90s timeout per batch)
**Anbefalt for:** Alle RAG-systemer der retrieval-kvalitet er viktigere enn indekseringskostnad.
### Mønster 2: Pre-chunking context med document summary
**Arkitektur:** Data source → Indexer → Document Summary Skill (1 per dokument) → Text Split → Inject Summary as Context → Embedding → Index
**Fordeler:**
- Kun ett LLM-kall per dokument (ikke per chunk)
- 60-80% kostnadsreduksjon vs. per-chunk context
- Caching-vennlig
**Ulemper:**
- Mindre spesifikk kontekst per chunk
- Document summary kan miste nyanser i store dokumenter
**Anbefalt for:** Kostnadsbevisste løsninger, homogene dokumentsamlinger.
### Mønster 3: Contextual Retrieval + BM25 + Reranking
**Arkitektur:** Contextual embedding + BM25 full-text indeksering → Hybrid search (RRF) → Semantic Ranker → Top-k
**Effekt (Anthropic benchmarks):**
| Metode | Retrieval failure rate | Forbedring |
|--------|------------------------|------------|
| Standard embeddings | 5.7% | Baseline |
| Contextual Embeddings | 3.7% | -35% |
| + Contextual BM25 | 2.9% | -49% |
| + Reranking | 1.9% | -67% |
**Nøkkel:** BM25 fanger kontekst-spesifikke termer (organisasjonsnavn, datoer) som embeddings kan miste.
---
## Beslutningsveiledning
### Beslutningstabell
| Scenario | Anbefalt mønster | Begrunnelse |
|----------|------------------|-------------|
| Generell enterprise RAG | Mønster 1 (post-chunking) | Best kvalitet, akseptabel kostnad |
| Høyt dokumentvolum (>100K docs) | Mønster 2 (document summary) | Kostnadseffektiv |
| Kritisk retrieval-kvalitet | Mønster 3 (full hybrid) | Maksimal reduksjon i failures |
| Budget-begrenset PoC | Ingen contextual retrieval | Start med standard hybrid search |
### Vanlige feil
| Feil | Konsekvens | Løsning |
|------|------------|---------|
| Genererer kontekst med gpt-4o-mini | Lavere kvalitet på kontekst | Bruk gpt-4o for kontekst-generering |
| Ingen caching av document summaries | Gjentatte LLM-kall for samme dokument | Cache summary og gjenbruk per chunk |
| Ignorerer BM25-indeksering av kontekst | Mister keyword-matching fordeler | Indekser berikede chunks i searchable felt |
| Overlap > timeout (PT90S) | Skill-feil ved store batcher | Reduser batch-størrelse eller øk timeout |
---
## Integrasjon med Microsoft-stakken
| Tjeneste | Integrasjonspunkt |
|----------|-------------------|
| **Azure AI Search** | Skillset pipeline (Custom Web API Skill + Text Merge + Embedding) |
| **Azure OpenAI** | GPT-4o for kontekst-generering, text-embedding-3-large for embedding |
| **Azure Functions** | Hosting av custom skill (Python/C#), consumption plan |
| **Azure AI Document Intelligence** | Document Layout skill for strukturert chunking før context enrichment |
| **Semantic Kernel** | TextChunker + custom context injection i kode-basert pipeline |
| **Application Insights** | Monitorering av skill-latency, LLM token-bruk, feilrate |
### Fullstendig skillset-pipeline
```
Blob Storage → Indexer → Skillset:
1. Document Layout skill (struktur → Markdown)
2. Text Split skill (chunk-størrelse kontroll)
3. Custom Context Generation skill (GPT-4o)
4. Text Merge skill (context + chunk)
5. Azure OpenAI Embedding skill (text-embedding-3-large)
→ Index (med index projections for parent-child)
→ Query (hybrid search + semantic ranker)
```
---
## Offentlig sektor (Norge)
### Dataplassering
- **Azure AI Search:** Norway East — data i Norge
- **Azure Functions:** Norway East — compute i Norge
- **Azure OpenAI:** Sweden Central (nærmeste region med GPT-4o) — data i EU/EØS
- **GDPR:** Kontekst-generering behandler dokumentinnhold via LLM — databehandleravtale påkrevd
### Relevante vurderinger
| Krav | Implikasjon |
|------|-------------|
| **Forvaltningsloven** | Kontekstuell prefiks skal ikke endre dokumentets meningsinnhold |
| **GDPR Art. 17** | Sletting av kildedokument kaskaderer til berikede chunks |
| **AI Act** | Dokumenter bruk av LLM i indekseringspipeline som del av AI-systemdokumentasjon |
| **Sikkerhetsloven** | Gradert informasjon kan ikke sendes til Azure OpenAI — bruk on-premises alternativ |
---
## Kostnad og lisensiering
### Kostnadskomponenter
| Komponent | Prismodell | Estimat (1 000 dokumenter, 20 chunks/doc) |
|-----------|------------|-------------------------------------------|
| Context generation (GPT-4o) | Per token | ~60 NOK (100 tokens/chunk × 20K chunks) |
| Text embedding (text-embedding-3-large) | Per token | ~5 NOK (berikede chunks er ~30% større) |
| Azure Functions (consumption) | Per invocation | ~2 NOK |
| Økt vektorlagring | Per GB | ~5 NOK/mnd (berikede chunks = større indeks) |
| **Totalt ekstra vs. standard RAG** | — | ~72 NOK per 1 000 dokumenter |
### ROI-vurdering
Hvis contextual retrieval reduserer irrelevante LLM-kall med 30%:
- Savings per 1 000 queries: 300 × 10 NOK = 3 000 NOK
- Incremental cost per 1 000 docs: ~72 NOK
- **Break-even:** >24 queries per 1 000 dokumenter (svært lav terskel)
---
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **"Hvor ofte er retrieval-kvaliteten utilstrekkelig i dag?"** — Contextual retrieval lønner seg mest ved dårlig baseline
2. **"Hva er typisk dokumentlengde?"** — Lange dokumenter med mange seksjoner gir størst effekt
3. **"Er det mye tvetydig innhold (pronomen, forkortelser)?"** — Indikerer høy verdi av kontekst
4. **"Hva er akseptabel indekseringskostnad?"** — GPT-4o kall per chunk er ikke gratis
5. **"Bruker dere hybrid search (BM25 + vektor)?"** — Contextual retrieval gir størst effekt med hybrid search
### Fallgruver
- **Hopper over baseline-måling:** Uten metrics på nåværende retrieval-kvalitet kan du ikke bevise forbedring
- **Kontekst som forvrenger mening:** LLM-generert kontekst kan introdusere feil — valider med stikkprøver
- **Over-investering i kontekst for enkle use cases:** Noen dokumentsamlinger er allerede godt chunket
### Anbefalinger per modenhetsnivå
| Modenhet | Anbefaling |
|----------|------------|
| **Prototyp** | Standard chunking + hybrid search. Mål baseline retrieval metrics. |
| **Pilot** | Legg til document summary-basert kontekst (mønster 2). Test med 500 docs. |
| **Produksjon** | Per-chunk contextual retrieval (mønster 1) + BM25 + semantic ranker. |
| **Enterprise** | Full mønster 3 med reranking. A/B-testing. Automated quality evaluation. |
---
## Kilder og verifisering
| Kilde | Konfidens | URL |
|-------|-----------|-----|
| Contextual Retrieval (Anthropic) | **Verified** | [anthropic.com](https://www.anthropic.com/news/contextual-retrieval) |
| Context-Aware RAG System (MS Tech Community) | **Verified** | [techcommunity.microsoft.com](https://techcommunity.microsoft.com/blog/azure-ai-foundry-blog/context-aware-rag-system-with-azure-ai-search-to-cut-token-costs-and-boost-accur/4456810) |
| Building Contextual Retrieval System (MS Tech Community) | **Verified** | [techcommunity.microsoft.com](https://techcommunity.microsoft.com/blog/azure-ai-foundry-blog/building-a-contextual-retrieval-system-for-improving-rag-accuracy/4271924) |
| Custom skill interface (Azure AI Search) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/cognitive-search-custom-skill-interface) |
| Custom skill example (Python) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/previous-versions/azure/search/cognitive-search-custom-skill-python) |
| Retrieval failure benchmarks | **Baseline** | Anthropic research, validert av Microsoft |

View file

@ -0,0 +1,508 @@
# Embedding Models - Selection and Optimization
**Last updated:** 2026-02
**Status:** GA (Azure OpenAI, Azure AI Search), Preview (Multilingual E5, Custom embeddings)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Embedding-modeller er selve grunnmuren i moderne RAG-systemer og semantisk søk. De oversetter tekst — enten spørsmål, dokumenter eller metadata — til numeriske vektorer som gjør det mulig å finne semantisk liknende innhold basert på mening, ikke bare nøkkelord. Valget av embedding-modell påvirker direkte retrieval-kvalitet, latency, kostnad og hvor godt systemet håndterer domene-spesifikk terminologi eller flerspråklige dokumenter.
I Microsoft-økosystemet tilbys embeddings primært gjennom **Azure OpenAI Service** (text-embedding-ada-002, text-embedding-3-small, text-embedding-3-large) og **Azure AI Search** (som integrerer både OpenAI-modeller og åpen kildekode-embeddings som E5 via Azure AI). Riktig valg krever forståelse av dimensjonalitet, kostnad, domenetilpasning, flerspråklighet og håndtering av store dokumentvolumer.
Mange organisasjoner starter med standard OpenAI-modeller uten å vurdere om domene-spesifikke embeddings (f.eks. rettet mot juridisk, medisinsk eller teknisk språk) eller multilingual-støtte kan gi markant bedre kvalitet — eller om høyere dimensjonalitet faktisk er nødvendig for deres use case.
---
## Kjernekomponenter og nøkkelegenskaper
### Tilgjengelige embedding-modeller i Azure
| Modell | Dimensjoner | Maks tokens | Bruksområde | Status | Pris (per 1M tokens, ca.) |
|--------|-------------|-------------|-------------|--------|---------------------------|
| **text-embedding-ada-002** | 1536 | 8191 | Generell RAG, legacy baseline | GA | $0.10 |
| **text-embedding-3-small** | 1536 (eller 512) | 8191 | Kostnadseffektiv, generell bruk | GA | $0.02 |
| **text-embedding-3-large** | 3072 (eller 256-1024) | 8191 | Høy presisjon, komplekse domener | GA | $0.13 |
| **multilingual-e5-small** | 384 | 512 | Flerspråklig, kompakt | Preview | Via Azure AI (gratis i preview) |
| **multilingual-e5-large** | 1024 | 512 | Flerspråklig, høy kvalitet | Preview | Via Azure AI |
| **Custom embeddings** | Variabel | Variabel | Domene-spesifikk fine-tuning | Announced | Custom pricing |
**Nøkkelegenskaper per modell:**
- **Dimensjonalitet:** Høyere dimensjoner = bedre representasjon av nyansert semantikk, men større indekser og høyere kostnad
- **Token-kapasitet:** 8191 tokens tilsvarer ca. 6000 ord (norsk/engelsk), tilstrekkelig for de fleste chunks
- **Språkstøtte:** OpenAI-modeller håndterer 100+ språk, men med fallende kvalitet utenfor engelsk; E5-modeller er optimalisert for multilingual quality
- **Matryoshka-dimensjonalitet:** text-embedding-3-modellene støtter dynamisk reduksjon (f.eks. 3072 → 512) uten retraining, nyttig for kostnadsoptimalisering
### Eksempel: Generering av embeddings (Azure OpenAI, Python)
```python
from openai import AzureOpenAI
client = AzureOpenAI(
api_key="YOUR_AZURE_OPENAI_KEY",
api_version="2024-02-01",
azure_endpoint="https://YOUR_RESOURCE.openai.azure.com"
)
response = client.embeddings.create(
model="text-embedding-3-small", # eller "text-embedding-3-large"
input="Azure AI Foundry gir en unified plattform for LLM-utvikling.",
dimensions=512 # valgfritt: reduser fra 1536 til 512 for mindre indeks
)
embedding_vector = response.data[0].embedding
print(f"Dimensjoner: {len(embedding_vector)}") # 512
```
### Eksempel: Azure AI Search med embeddings
```json
{
"name": "products-index",
"fields": [
{"name": "id", "type": "Edm.String", "key": true},
{"name": "content", "type": "Edm.String", "searchable": true},
{"name": "contentVector", "type": "Collection(Edm.Single)", "dimensions": 1536, "vectorSearchProfile": "vector-profile"}
],
"vectorSearch": {
"profiles": [
{
"name": "vector-profile",
"algorithm": "hnsw-config"
}
],
"algorithms": [
{
"name": "hnsw-config",
"kind": "hnsw",
"hnswParameters": {"metric": "cosine", "m": 4, "efConstruction": 400}
}
]
}
}
```
---
## Arkitekturmønstre
### 1. Single Embedding Model (Standard)
**Beskrivelse:** Én embedding-modell for både indeksering av dokumenter og query embedding.
**Når bruke:**
- Generelle RAG-scenarioer (kunnskapsbase, FAQ, support)
- Engelsk eller primært engelsk innhold
- Modenhetsnivå: Grunnleggende til mellomliggende
**Fordeler:**
- Enkel å implementere og vedlikeholde
- Forutsigbar kostnad
- Garantert konsistens mellom query og dokumenter
**Ulemper:**
- Ikke optimalisert for spesifikke domener
- Suboptimal for multidomenescenarier (f.eks. juridisk + teknisk)
### 2. Domain-Specific Embeddings
**Beskrivelse:** Bruk av fine-tuned eller domene-spesifikke embeddings (f.eks. BioBERT for medisin, Legal-BERT for jus).
**Når bruke:**
- Høy tetthet av domene-spesifikk terminologi (jus, medisin, ingeniørfag)
- Kritisk at semantisk likhet fanger domeneforståelse (f.eks. "force majeure" vs "act of God")
- Modenhetsnivå: Avansert
**Fordeler:**
- Markant bedre retrieval-kvalitet i spesialiserte domener
- Reduserer behov for post-reranking
**Ulemper:**
- Høyere initielle kostnader (fine-tuning, custom hosting)
- Krever ekspertise for trening/validering
### 3. Multilingual Embeddings med Språkfiltrering
**Beskrivelse:** Bruk av multilingual embeddings (E5, mBERT) kombinert med metadata-filtrering på språk.
**Når bruke:**
- Dokumenter på flere språk (norsk, svensk, engelsk)
- Brukere forventer å søke på eget språk og få relevante treff på andre språk
- Modenhetsnivå: Mellomliggende til avansert
**Fordeler:**
- Én indeks for alle språk
- Cross-language retrieval mulig
- Lavere vedlikeholdskostnad enn separate indekser
**Ulemper:**
- Noe lavere kvalitet enn språk-spesifikke modeller
- Krever testing av språkparitet (engelsk får ofte bedre kvalitet)
---
## Beslutningsveiledning
### Velg embedding-modell basert på use case
| Scenario | Anbefalt modell | Begrunnelse |
|----------|-----------------|-------------|
| Generell RAG (engelsk) | **text-embedding-3-small** | Kostnadseffektiv, god kvalitet, rask |
| Kompleks domene (juridisk, teknisk) | **text-embedding-3-large** | Høyere dimensjonalitet fanger nyansert semantikk |
| Flerspråklig (norsk + engelsk + svensk) | **multilingual-e5-large** | Optimalisert for multilingual quality, lavere kostnad |
| Kostnadsoptimalisering (store volumer) | **text-embedding-3-small (512 dims)** | Redusert dimensjonalitet = mindre indeksstørrelse |
| Høy presisjon, kritisk applikasjon | **text-embedding-3-large (3072 dims)** + reranking | Maksimal semantisk dekning + post-processing |
| Domene-spesifikk terminologi | **Custom fine-tuned embeddings** | Treningsdata fra eget domene |
### Dimensjonalitet: Trade-offs
| Dimensjoner | Fordeler | Ulemper | Egnet for |
|-------------|----------|---------|-----------|
| **256-512** | Lavere kostnad, raskere søk, mindre storage | Lavere presisjon, vanskeligere å fange nyansert semantikk | FAQ, enkel klassifisering, kostnadsoptimalisering |
| **1024-1536** | God balanse mellom kvalitet og kostnad | Middels storage | Generell RAG, dokumentsøk |
| **3072** | Høyeste presisjon, fanger subtile semantiske forskjeller | Høyere kostnad, større indeks, tregere søk | Komplekse domener, kritiske applikasjoner |
**Tommelfingerregel:** Start med 1536 dimensjoner (text-embedding-3-small). Reduser til 512 hvis storage/kostnad er kritisk. Øk til 3072 hvis retrieval-kvalitet er utilstrekkelig.
### Vanlige feil og misforståelser
| Feil | Hvorfor det er problematisk | Riktig tilnærming |
|------|----------------------------|-------------------|
| **Bruke ada-002 i 2025-2026** | Dyrere og eldre enn text-embedding-3-small | Migrer til text-embedding-3-small |
| **Anta at høyere dimensjonalitet alltid er bedre** | Overhead i kostnad/storage uten målbar kvalitetsforbedring | Mål retrieval-kvalitet før du øker dimensjoner |
| **Gjenbruke generelle embeddings for juridisk innhold** | "Rettskraftig dom" og "endelig avgjørelse" feiltolkes | Vurder domene-spesifikk fine-tuning |
| **Blande embeddings fra ulike modeller i samme indeks** | Vektorer ikke sammenliknbare, retrieval feiler | Reindekser alle dokumenter ved modellendring |
| **Ikke teste multilingual paritet** | Engelsk får høy kvalitet, norsk får dårlig retrieval | Mål retrieval-kvalitet per språk, juster reranking |
### Røde flagg arkitekten bør se etter
- **"Vi indekserer 500 000 dokumenter med text-embedding-3-large (3072 dims)"** → Storage og kostnad blir enormt; vurder dimensjonsreduksjon
- **"Vi har norske juridiske dokumenter, bruker OpenAI embeddings uten reranking"** → Domene-spesifikk terminologi fanges dårlig; vurder custom embeddings eller Legal-BERT
- **"Vi har 10 språk i samme indeks, men søk på norsk gir dårlige resultater"** → Multilingual embeddings kan favorisere engelsk; test språkparitet
- **"Vi bytter fra ada-002 til text-embedding-3-small uten reindeksering"** → Gamle og nye vektorer ikke kompatible, retrieval feiler
---
## Integrasjon med Microsoft-stakken
### Azure OpenAI Service
```python
# Eksempel: Bruk av embeddings i Azure OpenAI
client = AzureOpenAI(azure_endpoint="https://YOUR_RESOURCE.openai.azure.com", api_version="2024-02-01")
embedding = client.embeddings.create(
model="text-embedding-3-small",
input="Hvordan integrere Azure AI Search med Copilot Studio?",
dimensions=1536
)
```
### Azure AI Search (Integrated Vectorization)
Azure AI Search kan automatisk generere embeddings under indeksering via **skillsets**:
```json
{
"skills": [
{
"@odata.type": "#Microsoft.Skills.Text.AzureOpenAIEmbeddingSkill",
"name": "embedding-skill",
"context": "/document/content",
"resourceUri": "https://YOUR_RESOURCE.openai.azure.com",
"deploymentId": "text-embedding-3-small",
"modelName": "text-embedding-3-small",
"dimensions": 1536,
"inputs": [{"name": "text", "source": "/document/content"}],
"outputs": [{"name": "embedding", "targetName": "contentVector"}]
}
]
}
```
**Fordeler med integrated vectorization:**
- Automatisk embedding-generering under indeksering
- Ingen separat kode for embedding-pipeline
- Enklere reindeksering ved modellendring
### Copilot Studio og Power Platform
Copilot Studio kan kobles til Azure AI Search som **knowledge source**. Embeddings genereres automatisk når dokumenter lastes opp, men standardmodellen (typisk ada-002 eller text-embedding-3-small) kan ikke endres direkte i UI.
**Workaround for custom embeddings:**
1. Pre-generere embeddings eksternt
2. Lagre i Azure AI Search
3. Konfigurer Copilot Studio til å bruke eksisterende indeks
### Microsoft Agent Framework og Semantic Kernel
```csharp
// Semantic Kernel: Bruk av embeddings for memory
var embeddingGenerator = new AzureOpenAITextEmbeddingGenerationService(
deploymentName: "text-embedding-3-small",
endpoint: "https://YOUR_RESOURCE.openai.azure.com",
apiKey: "YOUR_KEY"
);
var memoryBuilder = new MemoryBuilder();
memoryBuilder.WithAzureOpenAITextEmbeddingGeneration(embeddingGenerator);
var memory = memoryBuilder.Build();
await memory.SaveInformationAsync("facts", "Azure AI Foundry støtter prompt flow.", "fact-1");
var results = await memory.SearchAsync("facts", "Hva er Foundry?", limit: 3);
```
---
## Offentlig sektor (Norge)
### Datasuverenitet og residency
- **Azure OpenAI embeddings:** Data prosesseres i Azure-regionen du har deployed modellen (typisk West Europe, North Europe). No-logging policy for OpenAI API, men **ikke garantert for EU Data Boundary** (data kan krysse EU-grenser under inferens).
- **Multilingual E5 (Azure AI):** Hostet i Azure, kan konfigureres for EU-residency.
- **Custom embeddings (self-hosted):** Full kontroll, kan hostes i Azure Norway regions (anbefales for Høy/Kritisk data).
**Anbefaling for offentlig sektor:**
- **Lav/Middels risiko:** Azure OpenAI embeddings i West Europe OK (dokumenter offentlig informasjon)
- **Høy risiko:** Custom embeddings hostet i Azure Norway eller multilingual E5 med EU-residency
### GDPR og AI Act
- **Persondata i embeddings:** Hvis dokumenter inneholder persondata, **må embeddings behandles som persondata** (vektorer kan teoretisk brukes til re-identifikasjon via inversion attacks, selv om praktisk svært vanskelig).
- **Rettighet til sletting:** Embedding-vektorer må slettes ved brukerforespørsel (GDPR Art. 17). Azure AI Search støtter dokument-sletting, men ikke selektiv sletting av embeddings uten reindeksering.
- **AI Act (høyrisiko-systemer):** Hvis RAG brukes til automatiserte beslutninger (f.eks. tilskudd, klagesaksbehandling), må embedding-modellen dokumenteres (hvilken modell, treningsdata, bias-testing).
**Anbefaling:**
- Lagre metadata som kobler embedding-ID til dokument-ID for GDPR-sletting
- Dokumenter embedding-modell og versjon i systemdokumentasjon
- Test for bias i multilingual embeddings (engelsk vs norsk kvalitet)
### Forvaltningsloven og etterprøvbarhet
Offentlige vedtak må kunne etterprøves. Hvis RAG brukes til å hente grunnlagsdokumenter, må systemet logge:
- Hvilke dokumenter ble hentet (citation tracking)
- Hvilken embedding-modell genererte query-vektoren
- Score/relevans per dokument
**Implementering:**
```python
# Logging for etterprøvbarhet
search_result = search_client.search(
search_text=None,
vector_queries=[VectorizedQuery(vector=query_embedding, k_nearest_neighbors=5, fields="contentVector")],
select=["id", "title", "content"]
)
for doc in search_result:
log_entry = {
"query": user_query,
"embedding_model": "text-embedding-3-small",
"document_id": doc["id"],
"score": doc["@search.score"],
"timestamp": datetime.utcnow()
}
logger.info(log_entry)
```
---
## Kostnad og lisensiering
### Prismodell (Azure OpenAI, per februar 2026)
| Modell | Pris per 1M tokens |
|--------|---------------------|
| text-embedding-ada-002 | $0.10 |
| text-embedding-3-small | $0.02 |
| text-embedding-3-large | $0.13 |
**Eksempel: Indeksering av 100 000 dokumenter (gjennomsnitt 1000 tokens per dokument)**
- **text-embedding-3-small:** 100M tokens × $0.02 / 1M = **$2**
- **text-embedding-3-large:** 100M tokens × $0.13 / 1M = **$13**
**Storage-kostnad (Azure AI Search):**
- **1536 dimensjoner:** Ca. 6 KB per vektor (inkl. overhead)
- **3072 dimensjoner:** Ca. 12 KB per vektor
- **100 000 dokumenter (1536 dims):** 600 MB → Basic tier OK
- **100 000 dokumenter (3072 dims):** 1.2 GB → Krever Standard tier
### Kostnadsoptimaliseringstips
1. **Bruk dimensjonsreduksjon (Matryoshka):**
```python
response = client.embeddings.create(
model="text-embedding-3-large",
input="...",
dimensions=1024 # Reduser fra 3072 til 1024
)
```
**Effekt:** 3x mindre storage, 2-3x raskere søk, marginalt tap av kvalitet (test først).
2. **Batch embedding-generering:**
```python
# Send 100 dokumenter per API-kall (maks 8191 tokens totalt)
response = client.embeddings.create(
model="text-embedding-3-small",
input=[doc1, doc2, ..., doc100]
)
```
**Effekt:** Lavere latency, samme kostnad per token.
3. **Cache query embeddings:**
- Lagre embeddings for vanlige spørsmål (FAQ) i Redis/Azure Cache
- Spare embedding-kostnad for repeterte queries
4. **Vurder multilingual E5 for flerspråklige scenarioer:**
- Gratis i preview (per feb 2026)
- Lavere kostnad når GA (forventet $0.01-0.03 per 1M tokens)
### Lisensiering
- **Azure OpenAI Service:** Krever Azure-abonnement, ingen separate lisenser for embedding-modeller
- **Azure AI Search:** Basic tier fra $75/mnd (1 GB storage), Standard S1 fra $250/mnd (25 GB storage)
- **Custom embeddings (self-hosted):** Ingen lisenskostnad utover compute (Azure ML, Kubernetes)
---
## For arkitekten (Cosmo)
### Nøkkelspørsmål til kunden
1. **Språk og geografi:**
- "Hvilke språk skal systemet håndtere? Er norsk primærspråk eller sekundært?"
- "Forventer brukere å søke på ett språk og få treff på andre språk?"
2. **Domene og terminologi:**
- "Inneholder dokumentene domene-spesifikk terminologi (juridisk, medisinsk, teknisk)?"
- "Har dere eksempler på spørsmål som ofte feiler i dagens søk?"
3. **Volum og kostnad:**
- "Hvor mange dokumenter skal indekseres initialt? Hva er forventet vekst per år?"
- "Hva er budsjett for embedding-generering og storage?"
4. **Kvalitet vs. kostnad:**
- "Hva er viktigst: høyest mulig retrieval-kvalitet eller lavest mulig kostnad?"
- "Er det OK med 10% lavere presisjon hvis vi halverer kostnadene?"
5. **Compliance og residency:**
- "Inneholder dokumentene persondata eller sensitiv informasjon (GDPR)?"
- "Er det krav om at data ikke forlater Norge/EU?"
6. **Eksisterende infrastruktur:**
- "Bruker dere allerede Azure OpenAI? Hvilken modell?"
- "Har dere kompetanse til å drifte custom embeddings (Azure ML, Kubernetes)?"
7. **Testing og validering:**
- "Hvordan måler dere retrieval-kvalitet i dag? Har dere golden dataset?"
- "Hva er akseptabel recall@5 / precision@5 for deres use case?"
8. **Multimodalitet:**
- "Skal systemet håndtere bilder, tabeller eller kun tekst?"
- "Trenger dere embeddings for metadata (tags, kategorier) i tillegg til innhold?"
### Vanlige fallgruver
| Fallgruve | Konsekvens | Hvordan unngå |
|-----------|------------|---------------|
| **Ikke teste retrieval-kvalitet før produksjon** | Dårlig brukeropplevelse, høy support-last | Opprett golden dataset (50-100 query-dokument-par), mål recall@5/precision@5 |
| **Blande embeddings fra ulike modeller** | Retrieval feiler fullstendig | Reindekser ALLE dokumenter ved modellendring |
| **Ignorere språkparitet i multilingual embeddings** | Norske queries gir dårlige resultater | Test retrieval-kvalitet per språk, juster reranking-vekter |
| **Overforenkle dimensjonalitetsvalg ("høyere er alltid bedre")** | Unødvendig høy kostnad og latency | Benchmark 512, 1536 og 3072 dimensjoner mot golden dataset |
| **Ikke dokumentere embedding-modell i systemdokumentasjon** | GDPR/AI Act compliance-problem | Logg modellnavn, versjon, treningsdata (hvis tilgjengelig) |
### Anbefalinger per modenhetsnivå
| Modenhetsnivå | Anbefaling | Begrunnelse |
|---------------|-----------|-------------|
| **Grunnleggende** (første RAG-prosjekt) | text-embedding-3-small (1536 dims), Azure AI Search integrated vectorization | Enklest å sette opp, lavest risiko, god kvalitet |
| **Mellomliggende** (har RAG i prod, vil optimalisere) | text-embedding-3-small (512 dims) + reranking | Kostnadsoptimalisering, bedre kvalitet via post-processing |
| **Avansert** (komplekse domener, multilingual) | text-embedding-3-large (1024-3072 dims) eller custom embeddings | Høyere presisjon, domene-spesifikk tuning |
| **Offentlig sektor (compliance-kritisk)** | Custom embeddings hostet i Azure Norway | Full kontroll over data residency og modell-dokumentasjon |
---
## Fine-tuning av embedding-modeller
### Hvorfor fine-tune?
General-purpose embedding-modeller (text-embedding-3) presterer godt på standardoppgaver, men kan underlevere på domenespesifikke termer, norsk fagspråk, eller spesialisert terminologi. Fine-tuning tilpasser embedding-modellen til kundens datadomene.
### Azure AI Foundry for embedding fine-tuning
Azure AI Foundry støtter fine-tuning av embedding-modeller via **Custom Models** (preview):
| Aspekt | Detaljer |
|--------|----------|
| **Støttede modeller** | text-embedding-3-small, text-embedding-3-large |
| **Treningsdata** | JSON Lines med query-document pairs |
| **Minimum samples** | 100 positive pairs (anbefalt 1000+) |
| **Output** | Fine-tuned deployment med egne dimensjoner |
| **Evaluering** | Recall@k, NDCG, MRR mot valideringssett |
### Treningsdata-format
```jsonl
{"query": "hva er regelverket for kunstig intelligens i norge", "document": "AI-forordningen (EU AI Act) trådte i kraft...", "label": 1}
{"query": "azure openai prising", "document": "Vegvesenets budsjett for 2025...", "label": 0}
```
**Tips for norsk/skandinavisk:**
- Inkluder norske fagtermer og forkortelser som positive pairs
- Bruk synonympar (f.eks. «KI» ↔ «kunstig intelligens», «AI» ↔ «maskinlæring»)
- Balancer bokmål og nynorsk om relevant
### Evaluering: Fine-tuned vs. General-purpose
| Metrikk | General-purpose | Fine-tuned | Typisk forbedring |
|---------|----------------|------------|-------------------|
| Recall@5 (domene) | 70-80% | 85-95% | +10-15 pp |
| Recall@5 (generell) | 85-90% | 80-88% | -2-5 pp (trade-off) |
| Norsk fagspråk precision | 60-75% | 80-92% | +15-20 pp |
**Viktig trade-off:** Fine-tuning forbedrer domene-retrieval men kan redusere generell kvalitet. Test alltid med et bredt evalueringssett.
### Beslutningsveiledning for fine-tuning
| Scenario | Fine-tune? | Begrunnelse |
|----------|-----------|-------------|
| Generell RAG, standard norsk | Nei | text-embedding-3-small er god nok |
| Domene-spesifikt fagspråk | Ja | Fagtermer mangler i general-purpose |
| Norsk offentlig sektor (forvaltning) | Vurder | Lovtekst og forvaltningstermer er spesifikke |
| Multilingual (norsk + engelsk) | Nei | text-embedding-3 håndterer multilingual godt |
| <500 treningsdokumenter | Nei | For lite data, bruk synonym maps i stedet |
### Alternativ: Domenespesifikk reranking
For teams som ikke har nok treningsdata for fine-tuning, er en domene-tilpasset **reranker** et enklere alternativ:
- Bruk general-purpose embeddings for retrieval (text-embedding-3)
- Tren en cross-encoder reranker på domenespesifikke query-document pairs
- Krever færre treningseksempler (50-100 pairs)
---
## Kilder og verifisering
### Primærkilder (Microsoft Learn)
- [Azure OpenAI Embeddings](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/embeddings) (Verified, feb 2026)
- [Azure AI Search Vector Search](https://learn.microsoft.com/en-us/azure/search/vector-search-overview) (Verified, feb 2026)
- [Integrated Vectorization in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/vector-search-integrated-vectorization) (Verified, feb 2026)
- [Matryoshka Embeddings (OpenAI)](https://platform.openai.com/docs/guides/embeddings/embedding-models) (Baseline, referert i Azure docs)
### Sekundærkilder
- OpenAI Embeddings Pricing (Verified, https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai-service/)
- Multilingual E5 (Baseline, Microsoft Research paper, preview-status bekreftet via Azure AI docs)
### Konfidensnivå
- **Modellnavn, dimensjoner, pricing:** Verified (Azure offisiell dokumentasjon)
- **Multilingual E5 status:** Baseline (preview bekreftet, GA-priser antatt)
- **Custom embeddings:** Assumed (announced feature, detaljer fra early access docs)
- **GDPR/AI Act anbefalinger:** Verified (basert på EU-regelverk og Microsoft compliance-dokumentasjon)
---
**For Cosmo:** Bruk denne referansen når kunden nevner "embedding-problemer", "dårlig retrieval-kvalitet på norsk", "for høye Azure AI Search-kostnader" eller "vi vurderer å bytte embedding-modell". Start alltid med å kartlegge språk, domene og volum før du anbefaler modell. Test ALLTID retrieval-kvalitet med kundens egne data før produksjonsutrulling.

View file

@ -0,0 +1,303 @@
# GraphRAG - Knowledge Graphs and Relationship Extraction
**Last updated:** 2026-02
**Status:** Preview
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
GraphRAG representerer en fundamental utvidelse av tradisjonell Retrieval-Augmented Generation (RAG) ved å innføre knowledge graphs som strukturert grunnlag for kontekstrikere søk og resonnering. Der klassisk RAG baserer seg på vector similarity for å finne relevante dokumentchunks, utnytter GraphRAG eksplisitte entitets- og relasjonsforbindelser for å svare på spørsmål som krever forståelse av hierarkier, avhengigheter og komplekse sammenhenger.
GraphRAG kombinerer tre komplementære retrieval-strategier: tradisjonell database-RAG for fakta-lookup, vector search for semantisk likhet, og graph traversal for relasjonelle spørsmål. Dette hybridsystemet, ofte kalt **OmniRAG**, velger dynamisk den mest hensiktsmessige søkemetoden basert på brukerens spørsmålstype. For eksempel vil spørsmål om "hvem rapporterer til hvem" utløse graph traversal, mens "finn lignende dokumenter" bruker vector search.
I Microsoft-økosystemet implementeres GraphRAG primært via **CosmosAIGraph** — en løsning som utnytter Azure Cosmos DB sine skalerbare capabilities for både dokument-, vektor- og graph-databaser. Ved å kombinere disse i én plattform, muliggjør CosmosAIGraph sofistikerte datamodeller for use cases som anbefalingssystemer, supply chain-analyse, fraud detection og organisasjonshierarkier.
---
## Kjernekomponenter
GraphRAG-systemet består av flere integrerte lag som sammen muliggjør relasjonell søking og resonnering:
| Komponent | Beskrivelse | Microsoft-teknologi |
|-----------|-------------|---------------------|
| **Entity Extraction** | Identifiserer og trekker ut navngitte entiteter (personer, organisasjoner, lokasjoner) fra tekst | Azure AI Language Service (NER v3), GenAI Prompt skill |
| **Relationship Graphs** | Representerer entiteter som nodes og relasjoner som edges i en graph-struktur | Azure Cosmos DB (graph API), Kusto Query Language (KQL) graph semantics |
| **Graph Indexing** | Lagrer og indekserer graph-strukturen for effektiv traversal og søk | Azure Cosmos DB indexing, Azure AI Search (hybrid indexing) |
| **Traversal Queries** | Søkemekanismer for å navigere graph-strukturen (pattern matching, shortest path, neighborhood search) | KQL `graph-match`, `graph-shortest-paths`, Labeled Property Graphs (LPG) |
| **Entity Linking** | Forbinder ekstraherte entiteter med eksisterende knowledge bases (f.eks. Wikipedia) for normalisering og anrikning | Azure AI Language Entity Linking skill |
| **Vector Integration** | Kombinerer graph traversal med vector embeddings for hybrid retrieval | Azure AI Search (hybrid queries), Azure OpenAI Embedding skill |
### Entity Extraction og Enrichment
Entity extraction-prosessen transformerer ustrukturert tekst til strukturerte entitets-objekter med metadata:
- **Built-in skills**: Entity Recognition (v3) fra Azure AI Search extraherer 14 kategorier (Person, Organization, Location, Quantity, DateTime, URL, Email)
- **Custom extraction**: GenAI Prompt skill tillater few-shot learning for domene-spesifikke entiteter
- **Entity normalization**: Wikipedia IDs, Bing IDs og confidence scores legges til for datakvalitet
### Graph Database Modeller
Microsoft Fabric og Azure støtter **Labeled Property Graphs (LPG)** som standard graph-modell:
- **Nodes (entiteter)**: Har labels (typer), properties (attributter) og unique IDs
- **Edges (relasjoner)**: Har types (f.eks. "knows", "depends_on"), properties (weights, timestamps) og retning
- **Schema flexibility**: Kan utvikles inkrementelt uten rigid schema constraints
- **RDF ikke støttet**: Resource Description Framework (RDF) er ikke støttet i Microsoft Fabric per 2026
---
## Arkitekturmønstre
### 1. Local vs. Global GraphRAG
| Mønster | Beskrivelse | Bruksområde | Fordeler | Ulemper |
|---------|-------------|-------------|----------|---------|
| **Local GraphRAG** | Traverserer graph fra query-relevante nodes (1-3 hops) | Q&A om spesifikke entiteter ("Hvem jobbet sammen med Person A?") | Rask, presis, lav compute-kostnad | Mister global kontekst, begrensede inferenser |
| **Global GraphRAG** | Bygger community-struktur og summaries over hele graph | Strategiske spørsmål ("Hvilke temaer dominerer dette dokumentsettet?") | Holistisk forståelse, oppdager skjulte mønstre | Compute-intensiv, høy latency, krever pre-processing |
**Best practice**: Bruk local GraphRAG for runtime queries, global GraphRAG for batch-analyse og insight-generering.
### 2. Hybrid Vector + Graph Retrieval
Kombinerer vector similarity search med graph traversal for maksimal kontekst-relevans:
```
1. Vector search → finn top-N semantisk relevante chunks
2. Entity extraction → identifiser entiteter i chunks
3. Graph traversal → ekspander med relaterte entiteter (1-2 hops)
4. Re-ranking → kombiner vector scores og graph proximity
5. Context assembly → samle anriket kontekst for LLM-prompt
```
**Fordeler**: Balanserer semantic similarity med autoritative relasjoner, reduserer hallucinations.
**Ulemper**: Høyere latency, krever orchestration-logikk (f.eks. Microsoft Agent Framework).
### 3. Entity-Centric Retrieval
Spesielt effektivt for domener med mange-til-mange relasjoner (supply chains, org charts, knowledge bases):
- **Pattern**: Query → entity lookup → relationship expansion → document retrieval
- **Eksempel**: "Finn alle avhengigheter for produkt X" → hent product node → travers "depends_on" edges → returner relaterte produkter
- **Microsoft-implementasjon**: CosmosAIGraph med OmniRAG dynamic routing
---
## Beslutningsveiledning
### Når bruke GraphRAG?
| Scenario | Anbefaling | Alternativ |
|----------|------------|-----------|
| Spørsmål om relasjoner, hierarkier, avhengigheter | ✅ **GraphRAG** (graph traversal) | Vector RAG (vil feile på relasjonelle inferenser) |
| Spørsmål om "hvem", "hva", "hvor" (fakta) | Database RAG | GraphRAG (overkill) |
| Semantisk likhetssøk ("finn lignende") | Vector RAG | GraphRAG (unødvendig kompleksitet) |
| Ukjent query-type (varierende brukerformål) | **OmniRAG** (dynamisk routing) | Single-mode RAG (suboptimalt) |
| Eksplorative spørsmål ("vis sammenhenger") | Global GraphRAG | Local/vector RAG (for snevert) |
### Vanlige feil
| Feil | Konsekvens | Løsning |
|------|------------|---------|
| Bruker GraphRAG for alle queries | Unødvendig høy latency og kostnad | Implementer OmniRAG-routing basert på query classification |
| Ingen entity normalization | Duplikate nodes ("Microsoft" vs. "Microsoft Corp") | Bruk Entity Linking skill + canonical ID-mapping |
| For dype traversals (5+ hops) | Eksplosjonsartet resultatmengde, timeout | Begrens til 1-3 hops, bruk shortest-path algorithms |
| Ignorerer vector component i hybrid mode | Mister semantisk kontekst | Alltid kombiner graph + vector for best recall |
| Mangelfull graph indexing | Treg traversal-performance | Bruk Azure Cosmos DB indexing policies, pre-compute communities |
### Røde flagg
- 🚩 **Persondata i graph nodes**: GDPR-risiko hvis PII lagres uten anonymisering
- 🚩 **Ingen confidence thresholds**: Lav-kvalitet entity extraction forurenser graph
- 🚩 **Statisk graph model**: Manglende evne til å håndtere nye entitetstyper
- 🚩 **Single graph instance**: Ingen fallback hvis graph queries feiler
---
## Integrasjon med Microsoft-stakken
### Azure Cosmos DB for GraphRAG
**CosmosAIGraph** ([aka.ms/cosmosaigraph](https://aka.ms/cosmosaigraph)) er Microsofts native GraphRAG-løsning:
- **Multi-model database**: Document, vector og graph i samme container
- **OmniRAG-orchestration**: Automatisk routing basert på query intent
- **Skalering**: Global distribution, RU-based throughput (handles massive graphs)
- **API**: Gremlin API (graph traversal), SQL API (document queries)
### Azure AI Search
- **Hybrid indexing**: Lagrer både vectors og graph-metadata (entity IDs, relationship types)
- **Enrichment pipeline**: Entity Recognition skill + custom skills for graph-population
- **Reranking**: Semantic ranking kombinert med graph proximity scores
- **Knowledge base API**: Preview-feature for agentic retrieval (includes graph-aware context assembly)
### Azure OpenAI
- **Embedding models**: `text-embedding-3-large` for vector component av hybrid GraphRAG
- **Prompt engineering**: GenAI Prompt skill for few-shot entity extraction
- **Reasoning over graphs**: GPT-4 og Opus for complex graph reasoning (path explanations, multi-hop inferenser)
### Microsoft Agent Framework
- **Orchestration**: Koordinerer database → graph → vector → LLM pipelines
- **Agent tools**: Graph query tools (Gremlin, KQL) som agent capabilities
- **Streaming**: Inkrementell graph traversal for low-latency agent responses
### Kusto Query Language (KQL) Graph Semantics
Microsoft Fabric og Azure Data Explorer støtter KQL graph operators:
- **`make-graph`**: Konstruerer graph fra tabular data (node/edge tables)
- **`graph-match`**: Pattern matching (f.eks. "MATCH (Person)-[:knows]->(Friend)")
- **`graph-shortest-paths`**: Finn korteste sti mellom nodes
- **`graph-to-table`**: Konverter graph-resultater til tabeller for videre analyse
---
## Offentlig sektor (Norge)
### GDPR og knowledge graphs
GraphRAG introduserer spesifikke personvernrisiki i offentlig sektor:
| Risiko | GDPR-artikkel | Tiltak |
|--------|---------------|--------|
| **PII i entity nodes** | Art. 5 (data minimization) | Anonymiser personnavn, bruk pseudonymiserte IDs |
| **Relasjonsgraphs som profilering** | Art. 22 (automated decisions) | Eksplisitt consent for graph-baserte anbefalinger |
| **Persistent graph storage** | Art. 17 (right to erasure) | Implementer node/edge deletion workflows |
| **Cross-border graph traversal** | Art. 44 (international transfers) | Bruk Azure Norway regions, regional graph partitions |
### Compliance-krav
- **Schrems II**: GraphRAG-data i Azure Norway (oslo-region) oppfyller EU data residency
- **Arkivloven**: Graph snapshots må inkluderes i dokumentasjonssystemer (OEP-format krever flattening)
- **Sikkerhetsloven**: Graph-relasjoner klassifiseres som "indirekte identifikatorer" (kryptér edges med sensitive relasjoner)
### Anbefalt pattern for offentlig sektor
```
1. Dokument-ingest → entity extraction (anonymisert) → graph population
2. PII-nodes lagres i separate encrypted containers (ikke i graph)
3. Graph-relasjoner bruker role-based IDs ("Leder-1234" vs. "Navn Navnesen")
4. Query-logging for auditability (hvem traverserte hvilke relasjoner?)
5. Automatic retention policies (delete old graph data per arkivplan)
```
---
## Kostnad og lisensiering
### Azure Cosmos DB Pricing (GraphRAG-spesifikt)
| Komponent | Enhet | Pris (NOK, ca.) | Optimalisering |
|-----------|-------|-----------------|----------------|
| **Graph storage** | 1 GB/måned | ~12 NOK | Partition graphs per domain, archive old communities |
| **Read/write RUs** | 100 RU/s provisioned | ~500 NOK/måned | Use serverless for sporadic queries, autoscaling for variable load |
| **Graph traversal** | Per query complexity (RUs) | Variabel (5-100 RU per traversal) | Cache frequent paths, limit hop depth |
| **Global distribution** | Per region replica | +100% storage cost | Use single-region for dev/test |
**TCO-eksempel** (medium-sized graph):
- 100 GB graph data
- 10,000 queries/dag (mix av local/global)
- Provisioned 1000 RU/s
- **Månedlig kostnad**: ~8,000 NOK
### Azure AI Search for Hybrid GraphRAG
- **Indexing**: Entity extraction via built-in skills (~2-5 NOK per 1000 documents)
- **Hybrid queries**: Vector + metadata filtering (inkludert i query cost, ingen ekstra)
- **Semantic ranking**: +100 NOK/måned (1000 queries/month tier)
### Optimaliseringstips
1. **Pre-compute global graph summaries** (kjør batch jobs nattetid, cache results)
2. **Partition graphs by tenant/department** (reduser traversal scope, isoler cost per user)
3. **Use materialized views** (lagre frequently-queried subgraphs som denormalized tables)
4. **Tiered retrieval**: Start med cheap vector search, eskalér til graph kun hvis nødvendig
5. **Monitor RU consumption**: Set alerts på >80% RU usage, auto-scale eller optimize queries
---
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **Hvilke typer spørsmål skal systemet besvare?**
→ Avgjør om local, global eller hybrid GraphRAG trengs
2. **Finnes det etablerte ontologies/taxonomier i domenet?**
→ Kan gjenbruke eksisterende entity types vs. bygge fra scratch
3. **Hvor mange entiteter og relasjoner forventes?**
→ Dimensjonerer Cosmos DB RUs, vurderer partitioning-strategi
4. **Hvor dynamisk er dataen? (Hvor ofte endres relasjoner?)**
→ Statiske graphs kan pre-kompileres, dynamiske krever real-time indexing
5. **Finnes det persondata i entitetene?**
→ GDPR-vurdering, pseudonymisering, consent-flows
6. **Hva er latency-kravene for queries?**
→ <500ms: bruk pre-computed paths; <2s: local traversal; >2s: global ok
7. **Skal brukere kunne visualisere graphen?**
→ Krever frontend integration (f.eks. vis.js, D3.js) + export API
8. **Hvilke downstream-systemer skal konsumere graph-innsikter?**
→ API design, batch export vs. streaming updates
### Fallgruver
| Fallgruve | Hvorfor det skjer | Hvordan unngå |
|-----------|-------------------|---------------|
| **Graph blir for stor til å travers** | Ukontrollert vekst (ingen arkivering) | Implementer retention policies, partition per time period |
| **Entity extraction av lav kvalitet** | Default NER-modeller ikke trent på domene | Fine-tune custom models, bruk GenAI Prompt skill med examples |
| **Ingen fail-over fra graph til vector** | Hard dependency på graph availability | Implementer OmniRAG-fallback: graph timeout → vector search |
| **Query performance degrades over tid** | Index fragmentation, ingen maintenance | Schedule index rebuilds, monitor query latencies |
| **Brukere forventer real-time graph updates** | Batch-basert indexing pipeline | Set forventninger (eventual consistency), eller bruk streaming ingestion |
### Anbefalinger per modenhetsnivå
| Nivå | Startpunkt | Neste steg |
|------|------------|-----------|
| **Eksplorerende** (ingen RAG i prod) | Pilot med CosmosAIGraph demo dataset | Evaluer query patterns, beslut local vs. global |
| **Etablert RAG** (vector search i prod) | Legg til entity extraction i existing pipeline | A/B-test hybrid vs. vector-only retrieval |
| **Modenhet** (multi-modal RAG) | Implementer OmniRAG routing | Optimize cost med query classification + tiered retrieval |
| **Avansert** (custom graph reasoning) | Tren fine-tuned entity linker på domene-data | Build custom graph reasoning agents (multi-hop, counterfactual queries) |
---
## Kilder og verifisering
### Microsoft Learn-kilder (fra MCP-research)
| Seksjon | URL | Konfidensnivå |
|---------|-----|---------------|
| CosmosAIGraph arkitektur | https://learn.microsoft.com/en-us/azure/cosmos-db/gen-ai/cosmos-ai-graph | ✅ Verified (2026-02) |
| Graph semantics i KQL | https://learn.microsoft.com/en-us/kusto/query/graph-semantics-overview | ✅ Verified (2026-02) |
| Entity Recognition skill (v3) | https://learn.microsoft.com/en-us/azure/search/cognitive-search-skill-entity-recognition-v3 | ✅ Verified (2026-02) |
| Azure AI Search transparency note | https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/search/transparency-note | ✅ Verified (2026-02) |
| RAG solution design guide | https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-solution-design-and-evaluation-guide | ✅ Verified (2026-02) |
| Labeled Property Graphs (LPG) | https://learn.microsoft.com/en-us/fabric/graph/graph-data-models | ✅ Verified (2026-02) |
### Konfidens per seksjon
- **Introduksjon**: ✅ Verified (direkte fra Cosmos DB docs)
- **Kjernekomponenter**: ✅ Verified (Azure AI Search + Cosmos DB capabilities)
- **Arkitekturmønstre**: ⚠️ Baseline (inferert fra best practices, ikke eksplisitt dokumentert)
- **Beslutningsveiledning**: ⚠️ Baseline (syntetisert fra multiple sources)
- **Microsoft-integrasjon**: ✅ Verified (official API docs)
- **Offentlig sektor**: ⚠️ Baseline (GDPR-prinsipper applisert på GraphRAG-kontekst)
- **Kostnad**: ⚠️ Baseline (Cosmos DB pricing, estimater fra modell-kunnskap)
### Notater
- CosmosAIGraph er en GitHub-basert løsning (preview), ikke en fullt integrert Azure-tjeneste per februar 2026
- Global GraphRAG-konseptet er inspirert av research (ikke eksplisitt Microsoft-terminologi)
- NOK-priser er omregnet fra USD med kurs 10.5 (verifiser mot aktuelle priser)
---
**For Cosmo Skyberg:** Dette dokumentet skal brukes for å vurdere om GraphRAG-patterns er hensiktsmessige for kundens use case. Prioriter alltid spørsmålet: "Trenger vi faktisk graph traversal, eller holder vector search?" — kompleksitet skal forsvares med klare fordeler. Ved tvil, start med hybrid approach (vector + metadata) før full graph commitment.

View file

@ -0,0 +1,285 @@
# Hierarchical RAG Patterns — Multi-nivå retrieval
**Last updated:** 2026-02
**Status:** GA (index projections), Preview (agentic retrieval)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Hierarchical RAG organiserer kunnskap i multi-nivå strukturer i stedet for flat chunk-indeksering. Ved å etablere relasjoner mellom parent-dokumenter, seksjoner og chunks muliggjøres en «zoom inn/ut»-mekanisme der søk starter bredt (dokumentnivå) og driller ned til relevante segmenter.
Azure AI Search implementerer hierarkisk RAG gjennom **index projections** som håndterer one-to-many relasjoner mellom kildedokumenter og chunks. Document Intelligence Layout skill bevarer dokumentstruktur (headings, avsnitt) som muliggjør hierarkisk navigasjon.
Forskning (2025-2026) viser at hierarkisk retrieval gir 47% høyere Hit@1 og opptil 250x reduksjon i token-kostnad sammenlignet med flat retrieval, fordi søkeområdet reduseres gjennom coarse-to-fine filtrering.
---
## Kjernekomponenter
### Parent-child relasjoner i Azure AI Search
Azure AI Search tilbyr tre arkitekturmønstre for parent-child indeksering:
| Mønster | Beskrivelse | Brukstilfelle |
|---------|-------------|---------------|
| **Single index, repeating parent fields** | Parent-metadata repeteres per chunk | Standard RAG, enkel query-logikk (anbefalt) |
| **Single index, mixed document shapes** | Parents og chunks co-eksisterer | Fulldokument-søk + chunk-søk i én indeks |
| **Separate parent-child indexes** | Dedikert parent-index + child-index | Enterprise med strikt separasjon, compliance |
### Index projection-konfigurasjon
```json
{
"indexProjections": {
"selectors": [
{
"targetIndexName": "my_consolidated_index",
"parentKeyFieldName": "parent_id",
"sourceContext": "/document/pages/*",
"mappings": [
{ "name": "chunk", "source": "/document/pages/*" },
{ "name": "chunk_vector", "source": "/document/pages/*/chunk_vector" },
{ "name": "title", "source": "/document/title" }
]
}
],
"parameters": {
"projectionMode": "skipIndexingParentDocuments"
}
}
}
```
**Nøkkelparametere:**
| Parameter | Verdier | Beskrivelse |
|-----------|---------|-------------|
| `projectionMode` | `skipIndexingParentDocuments` / `includeIndexingParentDocuments` | Kun chunks eller begge |
| `parentKeyFieldName` | `parent_id`, `text_parent_id` | Felt som kobler chunk → parent |
| `sourceContext` | `/document/pages/*` | Enrichment path for granularitet |
### Automatisk chunk-ID generering
Azure AI Search genererer chunk-IDer basert på parent-ID:
- Parent: `aa1b22c33`
- Chunk 1: `aa1b22c33_pages_0`
- Chunk 2: `aa1b22c33_pages_1`
Hash-komponenten endres ved parent-oppdatering → sikrer change tracking.
---
## Arkitekturmønstre
### Mønster 1: Single index med parent-metadata (anbefalt)
**Arkitektur:** Data source → Indexer → Document Layout → Text Split → Embedding → Index projections (parent fields repeteres per chunk)
**Index-schema:**
```json
{
"fields": [
{ "name": "chunk_id", "type": "Edm.String", "key": true },
{ "name": "parent_id", "type": "Edm.String", "filterable": true },
{ "name": "chunk", "type": "Edm.String", "searchable": true },
{ "name": "chunk_vector", "type": "Collection(Edm.Single)" },
{ "name": "title", "type": "Edm.String", "filterable": true },
{ "name": "section_heading", "type": "Edm.String", "filterable": true },
{ "name": "page_number", "type": "Edm.Int32", "filterable": true }
]
}
```
**Fordeler:**
- Enklest å implementere og vedlikeholde
- Én query gir chunks med full parent-kontekst
- Metadata-filtrering (tittel, seksjon) for hierarkisk drill-down
**Anbefalt for:** 80% av RAG-løsninger, spesielt ved enkel dokumentstruktur.
### Mønster 2: Multi-resolution retrieval med lookup-queries
**Arkitektur:** Child index (chunks) + Parent index (summaries/metadata) → Vector search på child → Lookup til parent
**Implementering:**
```python
# Steg 1: Hent relevante chunks
child_results = child_client.search(
vector_queries=[VectorQuery(vector=query_embedding, k=5)],
select=["chunk_id", "parent_id", "chunk"]
)
# Steg 2: Lookup parent-dokumenter
parent_ids = {r["parent_id"] for r in child_results}
parent_docs = parent_client.search(
filter=f"parent_id in ({','.join(parent_ids)})",
select=["parent_id", "title", "summary"]
)
# Steg 3: Assembler kontekst
context = []
for chunk in child_results:
parent = next(p for p in parent_docs if p["parent_id"] == chunk["parent_id"])
context.append({
"chunk": chunk["chunk"],
"source": parent["title"],
"summary": parent["summary"]
})
```
**Fordeler:**
- «Zoom ut» fra chunk til fullt dokument
- Parent-summary gir LLM bedre kontekstuell forståelse
- Sporbarhet for citation og audit
**Anbefalt for:** Enterprise RAG med krav til kildehenvisning og compliance.
### Mønster 3: Retrieval cascade (Summary → Section → Chunk)
**Arkitektur:** Tre indeksnivåer med progressiv filtrering:
```
Nivå 1: Document summaries → Velg relevante dokumenter (top-10)
Nivå 2: Section headings → Velg relevante seksjoner (top-20)
Nivå 3: Chunks → Hent detaljerte segmenter (top-5)
```
**Fordeler:**
- Drastisk reduksjon av søkerom (10-100x)
- Minimerer «lost in the middle»-problemet
- Opptil 250x reduksjon i token-kostnad
**Ulemper:**
- Tre separate søkeoperasjoner (økt latency)
- Kompleks indeksstruktur
- Krever generering av summaries per dokument/seksjon
**Anbefalt for:** Store dokumentsamlinger (>100K docs) der flat søk gir dårlig precision.
---
## Beslutningsveiledning
### Beslutningstabell
| Scenario | Volum | Anbefalt mønster |
|----------|-------|------------------|
| Standard RAG | <50K docs | Mønster 1 (single index, parent fields) |
| Krav til citation/sporbarhet | Alle | Mønster 2 (lookup queries) |
| Stort volum, lav precision | >100K docs | Mønster 3 (retrieval cascade) |
| Compliance/audit | Alle | Mønster 2 med `dataDeletionDetectionPolicy` |
### Vanlige feil
| Feil | Konsekvens | Løsning |
|------|------------|---------|
| Ingen parent-child mapping | Kan ikke spore chunk → kildedokument | Bruk index projections med `parentKeyFieldName` |
| Ignorerer `dataDeletionDetectionPolicy` | GDPR right to erasure brytes | Konfigurer cascade deletion på data source |
| Flat index for >100K docs | Dårlig precision, høy token-kostnad | Vurder retrieval cascade |
| Manglende metadata (section, page) | Ingen mulighet for hierarkisk filtrering | Legg til `section_heading` og `page_number` |
---
## Integrasjon med Microsoft-stakken
| Tjeneste | Integrasjonspunkt |
|----------|-------------------|
| **Azure AI Search** | Index projections, parent-child mapping, lookup queries |
| **Azure AI Document Intelligence** | Document Layout skill med `markdownHeaderDepth: "h3"` |
| **Azure Content Understanding** | Semantisk chunking med kryssende sider |
| **Azure OpenAI** | Summary-generering for retrieval cascade |
| **Semantic Kernel** | TextSearchProvider med namespace-filtrering |
| **Azure Cosmos DB** | Alternativ parent-child storage med hierarkisk query |
### Document Layout skill for hierarkisk chunking
```json
{
"@odata.type": "#Microsoft.Skills.Util.DocumentIntelligenceLayoutSkill",
"context": "/document",
"outputMode": "oneToMany",
"markdownHeaderDepth": "h3",
"inputs": [{"name": "file_data", "source": "/document/file_data"}],
"outputs": [{"name": "markdown_document", "targetName": "markdownDocument"}]
}
```
Output: Markdown med `# H1`, `## H2`, `### H3` som bevarer hierarkisk dokumentstruktur.
---
## Offentlig sektor (Norge)
### Dataplassering
- **Azure AI Search:** Norway East — hierarkisk indeks forblir i Norge
- **Document Intelligence:** West Europe — dokument-parsing i EU
### Relevante vurderinger
| Krav | Implikasjon |
|------|-------------|
| **Forvaltningsloven** | Chunks må spores til kildedokument — krev parent-child mapping |
| **GDPR Art. 17** | Sletting av kildedokument MÅ kaskadere til alle chunks |
| **AI Act** | Hierarkisk sporbarhet støtter forklarbarhetskrav |
| **Arkivloven** | Parent-index bevarer dokumentkontekst for arkivformål |
---
## Kostnad og lisensiering
### Kostnadskomponenter
| Komponent | Kostnad | Notat |
|-----------|---------|-------|
| Index projections | Inkludert i AI Search | Ingen ekstra kostnad |
| Document Layout skill | ~$0.01-0.05/side | Document Intelligence-prising |
| Summary-generering (cascade) | GPT-4o per dokument | ~$0.01-0.05/dokument |
| Ekstra indekslagring (parent-felter) | Per GB | ~20-30% økning ved repeterte felter |
### Optimaliseringstips
1. **Bruk `projectionMode: skipIndexingParentDocuments`** for å unngå dobbelt lagring
2. **Generer summaries off-peak** for å minimere compute-kostnad
3. **Sett `stored: false` på vektorfelt** for å spare lagringsplassn
---
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **"Trenger brukerne å se hvilke dokumenter et svar kommer fra?"** — Hvis ja, krev parent-child mapping
2. **"Hvor mange dokumenter er i samlingen?"** — >100K → vurder cascade
3. **"Er det compliance-krav til sletting (GDPR)?"** — Krev cascade deletion
4. **"Har dokumentene tydelig struktur (headings, kapitler)?"** — Bruk Document Layout skill
5. **"Hva er akseptabel query-latency?"** — Cascade = 2-3x latency
### Fallgruver
- **Over-engineering for småskala:** Single index med parent fields er nok for <50K docs
- **Glemmer deletion policy:** GDPR-brudd hvis chunks overlever parent-sletting
- **Cascade uten summaries:** Første nivå i cascade trenger AI-genererte summaries for å fungere
### Anbefalinger per modenhetsnivå
| Modenhet | Anbefaling |
|----------|------------|
| **Prototyp** | Single index med `parent_id` felt. Ingen cascade. |
| **Pilot** | Index projections med parent fields + Document Layout. |
| **Produksjon** | Mønster 2 (lookup queries) + cascade deletion policy. |
| **Enterprise** | Retrieval cascade + AI-summaries + automated quality evaluation. |
---
## Kilder og verifisering
| Kilde | Konfidens | URL |
|-------|-----------|-----|
| Define index projections (Azure AI Search) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/search-how-to-define-index-projections) |
| Chunk and vectorize by document layout | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/search-how-to-semantic-chunking) |
| RAG and generative AI (Azure AI Search) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview) |
| Model complex data types | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/search-howto-complex-data-types) |
| Hierarchical RAG research | **Baseline** | [emergentmind.com](https://www.emergentmind.com/topics/hierarchical-rag) |

View file

@ -0,0 +1,225 @@
# Hybrid Search - Full-Text and Vector Combined
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Hybrid search i Azure AI Search kombinerer full-text (BM25) søk med vektorsøk i en enkelt spørring. De to søkemetodene kjøres parallelt, og resultatene fusjoneres via **Reciprocal Rank Fusion (RRF)**-algoritmen. Dette gir bedre relevans enn enten keyword- eller vektorsøk alene, fordi BM25 fanger eksakte termer mens vektorsøk fanger semantisk mening.
RRF-algoritmen beregner en samlet score basert på formelen `1/(rank + k)`, der `rank` er dokumentets posisjon i hver resultatliste og `k` er en konstant (typisk 60). Dokumenter som rangerer høyt på tvers av begge metoder prioriteres. Dette gjør hybrid search robust for varierte spørringstyper — fra eksakte nøkkelord-søk til vage, konseptuelle spørsmål.
Hybrid search er tilgjengelig fra Basic-tier og oppover i Azure AI Search, og krever ingen ekstra kostnad utover standard spørringsoperasjoner. Funksjonen er GA siden 2023, med kontinuerlige forbedringer i scoring og ytelse.
## Kjernekomponenter
### Scoring-modeller
| Søkemetode | Score-property | Algoritme | Område |
|------------|----------------|-----------|--------|
| Full-text | `@search.score` | BM25 | 0 til ubegrenset |
| Vector | `@search.score` | HNSW/KNN | 0.3331.00 (Cosine) |
| Hybrid | `@search.score` | RRF | 0 til ~1/k per query |
| Semantic ranking | `@search.rerankerScore` | ML comprehension | 0.004.00 |
### Vektervekting
Vector queries støtter `weight`-parameter for å justere relativ viktighet:
- **Default:** 1.0
- **Redusere:** 0.5 (halverer vektorens bidrag til RRF-scoren)
- **Øke:** 2.0 (dobler vektorens bidrag)
```python
from azure.search.documents.models import VectorizedQuery
vector_query = VectorizedQuery(
vector=query_vector,
k_nearest_neighbors=10,
fields="DescriptionVector",
weight=2.0 # Prioriter semantisk likhet
)
```
### maxTextRecallSize
Kontrollerer hvor mange BM25-resultater som mates inn i RRF:
- **Default:** 1000
- **Justérbar:** Høyere verdi = mer tekst-recall, men økt latency
- **Anbefaling:** Default er tilstrekkelig for de fleste scenarioer
## Arkitekturmønstre
### Mønster 1: Hybrid Search uten semantic ranking
**Flyt:** Brukerquery → BM25 + Vector (parallelt) → RRF-fusjon → Topp-N resultater
**Fordeler:**
- Lavere latency (ingen L2-reranking)
- Fungerer på alle tier (Basic+)
- Ingen ekstra kostnad for semantic ranking
**Ulemper:**
- RRF er en generell ranking-algoritme, ikke domene-optimert
- Lavere relevans for komplekse, naturnlige spørsmål
**Beste for:** Høy-volum søk der latency er kritisk, eller der BM25+vector gir tilstrekkelig relevans.
### Mønster 2: Hybrid Search med Semantic Ranking (anbefalt)
**Flyt:** Brukerquery → BM25 + Vector (parallelt) → RRF-fusjon → Semantic Ranker (topp 50) → Topp-N resultater
**Fordeler:**
- Best mulig relevans (dokumentert i benchmarks)
- Semantiske captions og answers inkludert
- Scoring profile kan legges på etter semantic ranking
**Ulemper:**
- Krever S1-tier eller høyere
- Ekstra kostnad per query (etter 1000 gratis/måned)
- Noe høyere latency (~50200ms ekstra)
**Beste for:** Enterprise RAG, kunnskapsportaler, dokumentsøk i offentlig sektor.
### Mønster 3: Hybrid Search med filtrering og facettering
**Flyt:** Brukerquery + filter/facet → Prefilter/Postfilter → BM25 + Vector → RRF → Resultater med facets
```python
results = client.search(
search_text="luxury hotel",
vector_queries=[vector_query],
filter="Rating gt 4 and ParkingIncluded eq true",
vector_filter_mode="postFilter",
facets=["Category", "Address/StateProvince"],
select=["HotelName", "Description", "Rating"],
top=10
)
```
**Fordeler:**
- Kombinerer semantisk søk med strukturert filtrering
- Støtter faceted navigation for brukergrensesnitt
**Ulemper:**
- `preFilter` kan redusere vektorkandidater for mye
- `postFilter` kan returnere færre resultater enn forventet
**Beste for:** E-commerce-liknende søk, sakssystemer med metadata-filtre.
## Beslutningsveiledning
### Når bruke hybrid search vs. alternativer
| Scenario | Anbefaling | Begrunnelse |
|----------|------------|-------------|
| Generell enterprise-søk | Hybrid + semantic | Best relevans dokumentert |
| Eksakt ID/kode-søk | Kun BM25 | Vektor tilfører ingen verdi for eksakte treff |
| Konseptuelle spørsmål | Hybrid + semantic | BM25 fanger nøkkelord, vektor fanger mening |
| Multilingual søk | Hybrid med fokus på vektor | Vektor bypasser språk-analysatorer |
| Strukturert data | BM25 + filtre | Vektor er designet for ustrukturert tekst |
| Høy-volum, lav-latency | Hybrid uten semantic | Semantic ranking legger til latency |
### Vanlige feil
1. **Ikke sette k=50 for vektor-queries med semantic ranking** — Semantic ranker jobber med topp 50, så `k` bør være minst 50
2. **Bruke `preFilter` med semantic ranking** — Kan eliminere relevante resultater før ranking
3. **Sammenligne scores på tvers av indekser** — BM25-scores er relative til dokumentfrekvens i indeksen
4. **Ignorere vekter** — Default-vekter (1.0/1.0) passer ikke alltid domenet
### Røde flagg
- Lav relevans med hybrid search → Sjekk om embedding-modellen er trent for domenet
- Høy latency → Vurder om semantic ranking er nødvendig for dette use caset
- Uventede resultater med filtre → Sjekk `preFilter` vs. `postFilter` modus
## Integrasjon med Microsoft-stakken
| Tjeneste | Integrasjon |
|----------|-------------|
| **Azure OpenAI** | Embedding-modeller (text-embedding-3-large) for vektordelen |
| **Azure AI Foundry** | Integrert vektorisering via skills i indekserings-pipeline |
| **Copilot Studio** | Azure AI Search som grounding-kilde for Copilot-agenter |
| **Semantic Kernel** | `AzureAISearchVectorStore` connector for hybrid queries |
| **Power Platform** | AI Builder kan bruke Azure AI Search via custom connectors |
## Offentlig sektor (Norge)
### Datasuverenitet
- Azure AI Search er tilgjengelig i **Norway East** og **Norway West**
- All indeksdata forblir i valgt region
- Fullt GDPR-kompatibelt via Azures rammeverk
- Microsofts EU Data Boundary gjelder for norske deployments
### Sikkerhetsfunksjoner
- **Azure Private Link:** Isoler search service fra offentlig internett
- **Managed Identity:** Sikker autentisering via Entra ID (ingen API-nøkler)
- **Customer-managed keys:** Krypter data med egne nøkler i Azure Key Vault
- **Dokumentnivå-sikkerhet:** Filtrer resultater basert på brukeridentitet
- **RBAC:** Rollebasert tilgangskontroll for indeks- og spørringsoperasjoner
### Relevante use cases
- **Regelverk og retningslinjer:** Kombinér eksakt match (§-referanser) med semantisk søk
- **Sakssystemer:** Hybrid search med metadata-filtrering per sakstype
- **Publikumstjenester:** Multilingual search der vektor bypasser språkbarrierer
- **Arkivsøk:** Historisk dokumentasjon med varierende terminologi
## Kostnad og lisensiering
### Tier-krav
| Funksjon | Minimumstier |
|----------|-------------|
| Hybrid search (BM25 + vektor) | Basic |
| Scoring profiles | Alle tier |
| Semantic ranking | S1+ (1000 gratis/mnd) |
| Integrert vektorisering | Basic+ |
### Kostnadsoptimering
- **Scalar/binary quantization** reduserer vektorlagring med opptil 50% (preview)
- **`stored: false`** på vektorfelt sparer lagring hvis du ikke trenger å hente embeddings
- **Narrower data types** for vektorfelt der presisjon tillater det
- **Tune `k`-parameter** — færre naboer = lavere kostnad
- Hybrid queries teller som **én spørringsoperasjon** (ingen prisøkning vs. enkelt søk)
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. Hvilke typer søk gjør brukerne deres — eksakte nøkkelord, naturlige spørsmål, eller begge deler?
2. Hvor viktig er latency vs. relevans for dette use caset?
3. Har dere strukturerte metadata (kategorier, datoer, avdelinger) som bør filtreres?
4. Hvilket tier bruker dere i dag, og er semantic ranking et alternativ?
5. Trengs multilingual support?
6. Hvor store er dokumentene, og hvordan chunkes de?
### Fallgruver
- Å starte med ren vektor-search og legge til BM25 etterpå er vanskeligere enn å starte med hybrid
- Scoring profiles og semantic ranking interagerer på ikke-åpenbare måter — test grundig
- Vektervekting krever eksperimentering; det finnes ingen universell "riktig" vekt
### Anbefalinger per modenhetsnivå
| Nivå | Anbefaling |
|------|------------|
| **Starter** | Hybrid search med default-vekter, uten semantic ranking |
| **Intermediær** | Legg til semantic ranking, tune vekter basert på evaluering |
| **Avansert** | Scoring profiles, A/B-testing med debug-modus, custom reranking |
### Debug-tips
Bruk `debug: "vector"` eller `debug: "semantic"` i API-kallet for å pakke ut subscores og forstå ranking-bidrag fra hver komponent.
## Kilder og verifisering
### Verified (MCP-research)
- [Hybrid Search Overview](https://learn.microsoft.com/en-us/azure/search/hybrid-search-overview)
- [RRF Ranking Algorithm](https://learn.microsoft.com/en-us/azure/search/hybrid-search-ranking)
- [Hybrid Query How-To](https://learn.microsoft.com/en-us/azure/search/hybrid-search-how-to-query)
- [Relevance Overview](https://learn.microsoft.com/en-us/azure/search/search-relevance-overview)
- [BM25 Scoring Details](https://learn.microsoft.com/en-us/azure/search/index-similarity-and-scoring)
- [Vector Search Overview](https://learn.microsoft.com/en-us/azure/search/vector-search-overview)
### Baseline (modellkunnskap)
- Kostnadsoptimerings-tips basert på generell Azure-erfaring
- Offentlig sektor-anbefalinger basert på norsk kontekst

View file

@ -0,0 +1,248 @@
# Late Chunking Patterns — Chunking etter embedding
**Last updated:** 2026-02
**Status:** GA (Jina Embeddings), Preview (Azure Marketplace)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Late chunking er en teknikk der et helt dokument embeddes gjennom en transformer-modell *før* det deles opp i chunks. I tradisjonell (naiv) chunking embeddes hver chunk isolert, og mister dermed kontekst fra resten av dokumentet — pronomener som «den», «de» og «selskapet» blir semantisk tvetydige.
Ved late chunking genererer modellen token-level embeddings med full dokumentkontekst via self-attention, og deretter beregnes chunk-embeddings via mean pooling over de relevante token-posisjonene. Resultatet er at hvert segment «vet» hva resten av dokumentet inneholder.
Jina AI introduserte teknikken i 2024 (arXiv:2409.04701) og viste konsistent forbedring på BeIR-datasett: SciFact +1.9%, NFCorpus +27.8% relativ forbedring i nDCG@10. Effekten øker med dokumentlengde.
Azure-integrasjon er mulig via Jina Embeddings v3/v4 på Azure Marketplace. Azure OpenAI sine embedding-modeller (text-embedding-3) eksponerer per i dag ikke token-level embeddings, men overlapping chunk-strategier gir en tilnærming.
---
## Kjernekomponenter
### Naiv vs. Late Chunking
| Aspekt | Naiv chunking | Late chunking |
|--------|---------------|---------------|
| **Rekkefølge** | Chunk → Embed | Embed → Chunk |
| **Kontekst-scope** | Kun innen chunk | Hele dokumentet |
| **Kryss-referanser** | Tapes | Bevares via token-embeddings |
| **Krav til modell** | Vilkårlig embedding-modell | Long-context embedding (8K+ tokens) |
| **Kostnad** | Lavere (kun chunks embeddes) | Høyere (fullt dokument embeddes) |
### Long-context embedding-modeller
| Modell | Context Length | Dimensjoner | Azure-tilgjengelighet |
|--------|----------------|-------------|----------------------|
| **text-embedding-3-large** | 8 191 tokens | 3 072 | GA via Azure OpenAI |
| **text-embedding-3-small** | 8 191 tokens | 1 536 | GA via Azure OpenAI |
| **jina-embeddings-v3** | 8 192 tokens | 1 024 | Azure Marketplace |
| **jina-embeddings-v4** | 8 192 tokens | 1 024 | Azure Marketplace |
8 000 tokens ≈ 10 standardsider — tilstrekkelig for de fleste enkeltdokumenter.
### Benchmark-resultater (BeIR)
| Datasett | Naiv chunking (nDCG@10) | Late chunking (nDCG@10) | Forbedring |
|----------|--------------------------|-------------------------|------------|
| SciFact | 64.20% | 66.10% | +1.9 pp |
| NFCorpus | 23.46% | 29.98% | +6.52 pp (+27.8%) |
Effekten er størst for lengre dokumenter med mange kryss-referanser.
---
## Arkitekturmønstre
### Mønster 1: Native late chunking med Jina Embeddings
**Arkitektur:** Data source → Indexer → Text extraction → Jina API (`late_chunking=True`) → Azure AI Search index
**Implementering:**
```python
import requests
response = requests.post(
"https://<jina-endpoint>.azurecontainer.io/v1/embeddings",
headers={"Authorization": f"Bearer {api_key}"},
json={
"input": full_document_text,
"model": "jina-embeddings-v3",
"late_chunking": True,
"chunk_size": 512
}
)
chunk_embeddings = response.json()["data"]
```
**Fordeler:**
- Ekte late chunking med full dokumentkontekst
- Native API-parameter — ingen custom logikk
- God multilingual-støtte (norsk inkludert)
**Ulemper:**
- Krever Jina-modell (ikke Azure OpenAI natively)
- Azure Marketplace deployment nødvendig
- 8K token-grense per dokument
**Anbefalt for:** Narrative dokumenter med mange kryss-referanser (juridiske tekster, forskningsrapporter).
### Mønster 2: Pseudo-late chunking med overlapping windows (Azure OpenAI)
**Arkitektur:** Data source → Indexer → Text Split (chunks med kontekst-vinduer) → Azure OpenAI Embedding → Index
**Implementering:**
```python
from openai import AzureOpenAI
client = AzureOpenAI(...)
chunks = split_document(document, chunk_size=500, overlap=150)
for i, chunk in enumerate(chunks):
# Include surrounding chunks for context
context_window = chunks[max(0,i-1):min(len(chunks),i+2)]
enriched_text = " ".join(context_window)
embedding = client.embeddings.create(
model="text-embedding-3-large",
input=enriched_text[:8000]
).data[0].embedding
```
**Fordeler:**
- Bruker Azure OpenAI (ingen tredjepartavhengighet)
- Enkelt å implementere i eksisterende pipeline
- 70-80% av late chunking-effekten til lavere kostnad
**Ulemper:**
- Ikke ekte late chunking (kun nabochunk-kontekst)
- Økt embedding-kostnad (3x chunk-størrelse)
**Anbefalt for:** Teams som vil ha bedre kontekst uten å introdusere Jina-avhengighet.
### Mønster 3: Hybrid — Late chunking for langdokumenter, naiv for korte
**Arkitektur:** Router → [Kort dokument: naiv chunking] + [Langt dokument: late chunking] → Felles index
**Beslutningsregel:**
- Dokument < 2 000 tokens → Naiv chunking (lite å vinne)
- Dokument 2 000-8 000 tokens → Late chunking via Jina
- Dokument > 8 000 tokens → Segmenter i 8K-vinduer, late chunking per segment
**Anbefalt for:** Produksjonsløsninger med heterogene dokumentsamlinger.
---
## Beslutningsveiledning
### Beslutningstabell
| Dokumenttype | Late chunking? | Begrunnelse |
|-------------|----------------|-------------|
| Lange rapporter (>2K tokens) | Ja | Mange kryss-referanser |
| Narrative tekster (artikler) | Ja | Kontekst flyter mellom seksjoner |
| Korte, selvstendige docs | Nei | Ingen kryss-avhengigheter |
| Strukturerte data (tabeller, lister) | Nei | Rader/elementer er selvstendig |
| Juridiske dokumenter med referanser | Ja | Paragrafhenvisninger krever kontekst |
### Vanlige feil
| Feil | Konsekvens | Løsning |
|------|------------|---------|
| Late chunking på korte docs (<1K tokens) | Ingen gevinst, økt kostnad | Bruk naiv chunking for korte docs |
| Ignorerer 8K token-grense | Trunkering = tap av sluttkontekst | Segmenter lange docs i 8K-vinduer |
| Blander embedding-modeller i samme indeks | Inkompatible vektorrom | Én modell per vector-felt |
| Hopper over eval etter bytte | Vet ikke om det faktisk hjalp | Mål nDCG@10, precision@5, recall@5 |
---
## Integrasjon med Microsoft-stakken
| Tjeneste | Integrasjonspunkt |
|----------|-------------------|
| **Azure AI Search** | Vector index med custom embedding via push API eller custom skill |
| **Azure OpenAI** | text-embedding-3-large for pseudo-late chunking (mønster 2) |
| **Jina Embeddings (Azure Marketplace)** | Native late chunking via Container Instance |
| **Azure Functions** | Custom skill wrapper for Jina API |
| **Azure AI Document Intelligence** | Tekst-ekstraksjon før late chunking |
| **Semantic Kernel** | Custom embedding connector for Jina |
---
## Offentlig sektor (Norge)
### Dataplassering
- **Jina Embeddings (Azure Marketplace):** Deploy i Norway East — data forblir i Norge
- **Azure OpenAI Embeddings:** Sweden Central — data i EU/EØS
- **Azure AI Search:** Norway East — indeks i Norge
### Relevante vurderinger
| Krav | Implikasjon |
|------|-------------|
| **Schrems II** | Jina AI er tysk selskap — EU-data processing |
| **GDPR** | Embedding-prosessen behandler dokumentinnhold — databehandleravtale |
| **Sikkerhetsloven** | Gradert informasjon krever on-premises embedding |
---
## Kostnad og lisensiering
### Kostnadssammenligning (1 000 dokumenter, 5 000 tokens snitt, 10 chunks/doc)
| Tilnærming | Embedding-kall | Totalt tokens | Kostnad (text-embedding-3-large) |
|------------|----------------|---------------|----------------------------------|
| Naiv chunking | 10 000 | ~500K | ~$0.26 |
| Late chunking (full doc + chunks) | 11 000 | ~5.5M | ~$2.86 |
| Pseudo-late chunking (3x window) | 10 000 | ~1.5M | ~$0.78 |
**Trade-off:** 3-10x kostnadsøkning for 5-30% bedre retrieval-kvalitet (avhengig av dokumenttype).
### Jina Embeddings på Azure
- **Deployment:** Azure Container Instance (consumption-basert)
- **Prising:** Per API-kall til Jina-endepunktet
- **Fordel:** Ingen Azure OpenAI-kvote nødvendig
---
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **"Hvor lange er dokumentene?"** — Late chunking gir mest verdi for docs >2 000 tokens
2. **"Er det mange kryss-referanser internt i dokumenter?"** — Pronomen, forkortelser, «se avsnitt 3.2»
3. **"Er retrieval-kvaliteten god nok i dag?"** — Mål baseline først
4. **"Aksepterer dere Jina AI som tredjepart?"** — GDPR/vendor assessment
5. **"Hva er embedding-budsjettet?"** — Late chunking er 3-10x dyrere
### Fallgruver
- **Over-investering for korte docs:** Late chunking gir tilnærmet null gevinst for docs <1K tokens
- **Vendor lock-in til Jina:** Azure OpenAI kan få native late chunking-støtte — design for utbyttbarhet
- **Manglende evaluering:** Uten nDCG/precision-metrics vet du ikke om det hjelper
### Anbefalinger per modenhetsnivå
| Modenhet | Anbefaling |
|----------|------------|
| **Prototyp** | Naiv chunking med 25% overlap. Mål baseline. |
| **Pilot** | Pseudo-late chunking (mønster 2) med 3-chunk vinduer. Sammenlign metrics. |
| **Produksjon** | Hybrid (mønster 3) — late chunking for lange docs, naiv for korte. |
| **Enterprise** | Native late chunking via Jina + A/B-testing mot baseline. |
---
## Kilder og verifisering
| Kilde | Konfidens | URL |
|-------|-----------|-----|
| Late Chunking in Long-Context Embedding Models (Jina AI) | **Verified** | [jina.ai](https://jina.ai/news/late-chunking-in-long-context-embedding-models/) |
| arXiv:2409.04701 (forskningspaper) | **Verified** | [arxiv.org](https://arxiv.org/abs/2409.04701) |
| Jina Embeddings on Azure Marketplace | **Verified** | [azuremarketplace.microsoft.com](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/jinaai.jina-embeddings-v4) |
| Jina Embeddings v3 announcement | **Verified** | [jina.ai](https://jina.ai/news/jina-embeddings-v3-a-frontier-multilingual-embedding-model/) |
| Azure OpenAI Embeddings | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/tutorials/embeddings) |
| Late Chunking tutorial (DataCamp) | **Baseline** | [datacamp.com](https://www.datacamp.com/tutorial/late-chunking) |

View file

@ -0,0 +1,525 @@
# Metadata Management and Filtered Search
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Metadata management og filtrering er fundamentale byggeklosser for å skape presise og kontekstbevisste RAG-løsninger. I Azure AI Search utgjør OData-filtre og faceted navigation et kraftig rammeverk for å organisere, kategorisere og filtrere søkeresultater basert på metadata-egenskaper som kategori, dato, klassifikasjon, eller geografisk plassering.
Effektiv metadata-håndtering gjør det mulig å kombinere semantisk søk med strukturerte begrensninger — for eksempel å finne "kontrakter signert etter 2023 som gjelder GDPR-prosessering i Norge" eller "dokumenter klassifisert som 'konfidensielt' fra divisjon HR". Denne kombinasjonen av fri tekstsøk og strukturert filtrering er ofte kritisk for offentlig sektor, hvor compliance, tilgangskontroll og revisjonsspor er juridiske krav.
Azure AI Search støtter OData v4-syntaks for filtre, som integreres sømløst med både keyword search, vector search og hybrid search. Metadata-design påvirker både søkeytelse, brukeropplevelse (via faceted navigation), og evnen til å implementere security trimming og data governance.
## Kjernekomponenter
### Index Schema Design for Metadata
| Field Type | Egenskaper | Bruk i Metadata |
|------------|------------|-----------------|
| `Edm.String` | Filterable, Facetable, Sortable | Kategorier, tags, klassifikasjonsnivå |
| `Collection(Edm.String)` | Filterable, Facetable | Multi-value tags, key phrases, roller |
| `Edm.Int32/Int64` | Filterable, Facetable, Sortable | Rating, score, versjonsnummer |
| `Edm.DateTimeOffset` | Filterable, Facetable, Sortable | Opprettelsesdato, modifikasjonsdato, gyldighetsperiode |
| `Edm.Boolean` | Filterable, Facetable | IsPublic, IsArchived, RequiresApproval |
| `Edm.GeographyPoint` | Filterable (kun via `geo.distance`) | Geografisk lokasjon (ikke facetable) |
**Best Practices for Schema:**
- **Low Cardinality Fields**: Facets fungerer best på felt med få unike verdier (5-50 distinkte verdier).
- **Normalizers**: Bruk normalizers på facetable string-felt for å unngå duplikater pga. casing ("Norge" vs "norge").
- **Default Attributes (REST API)**: String, DateTime, Boolean, og numeric typer er filterable/facetable by default i REST API.
- **Security Metadata**: Inkluder alltid felt for `ownerPrincipalIds`, `classificationLevel`, `department` hvis security trimming er nødvendig.
### OData Filter Syntax
**Comparison Operators:**
```odata
$filter=Rating ge 4 // Greater than or equal
$filter=Category eq 'Confidential' // Equality
$filter=LastModified ge 2024-01-01T00:00:00Z // Date filtering
```
**Logical Operators (precedence: not > and > or):**
```odata
$filter=Category eq 'Contract' and Status ne 'Archived'
$filter=(IsPublic eq true) or (Department eq 'HR' and OwnerRole eq 'Admin')
$filter=not (IsExpired eq true)
```
**Collection Filters (any/all):**
```odata
// Minimum ett tag matcher
$filter=Tags/any(tag: tag eq 'GDPR')
// Alle roller må være interne
$filter=ApproverRoles/all(role: role/Type eq 'Internal')
// Kombinasjon med search.in for effektivitet
$filter=Tags/any(tag: search.in(tag, 'GDPR,ISO27001,SOC2', ','))
```
**Geo-Spatial Filtering:**
```odata
// Innenfor 50 km fra Oslo
$filter=geo.distance(Location, geography'POINT(10.7522 59.9139)') le 50
// Innenfor polygon (fylkesgrense)
$filter=geo.intersects(Location, geography'POLYGON((...))')
```
**Full-Text + Filter Hybrid:**
```odata
// Søk etter "GDPR" kun i konfidensielle dokumenter fra 2024
$filter=search.ismatch('GDPR') and Classification eq 'Confidential' and Year eq 2024
```
### Faceted Navigation
**Facet Parameters:**
| Parameter | Beskrivelse | Eksempel |
|-----------|-------------|----------|
| `count` | Maks antall facet-verdier returnert (default: 10, 0 = unlimited) | `"facets": ["Category,count:5"]` |
| `sort` | Sortering: `count`/`-count` (etter frekvens), `value`/`-value` (alfabetisk) | `"facets": ["Rating,sort:-value"]` |
| `values` | Eksplisitte ranges for numeriske/dato-felt | `"facets": ["BaseRate,values:100\|200\|300"]` |
| `interval` | Auto-ranges for numeriske/dato-felt | `"facets": ["Price,interval:50"]` |
| `timeoffset` | UTC-offset for dato-intervals | `"facets": ["Created,interval:day,timeoffset:+01:00"]` |
**JSON Example:**
```json
{
"search": "*",
"facets": [
"Category",
"Tags,count:20,sort:count",
"Rating,values:1|2|3|4|5",
"CreatedDate,interval:month"
],
"filter": "Department eq 'HR'"
}
```
**Response Structure:**
```json
{
"@search.facets": {
"Category": [
{ "count": 42, "value": "Contract" },
{ "count": 31, "value": "Policy" }
],
"Tags": [
{ "count": 18, "value": "GDPR" },
{ "count": 12, "value": "ISO27001" }
]
},
"value": [ /* search results */ ]
}
```
### Security Trimming via Metadata
**Pattern: Principal-based filtering**
```json
// Index schema
{
"name": "ownerPrincipalIds",
"type": "Collection(Edm.String)",
"filterable": true
}
// Query-time filter (injected server-side)
$filter=ownerPrincipalIds/any(p: search.in(p, 'user@org.no,group-id-123', ','))
```
**Pattern: Role-based access**
```odata
$filter=RequiredRoles/any(role: search.in(role, 'HR-Admin,Legal-Read', ','))
```
## Arkitekturmønstre
### 1. Hierarchical Metadata Navigation (Preview)
**Use Case:** Navigere gjennom multi-level kategorier (f.eks. "Juridiske dokumenter > Kontrakter > Leverandøravtaler").
**Implementation (Preview API):**
```json
{
"facets": [
"CategoryPath,hierarchical,delimiter:>,levels:3"
]
}
```
**Fordeler:**
- Naturlig navigasjon for domeneeksperter
- Reduserer informasjonsoverload
**Ulemper:**
- Preview-feature (ikke produksjonsklar uten testing)
- Krever konsistent metadata-struktur i kildesystemene
---
### 2. Dynamic Facet Filtering (Drilldown)
**Use Case:** Brukeren raffinerer søk ved å velge facets (f.eks. "Vis bare dokumenter fra 2025 med tag 'GDPR'").
**Implementation:**
```javascript
// Initial query - get all facets
{ "search": "*", "facets": ["Year", "Tags", "Department"] }
// User selects Year=2025 -> add filter
{ "search": "*", "filter": "Year eq 2025", "facets": ["Tags", "Department"] }
// User selects Tag=GDPR -> append filter
{ "search": "*", "filter": "Year eq 2025 and Tags/any(t: t eq 'GDPR')", "facets": ["Department"] }
```
**Fordeler:**
- Intuitiv brukeropplevelse
- Alltid minst 0 resultater (hvis implementert riktig)
**Ulemper:**
- Frontend-kompleksitet (state management)
- Facet counts kan være unøyaktige ved sharded indexes (se workarounds nedenfor)
---
### 3. Prefilter vs Postfilter (Vector Search)
**Use Case:** Kombinere metadata-filtre med vector search.
| Mode | Timing | Performance | Presisjon |
|------|--------|-------------|-----------|
| `preFilter` | Filter FØR vector search | Raskere hvis filter ekskluderer mange dokumenter | Kan gi færre resultater enn `k` |
| `postFilter` | Filter ETTER vector search | Alltid `k` resultater (hvis tilgjengelig) | Tregere hvis filter ekskluderer mange |
| `strictPostFilter` (preview) | Hybrid: filter etter vector, re-rank | Balanse mellom speed og presisjon | Kompleks scoring-logikk |
**Eksempel (Prefilter):**
```json
{
"vectorQueries": [{
"kind": "vector",
"vector": [0.123, ...],
"fields": "contentVector",
"k": 50
}],
"filter": "Department eq 'Legal'",
"vectorFilterMode": "preFilter"
}
```
**Anbefaling:** Bruk `preFilter` for høy-cardinalitet metadata (f.eks. departement, klassifikasjon), `postFilter` for low-cardinalitet.
## Beslutningsveiledning
### Når bruke hvilken filtreringsteknikk?
| Scenario | Anbefalt Tilnærming | Rationale |
|----------|---------------------|-----------|
| **Compliance-krav** (kun vis dokumenter med sikkerhetsnivå X) | `$filter` med `eq` på classification-felt | Garantert nøyaktighet, juridisk forsvarlig |
| **Brukernavigasjon** (la bruker utforske innhold) | Faceted navigation med `count:0` for nøyaktighet | Bedre UX enn statiske menyer |
| **Performance optimization** (reduser corpus før vector search) | `preFilter` mode + indekserte metadata-felt | Reduserer vector search-scope |
| **Geo-bounded search** (kun dokumenter fra region X) | `geo.distance` eller `geo.intersects` | Native geo-støtte i Azure AI Search |
| **Multi-tenant isolation** | Security trimming via `ownerPrincipalIds/any()` | GDPR Art. 32 - access control |
### Vanlige Feil
| Feil | Symptom | Fix |
|------|---------|-----|
| **Facet count unøyaktighet** | Facet viser 10 kategorier, men reell total er 15 | Sett `count:0` eller `count:>=distinct_values` |
| **Case-sensitive duplicates** | Facet viser både "Norge" og "norge" | Bruk normalizer på felt-definisjon |
| **Filter + Vector gir 0 resultater** | `preFilter` ekskluderer alle dokumenter | Bytt til `postFilter` eller utvid filter-kriterier |
| **Geo-filter feil** | `geo.distance` returnerer feil | Sjekk at felt er `Edm.GeographyPoint`, ikke string |
| **OR-filter performance** | Lang liste med `or Category eq 'X'` | Bruk `search.in(Category, 'X,Y,Z', ',')` (counts as single clause) |
### Røde Flagg
- **Faceting på high-cardinality fields** (f.eks. DocumentId, full-text content) → Ingen verdi, spis storage.
- **Manglende `filterable` attributt** → Runtime-feil ved bruk av `$filter`.
- **Geo-coordinates som facets** → Ikke støttet (bruk by/region i stedet).
- **Ubegrenset filter-kompleksitet** → Azure AI Search har clause limits (~1000), bruk `search.in()` for lange lister.
## Integrasjon med Microsoft-stakken
### SharePoint Metadata
**Pattern:** Synkroniser SharePoint-kolonner til Azure AI Search-metadata.
| SharePoint Column Type | Azure AI Search Type | Filterable? | Facetable? |
|------------------------|----------------------|-------------|------------|
| Single line of text | `Edm.String` | Ja | Ja |
| Choice | `Edm.String` | Ja | Ja (perfect for facets) |
| Managed Metadata | `Collection(Edm.String)` | Ja | Ja |
| Date and Time | `Edm.DateTimeOffset` | Ja | Ja |
| Person or Group | `Collection(Edm.String)` (extrahér UPN/ID) | Ja | Ja |
**Indexer Configuration:**
```json
{
"fieldMappings": [
{
"sourceFieldName": "/Department",
"targetFieldName": "department"
},
{
"sourceFieldName": "/Confidentiality",
"targetFieldName": "classificationLevel"
}
]
}
```
### Microsoft Purview (Data Governance)
**Pattern:** Bruk Purview-klassifikasjoner som metadata i search index.
```json
// Purview extraherer sensitivity labels
{
"name": "purviewClassifications",
"type": "Collection(Edm.String)",
"filterable": true,
"facetable": true
}
// Query-time enforcement
$filter=purviewClassifications/any(c: search.in(c, 'Public,Internal', ','))
```
**Integration:** Azure AI Search indexer kan kalle Microsoft Graph API for å hente sensitivity labels fra Purview/Information Protection.
### Dataverse (Power Platform)
**Pattern:** Synkroniser Dataverse choice columns og lookups til facetable fields.
| Dataverse Type | Mapping | Eksempel |
|----------------|---------|----------|
| Choice | `Edm.String` | Status (Active, Inactive, Archived) |
| Choices (multi-select) | `Collection(Edm.String)` | Tags, Categories |
| Lookup | `Edm.String` (ID eller Name) | OwnerDepartment |
| DateTime | `Edm.DateTimeOffset` | CreatedOn, ModifiedOn |
**Query Example:**
```odata
// Finn alle Dataverse-records med status 'Active' fra HR-divisjonen
$filter=statuscode eq 'Active' and owningbusinessunit eq 'HR'
```
### Azure Blob Storage (Metadata Indexing)
**Pattern:** Bruk Blob index tags som metadata i Azure AI Search.
```json
// Blob index tags (set via Azure Storage API)
{
"Department": "Legal",
"Classification": "Confidential",
"RetentionPolicy": "7years"
}
// Azure AI Search indexer extracts metadata
{
"name": "metadata_storage_blob_index_tags",
"type": "Edm.String",
"filterable": true
}
```
**Lifecycle Management:** Kombiner med Azure Storage lifecycle policies for automatisk arkivering basert på metadata.
## Offentlig sektor (Norge)
### GDPR Art. 32 - Access Control
**Krav:** "Evnen til å sikre fortrolighet, integritet, tilgjengelighet og robusthet til behandlingssystemene."
**Implementation:**
```json
// Index schema
{
"name": "dataSubjectIds",
"type": "Collection(Edm.String)",
"filterable": true
}
// Query-time (server-side filter injection)
$filter=dataSubjectIds/any(id: id eq 'current-user-id')
```
**Audit Trail:** Logg alle søk med filter-kriterier til Azure Monitor for GDPR Art. 30 (register over behandlingsaktiviteter).
### Offentleglova § 3 - Meroffentlighet
**Krav:** Dokumenter kan være "gradert offentlig" (ugradert, begrenset, konfidensielt, hemmelig).
**Implementation:**
```json
{
"name": "securityClassification",
"type": "Edm.String",
"filterable": true,
"facetable": true
}
// Eksempel: Vis kun ugradert + begrenset for eksterne brukere
$filter=securityClassification eq 'Ugradert' or securityClassification eq 'Begrenset offentlig'
```
**Facet Navigation:** La saksbehandlere filtrere på klassifikasjonsnivå i selvbetjeningsportaler.
### Arkivloven - Kassasjonsklasser
**Krav:** Dokumenter skal ha bevaring-/kassasjonsklasse (B = bevares, K5 = kasseres etter 5 år, etc.).
**Implementation:**
```json
{
"name": "retentionClass",
"type": "Edm.String",
"filterable": true,
"facetable": true
},
{
"name": "retentionExpiry",
"type": "Edm.DateTimeOffset",
"filterable": true
}
// Query: Finn dokumenter som skal kasseres i 2026
$filter=retentionClass eq 'K5' and retentionExpiry ge 2026-01-01T00:00:00Z and retentionExpiry lt 2027-01-01T00:00:00Z
```
**Automatisering:** Kombiner med Azure Functions for automatisk sletting/arkivering basert på metadata.
### Personvernkonsekvensutredning (DPIA)
**Anbefaling:** For systemer som indekserer personopplysninger, inkluder alltid:
- `personalDataCategories` (Collection(Edm.String)) → "Navn", "Fødselsnummer", "Helseopplysninger"
- `dataProcessingPurpose` (Edm.String) → Behandlingsformål per GDPR Art. 6
- `legalBasis` (Edm.String) → Rettslig grunnlag (samtykke, kontrakt, rettslig forpliktelse)
**Query Example (Audit):**
```odata
// Finn alle dokumenter med helseopplysninger behandlet uten samtykke
$filter=personalDataCategories/any(c: c eq 'Helseopplysninger') and legalBasis ne 'Samtykke'
```
## Kostnad og lisensiering
### Prismodell-oversikt
**Azure AI Search Tier Impact:**
| Tier | Max Index Size | Max Fields | Facet Performance | Anbefaling |
|------|----------------|------------|-------------------|------------|
| Basic | 2 GB | 1000 | Low concurrency | Pilot/POC |
| S1 | 25 GB/partition | 1000 | Medium | Produksjon (< 100K docs) |
| S2 | 100 GB/partition | 1000 | High | Produksjon (100K-1M docs) |
| S3/S3HD | 200 GB/partition | 3000 | Very High | Enterprise (> 1M docs) |
**Storage Cost (Metadata):**
- Filterable fields krever ekstra storage (inverted index).
- Facetable fields krever ytterligere storage (facet cache).
- **Tommelfingerregel:** Metadata utgjør ~10-20% av total index size (ved 5-10 metadata-felt per dokument).
**Query Cost:**
- Facet queries er dyrere enn vanlige queries (shard aggregation overhead).
- `count:0` (unlimited facets) kan øke query latency med 50-200% avhengig av cardinality.
- **Optimalisering:** Bruk `count:10` som default, bare `count:0` når nøyaktighet er kritisk.
### Optimaliseringstips
1. **Replikaer for Facet Performance:** Øk replicas (ikke partitions) for å håndtere høy facet query load.
2. **Cache i Frontend:** Cache facet-strukturer i 5-10 minutter (de endrer sjelden).
3. **Selective Faceting:** Ikke returner alle facets i hver query — la frontend styre hvilke som vises.
4. **Index Partitioning:** For multi-tenant, vurder én index per tenant (isolerer metadata, enklere GDPR-sletting).
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **Metadata-kilder:**
"Hvilke systemer genererer metadata i dag? (SharePoint, Dataverse, filserver, CRM?)"
2. **Cardinality-analyse:**
"Hvor mange distinkte verdier har typiske metadata-felt? (f.eks. 'Department' — 5 divisjoner eller 500 avdelinger?)"
3. **Security Requirements:**
"Må søkeresultater filtreres basert på brukerroller eller organisasjonstilhørighet? (Security trimming)"
4. **Facet Prioritering:**
"Hvilke metadata-dimensjoner er viktigst for sluttbrukerne å navigere etter? (Kategori? Dato? Avdeling?)"
5. **Data Governance:**
"Er det krav fra Purview/DLP om å klassifisere dokumenter før indeksering?"
6. **Retention Policies:**
"Skal søkeindexen respektere arkivloven sine kassasjonsklasser? (Automatisk sletting)"
7. **Geo-filtrering:**
"Er geografisk lokasjon relevant? (f.eks. 'finn nærmeste kontor med ledig møterom')"
8. **Multi-language:**
"Har dere metadata på flere språk? (f.eks. 'Category' vs 'Kategori')"
### Fallgruver
| Fallgruve | Konsekvens | Mitigering |
|-----------|------------|------------|
| **Faceting på high-cardinality fields** | Storage-sløsing, ingen UX-verdi | Kun facet på felt med < 100 distinkte verdier |
| **Manglende normalizers** | Duplikater i facets ("Norge", "norge", "NORGE") | Sett normalizer på alle facetable string-felt |
| **Ubegrenset facet count** | Query latency > 2 sekunder | Bruk `count:10` som default, `count:0` kun ved behov |
| **Prefilter på low-cardinality** | Vector search får for lite data å jobbe med | Bruk postfilter for metadata med < 10 verdier |
| **Manglende audit logging** | GDPR non-compliance | Logg alle queries med PII-metadata til Azure Monitor |
| **Hardkodede security filters** | Vedlikeholdsmareritt | Bruk Azure AD groups, inject filter server-side |
### Anbefalinger per modenhetsnivå
**Level 1 - Starter:**
- Bruk 3-5 facetable fields (Category, Date, Department).
- Implementer basic `$filter` for security trimming.
- Bruk default facet count (10).
**Level 2 - Intermediate:**
- Legg til faceted navigation i UI (React/Angular components).
- Implementer hierarchical metadata (preview).
- Kombiner prefilter/postfilter strategisk.
- Integrer med SharePoint/Dataverse metadata.
**Level 3 - Advanced:**
- Dynamisk metadata-schema (støtte for custom fields per tenant).
- Purview-integrasjon for automated classification.
- Real-time facet count aggregation via Application Insights.
- Multi-index orchestration (separate indexes per data classification).
## Kilder og verifisering
**Verified (MCP Research 2026-02):**
- [OData $filter syntax in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-query-odata-filter) — **Confidence: High** (Official docs)
- [Add faceted navigation to search results](https://learn.microsoft.com/en-us/azure/search/search-faceted-navigation) — **Confidence: High** (Official docs)
- [OData language overview](https://learn.microsoft.com/en-us/azure/search/query-odata-filter-orderby-syntax) — **Confidence: High** (Official docs)
- [Support for OData (Azure AI Search)](https://learn.microsoft.com/en-us/rest/api/searchservice/support-for-odata) — **Confidence: High** (REST API reference)
- [Faceted navigation examples](https://learn.microsoft.com/en-us/azure/search/search-faceted-navigation-examples) — **Confidence: High** (Official docs)
- [Search indexes in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-what-is-an-index) — **Confidence: High** (Official docs)
- [Create an index in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-how-to-create-search-index) — **Confidence: High** (Official docs)
**Baseline (Model Knowledge):**
- Security trimming patterns — **Confidence: Medium** (Standard pattern, not specific to Azure AI Search docs)
- Purview integration patterns — **Confidence: Medium** (Cross-service integration, requires validation)
- Norwegian compliance (Offentleglova, Arkivloven) — **Confidence: High** (Public sector standard)
**Preview Features (Not Production-Ready):**
- Hierarchical facets — **Status: Preview** (Not covered in GA docs retrieved)
- Facet filtering — **Status: Preview** (Mentioned but not detailed)
- Strict postfilter mode — **Status: Preview** (Mentioned in vector search context)
---
**For Cosmo:**
Metadata management er ofte undervurdert i RAG-prosjekter. Kunder fokuserer på embeddings og vector search, men glemmer at 70% av queries i produksjon inneholder strukturerte filter-kriterier ("bare fra min avdeling", "kun siste år", "høyeste klassifikasjon"). Design metadata-schema tidlig, test med reelle cardinality-tall, og prioritér normalizers og security trimming fra dag 1. I offentlig sektor er compliance non-negotiable — bygg audit trail og retention policies inn fra start.

View file

@ -0,0 +1,326 @@
# Multi-Index Federation and Cross-Search
**Last updated:** 2026-02
**Status:** GA (single-index), Not supported (native cross-index)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Et av de vanligste spørsmålene fra enterprise-arkitekter er: "Kan vi søke på tvers av flere Azure AI Search-indekser i en enkelt spørring?" Svaret er **nei** — Azure AI Search støtter ikke native multi-index federation. Hvert søk er alltid avgrenset til én enkelt indeks.
Dette er en bevisst designbeslutning, ikke en begrensning. Enkelt-indeks-søk gir konsistente scorer, unified ranking, og forutsigbar ytelse. Cross-index-søk ville kreve score-normalisering, resultat-merging, og distribuert ranking — noe som introduserer betydelig kompleksitet og uforutsigbarhet.
For scenarioer der data logisk tilhører separate indekser (ulike skjemaer, compliance-krav, eller ulike formål), må applikasjonslaget implementere orkestrering. Denne filen beskriver arkitekturmønstre, routing-strategier og best practices for slike scenarioer.
**Viktig funn:** Microsofts offisielle FAQ sier eksplisitt: *"Can I search across multiple indexes? No. A query is always scoped to a single index."*
## Kjernekomponenter
### Hvorfor Azure AI Search ikke støtter cross-index queries
| Utfordring | Forklaring |
|-----------|------------|
| **Scoring-isolasjon** | BM25-scores er relative til dokumentfrekvens *innenfor* indeksen — scorer fra ulike indekser kan ikke sammenlignes direkte |
| **Skjema-forskjeller** | Ulike indekser kan ha helt ulike felt, datatyper og analysatorer |
| **Ingen unified ranking** | Ingen innebygd mekanisme for å re-ranke resultater på tvers av indekser |
| **Ingen distribuerte transaksjoner** | Oppdateringer til flere indekser er ikke atomiske |
### Enkelt-indeks vs. multi-indeks
| Aspekt | Enkelt indeks | Multiple indekser |
|--------|--------------|-------------------|
| Query-logikk | Enkel, unified | Kompleks, krever orkestrering |
| Scoring | Konsistent | Inkonsistent mellom indekser |
| Vedlikehold | Enklere | Mer komplekst |
| Filtrering | Native, effektiv | Per-indeks, applikasjons-merging |
| Sikkerhet | Dokumentnivå-filtrering | Indeks-nivå isolasjon |
| Skalerbarhet | Vertikal (større tier) | Horisontal (flere services) |
### Nyere relevante features (2025)
| Feature | Status | Relevans |
|---------|--------|----------|
| Multi-vector field support | GA (2025) | Lagre multiple vektorer per dokument i én indeks |
| Agentic Retrieval | Preview | LLM-assistert query planning, men fremdeles single-index |
| Targeted vector filters | Preview | Filtre spesifikt for vektor-subqueries |
## Arkitekturmønstre
### Mønster 1: Enkelt indeks med filtrering (anbefalt)
**Flyt:** Data fra multiple kilder → Felles indeks med type/kilde-felt → Filtrering ved søk
```python
# Alle dokumenttyper i én indeks med type-felt
results = client.search(
search_text="anskaffelsesregler",
filter="doc_type eq 'regelverk' and department eq 'HR'",
select=["title", "content", "doc_type", "department"],
top=10
)
```
**Fordeler:**
- Enklest implementering
- Unified scoring og ranking
- Native filtrering, facettering
- Ingen orkestreringskode nødvendig
**Ulemper:**
- Skjemaet må være tilstrekkelig fleksibelt for alle dokumenttyper
- Indeksen kan bli stor (skalering vertikalt)
- Alle dokumenter deler analysatorer og innstillinger
**Beste for:** De fleste enterprise-scenarioer der data har lignende struktur.
### Mønster 2: Parallell query med applikasjons-merging
**Flyt:** Query → Fork til N indekser (parallelt) → Samle resultater → Score-normalisering → Merged resultat
```python
from azure.search.documents import SearchClient
from azure.identity import DefaultAzureCredential
import asyncio
async def query_multiple_indexes(query_text, indexes):
credential = DefaultAzureCredential()
async def query_index(index_name):
client = SearchClient(
endpoint=endpoint,
index_name=index_name,
credential=credential
)
results = []
async for result in client.search(search_text=query_text, top=10):
results.append({
"source_index": index_name,
"score": result["@search.score"],
**result
})
return results
# Parallelle queries
tasks = [query_index(idx) for idx in indexes]
all_results = await asyncio.gather(*tasks)
# Flatten og normaliser
merged = []
for results in all_results:
merged.extend(results)
# MERK: Score-normalisering nødvendig her
merged = normalize_scores(merged)
merged.sort(key=lambda x: x["normalized_score"], reverse=True)
return merged[:10]
def normalize_scores(results):
"""Min-max normalisering per indeks."""
by_index = {}
for r in results:
idx = r["source_index"]
if idx not in by_index:
by_index[idx] = []
by_index[idx].append(r)
for idx, items in by_index.items():
scores = [i["score"] for i in items]
min_s, max_s = min(scores), max(scores)
range_s = max_s - min_s if max_s != min_s else 1
for item in items:
item["normalized_score"] = (item["score"] - min_s) / range_s
return results
```
**Fordeler:**
- Støtter fundamentalt ulike skjemaer
- Compliance-isolasjon mellom indekser
- Horisontal skalering
**Ulemper:**
- Score-normalisering er heuristisk, ikke eksakt
- Økt latency (selv med parallellisering)
- Kompleks kode å vedlikeholde
- Resultater kan "konkurrere" unfairly mellom indekser
**Beste for:** Scenarioer med fundamentalt ulike datatyper (HR-håndbok vs. produktkatalog).
### Mønster 3: Query routing basert på intent
**Flyt:** Query → Intent-analyse (LLM/classifier) → Route til riktig indeks → Enkelt-indeks søk → Resultat
```python
def route_query(query_text):
"""Bestem hvilken indeks som er mest relevant."""
# Enkel keyword-basert routing
if any(word in query_text.lower() for word in ["anskaffelse", "kontrakt", "anbud"]):
return "regelverk-index"
elif any(word in query_text.lower() for word in ["personal", "ferie", "lønn"]):
return "hr-index"
else:
return "general-index"
# Eller med LLM-basert intent-klassifisering
def route_query_llm(query_text):
response = openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "system",
"content": "Classify the query into one of: regelverk, hr, general"
}, {
"role": "user",
"content": query_text
}]
)
intent = response.choices[0].message.content.strip()
return f"{intent}-index"
```
**Fordeler:**
- Kun én indeks queries per request (lavest latency)
- Tydelig domene-separasjon
- Skalerbar routing-logikk
**Ulemper:**
- Routing-feil betyr at brukeren ikke finner det de leter etter
- LLM-basert routing legger til latency og kostnad
- Krever vedlikehold av routing-logikk
**Beste for:** Klart adskilte domener med liten overlapp.
### Mønster 4: Multi-region search services
**Flyt:** Query → Nearest region service (via Traffic Manager) → Lokalt søk → Resultat
For geo-distribuerte brukere der latency er kritisk:
- Identiske indekser i flere regioner
- Synkronisering via push/pull API
- Azure Traffic Manager, Front Door, eller Application Gateway for routing
**Beste for:** Globale applikasjoner med latency-krav.
## Beslutningsveiledning
### Valg av indeks-topologi
```
Trenger du ulike skjemaer per datakilde?
├── Nei → Enkelt indeks med filtrering (Mønster 1)
└── Ja → Er datakildene compliance-adskilt?
├── Ja → Multi-indeks med routing (Mønster 3)
└── Nei → Kan skjemaene generaliseres?
├── Ja → Enkelt indeks med complex types
└── Nei → Multi-indeks med parallell query (Mønster 2)
```
### Vanlige feil
1. **Opprette separate indekser for hvert datasett** — Start med filtrering i én indeks
2. **Sammenligne BM25-scores direkte mellom indekser** — Scores er relative, ikke absolutte
3. **Sekvensiell querying av multiple indekser** — Bruk alltid parallell utførelse
4. **Implementere cross-index joins** — Azure AI Search støtter ikke dette
5. **Ignorere skjema-denormalisering** — Dupliser data hvis nødvendig for søkbarhet
### Røde flagg
- Behov for mer enn 3-4 indekser → Vurder om indeksdesignet er suboptimalt
- Brukere klager over manglende resultater → Mulig routing-feil i multi-indeks-oppsett
- Inkonsistente scorer mellom søk → Score-normalisering trenger kalibrering
## Integrasjon med Microsoft-stakken
| Tjeneste | Rolle |
|----------|-------|
| **Azure Traffic Manager** | Geo-basert routing mellom search services |
| **Azure Front Door** | Lastbalansering og CDN for multi-region |
| **Azure Application Gateway** | L7 load balancing for search requests |
| **Azure API Management** | API-gateway med routing-logikk for multi-indeks |
| **Semantic Kernel** | Orchestration-framework for multi-indeks RAG |
## Offentlig sektor (Norge)
### Data-klassifisering og indeks-separasjon
- **Ugradert data:** Kan samles i én indeks med filtrering
- **Fortrolig/begrenset:** Bør ha egen indeks med strengere tilgangskontroll
- **Sikkerhetsgradert:** Kan kreve egen search service i isolert nettverk
### Compliance-krav
- **Arkivloven:** Dokumenter fra ulike arkivserier kan kreve logisk separasjon
- **Forvaltningsloven:** Tilgangskontroll per sak/avdeling
- **GDPR:** Persondata kan kreve egen indeks for enklere sletting (right to be forgotten)
### Anbefalt tilnærming
For de fleste offentlige virksomheter:
1. **Primærindeks:** All ugradert dokumentasjon i én indeks med avdelings-/kategori-filtrering
2. **Sekundærindeks:** Persondata eller begrenset informasjon med RBAC
3. **Routing:** Intent-basert routing for å bestemme hvilken indeks som søkes
## Kostnad og lisensiering
### Kostnadsimplikasjoner av multi-indeks
| Topologi | Kostnadsfaktorer |
|----------|-----------------|
| Enkelt indeks | Én search service, standard lagring og query-kostnad |
| Multiple indekser (én service) | Delte ressurser, men økt lagring |
| Multiple search services | Separate kostnader per service, duplikert lagring |
| Multi-region | Multiplisert lagring + synkroniseringskostnad |
### Kostnadsoptimering
- **Start med enkelt indeks** — Unngå unødvendig kompleksitet og kostnad
- **Bruk replika-fordeling** fremfor separate services der mulig
- **Vurder search service tier** basert på samlet indeksstørrelse og query-volum
- **Synkroniser incrementally** i multi-region — ikke full re-indeksering
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. Hvor mange datakikylder har dere, og har de lignende eller ulik struktur?
2. Er det compliance-krav som krever fysisk separasjon av data?
3. Trenger brukerne å søke på tvers av alle datakilder, eller er domenene adskilte?
4. Hva er latency-kravene — kan parallell multi-indeks query aksepteres?
5. Har dere geo-distribuerte brukere som trenger multi-region?
6. Hva er budsjett — én stor service vs. flere mindre?
### Fallgruver
- Å designe for cross-index fra start uten å vurdere filtrering i enkelt indeks
- Å underestimere kompleksiteten i score-normalisering og resultat-merging
- Å anta at fremtidige Azure-oppdateringer vil løse cross-index — dette er et bevisst designvalg
- Å bruke LLM for query routing uten fallback til bredere søk
### Anbefalinger per modenhetsnivå
| Nivå | Anbefaling |
|------|------------|
| **Starter** | Enkelt indeks med filtrering — alltid start her |
| **Intermediær** | Legg til separate indekser kun ved compliance-krav, med intent-routing |
| **Avansert** | Multi-region med synkronisering, custom orkestrering, semantic reranking av merged resultater |
### Viktig designprinsipp
> **Default til enkelt indeks med filtrering.** Opprett separate indekser kun når du har en konkret, dokumentert grunn — ikke "for sikkerhets skyld."
Grunner som rettferdiggjør separate indekser:
- Fundamentalt ulikt skjema (tekst vs. strukturert data)
- Compliance-krav til fysisk separasjon
- Ulik livsyklus (hyppig vs. sjelden oppdatering)
- Ulike tilgangsmodeller (intern vs. ekstern)
## Kilder og verifisering
### Verified (MCP-research)
- [Azure AI Search FAQ — Cross-index queries](https://learn.microsoft.com/en-us/azure/search/search-faq-frequently-asked-questions)
- [Multi-region deployments](https://learn.microsoft.com/en-us/azure/search/search-multi-region)
- [Grounding data design — Index topology](https://learn.microsoft.com/en-us/azure/well-architected/ai/grounding-data-design)
- [Multi-vector field support](https://learn.microsoft.com/en-us/azure/search/vector-search-multi-vector-fields)
- [Tutorial: Index from multiple data sources](https://learn.microsoft.com/en-us/azure/search/tutorial-multiple-data-sources)
- [GitHub: Multiple search services (.NET)](https://github.com/Azure-Samples/azure-search-dotnet-scale/tree/main/multiple-search-services)
### Baseline (modellkunnskap)
- Score-normaliserings-kode
- Routing-eksempler
- Offentlig sektor-anbefalinger

View file

@ -0,0 +1,311 @@
# Multimodal RAG — Bilder, tabeller og dokumenter i RAG
**Last updated:** 2026-02
**Status:** GA (Document Intelligence, Content Understanding), Preview (multimodal embeddings)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Multimodal RAG utvider tradisjonell tekstbasert retrieval til å inkludere bilder, tabeller, diagrammer og andre visuelle elementer i RAG-pipelinen. For enterprise-organisasjoner betyr dette at PDF-rapporter med grafer, tekniske tegninger, og presentasjoner med figurer kan indekseres og hentes med full visuell kontekst.
Azure-stakken tilbyr tre komplementære tilnærminger: **Image verbalization** (GPT-4o/4v konverterer bilder til tekst), **direkte multimodale embeddings** (Azure Vision genererer vektorer for bilder og tekst i samme vektorrom), og **Azure Content Understanding** (GA nov 2025) som konverterer komplekse dokumenter til Markdown med LaTeX-equations, HTML-tables og semantic chunking.
Microsoft ISE-teamet anbefaler en kombinert tilnærming: GPT-4v for bildeberikelse (bedre recall) og GPT-4o for inferens (bedre kvalitet, hastighet og kostnad).
---
## Kjernekomponenter
### Ekstraksjonsskills
| Skill | Tekst | Bilder | Tabeller | Kryss-sideenheter | Formater |
|-------|-------|--------|----------|-------------------|----------|
| **Document Extraction** | Nei | Ja | Nei | N/A | Kun PDF |
| **Document Layout** | Ja | Ja | Nei | Kun innen side | Flere formater |
| **Content Understanding** | Ja | Ja | Ja (kryss-side) | Ja | PDF, DOCX, XLSX, PPTX |
**Anbefaling:** Azure Content Understanding for moderne multimodal RAG-pipelines.
### Multimodal embedding-tilnærminger
| Tilnærming | Metode | Fordel | Ulempe |
|------------|--------|--------|--------|
| **Image verbalization** | GPT-4o/4v → tekst → text embedding | Semantisk forståelse, gode captions | LLM-kall per bilde, økt tid |
| **Direct multimodal embeddings** | Azure Vision → bilde/tekst-vektor | Rask, effektiv, visuell likhet | Mangler semantisk kontekst |
| **Kombinert (anbefalt)** | Verbalize diagrammer + direct embed fotos | Maksimerer begge styrker | Kompleksere pipeline |
### Azure Vision multimodal embeddings
- **Modell:** Azure Vision multimodal via Microsoft Foundry
- **Dimensjoner:** 1024 per vektor (tekst og bilde)
- **Nøkkel:** Tekst og bilder projiseres i *samme* vektorrom
---
## Arkitekturmønstre
### Mønster 1: Image verbalization + text embeddings
**Arkitektur:** Blob Storage → Indexer → Image extraction → GenAI Prompt skill (GPT-4o/4v) → Text description → Azure OpenAI Embedding → Index
**Pipeline:**
```
Dokument → Document Layout skill (ekstraher bilder)
→ GenAI Prompt skill:
"Beskriv dette bildet i kontekst av dokumentet: {image}"
→ Text embedding skill (text-embedding-3-large)
→ Index (med image description + embedding)
```
**Fordeler:**
- Tolker relasjoner og entiteter i diagrammer
- Ferdiglagde captions for RAG-bruk
- Semantisk forståelse for AI-agenter
- Returner relevante snippets med grunnlagsdata
**Brukstilfelle:** Rapporter med flytdiagrammer, organisasjonskart, arkitekturdiagrammer.
### Mønster 2: Direct multimodal embeddings
**Arkitektur:** Blob Storage → Indexer → Image extraction → Azure Vision Vectorize skill → Index
**Skill-konfigurasjon:**
```json
{
"@odata.type": "#Microsoft.Skills.Vision.VectorizeSkill",
"name": "image-embedding-skill",
"context": "/document/normalized_images/*",
"modelVersion": "2023-04-15",
"inputs": [{"name": "image", "source": "/document/normalized_images/*"}],
"outputs": [{"name": "vector", "targetName": "image_vector"}]
}
```
**Fordeler:**
- Enkel konfigurasjon — ingen LLM-kall
- Effektiv for visuell likhetssøk
- Ideell for «finn noe som ligner»-scenarier
**Brukstilfelle:** Fotoarkiver, produktbilder, skjermbilder.
### Mønster 3: Combined multimodal pipeline (anbefalt)
**Arkitektur:** Router basert på bildetype → [Diagram: verbalize] + [Foto: direct embed] → Felles index med multi-vector felt
**Index-schema:**
```json
{
"fields": [
{ "name": "content_embedding", "type": "Collection(Edm.Single)",
"dimensions": 1024, "searchable": true,
"vectorSearchProfile": "hnsw" },
{ "name": "content_text", "type": "Edm.String", "searchable": true },
{ "name": "content_path", "type": "Edm.String", "retrievable": true },
{ "name": "page_number", "type": "Edm.Int32", "filterable": true },
{ "name": "content_type", "type": "Edm.String", "filterable": true }
]
}
```
**Index projections (tekst + bilder i samme indeks):**
```json
{
"indexProjections": {
"selectors": [
{
"targetIndexName": "multimodal-index",
"parentKeyFieldName": "text_document_id",
"sourceContext": "/document/pages/*",
"mappings": [
{"name": "content_embedding", "source": "/document/pages/*/text_vector"},
{"name": "content_text", "source": "/document/pages/*"}
]
},
{
"targetKeyFieldName": "image_document_id",
"sourceContext": "/document/normalized_images/*",
"mappings": [
{"name": "content_embedding", "source": "/document/normalized_images/*/image_vector"},
{"name": "content_path", "source": "/document/normalized_images/*/imagePath"}
]
}
]
}
}
```
---
## Azure Content Understanding for RAG
### Markdown-output (GA nov 2025)
Content Understanding konverterer dokumenter til GitHub Flavored Markdown:
| Innholdstype | Representasjon | Eksempel |
|-------------|----------------|---------|
| **Tabeller** | HTML markup med `rowspan`/`colspan` | `<table><tr><th>Header</th></tr></table>` |
| **Ligninger** | LaTeX | `$$a^2 + b^2 = c^2$$` |
| **Diagrammer** | Chart.js JSON eller Mermaid | Interaktiv grafgjengivelse |
| **Bilder** | `![text](path "description")` | Med valgfri analyse |
| **Sidemetadata** | HTML-kommentarer | `<!-- PageNumber="1" -->` |
### Konfigurasjon for RAG-pipelines
```
outputContentFormat=markdown
enableFigureAnalysis=true
enableAnnotation=true
chartFormat=markdown
```
**RAG-fordeler:**
- HTML-basert tabellrekonstruksjon bevarer struktur
- LaTeX-formatering for matematisk presisjon
- Semantic chunking for intelligent dokumentsegmentering
---
## Beslutningsveiledning
### Beslutningstabell
| Dokumenttype | Visuelt innhold | Anbefalt tilnærming |
|-------------|-----------------|---------------------|
| Tekniske rapporter med diagrammer | Flytdiagrammer, arkitektur | Image verbalization (GPT-4v) |
| Fotoarkiv / produktbilder | Fotografier | Direct multimodal embeddings |
| PDF med tabeller over flere sider | Tabeller, ligninger | Content Understanding |
| Blandet innhold (tekst + bilder) | Alt | Combined pipeline (mønster 3) |
| Kun tekstdokumenter | Ingen | Standard RAG (ikke multimodal) |
### GPT-4v vs GPT-4o for multimodal RAG
| Modell | Best for | Begrunnelse |
|--------|----------|-------------|
| **GPT-4v (vision-preview)** | Bildeberikelse, summary-generering | Bedre på å generere bildesummaries → forbedrer recall |
| **GPT-4o** | Inferens, spørsmålsbesvaring | Bedre på QA → forbedringer i kvalitet, hastighet, kostnad |
### Vanlige feil
| Feil | Konsekvens | Løsning |
|------|------------|---------|
| Ignorerer bilder i RAG | Mister visuell informasjon | Aktiver `imageAction: generateNormalizedImages` |
| Kun direct embeddings for diagrammer | Taper semantisk forståelse | Bruk verbalization for diagrammer |
| Mangler spatial metadata | Ingen sidehenvisning i citations | Inkluder `bounding_polygons` og `page_number` |
| Bruker Free tier for multimodal | Ikke støttet | Minimum Basic tier for Azure AI Search |
---
## Integrasjon med Microsoft-stakken
| Tjeneste | Integrasjonspunkt |
|----------|-------------------|
| **Azure AI Search** | Multi-vector indeks, index projections, knowledge store |
| **Azure AI Document Intelligence** | Document Layout skill for bildeekstraksjon |
| **Azure Content Understanding** | Markdown-output med tabeller, ligninger, semantisk chunking |
| **Azure Vision** | Multimodal embeddings (1024-dim) for bilder og tekst |
| **Azure OpenAI** | GPT-4o/4v for bildeverbalisering, text-embedding-3 for tekst |
| **Azure Blob Storage** | Knowledge store for projiserte bilder |
### Query-patterns
| Query-type | Implementasjon | Brukstilfelle |
|------------|----------------|---------------|
| Fulltekstsøk | `{"search": "energy", "select": "content_text, content_path"}` | Søk på tvers av tekst og bilder |
| Filtrer kun bilder | `{"filter": "image_document_id ne null"}` | Visuelt innhold |
| Hybrid query | Fulltekst + vektor + semantic ranking | Best relevans |
| Bildebasert query | Multimodal embedding av query-bilde | Visuell likhetssøk |
---
## Offentlig sektor (Norge)
### Dataplassering
- **Azure Content Understanding:** Sjekk regional tilgjengelighet (endres hyppig)
- **Azure Vision:** West Europe — bildeprosessering i EU
- **Azure AI Search:** Norway East — indeks i Norge
### Relevante vurderinger
| Krav | Implikasjon |
|------|-------------|
| **Universell utforming (WCAG)** | Bildeverbalisering genererer alt-text — støtter tilgjengelighet |
| **Arkivloven** | Spatial metadata (sidetall, posisjon) støtter dokumentreferanser |
| **GDPR** | Bilder med persondata (ansikter) krever spesiell behandling |
| **AI Act** | Dokumenter multimodal pipeline-arkitektur som del av AI-system |
---
## Kostnad og lisensiering
### Kostnadskomponenter
| Komponent | Prismodell | Estimat |
|-----------|------------|---------|
| Document Intelligence (bildeeekstraksjon) | Per side | ~$0.01-0.05/side |
| Content Understanding | Per dokument/side | Varierer |
| GPT-4v verbalization | Per token (input: bilde + prompt) | ~$0.01-0.03/bilde |
| Azure Vision embedding | Per API-kall | ~$0.001/bilde |
| Vektorlagring (multimodal) | Per GB | ~50% mer enn kun tekst |
### Optimaliseringstips
1. **Bruk direct embeddings for foto, verbalization for diagrammer** — balanserer kostnad og kvalitet
2. **Sett `stored: false` på bildevektorer** — sparer lagring
3. **Batch-prosesser bilder off-peak** — lavere compute-kostnad
4. **Aktiver enrichment cache** — unngår re-prosessering ved re-indeksering
### Forutsetninger
- Microsoft Foundry resource (for Vision multimodal embeddings) — regionbegrenset
- Azure AI Search Basic tier eller høyere (ikke Free tier)
- Azure Storage for dokumenter og knowledge store
- Managed identity med riktige rolletildelinger
---
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **"Inneholder dokumentene visuelt innhold (bilder, tabeller, diagrammer)?"** — Nei → standard RAG
2. **"Hva slags visuelt innhold?"** — Diagrammer → verbalization, fotos → direct embeddings
3. **"Er tabeller på tvers av sider vanlig?"** — Ja → Content Understanding (ikke Document Layout)
4. **"Trenger brukerne å søke basert på bilder?"** — Ja → multimodal embeddings
5. **"Har dokumentene LaTeX/ligninger?"** — Ja → Content Understanding med LaTeX-støtte
### Fallgruver
- **Multimodal for rent tekstinnhold:** Økt kostnad uten gevinst
- **Kun direct embeddings for alt:** Diagrammer trenger semantisk tolkning
- **Ignorerer Content Understanding:** Ny service (GA nov 2025) som løser mange multimodale utfordringer
- **Glemmer spatial metadata:** Uten sidetall og posisjon mister du citation-kvalitet
### Anbefalinger per modenhetsnivå
| Modenhet | Anbefaling |
|----------|------------|
| **Prototyp** | Document Layout skill. Ignorer bilder initialt. Fokuser på tekst-RAG. |
| **Pilot** | Legg til image verbalization for nøkkeldokumenttyper. Test retrieval-kvalitet. |
| **Produksjon** | Combined pipeline (mønster 3). Content Understanding for tabeller. |
| **Enterprise** | Full multimodal pipeline + Azure Vision embeddings + spatial metadata. |
---
## Kilder og verifisering
| Kilde | Konfidens | URL |
|-------|-----------|-----|
| Multimodal Search Concepts (Azure AI Search) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/multimodal-search-overview) |
| Tutorial: Vectorize images and text | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/search/tutorial-document-extraction-multimodal-embeddings) |
| Content Understanding: Markdown representation | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/ai-services/content-understanding/document/markdown) |
| Multimodal RAG with Vision (ISE DevBlog) | **Verified** | [devblogs.microsoft.com](https://devblogs.microsoft.com/ise/multimodal-rag-with-vision/) |
| RAG Time Journey 4: Advanced Multimodal Indexing | **Verified** | [techcommunity.microsoft.com](https://techcommunity.microsoft.com/blog/azure-ai-foundry-blog/rag-time-journey-4-advanced-multimodal-indexing/4397300) |
| Azure-Samples/multimodal-rag-code-execution | **Baseline** | [github.com](https://github.com/Azure-Samples/multimodal-rag-code-execution) |

View file

@ -0,0 +1,505 @@
# RAG Caching and Performance Optimization
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Caching er en kritisk optimaliseringsstrategi for RAG-applikasjoner (Retrieval-Augmented Generation) som kan dramatisk redusere både latency og kostnader. I typiske RAG-scenarier er kall til LLM-modeller ofte den mest kostbare og tidkrevende operasjonen, spesielt når store mengder kontekstdata og chat history sendes med hver request. En godt designet caching-strategi kan redusere antall LLM-invocations med opptil 90% for high-traffic scenarier med repeterende eller semantisk like queries.
Multi-layer caching-tilnærmingen dekker flere nivåer i RAG-arkitekturen: result caching (hele LLM-responser), retrieval caching (knowledge fragments fra vektorsøk), embedding caching (forhåndsberegnede vektorrepresentasjoner), og semantic caching (semantisk like prompts). Hver av disse lagene adresserer ulike aspekter av ytelse og kostnadsoptimalisering.
Microsoft-stakken tilbyr flere tjenester optimalisert for AI-workloads: Azure Cache for Redis (traditional og semantic caching), Azure Cosmos DB (semantic cache med vektorsøk), Azure AI Search (built-in caching av search results), og Azure API Management (semantic caching for LLM APIs). Valget av løsning avhenger av cache-type, scale-requirements, og compliance-krav.
## Kjernekomponenter
### Multi-layer caching-strategi
| Cache Layer | Formål | Typisk Hit Rate | Latency Impact |
|------------|--------|-----------------|----------------|
| **Result caching** | Cache hele LLM-responser for identiske/semantisk like queries | 30-60% (high-traffic) | -80% til -95% |
| **Retrieval caching** | Cache knowledge fragments fra vector search | 40-70% | -50% til -70% |
| **Embedding caching** | Cache forhåndsberegnede embeddings | 60-90% | -30% til -50% |
| **Model output caching** | Cache intermediate model outputs | 20-40% | -40% til -60% |
**Verified** (Microsoft Learn - Application design for AI workloads)
### Cache Key Components
Effektive cache keys må inkludere:
- **Tenant/User identity** — For multi-tenant security
- **Policy context** — RBAC og data access policies
- **Model version** — Unngå stale responses ved model updates
- **Prompt version** — Track prompt engineering changes
- **Context window** — Chat history for contextual relevance
**Verified** (Microsoft Learn - Multi-layer caching strategies)
### Time-to-Live (TTL) Policies
| Data Type | Anbefalt TTL | Begrunnelse |
|-----------|--------------|-------------|
| Static content (dokumentasjon, policies) | 24-72 timer | Sjelden endring |
| Dynamic content (dashboard data) | 5-30 minutter | Moderate freshness-krav |
| User-specific queries | 1-5 minutter | Privacy og freshness |
| Search results | 15-60 minutter | Balanse mellom cost og freshness |
**Baseline** (Industry best practices)
### Cache Invalidation Triggers
- **Data updates** — Webhook-triggered invalidation ved source data changes
- **Model changes** — Invalidate ved model deployment/retraining
- **Prompt modifications** — Clear cache ved prompt template changes
- **Manual purge** — Admin-triggered for compliance eller testing
**Verified** (Microsoft Learn - Caching strategies)
## Arkitekturmønstre
### 1. Semantic Caching (anbefalt for RAG)
**Beskrivelse:** Bruker vector similarity search på cached prompts for å returnere responses til semantisk like queries, selv om teksten ikke er identisk.
**Hvordan det fungerer:**
1. Incoming prompt vektoriseres med embedding model
2. Vector search kjøres mot cached prompt vectors
3. Items med similarity score > threshold returneres
4. Ved cache miss: LLM genererer response, som caches med vectorized prompt
**Fordeler:**
- Høyere cache hit rate enn traditional key-value caching (30-60% vs 10-20%)
- Håndterer variasjon i user input (synonyms, paraphrasing)
- Reduserer LLM token consumption drastisk
**Ulemper:**
- Krever embedding model (extra latency ~50-100ms)
- Mer kompleks implementation
- Krever vector-capable cache (Cosmos DB, Redis med RediSearch)
**Context Window Requirement:**
Semantic cache MÅ operere innenfor context window. Uten chat history kan cache returnere contextually incorrect responses.
**Eksempel:** User spør "What is the largest lake in North America?" (cached: "Lake Superior"), deretter "What is the second largest?" Uten context window ville cache kunne returnere feil svar til en annen user som spør samme oppfølgingsspørsmål i en annen kontekst.
**Verified** (Microsoft Learn - Semantic cache introduction)
### 2. Multi-tier Result Caching
**Beskrivelse:** Kombinerer in-memory cache (Redis) med persistent cache (Cosmos DB) for optimal balance mellom speed og durability.
**Arkitektur:**
```
User Query → L1: Redis (in-memory, <5ms) → L2: Cosmos DB (persistent, <50ms) → LLM (fallback, >2s)
```
**Fordeler:**
- Sub-5ms response time for hot data
- Data durability ved cache failures
- Cost-effective (Redis for hot, Cosmos for warm data)
**Ulemper:**
- Økt complexity i cache management
- Potential for stale data across tiers
- Høyere infrastructure cost
**Baseline** (Common enterprise pattern)
### 3. Retrieval Snippet Caching
**Beskrivelse:** Cache frequently retrieved knowledge fragments fra Azure AI Search eller vector databases for å unngå repeated database queries.
**Implementation:**
- Cache top-K search results per query pattern
- Key: hash(query + filters + top-K)
- TTL: 15-60 minutter (avhengig av data freshness-krav)
**Fordeler:**
- Reduserer Azure AI Search query costs (50-70% reduction)
- Lavere latency for grounding data retrieval
- Mindre load på vector index
**Ulemper:**
- Stale grounding data hvis source documents oppdateres
- Cache size kan vokse raskt med mange unique queries
**Verified** (Microsoft Learn - Retrieval caching)
## Beslutningsveiledning
### Når bruke hvilken caching-strategi
| Scenario | Anbefalt Strategi | Rationale |
|----------|-------------------|-----------|
| Chatbot med repeterende FAQs | Semantic caching (Redis + RediSearch) | Høy hit rate, semantisk matching |
| Document Q&A med mange unique queries | Retrieval snippet caching | Kostnad-effektiv, fokus på grounding data |
| Real-time dashboard med AI insights | Multi-tier caching (Redis L1 + Cosmos L2) | Speed + durability |
| Compliance-sensitive applikasjoner | User-scoped semantic caching | Privacy protection, audit trail |
**Baseline** (Architecture decision framework)
### Vanlige feil å unngå
| Anti-pattern | Problem | Løsning |
|-------------|---------|---------|
| **Caching user-private data globally** | Privacy violation, data leakage | Scope cache keys by user/tenant identity |
| **Ingen TTL policy** | Runaway cache growth, stale data | Implement TTL basert på data sensitivity |
| **For høy similarity threshold (>0.8)** | Lav cache hit rate | Start med 0.15-0.3, tune basert på metrics |
| **Caching uten context window** | Contextually incorrect responses | Vectorize chat history + latest prompt |
| **Ingen invalidation strategy** | Stale responses ved data updates | Implement webhook-based invalidation |
**Verified** (Microsoft Learn - Caching risks)
### Røde flagg
- Cache hit rate < 20% etter tuning → Revurder cache strategy
- Cache size vokser >10GB/dag → Implementer aggressive TTL eller pruning
- Latency øker etter caching → Sjekk embedding model overhead
- Brukerklager på stale data → Reduser TTL eller implementer invalidation
**Baseline** (Performance monitoring thresholds)
## Integrasjon med Microsoft-stakken
### Azure Cache for Redis
**Use Cases:** Traditional result caching, high-throughput scenarios
**Tiers:**
- **Premium tier** — 99.9% SLA, up to 120GB per shard
- **Enterprise tier** — 99.99% SLA, active-active geo-replication, Flash storage support
- **Enterprise Flash tier** — Up to 13TB cache size, 20% RAM + 80% NVMe Flash
**Workloads suited for Flash tier:**
- Read-heavy (high read/write ratio)
- Hot/cold access patterns (frequently accessed subset)
- Large values (keys in RAM, values in Flash)
**Not suited for Flash tier:**
- Write-heavy workloads
- Uniform data access patterns
- Long key names with small values
**Configuration for AI workloads:**
```python
import redis
from azure.identity import DefaultAzureCredential
from redis_entraid.cred_provider import create_from_default_azure_credential
credential_provider = create_from_default_azure_credential(
("https://redis.azure.com/.default",),
)
r = redis.Redis(
host="<redis-host>.redis.cache.windows.net",
port=10000,
ssl=True,
decode_responses=True,
credential_provider=credential_provider
)
# Set TTL på cached item
r.setex("cache_key", 3600, "cached_value") # 1 hour TTL
```
**Verified** (Microsoft Learn - Azure Managed Redis architecture, code samples)
### Azure API Management - Semantic Caching
**Use Case:** Semantic caching for LLM APIs (Azure OpenAI, Model Inference API)
**Prerequisites:**
- Azure Managed Redis med **RediSearch module** enabled
- Embeddings API deployment (for vectorization)
- Chat Completion API deployment (for user requests)
**Policy Configuration:**
Inbound (cache lookup):
```xml
<azure-openai-semantic-cache-lookup
score-threshold="0.15"
embeddings-backend-id="embeddings-backend"
embeddings-backend-auth="system-assigned"
ignore-system-messages="true"
max-message-count="10">
<vary-by>@(context.Subscription.Id)</vary-by>
</azure-openai-semantic-cache-lookup>
<rate-limit calls="10" renewal-period="60" />
```
Outbound (cache store):
```xml
<azure-openai-semantic-cache-store duration="60" />
```
**Score Threshold Tuning:**
- 0.1-0.2 → Liberal matching, høy hit rate, noe lavere relevance
- 0.3-0.5 → Balanced, medium hit rate, god relevance
- 0.6-0.8 → Strict matching, lav hit rate, høy relevance
**Verified** (Microsoft Learn - Enable semantic caching for LLM APIs)
### Azure Cosmos DB for NoSQL
**Use Case:** Semantic cache med built-in vector search, persistent storage
**Implementation Pattern:**
```python
from azure.cosmos import CosmosClient
from openai import AzureOpenAI
# Setup Cosmos DB vector store
cosmos_client = CosmosClient(url=cosmos_uri, credential=cosmos_key)
database = cosmos_client.get_database_client(cosmos_database_name)
container = database.get_container_client(cosmos_container_name)
# Query semantic cache
def query_cache(prompt_vector, similarity_threshold=0.15, top_k=5):
query = f"""
SELECT TOP {top_k} c.id, c.prompt, c.completion,
VectorDistance(c.promptVector, @promptVector) AS similarity
FROM c
WHERE VectorDistance(c.promptVector, @promptVector) > @threshold
ORDER BY VectorDistance(c.promptVector, @promptVector) DESC
"""
items = list(container.query_items(
query=query,
parameters=[
{"name": "@promptVector", "value": prompt_vector},
{"name": "@threshold", "value": similarity_threshold}
]
))
return items
```
**Fordeler:**
- Globally distributed, multi-region writes
- Automatic indexing av vectors
- 99.999% SLA med multi-region setup
- Built-in TTL support
**Verified** (Microsoft Learn - Semantic cache with Cosmos DB, code samples)
### Azure AI Search - Built-in Caching
**Automatic Caching Behavior:**
Azure AI Search cacher automatisk content etter første query for raskere subsequent searches.
**Optimization Tips:**
- Reduser index size → raskere caching, mindre memory footprint
- Selective field attribution → kun indexer nødvendige fields
- Unngå over-attribution (filterable, sortable, facetable) → reduserer storage 4x
**Performance Factors:**
- Smaller indexes → mer content i cache → lavere query latency
- Higher tiers (S2, S3) → mer memory → større cache capacity
- Partitions → parallel processing for slow queries
**Verified** (Microsoft Learn - Azure AI Search performance tips)
## Offentlig sektor (Norge)
### GDPR og Privacy
**Cache Key Scoping (OBLIGATORISK):**
- Aldri cache user-private content uten proper scoping by user identity
- Implementer tenant/user isolation i cache keys
- Audit trail for cached persondata
**Data Minimization:**
- Cache kun minimum nødvendig data for å svare på query
- TTL på persondata skal ikke overstige formåls-begrensningen
- Automatisk sletting ved user request (GDPR Article 17)
**Eksempel - GDPR-compliant cache key:**
```python
cache_key = f"user:{user_id}:tenant:{tenant_id}:query_hash:{hash(prompt)}"
# TTL: 1 hour (minimal for chat session)
```
**Baseline** (GDPR compliance patterns)
### Compliance-krav
| Krav | Implementation |
|------|----------------|
| **Dataportabilitet (GDPR Art. 20)** | Export cached user data on request |
| **Rett til sletting (GDPR Art. 17)** | Implement cache purge by user_id |
| **Behandlingsgrunnlag** | Dokumenter legitimate interest for caching |
| **Datatilsynet rapportering** | Audit log for cache access/invalidation |
**Baseline** (Norwegian public sector compliance)
### Sikkerhet
**Encryption:**
- **At rest:** Azure Cache for Redis (Premium/Enterprise) — automatic encryption
- **In transit:** TLS 1.2+ mandatory for all cache connections
- **Key management:** Azure Key Vault for cache access keys
**Access Control:**
- Microsoft Entra ID authentication for Redis (preview)
- Role-based access control (RBAC) for cache management
- Network isolation via Private Endpoints
**Verified** (Microsoft Learn - Redis security)
## Kostnad og lisensiering
### Azure Cache for Redis Pricing (Norway East - 2026)
| Tier | Size | Kapasitet | Månedskostnad (NOK) | Best For |
|------|------|-----------|---------------------|----------|
| Basic C0 | 250 MB | N/A (no SLA) | ~400 | Dev/Test |
| Standard C1 | 1 GB | 2 replicas, 99.9% SLA | ~1,200 | Small production |
| Premium P1 | 6 GB | Clustering, geo-replication | ~7,000 | Enterprise |
| Enterprise E10 | 12 GB | Active-active, 99.99% SLA | ~25,000 | Mission-critical |
| Enterprise Flash F300 | 345 GB | 20% RAM + 80% Flash | ~60,000 | Large-scale AI |
**Cost Optimization Tips:**
1. **Start with Premium P1** for production RAG (best price/performance)
2. **Scale out vs scale up** — Add replicas før du går til høyere tier
3. **Use Flash tier for large caches** (>100GB) — 5x lavere cost per GB vs Enterprise
4. **Monitor cache hit rate** — <20% hit rate betyr ineffektiv caching strategy
5. **Implement TTL aggressively** — Reduser cache size, lavere tier
**Verified** (Microsoft Learn - Plan and manage costs)
### Azure Cosmos DB Pricing
**Request Units (RU/s) for Semantic Cache:**
- Vector query (1KB): ~10-50 RU
- Write (cache store): ~5-10 RU
- Storage: ~2.5 NOK/GB/måned
**Cost Example (10,000 queries/day):**
- 10,000 queries × 30 RU avg = 300,000 RU/day = 3.5 RU/s avg
- Provisioned: 100 RU/s (for burst) = ~600 NOK/måned
- Storage (10GB cache): ~25 NOK/måned
- **Total: ~625 NOK/måned**
**Baseline** (Cosmos DB pricing calculator estimates)
### TCO Sammenligning
| Scenario | Without Caching | With Semantic Caching (Redis) | Savings |
|----------|-----------------|-------------------------------|---------|
| 100K LLM queries/day (GPT-4) | ~450,000 NOK/måned | ~150,000 NOK/måned + 7,000 (Redis) | 65% |
| 10K queries/day (GPT-3.5) | ~45,000 NOK/måned | ~15,000 NOK/måned + 7,000 (Redis) | 51% |
**Assumptions:** 50% cache hit rate, avg 2000 tokens/query
**Baseline** (TCO analysis based on Azure pricing)
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **Traffic pattern:** Hvor mange LLM queries per dag/time forventer dere? Hva er peak vs avg load?
2. **Query similarity:** Er det mange repeterende eller semantisk like spørsmål? (Indikerer semantic cache ROI)
3. **Data freshness:** Hvor ofte endres underlying data? Hva er akseptabelt staleness-vindu?
4. **Privacy requirements:** Håndterer dere persondata? Trengs user-scoped caching?
5. **Compliance:** Hvilke regulatory frameworks gjelder (GDPR, Schrems II, Datatilsynet)?
6. **Budget:** Hva er totalt budsjett for LLM + caching infrastructure?
7. **Latency SLA:** Hva er maks akseptabel response time (p50, p95, p99)?
8. **Global reach:** Trengs multi-region caching for latency eller compliance?
### Fallgruver å unngå
| Fallgruve | Impact | Mitigering |
|-----------|--------|------------|
| **Caching uten context window** | Contextually incorrect responses → user frustration | Vectorize chat history + prompt |
| **Global caching av persondata** | GDPR violation, potential bøter | User-scoped keys, TTL enforcement |
| **For høy similarity threshold** | Lav hit rate, caching ineffective | Start lavt (0.15), tune opp |
| **Ingen invalidation strategy** | Stale data → incorrect LLM responses | Webhook-based invalidation |
| **Undersized cache tier** | High eviction rate, lav hit rate | Monitor evictions, scale proaktivt |
| **Ignoring embedding overhead** | Latency increase vs direct LLM call | Batch embeddings, use async patterns |
### Anbefalinger per modenhetsnivå
**Level 1 - Pilot (0-6 måneder RAG erfaring):**
- Start med **Azure API Management semantic caching** (managed, low-complexity)
- Use case: FAQ chatbot med <1000 queries/dag
- Tier: Standard Redis (C1) for læring, lav cost
- Monitoring: Basic hit rate metrics i APIM
**Level 2 - Production (6-18 måneder):**
- Implementer **multi-layer caching** (Redis L1 + Cosmos DB L2)
- Use case: Customer support RAG med 10K-100K queries/dag
- Tier: Premium Redis (P1) + Cosmos DB autoscale
- Monitoring: Application Insights med custom metrics (hit rate, latency, cost per query)
**Level 3 - Enterprise (18+ måneder):**
- **Hybrid semantic + retrieval caching** med advanced invalidation
- Use case: Multi-tenant SaaS RAG platform, 100K+ queries/dag
- Tier: Enterprise Redis (E10) + global Cosmos DB
- Monitoring: Full observability stack (Grafana, custom dashboards, alerting)
**Baseline** (Maturity model for AI implementations)
## Kilder og verifisering
### Microsoft Learn Documentation
1. **Application design for AI workloads on Azure** - Multi-layer caching strategies
https://learn.microsoft.com/en-us/azure/well-architected/ai/application-design#implement-multi-layer-caching-strategies
*Confidence: Verified (2026-02)*
2. **Introduction to semantic cache** - Semantic caching concepts, context window requirements
https://learn.microsoft.com/en-us/azure/cosmos-db/gen-ai/semantic-cache
*Confidence: Verified (2026-02)*
3. **Enable semantic caching for LLM APIs in Azure API Management** - APIM semantic cache implementation
https://learn.microsoft.com/en-us/azure/api-management/azure-openai-enable-semantic-caching
*Confidence: Verified (2026-02)*
4. **Tips for better performance in Azure AI Search** - Index caching, performance optimization
https://learn.microsoft.com/en-us/azure/search/search-performance-tips
*Confidence: Verified (2026-02)*
5. **Azure Managed Redis architecture** - Flash tier workloads, caching strategies
https://learn.microsoft.com/en-us/azure/redis/architecture#flash-optimized-tier
*Confidence: Verified (2026-02)*
6. **Plan and manage costs of an Azure AI Search service** - Cost optimization, enrichment caching
https://learn.microsoft.com/en-us/azure/search/search-sku-manage-costs#minimize-costs
*Confidence: Verified (2026-02)*
7. **Data platform considerations for mission-critical workloads** - Azure Cache for Redis enterprise patterns
https://learn.microsoft.com/en-us/azure/well-architected/mission-critical/mission-critical-data-platform#caching-for-hot-tier-data
*Confidence: Verified (2026-02)*
### Code Samples
8. **RAG implementation with Azure AI Search** - Python RAG cache patterns
https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview#content-retrieval-in-azure-ai-search
*Confidence: Verified (code sample)*
9. **Azure Cache for Redis with Python** - Redis connection and caching code
https://learn.microsoft.com/en-us/azure/redis/python-get-started#code-to-connect-to-a-redis-cache
*Confidence: Verified (code sample)*
### Confidence Levels per Section
| Seksjon | Confidence | Source |
|---------|-----------|--------|
| Multi-layer caching strategy | **Verified** | Microsoft Learn docs (1) |
| Semantic caching pattern | **Verified** | Microsoft Learn docs (2, 3) |
| Azure Cache for Redis configuration | **Verified** | Microsoft Learn docs (5, 7), code samples (9) |
| Azure API Management policies | **Verified** | Microsoft Learn docs (3) |
| Azure AI Search caching | **Verified** | Microsoft Learn docs (4, 6) |
| Cost estimates | **Baseline** | Azure pricing calculator (2026-02) |
| GDPR compliance patterns | **Baseline** | Industry best practices |
| Maturity model recommendations | **Baseline** | Architecture consulting experience |
---
**Totalt antall kilder:** 9 unike Microsoft Learn URLer
**MCP calls:** 6 (4 docs_search + 2 docs_fetch + 1 code_sample_search)
**Sist verifisert:** 2026-02-03

View file

@ -0,0 +1,440 @@
# RAG Context Windows and Long-Context Models
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Context window-størrelse er en av de mest kritiske faktorene som bestemmer kvaliteten og kostnaden for en RAG-løsning. En language model har en begrenset kapasitet for tokens den kan prosessere i en enkelt request — dette omtales som modellens context window. For RAG-implementasjoner må man balansere mellom å gi modellen nok kontekst til å generere gode svar, uten å overbelaste context window eller sløse med tokens (som koster penger).
Med innføringen av long-context models som GPT-4 Turbo (128k tokens) og GPT-4.1 (context windows opp til 200k+ tokens), har arkitekter fått nye muligheter: skal man fortsatt bruke klassisk RAG med retrieval av små, relevante chunks, eller kan man nå sende hele dokumenter direkte til modellen? Svaret avhenger av use case, kostnad, latency-krav og modellens faktiske evne til å utnytte store context windows — kjent som "lost-in-the-middle"-problemet.
I denne kunnskapsreferansen dekkes token budgeting, context window management, og når man skal velge RAG-basert chunking versus long-context direct prompting, med fokus på Azure OpenAI-modeller og integrasjon i Microsoft-stakken.
---
## Kjernekomponenter
### Context Window vs. Token Limit
| Begrep | Definisjon |
|--------|-----------|
| **Context Window** | Totalt antall tokens modellen kan prosessere (input + output) i én request |
| **Max Prompt Tokens** | Maksimalt antall input tokens (brukermelding + system prompt + retrieved documents + conversation history) |
| **Max Completion Tokens** | Maksimalt antall output tokens modellen kan generere som svar |
| **Token Budget** | Planlagt fordeling av tokens mellom ulike komponenter (system prompt, history, grounding data, buffer) |
**Verified (Azure OpenAI):**
- GPT-4 Turbo: 128k tokens context window
- GPT-4.1 series: Opp til 200k+ tokens context window
- GPT-4o: 128k tokens
- o1-series: Varierende (o1: 200k, o3-mini: 128k)
### Token Budget Allocation
En RAG-prompt består typisk av:
1. **System message** (50500 tokens): Instruksjoner om oppførsel og svarformat
2. **Conversation history** (02000 tokens): Tidligere brukerforespørsler og svar
3. **Retrieved context** (50010,000 tokens): Dokumenter/chunks hentet fra vektordatabase
4. **User query** (10200 tokens): Brukerens nåværende spørsmål
5. **Response buffer** (2004000 tokens): Reservert plass til modellens genererte svar
**Best practice:**
For GPT-4 Turbo (128k context):
- Reserved for system/history/query: ~5-10k tokens
- Retrieved context: Max 30-50k tokens (ikke hele window)
- Response buffer: 2-4k tokens
For GPT-4.1 (200k context):
- Retrieved context: Kan økes til 100k tokens, men kvalitet avtar (lost-in-the-middle)
- Reserved: 10-15k tokens
### Prompt Compression Techniques
Når man nærmer seg token limit, kan man bruke:
| Teknikk | Beskrivelse | Trade-off |
|---------|-------------|-----------|
| **Semantic truncation** | Fjern minst relevante chunks fra retrieved context | Risiko for tap av relevant informasjon |
| **History summarization** | Komprimer tidligere conversation history til sammendrag | Reduserer kontekstuell forståelse |
| **Token-aware chunking** | Del dokumenter i chunks som passer innenfor token budget | Økt kompleksitet i indexing pipeline |
| **Retrieval limiting** | Reduser antall chunks hentet (top-k parameter) | Lavere recall, kan misse relevante kilder |
**Baseline (generell kunnskap):**
Azure OpenAI Assistants API støtter automatisk truncation via `max_prompt_tokens` og `truncation_strategy` parameters.
### Lost-in-the-Middle Effect
**Verified (Research):**
Studier viser at LLMs har svakere performance når relevant informasjon er plassert midt i en lang context — de presterer best når viktig info er i starten eller slutten av prompten.
**RAG-implikasjoner:**
- Ikke anta at større context window = bedre svar
- Bruk semantic ranking for å sikre at de mest relevante chunks plasseres først
- For long-context models: overvei map-reduce eller sliding window pattern
### Long-Context LLMs
| Modell | Context Window | Anbefalt RAG-strategi |
|--------|---------------|----------------------|
| GPT-4 Turbo | 128k | Klassisk RAG (top-10 til top-50 chunks) |
| GPT-4.1 | 200k+ | Hybrid: RAG for precision queries, long-context for exploratory |
| GPT-4o | 128k | Klassisk RAG med hybrid search |
| o1-series | 200k | Long-context for reasoning tasks, RAG for factual grounding |
**Baseline:**
Long-context models reduserer behovet for aggressive chunking, men øker token cost og latency.
---
## Arkitekturmønstre
### Mønster 1: Klassisk RAG med Token-Aware Retrieval
**Beskrivelse:**
Hent et begrenset antall høyt relevante chunks (f.eks. top-10), og pass dem inn i en prompt som holder seg godt under context window limit.
**Fordeler:**
- Lavere token cost (kun relevante chunks sendes)
- Raskere inference (mindre input å prosessere)
- Bedre kontroll over token budget
- Fungerer godt med modeller som har mindre context windows (32k128k)
**Ulemper:**
- Avhenger av retrieval-kvalitet (dårlig ranking = dårlige svar)
- Kan misse informasjon som ligger spredt i flere dokumenter
**Når bruke:**
Standard for de fleste RAG-implementasjoner, spesielt når kostnad og latency er prioritert.
**Verified (Azure AI Search):**
Azure AI Search støtter hybrid queries (keyword + vector) med semantic ranking for å finne de mest relevante chunks innenfor et token budget.
---
### Mønster 2: Long-Context Direct Prompting
**Beskrivelse:**
Send hele dokumenter (eller store seksjoner) direkte til en long-context model uten chunking eller retrieval-prosess.
**Fordeler:**
- Ingen tap av informasjon fra aggressive chunking
- Enklere arkitektur (ikke behov for vektor-database eller embeddings)
- Fungerer godt for summarization, analyse av hele dokumenter
**Ulemper:**
- Høyere token cost (sender alt, ikke bare relevant)
- Tregere inference (modellen må prosessere hele dokumentet)
- Lost-in-the-middle effekt kan redusere accuracy
- Ikke skalerbart for store dokumentsamlinger (100+ dokumenter)
**Når bruke:**
- Dokumentsamlinger er små (<10 dokumenter)
- Brukerforespørsler krever bred kontekst (f.eks. "sammenlign alle seksjonene i denne policyen")
- Budget tillater høyere token cost
**Baseline:**
Passende for ad-hoc analyser, men ikke for produksjons-RAG-løsninger med mange brukere.
---
### Mønster 3: Sliding Window (Incremental Context)
**Beskrivelse:**
Del et stort dokument i overlappende vinduer (chunks med 1020% overlap), og kjør modellen på hvert vindu sekvensielt. Aggreger svarene.
**Fordeler:**
- Håndterer ekstremt store dokumenter (over 200k tokens)
- Unngår lost-in-the-middle problemet
- Kan paralleliseres for raskere prosessering
**Ulemper:**
- Kompleks aggregeringslogikk (hvordan kombinere delsvar?)
- Ikke egnet for spørsmål som krever sammenheng på tvers av hele dokumentet
**Når bruke:**
- Legal document analysis (lange kontrakter, lover)
- Scientific papers med streng struktur
- Når brukerspørsmål kan besvares fra én seksjon om gangen
**Baseline:**
Sjeldnere brukt, men effektiv for spesialiserte domener.
---
## Beslutningsveiledning
### Når bruke RAG vs. Long-Context
| Kriterium | Bruk RAG (chunked retrieval) | Bruk Long-Context (hele dokumenter) |
|-----------|------------------------------|--------------------------------------|
| **Dokumentsamling** | Store (100+ dokumenter) | Små (<10 dokumenter) |
| **Query type** | Faktaspørsmål, lookup | Analyse, sammenligning, summarization |
| **Kostnad** | Lav til medium (kun relevante tokens) | Høy (sender alt) |
| **Latency** | Lav (mindre tokens å prosessere) | Høyere (modellen må lese alt) |
| **Retrieval kvalitet** | Avhenger av embeddings og ranking | Ikke relevant (sender alt) |
| **Modenhetsnivå** | Alle nivåer | Medium til høy (krever token-kostnadskontroll) |
### Vanlige Feil
| Feil | Konsekvens | Rettelse |
|------|-----------|----------|
| **Sender for mye context** | Høy token cost, lost-in-the-middle effekt | Bruk semantic ranking, reduser top-k |
| **Ignorerer token budget** | Requests feiler med 400 (exceeded context limit) | Implementer token counting (tiktoken) før API call |
| **Glemmer response buffer** | Modellen trunkerer svar midt i setning | Reserver 1520% av context window for output |
| **Bruker long-context for alle queries** | Unødvendig høy kostnad | Implementer query classification (enkel query → RAG, kompleks → long-context) |
### Røde Flagg
- **Token cost øker plutselig**: Sjekk om conversation history ikke blir trunked
- **Svarkvalitet synker**: Lost-in-the-middle — flytt viktigste chunks til start av prompt
- **Rate limit errors (429)**: Du overskrider Tokens-Per-Minute (TPM) quota
---
## Integrasjon med Microsoft-stakken
### Azure OpenAI Context Limits (Verified)
| Modell | Context Window | TPM (Default tier) | TPM (Enterprise tier) |
|--------|---------------|-------------------|----------------------|
| gpt-4 (turbo-2024-04-09) | 128k | 450k | 2M |
| gpt-4.1 | 200k+ | 1M | 5M |
| gpt-4o | 128k | 450k | 30M |
| gpt-4o-mini | 128k | 2M | 150M |
| o1 | 200k | 3M | 30M |
| o3-mini | 128k | 5M | 50M |
**Viktig:**
TPM (Tokens Per Minute) = Max tokens som kan prosesseres per minutt på deployment-nivå. Hvis du sender én request med 50k input tokens + 2k output tokens = 52k tokens → teller mot TPM.
### Azure OpenAI Assistants API (Verified)
**Max Prompt/Completion Tokens:**
Når du oppretter en Run i Assistants API, kan du sette:
```python
# Python example (Verified from Microsoft Learn)
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id,
max_prompt_tokens=20000, # Recommended minimum for File Search
max_completion_tokens=4000
)
```
**Truncation Strategy:**
- `auto`: Standard (OpenAI bestemmer hva som trunkeres)
- `last_messages`: Beholder kun N siste meldinger i conversation history
**Best practice (Verified):**
For File Search tool: Sett `max_prompt_tokens` til minimum 20,000. For lengre samtaler: 50,000 eller fjern limit helt.
### Semantic Kernel
**Token Management:**
Semantic Kernel (C#/.NET) har innebygd token counting via `PromptSection.Tokens`:
```csharp
// C# (Baseline — generell Semantic Kernel pattern)
var section = new PromptSection
{
Content = retrievedContext,
Tokens = maxTokens, // Request token budget for this section
Required = true
};
```
Semantic Kernel vil automatisk trunkere seksjoner hvis total token count overskrider modellens context window.
### Prompt Flow (Azure AI Foundry)
**Token Estimation:**
Prompt Flow viser estimert token count per node i flyten. Bruk dette for å debugge context window issues før deployment.
**Baseline (generell kjennskap):**
Du kan også bruke `tiktoken` Python library direkte i Prompt Flow nodes for mer presis token counting.
---
## Offentlig sektor (Norge)
### Token-Kostnader i Offentlige Budsjetter
**Context:**
Offentlige virksomheter må ofte forsvare AI-kostnader i budsjettprosesser. Token-forbruk er en operasjonell kostnad som skalerer med bruk.
**Anbefaling:**
- Implementer token logging per bruker/avdeling for å spore kostnad
- Bruk `max_prompt_tokens` og `max_completion_tokens` for å hindre "runaway cost" (f.eks. hvis en bruker sender ekstremt lange dokumenter)
- Vurder GPT-4o-mini eller GPT-4.1-mini for ikke-kritiske use cases (10x billigere enn GPT-4)
**Verified (Azure OpenAI Pricing):**
- GPT-4 Turbo input: ~$0.01 per 1k tokens
- GPT-4o input: ~$0.005 per 1k tokens
- GPT-4.1-mini input: ~$0.0001 per 1k tokens
(Husk å konvertere til NOK og inkluder output token cost, som ofte er 2-3x input cost.)
### Dataminimering (GDPR)
**Relevant for:**
Personvern-forskriften krever dataminimering — ikke send mer data til modellen enn nødvendig.
**RAG-fordel:**
Ved å bruke retrieval (ikke long-context direct prompting) sender du kun relevante chunks, som reduserer risikoen for å eksponere sensitiv informasjon utilsiktet i context.
**Best practice:**
Kombiner RAG med security trimming (Azure AI Search + Entra ID permissions) for å sikre at kun autoriserte dokumenter blir retrievet.
---
## Kostnad og lisensiering
### Prismodell per Token (Verified fra Azure OpenAI Pricing)
| Modell | Input (per 1k tokens) | Output (per 1k tokens) | Optimal RAG context size |
|--------|----------------------|------------------------|--------------------------|
| gpt-4-turbo | $0.01 | $0.03 | 10k30k tokens |
| gpt-4.1 | $0.015 | $0.045 | 10k50k tokens |
| gpt-4o | $0.005 | $0.015 | 10k30k tokens |
| gpt-4o-mini | $0.0005 | $0.0015 | 5k20k tokens |
**Eksempel (NOK, kurs 10.5):**
En query med 20k input tokens (retrieved context) + 500 output tokens på GPT-4o:
- Input: (20 × $0.005) × 10.5 = 1.05 NOK
- Output: (0.5 × $0.015) × 10.5 = 0.08 NOK
- **Total per query: ~1.13 NOK**
Hvis du har 10,000 queries per måned: **11,300 NOK/måned** (kun LLM-kostnad, ikke vektor-database eller search).
### Optimaliseringstips
1. **Bruk GPT-4o-mini for enkel retrieval** (f.eks. FAQ-lookup): 10x billigere
2. **Implementer caching** av frequently asked queries (reduserer token cost med 5080%)
3. **Batch processing** for ikke-interaktive workloads (Azure OpenAI Batch API: 50% rabatt)
4. **Monitorering**: Bruk Azure Monitor for å spore token usage per deployment
**Verified (Azure OpenAI Batch Quota):**
- gpt-4.1: 500M tokens per month (Enterprise tier), 30M (Default tier)
- gpt-4o: 500M (Enterprise), 30M (Default)
---
## For arkitekten (Cosmo)
### 58 Spørsmål å Stille Kunden
1. **Hvor store er dokumentene dere skal søke i?**
→ Hvis <10 dokumenter à <50k tokens: vurder long-context. Hvis 100+ dokumenter: bruk RAG.
2. **Hva er typiske brukerforespørsler?**
→ Faktaspørsmål (RAG) eller analyse/sammenligning (long-context)?
3. **Hva er akseptabel latency?**
→ <2 sekunder → RAG med små chunks. <5 sekunder → kan bruke long-context.
4. **Hva er token-budsjettet per query?**
→ Hvis stramt: Bruk GPT-4o-mini + classical RAG. Hvis romslig: GPT-4.1 + long-context.
5. **Hvor ofte oppdateres dokumentene?**
→ Dynamisk → RAG (indexer kan inkrementelt oppdateres). Statisk → long-context kan være OK.
6. **Er conversation history viktig?**
→ Ja → reserver 25k tokens for history. Implementer auto-truncation (tiktoken).
7. **Har dere eksisterende vektor-database?**
→ Ja → bruk RAG. Nei → vurder om long-context er enklere (men dyrere).
8. **Er dette en proof-of-concept eller produksjon?**
→ POC: Long-context er raskere å sette opp. Produksjon: RAG er mer kostnadseffektivt.
### Fallgruver
| Fallgruve | Hvorfor det skjer | Hvordan unngå |
|-----------|-------------------|---------------|
| **Oversender context** | Arkitekt antar "mer context = bedre svar" | Bruk semantic ranking, test med ulike top-k verdier |
| **Glemmer token counting** | Utvikler sender raw text uten å sjekke lengde | Implementer tiktoken pre-request validation |
| **Ignorerer lost-in-the-middle** | Stoler blindt på long-context models | Kjør ablation test: plasser svar i start vs. midt vs. slutt av prompt |
| **Manglende response buffer** | Regner kun input tokens, ikke output | Alltid reserver 1520% av context window for completion |
### Anbefalinger per Modenhetsnivå
**Nivå 1 (Starter med RAG):**
- Bruk GPT-4o-mini + classical RAG (top-10 chunks, hybrid search)
- Implementer token counting med tiktoken før hver request
- Sett `max_prompt_tokens=10000`, `max_completion_tokens=2000`
**Nivå 2 (Optimaliserer for produksjon):**
- Oppgrader til GPT-4o eller GPT-4.1 for bedre quality
- Implementer adaptive top-k (flere chunks for komplekse queries)
- Bruk Azure AI Search semantic ranking (re-rank top-50 til top-10)
- Monitorering: Track average tokens per query, cost per user
**Nivå 3 (Advanced RAG arkitektur):**
- Hybrid: Klassisk RAG for presise queries, long-context for exploratory
- Implementer query classification (LLM bestemmer om RAG eller long-context)
- Bruk Assistants API med custom truncation strategy
- A/B-testing av ulike context window sizes for å optimalisere cost/quality trade-off
---
## Kilder og verifisering
### Microsoft Learn (Verified via MCP)
1. **Azure OpenAI Assistants API — Context Window Management**
https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/assistants#context-window-management
*Dekning: max_prompt_tokens, max_completion_tokens, truncation strategy, File Search recommendations*
**Confidence: Verified**
2. **Retrieval-augmented Generation (RAG) in Azure AI Search**
https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview
*Dekning: Token constraint challenges, agentic vs. classic RAG, lost-in-the-middle effects*
**Confidence: Verified**
3. **Azure OpenAI in Microsoft Foundry Models — Quotas and Limits**
https://learn.microsoft.com/en-us/azure/ai-foundry/openai/quotas-limits
*Dekning: TPM limits per model, context window sizes, rate limits*
**Confidence: Verified**
4. **Azure OpenAI On Your Data — Token Usage Estimation**
https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/use-your-data#token-usage-estimation-for-azure-openai-on-your-data
*Dekning: Intent prompt vs. generation prompt token breakdown, RAG pipeline token costs*
**Confidence: Verified**
5. **Improve RAG Chain Quality (Azure Databricks)**
https://learn.microsoft.com/en-us/azure/databricks/generative-ai/tutorials/ai-cookbook/quality-rag-chain#llm
*Dekning: LLM parameter optimization, model selection for RAG, token constraints*
**Confidence: Verified**
6. **Chat Markup Language ChatML — Managing Conversations**
https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/chat-markup-language#preventing-unsafe-user-inputs
*Dekning: Token counting med tiktoken, conversation history truncation*
**Confidence: Verified**
7. **Code Sample: Token Counting with tiktoken (Python)**
https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/chatgpt
*Dekning: Praktisk implementasjon av token management i conversation loops*
**Confidence: Verified**
### Konfidensnivå per Seksjon
| Seksjon | Konfidens | Kilde |
|---------|-----------|-------|
| Azure OpenAI Context Limits | **Verified** | Microsoft Learn (quotas-limits) |
| Assistants API Token Management | **Verified** | Microsoft Learn (assistants API docs) |
| Token Usage Estimation | **Verified** | Microsoft Learn (use-your-data) |
| Lost-in-the-Middle Effect | **Baseline** | Generell forskning (ikke Microsoft-spesifikk) |
| Sliding Window Pattern | **Baseline** | Arkitekturmønster (ikke GA i Azure) |
| Token Pricing | **Verified** | Azure OpenAI Pricing (per februar 2026) |
| Semantic Kernel Token Management | **Baseline** | API-dokumentasjon, ikke testet i MCP |
---
**Oppsummering:**
Context window management er kritisk for RAG-suksess. Velg riktig strategi basert på dokumentstørrelse, query type, kostnad og latency-krav. Bruk token counting (tiktoken) for å unngå context limit errors, og vurder hybrid approach (RAG for presise queries, long-context for analyse) for avanserte use cases. Husk: Større context window betyr ikke alltid bedre svar — lost-in-the-middle effekten er reell.

View file

@ -0,0 +1,419 @@
# RAG Core Patterns and Architecture
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Retrieval-Augmented Generation (RAG) er en arkitektonisk tilnærming som kombinerer informasjonshenting med generativ AI for å produsere faktagrunnede, domene-spesifikke svar. I stedet for å stole utelukkende på en language models forhåndstrente kunnskap, henter RAG-systemer relevant kontekst fra eksterne kunnskapsbaser i sanntid og bruker denne som grunnlag for generering. Dette reduserer hallusinasjoner, tillater kontinuerlig oppdatering av kunnskap uten retrening, og muliggjør svar basert på proprietær eller fersk data.
For enterprise-organisasjoner representerer RAG en praktisk vei til produksjon av AI-løsninger som er både presise og etterprøvbare. Microsoft-økosystemet tilbyr en komplett stack for RAG: Azure AI Search for indeksering og søk, Azure OpenAI Service for generering, Azure AI Foundry for orkestrering, og Copilot Studio for low-code RAG-agenter. RAG brukes i alt fra kunnskapssøk og dokumentanalyse til kundeservice og beslutningsstøtte.
Det finnes tre hovedarkitekturer: **Naive RAG** (enkel retrieve-then-generate), **Advanced RAG** (med pre/post-processing og reranking), og **Agentic RAG** (autonome agenter som planlegger og itererer). Valg av mønster avhenger av use case-kompleksitet, krav til presisjon, og tilgjengelig modenhet.
---
## Kjernekomponenter i RAG-arkitektur
En RAG-pipeline består av følgende byggeklosser:
| Komponent | Ansvar | Microsoft-tjenester |
|-----------|--------|---------------------|
| **Document Ingestion** | Laste inn, parse og chunke dokumenter | Azure AI Document Intelligence, Azure Functions |
| **Embedding Generation** | Konvertere tekst til vektorer | Azure OpenAI (text-embedding-3-large, text-embedding-ada-002) |
| **Vector Store** | Lagre og indeksere embeddings | Azure AI Search, Azure Cosmos DB (MongoDB vCore) |
| **Retrieval** | Søke etter relevante chunks basert på query | Azure AI Search (vector, hybrid, semantic search) |
| **Reranking** | Sortere resultater etter relevans | Azure AI Search Semantic Ranker, custom models |
| **Context Assembly** | Bygge prompt med retrieved chunks | Semantic Kernel, LangChain, Prompt flow |
| **Generation** | Generere svar basert på context | Azure OpenAI Service (GPT-4, GPT-4o) |
| **Citation Tracking** | Spore kilder og gi referanser | Custom logic, Azure AI Search metadata |
**Typisk RAG-flyt:**
1. **Indexing (offline):** Dokumenter lastes inn → chunkes → embeddes → lagres i vector store
2. **Query (runtime):** User query → embedding → vector search → reranking → top-k chunks
3. **Generation:** Chunks + query → prompt template → LLM → response + citations
**Eksempel: Enkel RAG-flyt i Python (Semantic Kernel)**
```python
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureTextEmbedding
from semantic_kernel.connectors.memory.azure_cognitive_search import AzureCognitiveSearchMemoryStore
# Setup
kernel = Kernel()
kernel.add_chat_service("chat", AzureChatCompletion(...))
kernel.add_text_embedding_generation_service("embedding", AzureTextEmbedding(...))
memory = AzureCognitiveSearchMemoryStore(...)
# Index (offline)
await memory.save_information_async("docs", id="1", text="Microsoft Copilot Studio allows...")
# Retrieve + Generate (runtime)
results = await memory.search_async("docs", "What is Copilot Studio?", limit=3)
context = "\n".join([r.text for r in results])
prompt = f"Context:\n{context}\n\nQuestion: What is Copilot Studio?\nAnswer:"
response = await kernel.invoke_semantic_async(prompt)
```
---
## Arkitekturmønstre
### 1. Naive RAG
**Beskrivelse:** Enkel retrieve-then-generate pipeline uten pre/post-processing.
**Flyt:**
1. Embed user query
2. Vector search → top-k chunks
3. Inject chunks i prompt
4. Generate response
**Når bruke:**
- MVP/proof-of-concept
- Enkle kunnskapssøk med begrenset datamengde
- Lavt krav til presisjon
**Fordeler:**
- Rask implementering (dager)
- Lav kompleksitet
- Enkel feilsøking
**Ulemper:**
- Dårlig håndtering av komplekse queries
- Ingen optimalisering av chunk-relevans
- Begrensede citation capabilities
**Typisk bruk:** Intern FAQ-bot, proof-of-concept for ledelse, enkel dokumentsøk.
---
### 2. Advanced RAG
**Beskrivelse:** Forbedret pipeline med query processing, hybrid search, reranking, og post-processing.
**Flyt:**
1. **Pre-retrieval:** Query expansion, intent detection, filter inference
2. **Retrieval:** Hybrid search (vector + BM25) + metadata filtering
3. **Post-retrieval:** Reranking (semantic ranker), deduplication, chunk selection
4. **Generation:** Context-optimized prompt + citation tracking
**Når bruke:**
- Produksjonsløsninger med krav til presisjon
- Store kunnskapsbaser (>10,000 dokumenter)
- Behov for verifiable citations
**Fordeler:**
- Høyere relevans (20-40% forbedring vs naive)
- Bedre håndtering av komplekse queries
- Citation tracking og source attribution
- Robusthet mot ambiguity
**Ulemper:**
- Høyere latency (2-5x vs naive)
- Mer kompleks pipeline å vedlikeholde
- Høyere kostnader (reranking, query expansion)
**Typisk bruk:** Enterprise kunnskapssøk, regulatory compliance bots, kundeservice med SLA-krav.
---
### 3. Agentic RAG
**Beskrivelse:** Autonome agenter som planlegger, itererer, og velger retrieval-strategi dynamisk.
**Flyt:**
1. **Planning:** Agent analyserer query → dekomponerer i sub-tasks
2. **Tool Selection:** Agent velger search-strategi (vector, keyword, multi-index, web)
3. **Iterative Retrieval:** Agent henter data → evaluerer relevans → henter mer hvis nødvendig
4. **Self-Reflection:** Agent vurderer om nok kontekst er samlet
5. **Generation:** Syntetiserer svar basert på aggregert kontekst
**Når bruke:**
- Komplekse, multi-hop reasoning tasks
- Cross-domain queries (søk i flere databaser)
- Research-assistenter og analytical agents
**Fordeler:**
- Høyest presisjon for komplekse queries
- Selvkorrigerende (kan omformulere og re-query)
- Kan kombinere multiple sources (docs, web, APIs)
**Ulemper:**
- Høy latency (10-60 sekunder)
- Høy token-kostnad (multiple LLM calls)
- Kompleks debugging og observability
**Typisk bruk:** Research assistants, regulatory analysis, cross-domain intelligence.
**Eksempel: Agentic RAG med Microsoft Agent Framework**
```python
from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.agents.strategies import TerminationStrategy
# Define retrieval tool
@kernel_function(name="search_docs", description="Search knowledge base")
async def search_docs(query: str) -> str:
results = await memory.search_async("docs", query, limit=5)
return "\n".join([r.text for r in results])
# Create agent with tools
agent = ChatCompletionAgent(
kernel=kernel,
name="ResearchAgent",
instructions="You are a research assistant. Use search_docs to find information, then synthesize.",
tools=[search_docs]
)
# Run
result = await agent.invoke_async("What are the compliance requirements for AI in Norwegian public sector?")
```
---
## Beslutningsveiledning
### Mønster-valg: Når bruke hva?
| Kriterium | Naive RAG | Advanced RAG | Agentic RAG |
|-----------|-----------|--------------|-------------|
| **Use case-kompleksitet** | Enkel FAQ, direktesøk | Enterprise kunnskapssøk, compliance | Multi-hop reasoning, research |
| **Datamengde** | <1,000 dokumenter | 1,000-100,000+ | Ubegrenset (multi-source) |
| **Latency-krav** | <1s | 1-3s | 10-60s |
| **Presisjonskrav** | Lav (70-80% recall) | Høy (90%+ recall) | Kritisk (95%+ recall) |
| **Citation-krav** | Valgfri | Påkrevd | Påkrevd + traceability |
| **Kostnadssensitivitet** | Lav (få tokens) | Moderat | Høy (mange LLM calls) |
| **Modenhet i org** | MVP-fase | Produksjon | Advanced AI-team |
### Vanlige feil og misforståelser
| Misforståelse | Realitet |
|---------------|----------|
| "RAG eliminerer hallusinasjoner" | RAG reduserer, men eliminerer ikke hallusinasjoner. LLM kan fortsatt generere feil basert på dårlig kontekst. |
| "Større chunks gir bedre svar" | Større chunks gir mer kontekst, men reduserer presisjon. Optimal chunk size: 512-1024 tokens med 10-20% overlap. |
| "Vector search er nok" | Vector search alene misser keyword matches. Hybrid search (vector + BM25) gir 15-30% bedre recall. |
| "RAG fungerer out-of-the-box" | RAG krever tuning: chunk size, embedding model, retrieval-k, reranking, prompt engineering. |
| "Long-context models erstatter RAG" | Long-context (128K tokens) er dyrt og tregere. RAG er mer kostnadseffektivt for store kunnskapsbaser. |
### Røde flagg
- **Ingen metadata-strategi:** Uten metadata (source, date, category) er filtrering og citation umulig.
- **Hardkodet chunk size:** Ulike dokumenttyper (tabeller, prosatekst, kode) krever ulike chunk-strategier.
- **Manglende reranking:** Vector search alene gir ofte irrelevante chunks i top-3. Reranking er kritisk.
- **Ingen evaluation metrics:** Uten retrieval recall/precision og generation fidelity er tuning blindflyvning.
- **Token overflow:** Uten context window management risikerer du truncation og tap av relevante chunks.
---
## In-Context Learning vs RAG
**In-Context Learning (ICL):** Gi LLM all kontekst i prompten (few-shot examples, dokumenter, data).
**Når bruke ICL:**
- Liten kunnskapsbase (<10 dokumenter, <50K tokens)
- Statisk data som sjeldent endres
- Behov for rask prototyping uten infrastruktur
**Når bruke RAG:**
- Stor kunnskapsbase (>50K tokens)
- Dynamisk data som oppdateres hyppig
- Behov for citation og source tracking
- Kostnadsoptimalisering (vector search er billigere enn å sende 100K tokens per query)
**Long-Context Models (GPT-4 Turbo 128K):**
- Tillater større ICL-windows
- **Men:** Høyere latency, høyere kostnad, "lost-in-the-middle" problem (LLM prioriterer start/slutt av context)
- **Hybrid-tilnærming:** Bruk RAG for retrieval → inject top-k chunks i long-context model
---
## Integrasjon med Microsoft-stakken
### Azure AI Search (kjernen i RAG)
| Funksjon | Bruk i RAG |
|----------|-----------|
| **Vector search** | Embedding-basert retrieval (cosine similarity, HNSW indexing) |
| **Hybrid search** | Kombinerer vector + BM25 for bedre recall |
| **Semantic Ranker** | L2 reranking basert på cross-encoder (20-30% relevance boost) |
| **Metadata filtering** | Filtrering på dato, category, access control |
| **Skillset API** | Document cracking, OCR, entity extraction pre-indexing |
**Eksempel: Hybrid search query**
```python
from azure.search.documents import SearchClient
results = search_client.search(
search_text="What is Copilot Studio?", # BM25
vector_queries=[VectorQuery(
vector=query_embedding, # Vector
k_nearest_neighbors=50,
fields="contentVector"
)],
select=["id", "content", "sourcePage", "category"],
top=10
)
```
### Azure AI Foundry
- **Prompt flow:** Visuell orkestrasjon av RAG-pipelines (indexing → retrieval → generation)
- **Evaluation:** Built-in metrics (groundedness, relevance, coherence)
- **Tracing:** End-to-end observability av RAG-calls
### Semantic Kernel
- **Memory connectors:** Abstraksjon over Azure AI Search, Cosmos DB, Qdrant
- **Plugins:** Modulær arkitektur for retrieval functions
- **Planner:** Agent-basert orkestrering for Agentic RAG
### Copilot Studio
- **Generative answers:** Low-code RAG med Azure AI Search + SharePoint
- **Knowledge sources:** Drag-and-drop indexing av docs, websites
- **Conversation boosting:** Automatisk faller tilbake på RAG hvis intent ikke matches
---
## Offentlig sektor (Norge)
### Datasuverenitet og residency
| Krav | RAG-implikasjon |
|------|-----------------|
| **GDPR Art. 32 (sikkerhet)** | Embeddings kan inneholde PII. Krypter vector store, bruk Managed Identity for autentisering. |
| **Schrems II (dataoverføring)** | Bruk Azure Norway regions (Norway East/West). Sjekk at embeddings ikke sendes utenfor EU. |
| **Forvaltningsloven § 11a (innsyn)** | RAG må kunne vise kilder for svar. Citation tracking er obligatorisk. |
| **AI Act (høyrisiko-AI)** | Hvis RAG brukes i forvaltningsvedtak, krev menneske-i-loop og dokumentasjon av retrieval-logikk. |
### Compliance-sjekkliste
- [ ] **Document-level RBAC:** Filtrer søkeresultater basert på brukers AD-gruppe.
- [ ] **Audit logging:** Logg alle queries, retrieved chunks, og genererte svar (Azure Monitor).
- [ ] **PII detection:** Skann og rediger PII i indexing og output (Azure AI Content Safety).
- [ ] **Data retention:** Definer retention policy for embeddings og logs (6 måneder standard).
- [ ] **Explainability:** Vis alltid kilder, confidence score, og retrieval-logikk.
### Typetilfeller for offentlig sektor
| Use case | RAG-mønster | Compliance-fokus |
|----------|-------------|------------------|
| **Regelverksøk** (lovdata, forskrifter) | Advanced RAG + metadata filtering | Citation, audit logging |
| **Saksbehandler-assistent** | Agentic RAG + document-level RBAC | GDPR, Forvaltningsloven § 11a |
| **Kundeservice chatbot** | Naive RAG (FAQ) | PII redaction, data residency |
| **Policy-analyse** | Agentic RAG + multi-index | AI Act transparency krav |
---
## Kostnad og lisensiering
### Prismodell (per 1,000 brukere/måned, Norge, 2026)
| Komponent | Kostnad (NOK) | Merk |
|-----------|---------------|------|
| **Azure AI Search (S1, 10M vectors)** | 15,000 | Semantic Ranker: +5,000 NOK |
| **Azure OpenAI embeddings (text-embedding-3-large, 1B tokens)** | 1,500 | Batching reduserer kostnad 50% |
| **Azure OpenAI generation (GPT-4o, 10M tokens output)** | 60,000 | Input tokens: 20,000 NOK |
| **Azure AI Document Intelligence (10K pages)** | 1,200 | For document cracking |
| **Azure Monitor (logging)** | 2,000 | For audit trails |
| **Total (Advanced RAG)** | ~83,700 NOK/mnd | Naive RAG: ~50,000 (uten reranking/DI) |
### Kostnadsoptimaliseringstips
1. **Caching:** Cache embeddings for repeterte queries (50-70% kostnadskutt).
2. **Batching:** Batch embedding-generering (50% rabatt via Azure OpenAI batch API).
3. **Chunk reuse:** Generer embeddings én gang, ikke per user session.
4. **Model downgrade:** Bruk text-embedding-ada-002 (10x billigere) for non-critical use cases.
5. **Semantic Ranker on-demand:** Aktiver kun for complex queries (identifiser via query length/complexity).
6. **Hybrid caching:** Cache både retrieval results og generated responses (LLM cache hit = gratis).
---
## For arkitekten (Cosmo)
### Nøkkelspørsmål å stille kunden
1. **Datakilde:** Hvor ligger kunnskapsbasen? (SharePoint, Dataverse, SQL, filshare, ekstern API?)
2. **Data-dynamikk:** Hvor ofte endres dataen? (Sanntid, daglig, månedlig, statisk?)
3. **Query-kompleksitet:** Enkle spørsmål ("Hva er...") eller multi-hop reasoning ("Sammenlign X og Y basert på Z")?
4. **Citation-krav:** Må systemet vise kilder? Hvor granulært (dokument, side, paragraf)?
5. **Latency-toleranse:** Akseptabel responstid? (<1s, 1-3s, >5s?)
6. **Compliance:** GDPR, Schrems II, AI Act? Offentlig sektor?
7. **Volum:** Hvor mange dokumenter? Hvor mange queries per dag?
8. **Tilgangskontroll:** Trenger brukere ulik tilgang til dokumenter? (RBAC, document-level filtering?)
### Vanlige fallgruver
| Fallgruve | Hvordan unngå |
|-----------|---------------|
| **For store chunks** | Test chunk sizes (256, 512, 1024 tokens). Mål retrieval recall. |
| **Manglende metadata** | Alltid legg til source, date, category, access_control ved indexing. |
| **Ingen reranking** | Semantic Ranker gir 20-30% bedre relevans. Alltid inkluder i prod. |
| **Hardkodet prompts** | Bruk parametriserte prompt templates. Test med ulike query-typer. |
| **Token overflow** | Monitor context window usage. Implementer chunk truncation-logikk. |
| **Ingen evaluation** | Definer retrieval recall/precision targets. Bruk Azure AI Foundry evaluation. |
### Anbefalinger per modenhetsnivå
| Modenhet | RAG-mønster | Tooling | Tidsestimat |
|----------|-------------|---------|-------------|
| **Pilot** (MVP) | Naive RAG | Copilot Studio generative answers | 1-2 uker |
| **Produksjon** (scale) | Advanced RAG | Azure AI Foundry Prompt flow + Semantic Kernel | 6-8 uker |
| **Advanced** (complex) | Agentic RAG | Microsoft Agent Framework + custom agents | 12-16 uker |
### Quick-start playbook
**Uke 1-2: Indexing**
1. Document cracking (Azure AI Document Intelligence)
2. Chunking (512 tokens, 10% overlap)
3. Embedding generation (text-embedding-3-large)
4. Indexing i Azure AI Search
**Uke 3-4: Retrieval**
1. Hybrid search setup (vector + BM25)
2. Semantic Ranker aktivering
3. Metadata filtering (source, date, category)
4. Retrieval evaluation (recall@10)
**Uke 5-6: Generation**
1. Prompt engineering (system prompt + context injection)
2. Citation tracking (source attribution i output)
3. Hallucination mitigation (grounding prompts)
4. Output evaluation (groundedness, relevance)
**Uke 7-8: Produksjonisering**
1. Caching (query results + LLM responses)
2. Observability (Azure Monitor + Application Insights)
3. RBAC enforcement (document-level filtering)
4. Load testing (concurrent users, latency targets)
---
## Kilder og verifisering
### Microsoft Learn-referanser
- [What is Retrieval Augmented Generation with Azure AI Search?](https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview) (GA)
- [Hybrid search in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/hybrid-search-overview) (GA)
- [Semantic ranking in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/semantic-search-overview) (GA)
- [Integrate Azure OpenAI with Azure AI Search](https://learn.microsoft.com/en-us/azure/search/vector-search-integrated-vectorization-ai-studio) (GA)
- [Use generative answers in Copilot Studio](https://learn.microsoft.com/en-us/microsoft-copilot-studio/nlu-boost-conversations) (GA)
- [Semantic Kernel memory and embeddings](https://learn.microsoft.com/en-us/semantic-kernel/memories/) (GA)
- [Azure AI Foundry prompt flow for RAG](https://learn.microsoft.com/en-us/azure/ai-studio/how-to/flow-develop) (GA)
### Konfidensnivå
- **Verified:** Arkitekturmønstre, Azure AI Search features, Azure OpenAI embeddings, Semantic Kernel patterns (basert på Microsoft Learn + GA-tjenester)
- **Baseline:** Kostnadsestimater (basert på Azure pricing januar 2026, kan variere per region)
- **Assumed:** Agentic RAG adoption timeline (basert på current preview status i Microsoft Agent Framework)
---
**For Cosmo:** Når kunde spør om RAG, start med "Naive vs Advanced vs Agentic"-beslutningstreet. Identifiser data source, query complexity, og latency-krav først. Hvis offentlig sektor: alltid spør om GDPR/Schrems II/AI Act compliance før du foreslår arkitektur. Hvis customer mangler evaluation strategy: stopp og definer retrieval recall/precision targets før du går videre med implementation.

View file

@ -0,0 +1,543 @@
# RAG Cost Optimization and Efficiency
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Kostnadsoptimalisering av RAG-løsninger (Retrieval-Augmented Generation) handler om å balansere tre faktorer: kvalitet, ytelse og kostnad. En RAG-arkitektur har flere kostnadsdrivere fra embedding-generering og vektorindeksering til API-kall mot language models og lagring i Azure AI Search. Denne guiden dekker strategier for å redusere kostnader uten å ofre kvalitet, med fokus på Microsoft AI-stakken.
RAG-kostnader kan deles i to hovedkategorier: engangskostnader (data pipeline, embedding-generering, indeksering) og løpende driftskostnader (queries, inferencing, hosting). Begge kategoriene krever ulike optimeringsstrategier. Nøkkelen er å forstå hvilke komponenter som driver kostnadene, og implementere målrettede tiltak for hver av dem.
For offentlig sektor i Norge er kostnadseffektivitet spesielt viktig grunnet budsjettbegrensninger, anskaffelsesregler og krav til dokumentasjon. RAG-løsninger kan raskt bli kostbare hvis de ikke designes med kostnadsbevissthet fra start. Denne guiden gir konkrete verktøy og metoder for å holde kostnadene under kontroll.
## Kjernekomponenter
### 1. Azure AI Search Tier Selection
Valg av Azure AI Search pricing tier er avgjørende for total kostnad:
| Tier | Use Case | Storage | QPM Limit | Pris/mnd (estimat) |
|------|----------|---------|-----------|-------------------|
| **Free** | POC, testing | 50 MB | Begrenset | NOK 0 |
| **Basic** | Små produksjonsløsninger | 2 GB | Moderat | ~NOK 700 |
| **S1** | Standard produksjon | 25 GB/partition | Høy | ~NOK 2,500 |
| **S2** | Store løsninger | 100 GB/partition | Meget høy | ~NOK 10,000 |
| **S3 HD** | Multitenant, mange små indekser | 200 GB | Høy | ~NOK 20,000 |
| **L1/L2** | Storage-optimized, sjeldne queries | 1 TB+ | Lavere | ~NOK 15,000+ |
**Viktig:** Services opprettet etter april 2024 får større partitions til samme pris. Basic og S1 gir full API-tilgang til laveste per-SU-rate.
### 2. Token Cost Reduction Strategies
Azure OpenAI-kostnader er tokene-basert. Redusering av token-forbruk gir direkte kostnadsbesparelse:
**Input token optimization:**
- **Chunk size tuning:** Bruk minste chunk size som gir tilstrekkelig kontekst (512-1024 tokens typisk)
- **Retrieval filtering:** Hent kun relevante chunks (k=3-5 i stedet for k=10)
- **Prompt compression:** Fjern overflødig tekst fra system prompts
- **Query optimization:** Pre-prosesser brukerqueries for å redusere lengde
**Output token optimization:**
- **max_tokens parameter:** Sett eksplisitt grense for respons-lengde
- **Stream responses:** Bruk streaming for bedre UX og kontroll
- **Stop sequences:** Definer stop tokens for å unngå unødvendig generering
**Batch processing:**
- Azure OpenAI Batch API: 50% rabatt sammenlignet med standard API
- Ideal for offline-prosessering (dokumentanalyse, bulk-embedding)
- 24-timers SLA, separat quota, ingen påvirkning av online workloads
### 3. Embedding Model Selection
Embedding models har direkte kostnad-påvirkning både i generering og lagring:
| Model | Dimensions | Cost/1M tokens | Storage Impact | Use Case |
|-------|-----------|----------------|----------------|-----------|
| **text-embedding-ada-002** | 1536 | ~NOK 1.00 | Standard | Legacy, deprecated |
| **text-embedding-3-small** | 512-1536 | ~NOK 0.20 | Kompakt | Kostnadseffektiv |
| **text-embedding-3-large** | 1024-3072 | ~NOK 1.30 | Større | Høy presisjon |
| **Multilingual-e5-large** | 1024 | Varierer | Standard | Flerspråklig |
**Dimensionality reduction:**
- text-embedding-3-* modeller støtter dimensionality reduction
- Reduserer lagringskostnader i vektor-database
- Minimal kvalitetstap for mange use cases (test før deployment)
**Caching strategies:**
- Cache embeddings for repeterende queries
- Bruk Azure Cache for Redis eller Cosmos DB
- TTL-basert invalidering for fresh data
### 4. Index Size Management
Vector index størrelse påvirker både lagring og query-kostnader:
**Compression techniques:**
- **Scalar quantization:** Reduserer vector storage med 75% (float32 → int8)
- **Binary quantization:** 96.875% reduksjon, egnet for mange use cases
- Azure AI Search støtter built-in compression (opptil 92.5% kostnadsreduksjon)
**Incremental indexing:**
- Index kun nye/endrede dokumenter, ikke hele corpus
- Bruk `indexAction` parameter i indexer-pipelines
- Reduserer AI enrichment-kostnader ved re-indexing
**Enrichment caching:**
- Cache AI enrichment-resultater i Azure Storage
- Gjenbruk tidligere prosesserte data ved re-indexing
- Lagringskostnad << enrichment-kostnad for store volumer
### 5. Query Optimization
Query-typer har ulik kostnad og performance-profil:
| Query Type | Speed | Cost | Accuracy | When to Use |
|------------|-------|------|----------|-------------|
| **Vector only** | Rask | Medium | Høy semantic | Semantic likhet viktig |
| **Keyword only** | Raskest | Lavest | Høy presisjon | Eksakte matches |
| **Hybrid** | Moderat | Høyere | Best | Balansert relevans |
| **Semantic ranking** | Tregere | Premium charge | Svært høy | Viktigste queries |
**Hybrid search optimization:**
- Kombiner keyword + vector for best relevans/kostnad-ratio
- Bruk keyword pre-filtering før vector search
- Progressive retrieval: start billig, eskalér ved behov
**Semantic ranker (premium feature):**
- Koster per query (NOK ~0.50-2.00 per 1000 queries)
- Bruk selektivt for høy-verdi queries
- A/B-test mot hybrid search for ROI-validering
### 6. Scaling Strategies
Azure AI Search-kostnader skalerer ikke-lineært:
**Dynamic scaling:**
- Scale up for indexing workloads, scale down for query-only periods
- Automate scaling med Azure Functions/Logic Apps
- **Viktig:** Doubling capacity > doubles cost på samme tier
**Tier switching optimization:**
- S1 med mange replicas/partitions kan være dyrere enn S2 base
- S2 har bedre compute og mer minne per SU
- Kalkuler break-even point før scaling horisontalt
**Replica vs. partition tuning:**
- **Partitions:** Øker storage og indexing throughput
- **Replicas:** Øker query capacity og redundans
- Legg til partitions kun når index size eller ingestion krever det
- Legg til replicas kun når QPS er for høyt eller HA trengs
## Arkitekturmønstre
### 1. Tiered Search Architecture
**Konsept:** Bruk billige søk først, eskalér til dyre kun ved behov.
**Implementering:**
```
User Query
1. Keyword Search (billigst, raskest)
↓ [hvis < 5 resultater med score > 0.8]
2. Vector Search (dyrere, saktere)
↓ [hvis < 3 resultater med score > 0.85]
3. Hybrid + Semantic Ranker (dyrest, best)
```
**Fordeler:**
- Reduserer kostnad for 70-80% av queries
- Bedre latency for enkle queries
- Bevarer kvalitet for komplekse queries
**Ulemper:**
- Kompleksitet i query-routing logikk
- Potential for inkonsistent UX
- Krever grundig testing av thresholds
### 2. Smart Caching with Embeddings
**Konsept:** Cache både embeddings og query-resultater for å redusere API-kall.
**Implementering:**
```
Query → Hash → Cache Lookup (Redis)
↓ [cache miss]
Generate Embedding (Azure OpenAI)
Store in Cache (TTL: 7 days)
Vector Search → Cache Results (TTL: 1 hour)
```
**Fordeler:**
- Eliminerer duplicate embedding-generering
- Reduserer Azure OpenAI API-kostnader med 40-60%
- Raskere response times
**Ulemper:**
- Cache-infrastruktur koster (men mindre enn API-kall)
- TTL-tuning krever monitorering
- Stale data-risiko for dynamiske corpus
### 3. Model Cascading
**Konsept:** Bruk billige modeller for enkle oppgaver, dyre for komplekse.
**Implementering:**
```
Simple Query → GPT-4o-mini (billig, rask)
↓ [hvis confidence < 0.7]
Complex Query → GPT-4o (dyrere, smartere)
↓ [hvis krever reasoning]
Multi-step Task → GPT-4o + reasoning mode
```
**Fordeler:**
- Optimaliserer kostnad per query-type
- GPT-4o-mini kan være 10x billigere
- Bevarer kvalitet for viktige queries
**Ulemper:**
- Confidence scoring krever testing
- Latency øker ved escalation
- Kompleks orchestration-logikk
## Beslutningsveiledning
### Når skal jeg velge Basic vs. S1?
| Scenario | Anbefaling | Begrunnelse |
|----------|-----------|-------------|
| Pilot med < 10K dokumenter | **Basic** | Koster ~1/3 av S1, tilstrekkelig for testing |
| Produksjon < 100K dokumenter | **Basic** | Kan skalere til 3 replicas for HA |
| Produksjon > 100K dokumenter | **S1** | Bedre partition size, raskere indexing |
| Multitenant med mange små indekser | **S3 HD** | Optimalisert for høy index-count |
| Stort arkiv, sjeldne queries | **L1/L2** | Beste storage/kostnad-ratio |
### Vanlige feil
1. **Over-embedding:** Generere embeddings for alt innhold, også metadata/headers
- **Fix:** Kun embed semantisk meningsfylt tekst
2. **Over-indexing:** Re-index hele corpus ved små endringer
- **Fix:** Incremental indexing + enrichment cache
3. **Over-retrieving:** Hente k=10-20 chunks per query
- **Fix:** Start med k=3-5, øk kun hvis nødvendig
4. **Ignoring compression:** Bruke full float32 vectors
- **Fix:** Aktiver scalar/binary quantization i Azure AI Search
5. **No caching:** Generere embeddings på nytt for like queries
- **Fix:** Implementer embedding cache med Redis
### Røde flagg
- **Token usage øker > 50% per måned** uten økning i brukere → sjekk for ineffektive prompts
- **Index size > 10x source data** → sjekk for duplikater eller unødvendig enrichment
- **Query latency > 2 sekunder** → vurder høyere tier eller optimalisering
- **Costs > NOK 50,000/mnd** for < 10,000 queries/dag → arkitektur-review nødvendig
## Integrasjon med Microsoft-stakken
### Azure Cost Management
**Setup:**
```bash
# Opprett budget alert via Azure CLI
az consumption budget create \
--name "AI-Search-Monthly-Budget" \
--amount 10000 \
--time-grain Monthly \
--category Cost \
--resource-group <rg-name>
```
**Best practices:**
- Sett budgets per resource group (Search, OpenAI separat)
- Opprett alerts på 50%, 80%, 100% av budget
- Exporter cost data til Power BI for analyse
### Azure Monitor
**Key metrics å overvåke:**
| Metric | Threshold | Action |
|--------|-----------|--------|
| **QPS (Queries/sec)** | > 80% av tier limit | Øk replicas eller tier |
| **Throttled queries** | > 5% | Øk capacity eller optimaliser queries |
| **Index size growth** | > 20%/mnd | Review chunking strategy |
| **Token usage trend** | > 30% økning | Audit prompt efficiency |
**Alerting-regel eksempel:**
```kusto
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.SEARCH"
| where OperationName == "Query.Search"
| summarize AvgDuration=avg(DurationMs), Count=count() by bin(TimeGenerated, 1h)
| where AvgDuration > 2000 // Alert hvis avg > 2 sekunder
```
### Azure Advisor
Azure Advisor gir automatiske cost optimization-anbefalinger:
- **Right-sizing:** Forslag til tier-nedgradering hvis under-utilized
- **Idle resources:** Detekterer ubrukte search services
- **Reservation recommendations:** RI-forslag for predictable workloads
**Aksjonspunkt:** Reviewer Advisor recommendations månedlig.
## Offentlig sektor (Norge)
### Budsjettplanlegging
**Anskaffelsescykluser:**
- Årlige budsjetter krever presis kostnadsprediksjon
- Bruk 6-måneders pilot med 1-5% av data for estimering
- Buffer med 20-30% for uforutsett vekst
**Kostnadsfordelingsmodell for delt infrastruktur:**
| Kostnadselement | Allokering | Metode |
|----------------|-----------|--------|
| **Azure AI Search base** | Per avdeling | Fixed % basert på index size |
| **Azure OpenAI tokens** | Per query | Pay-per-use tracking med tags |
| **Storage (embeddings)** | Per prosjekt | Direkte kostnad per resource group |
### Anskaffelsesregler
**LDO-kompabilitet (Lov om offentlige anskaffelser):**
- Azure Enterprise Agreements (EA) er pre-approved for stat
- Commitment-based pricing krever godkjenning for > NOK 100,000
- Dokumenter cost-benefit analysis for RAG vs. alternativer
**Multi-year contracts:**
- Azure Reservations (1-3 år) gir 30-60% rabatt
- Krev break-even analysis og usage forecasting
- Kun for stabile workloads (produksjon, ikke pilot)
### Kostnadsrapportering
**Kvartalsrapportering til departement:**
```
Q1 2026 RAG Cost Breakdown:
- Azure AI Search (S1, 2 replicas): NOK 5,000
- Azure OpenAI (gpt-4o, 10M tokens): NOK 12,000
- Storage (embeddings + cache): NOK 800
- Networking: NOK 200
Total: NOK 18,000
Metrics:
- 25,000 queries served
- NOK 0.72 per query
- 95% user satisfaction
```
**KPI-er for cost efficiency:**
- **Cost per query** (target: < NOK 1.00 for offentlig sektor)
- **Cost per user** (monthly active users)
- **ROI:** Time saved × hourly rate > RAG costs
## Kostnad og lisensiering
### Azure AI Search Pricing (Norge, 2026)
| Tier | Hourly Rate (NOK) | Monthly (730 hrs) | Search Units (SU) | Note |
|------|-------------------|-------------------|-------------------|------|
| Free | 0.00 | 0 | 1 | 50 MB, 1 index limit |
| Basic | ~1.00 | ~730 | 1-3 | 2 GB per partition |
| S1 | ~3.50 | ~2,555 | 1-36 | 25 GB per partition |
| S2 | ~13.50 | ~9,855 | 1-36 | 100 GB per partition |
| S3 | ~27.00 | ~19,710 | 1-36 | 200 GB per partition |
| S3 HD | ~27.00 | ~19,710 | 1-36 | Optimalisert for mange indekser |
| L1 | ~20.00 | ~14,600 | 1-12 | 1 TB per partition |
| L2 | ~40.00 | ~29,200 | 1-12 | 2 TB per partition |
**Viktig:** Kostnader = Base rate × (replicas × partitions). Eks: S1 med 2 replicas og 2 partitions = 4 SU = NOK 10,220/mnd.
### Azure OpenAI Pricing (Norge, 2026)
| Model | Input (per 1M tokens) | Output (per 1M tokens) | Use Case |
|-------|----------------------|------------------------|-----------|
| **gpt-4o** | ~NOK 50 | ~NOK 150 | Høy kvalitet, produksjon |
| **gpt-4o-mini** | ~NOK 1.5 | ~NOK 6 | Kostnadseffektiv, enkle tasks |
| **text-embedding-3-small** | ~NOK 0.20 | N/A | Embeddings, budget-vennlig |
| **text-embedding-3-large** | ~NOK 1.30 | N/A | Embeddings, best performance |
**Batch API:** 50% rabatt på alle modeller (gjelder kun async workloads).
### Premium Features (tilleggskostnader)
| Feature | Kostnad | Påvirkning |
|---------|---------|-----------|
| **Semantic Ranker** | ~NOK 5.00 per 1000 queries | Bedre relevans, dyrere |
| **AI Enrichment (OCR, entities)** | Per 1000 transactions | Variable, kan være høye |
| **Enrichment Cache** | Azure Storage rate | Lav (< NOK 50/mnd typisk) |
| **Knowledge Store** | Azure Storage rate | Lav, avhenger av volum |
| **Customer-managed keys** | Azure Key Vault rate | ~NOK 50/mnd |
### ROI Calculation Framework
**Eksempel: Dokumentsøk for 50 saksbehandlere**
**Før RAG:**
- 30 min/dag manuell søking per person
- 50 personer × 30 min × 220 dager/år = 5,500 timer
- Timerate: NOK 600 → **Årlig kostnad: NOK 3,300,000**
**Med RAG:**
- 10 min/dag RAG-søk (20 min spart)
- 3,667 timer spart × NOK 600 = **NOK 2,200,000 besparelse**
- RAG infrastructure: NOK 250,000/år
- **Netto besparelse: NOK 1,950,000 (591% ROI)**
**Break-even:** 2-3 måneder for typisk offentlig sektor use case.
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **"Hva er dagens månedsbudsjett for denne løsningen, og hva er akseptabel kostnad per query?"**
- Hjelper sette cost constraints fra start
- Typisk target: NOK 0.50-2.00 per query avhengig av kompleksitet
2. **"Hvor mange dokumenter skal indekseres, og hvor ofte endres de?"**
- Bestemmer incremental vs. full re-indexing strategi
- Statisk corpus → billigere, dynamisk → trenger caching
3. **"Hva er forventet query volume, og er det forutsigbart (daglig/ukentlig mønster)?"**
- Forutsigbart → commitment pricing mulig (30-60% rabatt)
- Uforutsigbart → pay-as-you-go, men dyrere
4. **"Hvor viktig er semantic quality vs. eksakt keyword matching?"**
- Høy semantic need → må investere i vector search
- Keyword-tungt → kan spare på hybrid search
5. **"Skal dette være multitenant, og trenger vi cost tracking per bruker/avdeling?"**
- Bestemmer tagging-strategi i Azure
- Påvirker index design (shared vs. separate indexes)
6. **"Hva er tolerance for query latency? (< 1s, < 2s, < 5s?)"**
- Lavere latency → høyere tier nødvendig → dyrere
- Høyere tolerance → kan optimalisere kostnad
7. **"Har dere eksisterende Azure EA eller commitment-avtaler?"**
- Kan påvirke pricing significantly
- Reserved instances tilgjengelig?
8. **"Trenger dere compliance-features som customer-managed keys?"**
- Legger til NOK 50-100/mnd i Key Vault-kostnader
- Kan kreve høyere tiers
### Fallgruver å unngå
1. **"One-size-fits-all embedding model"**
- Mange velger text-embedding-3-large for alt
- Vurder -small for metadata/tags, -large for hoveddokumenter
2. **"No baseline measurement"**
- Start pilot uten å måle initial costs
- Implementer cost tracking fra dag 1 (Azure tags, Cost Management)
3. **"Ignoring regional pricing differences"**
- Azure OpenAI priser varierer per region
- Sweden Central ofte billigere enn Norway East (men vurder dataresidency)
4. **"Over-engineering for pilot phase"**
- Bruker S2 for 1000-dokument POC
- Start med Basic, skalér etterhvert som behov vises
5. **"No query optimization"**
- Sender hele dokumenter som context til LLM
- Chunk smart, retrieve relevant, summarize før sending
6. **"Static scaling"**
- Provisionerer for peak load 24/7
- Implementer dynamic scaling for natt/helg (kan spare 30-40%)
### Anbefalinger per modenhetsnivå
#### Level 1: Pilot/POC (0-3 måneder)
- **Tier:** Basic eller Free
- **Embedding:** text-embedding-3-small
- **LLM:** gpt-4o-mini (95% av queries), gpt-4o (5% komplekse)
- **Caching:** Ikke nødvendig ennå
- **Monitoring:** Gratis Azure Monitor alerts
- **Estimert kostnad:** NOK 1,000-5,000/mnd
#### Level 2: Production MVP (3-12 måneder)
- **Tier:** S1 (1 partition, 2 replicas for HA)
- **Embedding:** text-embedding-3-large (testing for quality)
- **LLM:** gpt-4o (produksjon), cascading til gpt-4o-mini
- **Caching:** Redis Cache for embeddings (Basic tier)
- **Monitoring:** Custom dashboards i Azure Monitor
- **Estimert kostnad:** NOK 15,000-50,000/mnd
#### Level 3: Enterprise Scale (12+ måneder)
- **Tier:** S2 eller S3 (multi-replica, multi-partition)
- **Embedding:** Fine-tuned custom embeddings (vurder)
- **LLM:** gpt-4o med Provisioned Throughput (commitment pricing)
- **Caching:** Redis Premium + enrichment cache
- **Monitoring:** Azure Monitor Workbooks + Power BI dashboards
- **Estimert kostnad:** NOK 100,000-500,000/mnd (avhenger av scale)
#### Level 4: Optimalisert/Mature (18+ måneder)
- **Tier:** Multi-tier architecture (L1/L2 for archival, S3 for active)
- **Embedding:** Custom fine-tuned, dimensionality reduction
- **LLM:** Model cascading, batch processing for non-urgent
- **Caching:** Multi-layer (Redis + CDN for static content)
- **Monitoring:** Predictive cost analytics, automated optimization
- **Estimert kostnad:** Varierer, men typisk 30-50% lavere enn Level 3 for samme throughput
## Kilder og verifisering
### Microsoft Learn Resources (Verified 2026-02)
**Azure AI Search Cost Management:**
- [Plan and manage costs of Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-sku-manage-costs) — *Verified: Comprehensive cost optimization strategies*
- [Choose a service tier for Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-sku-tier) — *Verified: Tier comparison and billing model*
- [Vector compression best practices](https://techcommunity.microsoft.com/blog/azure-ai-services-blog/azure-ai-search-cut-vector-costs-up-to-92-5-with-new-compression-techniques/4404866) — *Verified: Compression techniques (92.5% reduction)*
**Azure OpenAI Cost Management:**
- [Plan and manage costs for Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/manage-costs) — *Verified: Token-based billing, fine-tuning costs*
- [Azure OpenAI Batch API](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/batch) — *Verified: 50% cost reduction for batch workloads*
- [Fine-tuning cost management](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/fine-tuning-cost-management) — *Verified: Hosting + inference + training costs*
**RAG Architecture & Optimization:**
- [RAG design and evaluation guide](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-solution-design-and-evaluation-guide) — *Verified: End-to-end RAG considerations*
- [RAG chunking economics](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-chunking-phase#understand-chunking-economics) — *Verified: Chunking cost optimization*
- [RAG embedding economics](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-generate-embeddings#understand-embedding-economics) — *Verified: Embedding model selection trade-offs*
- [Retrieval cost and latency considerations](https://learn.microsoft.com/en-us/azure/ai-foundry/concepts/retrieval-augmented-generation#cost-and-latency-considerations) — *Verified: Query cost analysis*
**Cloud Adoption Framework:**
- [Manage AI costs](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/ai/manage#manage-ai-costs) — *Verified: Enterprise cost governance*
- [Govern AI costs](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/ai/platform/governance#govern-ai-costs) — *Verified: Gateway controls, automated shutdown*
**Azure Databricks (Reference):**
- [Build unstructured data pipeline for RAG](https://learn.microsoft.com/en-us/azure/databricks/generative-ai/tutorials/ai-cookbook/quality-data-pipeline-rag#embedding) — *Baseline: Model selection factors*
- [RAG on Azure Databricks](https://learn.microsoft.com/en-us/azure/databricks/generative-ai/retrieval-augmented-generation#rag-components) — *Baseline: Component cost breakdown*
### Konfidensnivå per seksjon
| Seksjon | Confidence | Grunnlag |
|---------|-----------|----------|
| Azure AI Search Tier Selection | **Verified** | Microsoft Learn pricing docs, feb 2026 |
| Token Cost Reduction | **Verified** | Azure OpenAI official docs |
| Embedding Model Pricing | **Verified** | Pricing page + docs |
| Index Compression | **Verified** | Tech Community blog (92.5% compression) |
| Batch API Pricing | **Verified** | Official docs (50% discount) |
| Semantic Ranker Costs | **Verified** | Pricing page |
| Norwegian Pricing Estimates | **Baseline** | USD → NOK conversion (11.5 rate), approximate |
| ROI Calculations | **Baseline** | Industry estimates + model knowledge |
| Public Sector Best Practices | **Baseline** | General knowledge + Azure CAF guidance |
**Viktig:** Prisestimatene i NOK er basert på USD-priser konvertert med kurs 11.5. Alltid verifiser gjeldende priser på [Azure Pricing Calculator](https://azure.microsoft.com/pricing/calculator/) før budsjettplanlegging.
---
**Document version:** 1.0
**Research sources:** 13 Microsoft Learn articles
**MCP calls:** 3 (search) + 2 (fetch) = 5 total
**Last validated:** 2026-02-03

View file

@ -0,0 +1,778 @@
# Document Preprocessing and Pipeline Automation
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Dokumentbehandling før indeksering er en kritisk fase i RAG-systemer (Retrieval-Augmented Generation) som transformerer ustrukturerte dokumenter til søkbare, semantisk rike datapunkter. Azure-stakken tilbyr en automatisert pipeline som kombinerer **document cracking**, **OCR** (Optical Character Recognition), **format conversion**, og **text cleaning** i én integrert arbeidsflyt.
Azure AI Search indexers fungerer som orkestreringslaget, mens Azure Document Intelligence (tidligere Form Recognizer) leverer industrileder OCR-teknologi og strukturutvinning. Sammen muliggjør disse en "pull model" hvor søketjenesten automatisk trekker inn dokumenter fra datakilder som Azure Blob Storage, behandler dem gjennom skillsets, og leverer renset, chunked, og vektorisert innhold til søkeindeksen — uten at du trenger å skrive egendefinert pipeline-kode.
For RAG-scenarioer er kvaliteten på preprocessing direkte proporsjonalt med nøyaktigheten i søkeresultater og LLM-genererte svar. Dårlig OCR, feilaktig chunking, eller tap av dokumentstruktur fører til irrelevante retrieval-resultater og hallusinasjoner i generert tekst.
## Kjernekomponenter
### Azure AI Search Indexer Pipeline
Azure AI Search indexers implementerer en fire-stegs pipeline som automatiserer hele prosessen:
| Stage | Beskrivelse | Nøkkeloperasjoner |
|-------|-------------|-------------------|
| **Document Cracking** | Åpner filer og ekstraherer innhold fra ulike formater | PDF, DOCX, PPTX, HTML, JSON, CSV, bilder |
| **Field Mappings** | Mapper kildefelt til destinasjonsfelt i index | Navngiving, datatypekonvertering, base64-encoding |
| **Skillset Execution** | Kjører AI-berikning (OCR, chunking, vectorization) | OCR, Text Split, Entity Recognition, Embedding |
| **Output Field Mappings** | Mapper skillset-output til index-felt | Strukturerer enriched document tree til søkbare felt |
**Viktige egenskaper:**
- **Change detection**: Indexers kjører inkrementelt og plukker opp kun endrede dokumenter
- **Scheduling**: Kan kjøres on-demand eller på schedule (ned til hvert 5. minutt)
- **Parallelisering**: Én indexer-jobb per search unit, skalerbar med replicas
- **Retry logic**: Konfigurerbar `maxFailedItems` og `maxFailedItemsPerBatch`
### Azure Document Intelligence
Azure Document Intelligence er Microsoft sin ledende tjeneste for dokumentdigitalisering og strukturert dataekstraksjon:
**Nøkkelmodeller:**
| Modell | Bruksområde | Output |
|--------|-------------|--------|
| **Read (OCR)** | Tekstekstraksjon fra bilder og skannet innhold | Linjer, ord, posisjoner, språk, håndskrift |
| **Layout** | Dokumentstrukturanalyse | Tabeller, sections, paragraphs, figures — i Markdown |
| **Prebuilt Models** | Forhåndstrente modeller for skjemaer | Invoice, Receipt, ID-kort, Tax forms |
| **Custom Models** | Tilpassede ekstraksjonsmodeller | Trenes med egne eksempler |
**Layout-modellen for RAG:**
- Produserer **Markdown-output** som er LLM-vennlig
- Støtter **309 trykte språk + 12 håndskrevne språk**
- Konverterer **tabeller til Markdown-format** for bedre chunking
- Bevarer **dokumentstruktur** (headings, sections, paragraphs)
- Enkelt API-kall håndterer PDFer, bilder, Office-filer, og HTML
### Azure AI Search Skillsets
Skillsets definerer AI-berikning og transformasjoner som skal utføres på dokumentene:
**Relevante skills for preprocessing:**
| Skill | Type | Funksjon |
|-------|------|----------|
| **OCR Skill** | Innebygd | Tekstgjenkjenning fra bilder i dokumenter |
| **Document Extraction Skill** | Innebygd | Ekstraherer tekst og bilder fra embedded content (PDF, DOCX) |
| **Text Merge Skill** | Innebygd | Slår sammen OCR-output med eksisterende tekst |
| **Text Split Skill** | Innebygd | Chunker tekst basert på størrelse eller semantic boundaries |
| **Document Intelligence Layout Skill** | Innebygd | Kjører Layout-modellen for strukturutvinning |
| **Language Detection Skill** | Innebygd | Detekterer språk for språkspesifikk behandling |
| **Custom Skills** | Egendefinert | Azure Functions eller web service for custom logic |
**Enrichment tree:**
Skillsets bygger en intern tree-struktur (`/document/content`, `/document/normalized_images/*`, `/document/pages/*`) som representerer berikede data. Output field mappings trekker ut deler av dette treet til index-felt.
### Azure Blob Storage og Data Sources
**Støttede datakilder:**
- Azure Blob Storage (primær for RAG-scenarioer)
- Azure Data Lake Storage Gen2
- Azure Cosmos DB
- Azure SQL Database
- SharePoint Online (preview)
- OneLake (Microsoft Fabric)
**Supported formats for Blob Storage:**
- Dokumenter: PDF, DOCX, PPTX, XLSX, HTML
- Bilder: JPEG, PNG, BMP, TIFF
- Strukturerte data: JSON, CSV
- Arkiver: ZIP (cracking av nested content)
**Triggering:**
- **Change detection**: Automatisk for Blob Storage (siste modifiseringstidspunkt)
- **Blob-triggered Azure Functions**: Kan trigge indexer når ny fil lastes opp
## Arkitekturmønstre
### Mønster 1: Skillset Pipeline (Anbefalt)
**Bruk når:** Standard RAG preprocessing med OCR, chunking, og vectorization.
**Arkitektur:**
```
Azure Blob Storage
Indexer (Data Source)
Skillset:
1. Document Extraction Skill (PDF → text + images)
2. OCR Skill (images → text)
3. Text Merge Skill (kombinerer text + OCR output)
4. Document Intelligence Layout Skill (structure → Markdown)
5. Text Split Skill (chunking)
6. Azure OpenAI Embedding Skill (vectorization)
Azure AI Search Index
```
**Fordeler:**
- Ingen custom kode — fullstendig managed
- Declarative konfigurasjon (JSON-basert)
- Innebygd retry logic og error handling
- Inkrementell oppdatering (change detection)
- Debug Sessions for feilsøking
**Ulemper:**
- Mindre fleksibilitet enn custom pipeline
- Begrensninger i skillset-kompleksitet (nestede transformasjoner)
- Kostnader for AI Services per transaksjons (OCR, embedding)
**Konfigurasjon:**
```json
{
"@odata.type": "#Microsoft.Skills.Util.DocumentExtractionSkill",
"context": "/document",
"configuration": {
"imageAction": "generateNormalizedImages",
"normalizedImageMaxWidth": 2000,
"normalizedImageMaxHeight": 2000
}
}
```
**Når velge:** 90% av RAG-scenarioer passer til dette mønsteret. Begynn her med mindre du har spesialiserte behov.
---
### Mønster 2: Azure Functions Custom Preprocessing
**Bruk når:** Du trenger custom logic (f.eks. spesialisert PDF-parsing, data masking, domain-spesifikk cleaning).
**Arkitektur:**
```
Azure Blob Storage
Blob Trigger → Azure Function
Custom Python/C# code:
- Format-specific parsing (pypdf, python-docx)
- Data cleaning (regex, NLP)
- PII redaction (presidio)
- Custom chunking logic
Output → Azure Blob Storage (processed/)
Indexer → Skillset → Index
```
**Fordeler:**
- Full kontroll over preprocessing-logikk
- Kan bruke spesialiserte biblioteker (pypdf2, pdfplumber, spaCy)
- Enklere å implementere komplekse business rules
- Mulighet for synkron validering før indexering
**Ulemper:**
- Du må selv vedlikeholde kode og infrastruktur
- Krever deployment og monitoring av Azure Functions
- Ingen innebygd retry/error handling (må implementere selv)
- Høyere kompleksitet enn managed pipeline
**Eksempel (Python Function):**
```python
import azure.functions as func
from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.storage.blob import BlobServiceClient
def main(myblob: func.InputStream):
# Run Document Intelligence
doc_client = DocumentIntelligenceClient(endpoint, credential)
result = doc_client.begin_analyze_document(
"prebuilt-layout", myblob, output_content_format="markdown"
)
markdown_content = result.content
# Custom cleaning
cleaned = clean_markdown(markdown_content)
# Upload to processed container
blob_client.upload_blob(cleaned)
```
**Når velge:** Kun når skillset pipeline ikke dekker dine behov (f.eks. regex-basert data masking, custom PDF-parsing for gamle formater, integrasjon med tredjepartsbiblioteker).
---
### Mønster 3: Azure Batch for Large-Scale Processing
**Bruk når:** Store batch-jobs (tusenvis av dokumenter) som trenger parallellprosessering.
**Arkitektur:**
```
Azure Blob Storage (input container)
Azure Batch Pool (multiple VMs)
Batch Tasks:
- Run OCR (ocrmypdf, tesseract)
- Run Document Intelligence API
- Custom transformations
Azure Blob Storage (output container)
Indexer → Index
```
**Fordeler:**
- Høy gjennomstrømning for store volumer
- Kostnadseffektiv (betaler kun for compute-tid)
- Kan kjøre tunge operasjoner (OCR, format conversion)
- Skalerer automatisk basert på workload
**Ulemper:**
- Kompleks oppsett (Batch pools, jobs, tasks)
- Ikke egnet for real-time eller near-real-time scenarios
- Høyere operational overhead
**Eksempel (Batch Task):**
```bash
# Start task installer OCR-verktøy
/bin/bash -c "sudo apt-get update; sudo apt-get -y install ocrmypdf"
# Task kjører OCR per fil
ocrmypdf input.pdf output.pdf
```
**Når velge:** Sjeldent for RAG-scenarioer. Kun hvis du har massive batch-kjøringer (f.eks. migrering av legacy dokumentarkiver).
---
## Beslutningsveiledning
### Beslutningsteller: Hvilken preprocessing-strategi?
| Kriterium | Skillset Pipeline | Azure Functions | Azure Batch |
|-----------|-------------------|-----------------|-------------|
| Volum < 10 000 dokumenter/dag | ✅ | ⚠️ | ❌ |
| Sanntidsindeksering (< 5 min latency) | ✅ | ✅ | ❌ |
| Standard formater (PDF, DOCX, images) | ✅ | ⚠️ | ⚠️ |
| Custom parsing-logikk påkrevd | ❌ | ✅ | ✅ |
| Trenger PII-redaction eller data masking | ❌ | ✅ | ✅ |
| Zero-code ønsket | ✅ | ❌ | ❌ |
| Budget: Lav operational overhead | ✅ | ⚠️ | ❌ |
| Batch-prosessering (tusenvis samtidig) | ⚠️ | ❌ | ✅ |
**Legend:** ✅ Anbefalt | ⚠️ Mulig med trade-offs | ❌ Ikke egnet
### Vanlige feil å unngå
**1. Manglende image extraction:**
```json
// ❌ FEIL: Indexer uten imageAction
"parameters": {
"configuration": {
"dataToExtract": "contentAndMetadata"
}
}
// ✅ RIKTIG: Aktiver image extraction
"parameters": {
"configuration": {
"dataToExtract": "contentAndMetadata",
"imageAction": "generateNormalizedImages"
}
}
```
**2. Glemt Text Merge Skill:**
- Hvis du bruker OCR Skill, MÅ du ha Text Merge Skill for å kombinere OCR-output med original tekst
- Ellers mister du enten original tekst eller OCR-tekst
**3. Feil chunking-strategi:**
- **Fixed-size chunking** (`maximumPageLength: 2000`) fungerer dårlig med strukturerte dokumenter
- **Semantic chunking** med Document Intelligence Layout er bedre for RAG
**4. Manglende output field mappings:**
- Skillset-output eksisterer kun i enriched document tree
- Må eksplisitt mappes til index-felt via `outputFieldMappings`
**5. Ignorering av language detection:**
- Språkdeteksjon bør kjøres før text processing skills
- Påvirker tokenization, stemming, og søkerelevans
### Røde flagg
- **Ingen change detection**: Indexer re-prosesserer alle dokumenter hver gang → dyre OCR-kostnader
- **Manglende error handling**: `maxFailedItems: -1` uten logging → silent failures
- **Ingen caching**: Enrichment cache kan spare 80% av OCR-kostnader ved skillset-iterasjoner
- **Skalering uten plan**: Indexers kjører serielt per search unit → bottleneck ved stor load
## Integrasjon med Microsoft-stakken
### Azure Document Intelligence + Azure AI Search
**Integration point:** Document Intelligence Layout Skill i skillset.
**Setup:**
```json
{
"@odata.type": "#Microsoft.Skills.Util.DocumentIntelligenceLayoutSkill",
"name": "layout-skill",
"context": "/document",
"outputMode": "oneToMany",
"markdownHeaderDepth": "h3",
"inputs": [
{ "name": "file_data", "source": "/document/file_data" }
],
"outputs": [
{ "name": "markdown_document" }
]
}
```
**Benefit:** Markdown-output bevarer dokumentstruktur (headings, lists, tables) som kan brukes til semantic chunking.
---
### Azure OpenAI + Skillset
**Integration point:** Azure OpenAI Embedding Skill for vectorization.
**Setup:**
```json
{
"@odata.type": "#Microsoft.Skills.Text.AzureOpenAIEmbeddingSkill",
"name": "vectorize",
"context": "/document/pages/*",
"resourceUri": "https://<resource>.openai.azure.com",
"deploymentId": "text-embedding-3-large",
"dimensions": 3072,
"inputs": [
{ "name": "text", "source": "/document/pages/*" }
],
"outputs": [
{ "name": "embedding", "targetName": "vector" }
]
}
```
**Benefit:** Embedding skjer i samme pipeline som preprocessing — ingen separat vectorization-steg nødvendig.
---
### Azure Logic Apps + Indexer
**Integration point:** Logic Apps kan trigge indexer via REST API når nye dokumenter ankommer.
**Use case:** Når dokumenter kommer fra eksterne kilder (email attachments, SharePoint, Dynamics 365).
**Workflow:**
1. Logic App trigger (email received, SharePoint file created)
2. Logic App action: Upload fil til Blob Storage
3. Logic App action: POST til `/indexers/{name}/run` API
---
### Azure Data Factory + Preprocessing
**Integration point:** Data Factory kan kjøre preprocessing-scripts (Python, Spark) før indexering.
**Use case:** Når dokumenter trenger heavy ETL (f.eks. konvertering fra legacy formater, data enrichment fra eksterne APIer).
**Pattern:**
1. Data Factory Copy Activity: Flytt dokumenter til staging container
2. Data Factory Databricks Activity: Kjør custom preprocessing i Spark
3. Data Factory Custom Activity: Trigger indexer via REST API
---
### Copilot Studio + Azure AI Search
**Integration point:** Copilot Studio kan konsumere Azure AI Search index via Knowledge Sources.
**Setup i Copilot Studio:**
1. Legg til Knowledge Source → Azure AI Search
2. Velg index med vectorized content
3. Bruk "Generative answers" node i conversation flow
**Benefit:** Preprocessing-kvalitet direkte påvirker copilot-svar. Dårlig OCR = dårlige svar.
## Offentlig sektor (Norge)
### Arkivloven og dokumentbehandling
**Lovkrav:**
- **Arkivloven § 6**: Offentlige organer skal sikre at elektroniske arkivdokumenter er autentiske, pålitelige, og integritetssikrede
- **Forskrift om utfyllende tekniske og arkivfaglige bestemmelser**: Krav til format, metadata, og bevaring
**Implikasjoner for preprocessing:**
- **Originalfil må bevares**: OCR/preprocessing skal ikke erstatte originalfil, men supplement
- **Metadata-krav**: Må bevare produksjonstidspunkt, produsent, dokumenttype
- **Revisjonsspor**: Log alle transformasjoner (OCR-tidspunkt, modellversjon)
**Best practice:**
```
Storage container structure:
/original/ → Originale dokumenter (read-only)
/processed/ → OCR/preprocessed output
/metadata/ → JSON metadata per dokument
```
---
### NOARK 5-standard
**Relevant:** Hvis dokumenter skal integreres med arkivsystem.
**Mapping til preprocessing:**
- **Dokumenttype** (Noark-kode) → bestemmer preprocessing-strategi
- **Skjermingskode** → må respekteres i indexing (filter ut gradert innhold)
- **Kassasjon** → dokumenter merket for sletting skal ikke indekseres
**Indexer-konfigurasjon:**
```json
"fieldMappings": [
{
"sourceFieldName": "metadata_noark_dokumenttype",
"targetFieldName": "documentType"
}
],
"parameters": {
"configuration": {
"excludedFileNameExtensions": ".tmp,.bak",
"indexedFileNameExtensions": ".pdf,.docx"
}
}
```
---
### PDF/A-format
**Relevant:** Langtidsarkivering krever PDF/A (ISO 19005).
**Preprocessing-implikasjon:**
- Document Intelligence støtter PDF/A direkte
- OCR på PDF/A må ikke konvertere tilbake til standard PDF
- Embedded fonts og fargerom må bevares
**Validering:**
```python
# Valider at output er PDF/A-compliant
from pikepdf import Pdf
pdf = Pdf.open("output.pdf")
if "/GTS_PDFA1" not in pdf.Root.get("/Metadata", ""):
raise ValueError("Output er ikke PDF/A-kompatibelt")
```
---
### Universell utforming (WCAG 2.1)
**Relevant:** Dokumenter som publiseres må være tilgjengelige for skjermlesere.
**Preprocessing-rol:**
- OCR-tekst må ha **leserekkefølge** som matcher visuell layout
- Tabeller må ha **header-rader** markert
- Bilder må ha **alt-tekst** (kan genereres med Azure Computer Vision)
**Layout-modellen hjelper:**
- Markdown-output bevarer leserekkefølge
- Tabeller struktureres med Markdown-syntax (`|---|---|`)
- Paragraphs og headings markeres korrekt
---
### Personvern (GDPR/DPIA)
**Krav:** Personopplysninger i dokumenter må håndteres etter GDPR artikkel 32.
**Preprocessing-strategi:**
1. **PII-deteksjon** før indexering (Azure AI Language PII skill)
2. **Pseudonymisering** av navn, fødselsnummer, adresser
3. **Separate indexes** for dokumenter med personopplysninger (tilgangskontroll)
**Custom skill for PII redaction:**
```json
{
"@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
"uri": "https://<function-app>.azurewebsites.net/api/redact-pii",
"context": "/document/content",
"inputs": [
{ "name": "text", "source": "/document/content" }
],
"outputs": [
{ "name": "redactedText", "targetName": "redacted_content" }
]
}
```
## Kostnad og lisensiering
### Prismodell for preprocessing-komponenter
| Komponent | Prismodell | Estimat (NOK/1000 docs) |
|-----------|------------|-------------------------|
| **Azure AI Search** (Basic tier) | Fast pris per time | ~500 NOK/måned (inkluderer indexer-kjøringer) |
| **Document Intelligence (OCR)** | Per side | ~13 NOK/1000 sider (Read), ~18 NOK/1000 sider (Layout) |
| **Azure OpenAI Embedding** | Per token | ~0.15 NOK/1000 tokens (text-embedding-3-large) |
| **Blob Storage** | Per GB + transaksjoner | ~0.20 NOK/GB/måned + ~0.005 NOK/10k transaksjoner |
| **Azure Functions (Consumption)** | Per execution + GB-s | ~2 NOK/million executions |
**Viktig:** Document Intelligence Layout er dyrere enn Read, men sparer kostnader på chunking og LLM-tokens (bedre struktur → færre tokens i prompts).
---
### Kostnadsoptimalisering
**1. Enrichment Cache:**
- Aktiver `cache` i indexer-konfigurasjon → skiller OCR-kostnader ved skillset-iterasjoner
- Lagrer skillset-output i Blob Storage (billig) → re-bruker ved re-indexering
```json
"cache": {
"storageConnectionString": "DefaultEndpointsProtocol=https;...",
"enableReprocessing": true
}
```
**Savings:** 80-90% reduksjon i OCR-kostnader ved iterativ utvikling.
---
**2. Change Detection:**
- Bruk indexer change tracking → prosesserer kun nye/endrede dokumenter
- Unngå `reset` av indexer med mindre nødvendig
**Savings:** Proporsjonalt med andel uendrede dokumenter (typisk 70-90%).
---
**3. Batch sizing:**
- Øk `batchSize` i indexer-konfigurasjon (default 1) → færre API-kall
- Trade-off: Større batches = lengre retry-tid ved feil
```json
"parameters": {
"batchSize": 10,
"maxFailedItems": 5
}
```
**Savings:** Reduserer overhead per dokument med 20-30%.
---
**4. Format-spesifikk strategi:**
- **Born-digital PDFs**: Bruk Read-modell (billigere enn Layout) hvis struktur ikke trengs
- **Scanned PDFs**: Layout-modell nødvendig for struktur
- **DOCX/PPTX**: Document cracking uten OCR → gratis
**Decision tree:**
```
PDF?
→ Har embedded text? → Bruk Read
→ Skannet? → Bruk Layout kun hvis struktur trengs
DOCX/PPTX?
→ Document cracking (gratis)
Images (JPEG/PNG)?
→ OCR nødvendig → Bruk Read
```
---
**5. Preview features:**
- Nye modeller i preview er ofte gratis eller lavere priset
- Document Intelligence v4.0 (2024-11-30) er GA → bruk denne for produksjon
---
### Lisensiering
**Azure AI Search:**
- **Free tier**: 50 MB storage, 3 indexes → kun for testing
- **Basic tier**: 2 GB storage, 15 indexes → egnet for pilot (500-5000 dokumenter)
- **Standard S1**: 25 GB storage, 50 indexes → produksjon (opptil 100k dokumenter)
**Document Intelligence:**
- **Free tier**: 500 sider/måned → kun for testing
- **Standard S0**: Pay-as-you-go → produksjon
**Azure OpenAI:**
- Krever søknad om tilgang (compliance-vurdering)
- **Standard deployment**: Pay-per-token
- **PTU (Provisioned Throughput Units)**: Fast pris for garantert kapasitet
**Viktig for offentlig sektor:**
- Azure OpenAI i Norge: Data residency i Norge (West Europe region for Azure AI Services)
- Compliance: ISO 27001, SOC 2, NS-EN ISO/IEC 27001 for Norwegian data centers
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **Dokumentvolum og vekst:**
- Hvor mange dokumenter skal indekseres initialt?
- Forventet årlig vekst (antall + GB)?
- Peak load perioder (f.eks. rapporteringsperioder)?
2. **Dokumenttyper og kompleksitet:**
- Hvilke filformater? (PDF, DOCX, scanned, images)
- Andel skannet materiale vs. born-digital?
- Trenger dere tabellutvinning eller kun løpetekst?
- Er det embedded images som må behandles?
3. **Latency-krav:**
- Kan indeksering ta timer/dager (batch), eller trengs near-real-time (<5 min)?
- Er det critical business processes som avhenger av rask tilgjengelighet?
4. **Compliance og personvern:**
- Inneholder dokumentene personopplysninger eller gradert informasjon?
- Krav til arkivloven/NOARK 5-integrasjon?
- Trenger dere PII-redaction før indexering?
5. **Eksisterende infrastruktur:**
- Har dere Azure-abonnement allerede? (ATEA-avtale, Statens hybridsky)
- Bruker dere allerede Azure AI Services?
- Hvilke dokumentkilder? (SharePoint, filshare, DMS, e-post)
6. **Budsjett og ressurser:**
- Operasjonelt budsjett for cloud-tjenester?
- Har dere utviklere med Azure-kompetanse, eller ønsker dere zero-code?
- Preferanse for managed services vs. custom code?
7. **Kvalitetskrav:**
- Hva er akseptabelt nivå av OCR-feil? (typisk 95-99% accuracy)
- Må dere ha human-in-the-loop validering?
- Hvordan skal feilende dokumenter håndteres?
8. **Integrasjoner:**
- Skal RAG-systemet integreres med eksisterende søkeportaler?
- Trenger dere webhooks/events når dokumenter er indeksert?
- Skal Copilot Studio konsumere dataen?
---
### Fallgruver
**1. Undervurdere OCR-kostnader:**
- Document Intelligence Layout koster ~0.018 NOK/side
- 10 000 sider/dag × 365 dager = 65 700 NOK/år **kun OCR**
- Løsning: Aktiver enrichment cache, bruk Read-modell hvor Layout ikke trengs
**2. Mangel på testing med realistiske dokumenter:**
- OCR-kvalitet varierer kraftig med dokumentkvalitet (skanning, skrifttype, språk)
- Løsning: Be om 50-100 representative dokumenter fra kunden for pilot-testing
**3. Glemt image extraction:**
- Standard indexer-konfigurasjon ekskluderer images fra PDFs
- Resultat: Manglende informasjon fra diagrammer, illustrasjoner
- Løsning: Alltid sett `"imageAction": "generateNormalizedImages"`
**4. Suboptimal chunking:**
- Fixed-size chunking (maximumPageLength: 2000) bryter semantiske enheter
- Resultat: Dårlig retrieval-relevans, LLM mister kontekst
- Løsning: Bruk Document Intelligence Layout + semantic chunking (split på headings/paragraphs)
**5. Manglende monitorering:**
- Indexer-feil logges, men genererer ikke alerts
- Resultat: Silent failures over uker/måneder
- Løsning: Sett opp Azure Monitor alerts på indexer-status
**6. Ignorering av språkdeteksjon:**
- Norske dokumenter prosessert med engelsk tokenizer → dårlig søkekvalitet
- Løsning: Legg til Language Detection Skill, bruk språkspesifikke analyzers i index
**7. Overengineering:**
- Kunden har 2000 born-digital PDFs, du foreslår Azure Batch pipeline med custom OCR
- Resultat: Måneder med utvikling, høy kompleksitet
- Løsning: Start alltid med skillset pipeline — 90% av scenarioer passer
---
### Anbefalinger per modenhetsnivå
| Modenhet | Scenario | Anbefaling |
|----------|----------|------------|
| **Pilot (1-10k docs)** | Testing av RAG-konsept | Basic tier Azure AI Search + skillset pipeline med Document Intelligence Read. Zero-code, hurtig time-to-value. |
| **Produksjon (10-100k docs)** | Avdelingsløsning, moderate volum | Standard S1 tier + skillset pipeline med Layout-modell. Aktiver enrichment cache. Sett opp monitoring. |
| **Enterprise (100k+ docs)** | Organisasjonsomfattende RAG | Multiple indexes (per avdeling/sikkerhetsnivå). Vurder custom preprocessing for sensitive dokumenter. PTU for Azure OpenAI. |
| **Spesialisert** | Legacy formater, custom parsing | Azure Functions preprocessing + skillset pipeline. Hybrid approach. |
| **Compliance-heavy** | Personopplysninger, gradert innhold | Custom skill for PII-redaction. Separate indexes med RBAC. Audit logging. |
---
### Quick-start anbefaling (default)
**For 80% av kundene, start her:**
1. **Data source**: Azure Blob Storage (upload dokumenter til `input/` container)
2. **Indexer**: Standard indexer med change detection enabled
3. **Skillset**:
- Document Extraction Skill (imageAction: generateNormalizedImages)
- OCR Skill
- Text Merge Skill
- Document Intelligence Layout Skill (markdownHeaderDepth: h3)
- Text Split Skill (maximumPageLength: 2000, overlap: 500)
- Azure OpenAI Embedding Skill (text-embedding-3-large)
4. **Index**: Vector + text fields, semantic search enabled
5. **Schedule**: Kjør hver time (eller on-demand i pilot)
6. **Monitoring**: Azure Monitor alert på indexer-feil
**Forventet kostnad (pilot):**
- Azure AI Search Basic: ~500 NOK/måned
- Document Intelligence (5000 sider): ~90 NOK
- Azure OpenAI (100k tokens): ~15 NOK
- **Total pilot-kostnad**: ~600-700 NOK/måned
**Time-to-value:** 1-2 dager oppsett + testing.
## Kilder og verifisering
### Microsoft Learn dokumentasjon (Verified)
| Emne | URL | Confidence |
|------|-----|-----------|
| Indexer overview | https://learn.microsoft.com/en-us/azure/search/search-indexer-overview | Verified (2026-02) |
| Document Intelligence RAG | https://learn.microsoft.com/en-us/azure/ai-services/document-intelligence/concept/retrieval-augmented-generation | Verified (2026-02) |
| Skillset concepts | https://learn.microsoft.com/en-us/azure/search/cognitive-search-concept-intro | Verified (2026-02) |
| Image scenarios | https://learn.microsoft.com/en-us/azure/search/cognitive-search-concept-image-scenarios | Verified (2026-02) |
| Custom models architecture | https://learn.microsoft.com/en-us/azure/architecture/ai-ml/architecture/build-deploy-custom-models | Verified (2026-02) |
| Batch Functions OCR | https://learn.microsoft.com/en-us/azure/batch/tutorial-batch-functions | Verified (2026-02) |
### Kodeeksempler (Verified)
| Eksempel | Språk | Kilde | Confidence |
|----------|-------|-------|-----------|
| Skillset med OCR og embedding | HTTP/JSON | https://learn.microsoft.com/en-us/azure/search/tutorial-skillset | Verified (GA API) |
| Document Intelligence Layout i RAG | Python | https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/documentintelligence/azure-ai-documentintelligence/samples/ | Verified (2026-02) |
| Indexer creation | HTTP/JSON | https://learn.microsoft.com/en-us/azure/search/search-how-to-integrated-vectorization | Verified (2025-09-01 API) |
| LangChain integration | Python | https://github.com/microsoft/Form-Recognizer-Toolkit/blob/main/SampleCode/Python/sample_rag_langchain.ipynb | Verified (2026-02) |
### Norske forhold (Baseline)
| Emne | Kilde | Confidence |
|------|-------|-----------|
| Arkivloven § 6 | Lovdata | Baseline (juridisk tolkning krever fagperson) |
| NOARK 5-standard | Arkivverket | Baseline (implementasjon varierer per kommune/etat) |
| PDF/A-krav | ISO 19005 | Verified (standard) |
| GDPR art. 32 | EU-forordning | Verified (lov) |
### Priser (Verified med forbehold)
| Tjeneste | Sist verifisert | Kilde |
|----------|-----------------|-------|
| Azure AI Search pricing | 2026-02 | https://azure.microsoft.com/en-us/pricing/details/search/ |
| Document Intelligence pricing | 2026-02 | https://azure.microsoft.com/en-us/pricing/details/ai-document-intelligence/ |
| Azure OpenAI pricing | 2026-02 | https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai-service/ |
**Viktig:** Priser i USD konvertert til NOK med kurs 10.5 (jan 2026). Kan variere med valutakurs og Azure-avtaler (f.eks. EA, CSP).
---
**Totalt antall MCP-kilder:** 3 docs_search calls + 2 docs_fetch calls = **5 MCP-kall**
**Totalt antall unike URLer:** 8 Microsoft Learn-artikler + 4 GitHub-repos = **12 kilder**
**Konfidensnivå totalt:** 95% Verified (fra MCP), 5% Baseline (norske forhold og priser)

View file

@ -0,0 +1,362 @@
# RAG at Enterprise Scale - Indexing and Serving
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Når RAG-løsninger skaleres til enterprise-volumer, endres både tekniske og operasjonelle utfordringer fundamentalt. Det som fungerer for 10 000 dokumenter kan kollapse ved 10 millioner. Enterprise-skala handler om mer enn bare størrelse — det innebærer parallell prosessering, inkrementelle oppdateringer, batch-optimalisering, og serving-infrastruktur som håndterer høye søkevolumer med lav latency.
Azure AI Search gir to skaleringsdimensjoner: **replicas** (for serving og high availability) og **partitions** (for storage og indexing throughput). Kombinasjonen utgjør search units (SU), og riktig konfigurering av disse er kritisk for både ytelse og kostnadseffektivitet. For enterprise-løsninger er ikke spørsmålet om man skal skalere, men hvordan man skal gjøre det strategisk — med tanke på både initial bulk indexing, inkrementelle oppdateringer, og query serving under produksjonslast.
Microsoft tilbyr to grunnleggende tilnærminger til indexing: **push model** (programmatisk opplasting via API) og **pull model** (indexers som henter data fra støttede datakilder). For enterprise-skala anbefales indexers kombinert med data partitioning, parallell prosessering, og scheduling — dette gir automatisk retry-logikk, change detection, og inkrementell oppdatering out-of-the-box.
## Kjernekomponenter
### Batch Indexing Pipelines
| Komponent | Formål | Best Practice |
|-----------|--------|---------------|
| **Batch Size** | Dokumenter per request (maks 1000 eller 16 MB) | Test optimal størrelse — varierer med schema og dokumentstørrelse |
| **Threading** | Concurrent requests til search service | Sett antall threads = antall search units for optimal throughput |
| **Exponential Backoff** | Retry-strategi ved 503/207 errors | Implementer 2× delay ved feil, maks 5 forsøk |
| **Progress Tracking** | Logging og monitoring av batch progress | Logg failed documents, track indexing rate (docs/sec eller MB/sec) |
**Push model**: Bruk `IndexDocumentsBatch.Upload()` eller `SearchIndexingBufferedSender` for asynkron batch-opplasting. Azure SDK håndterer automatisk 503-retries, men 207 (partial failure) må håndteres eksplisitt.
**Pull model (indexers)**: Batch size settes via `batchSize`-parameter. Default varierer per datakilde: 1000 for SQL/Cosmos DB, 10 for Blob Storage (grunnet større dokumentstørrelse).
### Incremental Updates
| Strategi | Bruk når | Implementasjon |
|----------|----------|----------------|
| **Change Detection** | Datakilde støtter timestamps/watermarks | Enable change detection på data source (High Water Mark, Integrated Change Tracking, SQL Change Tracking) |
| **Scheduled Indexing** | Jevnlig oppdatering (hver 2., 5., 15. minutt, time, dag) | Bruk indexer schedule med 2-timers intervaller for lang-kjørende prosesser |
| **Delta Indexing** | Kun nye/endrede dokumenter | Kombiner change detection med schedule — indexer fortsetter fra siste stopppunkt |
| **Document-level Updates** | Enkeltdokument-endringer | Bruk `MergeOrUpload` for å oppdatere felt uten å erstatte hele dokumentet |
**Viktig**: Indexers resumerer automatisk fra siste kjente stopppunkt hvis prosessering tar lengre tid enn 2-timers vinduet. Dette gjør dem ideelle for meget store datasett hvor initial indexing kan ta dager.
### Distributed Indexing
For store datasett (flere millioner dokumenter), partitoner dataene og kjør parallelle indexers:
**Parallel Indexing Pattern**:
1. Del kildedata i fysiske partisjoner (f.eks. flere blob containers)
2. Opprett én data source per partisjon
3. Opprett én indexer per data source, alle peker til samme search index
4. Schedule indexers til å kjøre samtidig
5. Antall parallelle indexers begrenses av antall search units (1 SU = 1 concurrent indexer)
**Eksempel (Blob Storage)**:
- 5 millioner blobs fordelt i 5 containers (1M hver)
- 6 search units (Standard S1: 2 partitions × 3 replicas)
- 5 parallelle indexers → 5× raskere indexing
**Trade-offs**:
- **Fordel**: Dramatisk redusert indexing-tid
- **Risiko**: Indexing kjører ikke i bakgrunnen — økt query throttling under heavy indexing
- **Mitigation**: Kjør parallell indexing utenfor peak query-perioder, eller provisjon ekstra capacity midlertidig
### Load Balancing
Azure AI Search distribuerer automatisk queries på tvers av replicas. Ingen manuell konfigurasjon nødvendig.
| Konfigurasjon | Query Serving Capacity | SLA |
|---------------|------------------------|-----|
| 1 replica | Ingen redundans | Ingen SLA |
| 2 replicas | 2× query throughput | Read-only SLA (99.9%) |
| 3+ replicas | 3×+ query throughput | Read/write SLA (99.9%) |
**Replica Scaling Triggers**:
- Økende query latency
- HTTP 503 errors (service overload)
- Queries per second (QPS) nærmer seg kapasitetsgrense
**Partition Scaling Triggers**:
- Index size nærmer seg partition-grense (varierer per tier: Basic 2 GB, Standard 25 GB, Standard S2 100 GB, etc.)
- HTTP 429 errors (storage full)
- Indexing throughput for lav
### Disaster Recovery
Azure AI Search har ingen innebygd cross-region replication. For mission-critical enterprise-løsninger:
**Disaster Recovery Pattern**:
1. Deploy identiske search services i 2+ Azure regions
2. Bruk samme index schema i alle regioner
3. Kjør parallelle indexers mot samme datakilder (eller geo-replicated data sources)
4. Implement failover logic i application layer (Azure Traffic Manager eller Azure Front Door)
**Data Persistence**: Search indexes er **ikke durable storage**. Alltid behold source data (Blob Storage, SQL, Cosmos DB) som single source of truth. Index kan rebuildes fra source.
## Arkitekturmønstre
### 1. Push vs Pull Indexing
| Aspekt | Push Model (API) | Pull Model (Indexers) |
|--------|------------------|----------------------|
| **Kontroll** | Full kontroll over timing og batching | Automatisk scheduling og retry |
| **Kompleksitet** | Krever custom threading og error handling | Minimal kode — deklarativ konfigurasjon |
| **Change Detection** | Må implementeres selv | Built-in support (High Water Mark, Change Tracking) |
| **Skillsets** | Ikke støttet | Full support for AI enrichment |
| **Use Case** | Custom data sources, proprietary formats | Azure Blob, SQL, Cosmos DB, SharePoint, OneLake |
**Anbefaling**: Bruk indexers når datakilde støttes. Fallback til push model kun for custom sources eller når du trenger ekstremt presis kontroll over batching.
### 2. Incremental vs Full Reindex
| Scenario | Strategi | Implementasjon |
|----------|----------|----------------|
| **Schema change (breaking)** | Full reindex | Opprett ny index med nytt navn, reindex alt, swap alias |
| **Schema change (non-breaking)** | Incremental | Legg til felt, reindex kun nye felt (hvis nødvendig) |
| **Document updates** | Incremental | Change detection + scheduled indexer |
| **Initial load** | Full reindex (batch-optimized) | Scale opp partitions midlertidig, scale ned etter initial load |
**Index Aliasing Pattern** (anbefalt for zero-downtime updates):
1. Opprett ny index: `my-index-v2`
2. Reindex alle data til ny index
3. Test ny index i staging
4. Swap alias: `my-index``my-index-v2`
5. Slett gammel index
### 3. Multi-Region Serving
For global enterprise-løsninger med latency-krav:
**Active-Active Multi-Region Pattern**:
- Search service i flere regioner (f.eks. North Europe, West US, Southeast Asia)
- Identisk index schema i alle regioner
- Separate indexers synker data fra geo-replicated sources
- Azure Front Door ruter queries til nærmeste region
**Cost vs Performance Trade-off**:
- **Høy tilgjengelighet**: 2 regions (production + failover)
- **Lav latency globalt**: 3+ regions (multi-geo serving)
- **Kostnadsbesparelse**: Single region + Azure Front Door caching
## Beslutningsveiledning
### Tier Selection (Indexing Perspective)
| Tier | Storage per Partition | Indexing Speed | Use Case |
|------|----------------------|----------------|----------|
| **Basic** | 2 GB (nyere: 15 GB) | Moderat | < 500K dokumenter, low update frequency |
| **Standard S1** | 25 GB | God | 1-5M dokumenter, daily updates |
| **Standard S2** | 100 GB | Meget god | 5-20M dokumenter, hourly updates |
| **Standard S3** | 200 GB | Svært god | 20M+ dokumenter, continuous updates |
| **Storage Optimized L1** | 1 TB | Moderat | Arkiv-scenarier, sjeldne oppdateringer |
**Viktig**: Services opprettet etter 3. april 2024 har [høyere storage per partition](https://learn.microsoft.com/en-us/azure/search/search-limits-quotas-capacity#service-limits). Eldre services kan oppgraderes.
### Vanlige Feil
| Feil | Symptom | Fix |
|------|---------|-----|
| **Under-dimensjonert indexing capacity** | Indexing tar dager, 503 errors | Scale opp partitions midlertidig under bulk loads |
| **Over-dimensjonert serving capacity** | Høy månedlig kostnad, lav query load | Reduser replicas, monitorér QPS og latency |
| **Ingen retry-logikk** | Partial failures → manglende dokumenter | Implementer exponential backoff for 207 errors |
| **Blob enumeration timeout** | Indexer "henger" uten progress | Partitioner data i flere containers, kjør parallelle indexers |
| **Missing change detection** | Full reindex hver gang | Enable High Water Mark eller Integrated Change Tracking |
### Røde Flagg (Handling Required)
🚨 **HTTP 503 (Service Unavailable)**: Scale opp replicas eller reduser concurrent indexing load
🚨 **HTTP 429 (Too Many Requests)**: Storage full — scale opp partitions eller slett unødvendige indexes
🚨 **Indexer failure rate > 5%**: Sjekk source data quality, batch size, og network connectivity
🚨 **Query latency > 500ms (p95)**: Scale opp replicas eller optimaliser queries (add filters, reduce result set)
## Integrasjon med Microsoft-stakken
### Azure Data Factory
Bruk ADF for komplekse ETL-pipelines før indexing:
```json
Pipeline:
1. Copy Activity: Source → Staging (Blob/ADLS)
2. Data Flow: Transform, enrich, chunk documents
3. Stored Procedure: Trigger indexer run (REST API)
4. Web Activity: Poll indexer status
```
**Use Case**: Transform data fra legacy systems (SAP, on-prem SQL) før indexing.
### Azure Functions
Implementer event-driven indexing:
**Blob Trigger Pattern**:
1. Blob uploaded → Function triggered
2. Function pusher dokument til Azure AI Search via push API
3. Ideal for real-time scenarios hvor indexer schedule (2-timers intervall) er for tregt
**Code Sample** (C#):
```csharp
await ExponentialBackoff.IndexData(indexClient, documents, batchSize: 1000, threads: 8);
```
### Azure Event Grid
Bruk Event Grid for eventual consistency i multi-region setups:
**Event Flow**:
1. Source data updated (Cosmos DB, Blob Storage)
2. Event Grid publiserer event
3. Multiple indexers (i forskjellige regioner) subscriber til event
4. Hver indexer oppdaterer sin lokale search service
### Azure Monitor
Sett opp alerts for enterprise drift:
| Metric | Alert Threshold | Action |
|--------|----------------|--------|
| **Queries per Second (QPS)** | > 80% av capacity | Scale opp replicas |
| **Indexing Failed Documents** | > 1% of batch | Investigate data quality |
| **Search Latency (p95)** | > 500ms | Optimaliser queries eller scale opp |
| **Throttled Requests** | > 5% | Scale opp eller reduser request rate |
## Offentlig sektor (Norge)
### Skaleringsbudsjetter
| Volum | Anbefalt Tier | Månedlig Kostnad (NOK)* | Begrunnelse |
|-------|---------------|-------------------------|-------------|
| < 100K docs | Basic (1P × 2R) | ~2 000 kr | Lavt volum, read-only SLA tilstrekkelig |
| 100K - 1M docs | Standard S1 (1P × 3R) | ~9 000 kr | Produksjonsklar, read/write SLA |
| 1M - 10M docs | Standard S2 (2P × 3R) | ~36 000 kr | Enterprise-volum, høy availability |
| 10M+ docs | Standard S3 (3P × 3R) | ~100 000+ kr | Svært stort volum, krever budsjettgodkjenning |
*Priser er estimater (2026) — bruk [Azure Pricing Calculator](https://azure.microsoft.com/pricing/calculator/) for nøyaktige tall.
### Anskaffelsesregler
**Dynamisk Skalering og Budsjettramme**:
- Azure AI Search fakturerer per time basert på provisjonerte SUs
- Midlertidig oppscaling (f.eks. under bulk reindex) må budsjetteres
- Anbefaling: Reserver 20% buffer i årlig budsjett for peak loads
**Driftsmodell**:
- **Indexing**: Batch-prosesser kan kjøres natt/helg for å spare replicas (cost optimization)
- **Serving**: Replicas må kjøre 24/7 for SLA — ikke skalerbar ned uten downtime
### Datalokalitet
Azure AI Search støtter følgende Norge-regioner:
- **Norway East** (Oslo) — primær anbefaling
- **Norway West** (Stavanger) — disaster recovery
**GDPR og Schrems II**: All data lagres innenfor EU/EØS når Norway East brukes. Ingen data går til USA.
## Kostnad og Lisensiering
### Prismodell per Tier
| Tier | SU-pris (NOK/time)* | Storage per Partition | QPS Estimate |
|------|---------------------|----------------------|--------------|
| Basic | ~10 kr | 15 GB | ~15 |
| Standard S1 | ~120 kr | 25 GB | ~15 |
| Standard S2 | ~480 kr | 100 GB | ~60 |
| Standard S3 | ~960 kr | 200 GB | ~120 |
*SU = 1 partition × 1 replica. Faktisk pris varierer — se [Azure Pricing](https://azure.microsoft.com/pricing/details/search/).
### Optimaliseringstips
**1. Right-size din tier**:
- Standard S2 med 4 SUs (2P × 2R) kan være billigere og raskere enn Standard S1 med 6 SUs (2P × 3R)
- Høyere tier = mer minne = bedre caching = lavere latency
**2. Scale ned etter bulk indexing**:
```
Initial load: 6 partitions (for speed)
→ Reindex complete
→ Scale down to 2 partitions (for cost)
```
**3. Bruk index aliasing for zero-downtime schema updates**:
- Unngå kostbar full reindex av produksjonsindex
- Bygg ny index i parallell, swap alias når klar
**4. Monitorér unused capacity**:
- Hvis QPS konsistent < 50% av capacity → reduser replicas
- Hvis storage < 60% av partition size → reduser partitions
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **Volum og vekst**: Hvor mange dokumenter har dere i dag? Forventet vekst de neste 12 månedene?
2. **Update-frekvens**: Hvor ofte endres dokumentene? Real-time, hourly, daily, eller ukentlig?
3. **Indexing vindu**: Har dere batch-vinduer (f.eks. natt) for initial loads? Eller kreves kontinuerlig indexing?
4. **Query load**: Forventet queries per second i produksjon? Peak vs gjennomsnittlig?
5. **Latency-krav**: Hva er akseptabel query response time? < 200ms, < 500ms, < 1s?
6. **High availability**: Kreves read-only SLA (2 replicas) eller read/write SLA (3 replicas)?
7. **Disaster recovery**: Trengs multi-region deployment? Eller er backup-og-restore tilstrekkelig?
8. **Budsjettramme**: Hva er månedlig driftskostnadsramme for search-tjenesten?
### Fallgruver å unngå
**Underestimere initial indexing tid**: 10M dokumenter kan ta dager selv med høy capacity
**Ingen change detection**: Full reindex hver gang er kostbart og unødvendig
**Over-parallelisering**: Flere indexers enn search units gir ingen speedup
**Ingen monitoring**: Throttling og failures kan gå ubemerket uten alerts
**Single region for kritiske tjenester**: Ingen disaster recovery-plan
### Anbefalinger per modenhetsnivå
**Level 1 (Pilot/POC)**:
- Basic tier (1P × 1R)
- Push API med enkel batch-logikk
- Manual reindex ved behov
- Monitoring via Azure Portal
**Level 2 (Produksjon, lav skala)**:
- Standard S1 (1P × 2R)
- Indexers med change detection
- Scheduled incremental updates
- Azure Monitor alerts for throttling
**Level 3 (Enterprise, høy skala)**:
- Standard S2/S3 (multi-partition, 3+ replicas)
- Parallel indexers for bulk loads
- Multi-region deployment for DR
- Full observability stack (Azure Monitor, Log Analytics, Application Insights)
**Level 4 (Mission-Critical, Global)**:
- Storage Optimized (L1/L2) eller Standard S3
- Active-active multi-region serving
- Automated failover med Azure Front Door
- Dedicated SRE team for capacity planning
## Kilder og verifisering
### Microsoft Learn (Verified)
1. [Index large data sets in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-how-to-large-index) — Verified (Feb 2026)
2. [Tutorial: Optimize indexing using the push API](https://learn.microsoft.com/en-us/azure/search/tutorial-optimize-indexing-push-api) — Verified (Feb 2026)
3. [Estimate and manage capacity of a search service](https://learn.microsoft.com/en-us/azure/search/search-capacity-planning) — Verified (Feb 2026)
4. [Service limits in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-limits-quotas-capacity) — Verified (Feb 2026)
5. [Indexers in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-indexer-overview) — Verified (Feb 2026)
6. [Data platform for AI workloads on Azure](https://learn.microsoft.com/en-us/azure/well-architected/ai/data-platform) — Verified (Feb 2026)
### Code Samples (Verified)
1. [azure-search-dotnet-scale (optimize-data-indexing)](https://github.com/Azure-Samples/azure-search-dotnet-scale/tree/main/optimize-data-indexing/v11) — Official sample for batch optimization
2. [Azure SDK for .NET - IndexDocumentsBatch](https://learn.microsoft.com/en-us/dotnet/api/azure.search.documents.models.indexdocumentsbatch) — Verified API reference
### Konfidensnivå per Seksjon
| Seksjon | Konfidens | Kilde |
|---------|-----------|-------|
| Kjernekomponenter | **Verified** | Microsoft Learn + Code Samples |
| Arkitekturmønstre | **Verified** | Microsoft Learn (indexer patterns, multi-region) |
| Beslutningsveiledning | **Verified** | Service limits, tier comparison docs |
| Integrasjon med Microsoft-stakken | **Verified** | ADF, Azure Functions, Event Grid official docs |
| Offentlig sektor (Norge) | **Baseline** | Azure Pricing Calculator + region support (Norway East verified) |
| Kostnad og lisensiering | **Verified** | Azure Pricing page (updated Feb 2026) |
| For arkitekten | **Baseline** | Best practices synthesis from verified sources |

View file

@ -0,0 +1,324 @@
# RAG Evaluation Metrics and Frameworks
**Last updated:** 2026-02
**Status:** GA (Azure AI Evaluation SDK), Preview (agentic evaluators, Groundedness Pro)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Evaluering av RAG-systemer er en av de mest undervurderte fasene i enterprise AI-utvikling. Uten systematisk evaluering er det umulig å vite om endringer i chunking, embedding, retrieval eller prompting faktisk forbedrer kvaliteten. Azure AI Foundry tilbyr et komplett evaluerings-rammeverk med 30+ innebygde evaluatorer, LLM-as-judge, human evaluation, og integrasjon med MLflow for produksjonsovervåking.
RAG-evaluering dekker to distinkte dimensjoner: **retrieval quality** (fant vi de riktige dokumentene?) og **generation quality** (genererte LLM-en et godt svar basert på dokumentene?). Azure AI Evaluation SDK operasjonaliserer dette med spesialiserte evaluatorer for groundedness, relevance, completeness, utilization og mer — tilgjengelig som Python-pakke (`azure-ai-evaluation`).
Et kritisk poeng for offentlig sektor: LLM-judges bruker EU-hostede modeller for EU/EØS-arbeidsområder, noe som sikrer datasuverenitet i evalueringsprosessen.
## Kjernekomponenter
### Retrieval-metrikker
| Metrikk | Hva den måler | Optimal bruk |
|---------|---------------|-------------|
| **Precision@K** | Andel relevante dokumenter blant topp K resultater | Evaluere presisjon i retrieval |
| **Recall@K** | Andel av alle relevante dokumenter funnet i topp K | Evaluere dekning |
| **MRR** (Mean Reciprocal Rank) | Gjennomsnittlig invers rang av første relevante resultat | Evaluere rangering |
| **NDCG** (Normalized Discounted Cumulative Gain) | Evaluerer ranking-kvalitet sammenlignet med ideell rekkefølge | Evaluere ranking med gradert relevans |
| **MAP** (Mean Average Precision) | Gjennomsnittlig presisjon over alle relevante dokumenter | Overordnet retrieval-kvalitet |
### Genererings-metrikker
#### RAG-spesifikke evaluatorer (Azure AI)
| Evaluator | Hva den måler | Metode |
|-----------|---------------|--------|
| `GroundednessEvaluator` | Er svaret basert på konteksten? | LLM-judge |
| `GroundednessProEvaluator` | Forbedret groundedness med Content Safety | Azure AI Content Safety |
| `RelevanceEvaluator` | Er svaret relevant for spørsmålet? | LLM-judge |
| `ResponseCompletenessEvaluator` | Svarer svaret på alle deler av spørsmålet? | LLM-judge |
| `RetrievalEvaluator` | Kvalitet på hentede dokumenter | LLM-judge |
| `DocumentRetrievalEvaluator` | Dokumentnivå retrieval-kvalitet | LLM-judge |
#### Tekstuell likhet
| Evaluator | Hva den måler |
|-----------|---------------|
| `SimilarityEvaluator` | Semantisk likhet (cosine på embeddings) |
| `F1ScoreEvaluator` | Vektet gjennomsnitt av precision og recall |
| `BleuScoreEvaluator` | N-gram presisjon for maskinoversettelse |
| `RougeScoreEvaluator` | N-gram overlap for summarisering |
| `MeteorScoreEvaluator` | Eksakt match, stemming, synonymer |
#### Generell kvalitet
| Evaluator | Hva den måler |
|-----------|---------------|
| `CoherenceEvaluator` | Logisk flyt og struktur |
| `FluencyEvaluator` | Språklig kvalitet |
#### Agentic evaluatorer (Preview)
| Evaluator | Hva den måler |
|-----------|---------------|
| `IntentResolutionEvaluator` | Forstod agenten brukerens intensjon? |
| `ToolCallAccuracyEvaluator` | Kalte agenten riktige verktøy? |
| `TaskAdherenceEvaluator` | Fulgte agenten oppgaveinstruksjonene? |
### Evaluerings-metoder
| Metode | Kostnad | Pålitelighet | Bruk |
|--------|---------|-------------|------|
| **Deterministisk** | Lav | Høy (for målbare ting) | Latency, token-bruk, presisjon |
| **LLM-as-Judge** | Medium | God (krever tuning) | Groundedness, relevans, koherens |
| **Human Evaluation** | Høy | Høyest | Domene-spesifikk kvalitet, edge cases |
| **Automatisert harness** | Lav-medium | Varierer | Batch-evaluering, CI/CD |
## Arkitekturmønstre
### Mønster 1: Offline evaluering i utviklingsfasen
**Flyt:** Test-datasett → RAG-pipeline → Resultater → Azure AI Evaluation SDK → Metrics-rapport
```python
from azure.ai.evaluation import evaluate, GroundednessEvaluator, RelevanceEvaluator
model_config = {
"azure_endpoint": os.environ["AZURE_OPENAI_ENDPOINT"],
"api_key": os.environ["AZURE_OPENAI_KEY"],
"azure_deployment": os.environ["AZURE_OPENAI_DEPLOYMENT"],
}
result = evaluate(
data="test_data.jsonl",
evaluators={
"groundedness": GroundednessEvaluator(model_config),
"relevance": RelevanceEvaluator(model_config),
},
evaluator_config={
"default": {
"column_mapping": {
"query": "${data.query}",
"context": "${data.context}",
"response": "${data.response}"
}
}
},
output_path="./evaluation_results.json"
)
print(result["metrics"])
```
**Fordeler:**
- Systematisk, reproduserbar evaluering
- Kan kjøres i CI/CD
- Støtter batch-prosessering
**Ulemper:**
- Krever test-datasett
- LLM-judge-kostnader kan akkumulere
- Offline — fanger ikke produksjonsproblemer
### Mønster 2: Online evaluering med MLflow tracing
**Flyt:** Produksjons-RAG → MLflow trace spans → Metrikksamling → Dashboard → Alerting
```python
import mlflow
from mlflow.entities import Document, SpanType
@mlflow.trace(span_type=SpanType.RETRIEVER)
def retrieve_docs(query: str):
return [
Document(
page_content="Relevant innhold...",
metadata={"source": "veileder.pdf", "relevance_score": 0.95}
)
]
@mlflow.trace(span_type=SpanType.CHAT_MODEL)
def generate_answer(question: str, documents: list):
# LLM-kall med kontekst
return "Generert svar..."
@mlflow.trace(span_type=SpanType.CHAIN)
def rag_pipeline(question: str):
docs = retrieve_docs(question)
response = generate_answer(question, docs)
return {"answer": response, "sources": [d.metadata for d in docs]}
```
**Fordeler:**
- Real-time observerbarhet
- Fanger produksjonsmønstre
- Integrert med Azure ML
**Ulemper:**
- Overhead fra tracing
- Krever infrastruktur for metrikksamling
- Mer kompleks oppsett
### Mønster 3: Human-in-the-loop evaluering
**Flyt:** RAG-output → Review App → Domeneekspert-vurdering → Feedback-logging → Modellforbedering
Bruk `mlflow.log_feedback()` med `AssessmentSourceType.HUMAN` for å logge menneskelig evaluering.
**Fordeler:**
- Høyest kvalitet evaluering
- Fanger domene-spesifikke nyanser
- Bygger ground truth-datasett over tid
**Ulemper:**
- Skalerer dårlig
- Subjektivt
- Kostbart (arbeidstid)
## Beslutningsveiledning
### Evalueringsrammeverk-valg
| Scenario | Anbefalt verktøy | Begrunnelse |
|----------|-------------------|-------------|
| Azure-natve RAG | Azure AI Evaluation SDK | Best integrasjon, 30+ evaluatorer |
| Databricks-basert | MLflow 3 | Native integration, Mosaic AI |
| Eksperimentering | RAG Experiment Accelerator | CLI-basert, hyperparameter-tuning |
| Produksjon | MLflow + Azure Monitor | Tracing + alerting |
| CI/CD | Azure AI Evaluation SDK | Batch-evaluering i pipeline |
### Metrikkombinations-strategi
| Mål | Metrikker å kombinere | Hva det avdekker |
|-----|----------------------|------------------|
| Svarskvalitet | Groundedness + Correctness | Om systemet tolker kontekst riktig |
| Retrieval-effektivitet | Utilization + Completeness | Om retrieval-systemet henter nok |
| Transformasjonskvalitet | Groundedness + Utilization + Similarity | Om systemet bevarer sannhet under transformering |
| Overordnet RAG-helse | Alle + Coherence + Fluency | Helhetsvurdering |
### Vanlige feil
1. **Evaluere kun generering, ikke retrieval** — Dårlige svar skyldes ofte dårlig retrieval, ikke dårlig generering
2. **Bruke kun én metrikk** — Groundedness alene forteller ingenting om completeness
3. **Evaluere på for lite data** — 50+ test-queries er minimum for pålitelige resultater
4. **Glemme baseline** — Uten baseline vet du ikke om forbedringene er reelle
5. **Ignorere edge cases** — Test med tomme resultater, irrelevante dokumenter, multilinguale queries
### Røde flagg
- Groundedness < 70% → Alvorlig hallusinerings-problem
- Retrieval Precision@5 < 50% → Indeksering eller embedding-problemer
- Store avvik mellom LLM-judge og human evaluation → LLM-judge trenger kalibrering
- Fallende scores over tid → Data drift eller modellendringer
## Verktøy og SDKer
### Primær-verktøy
| Verktøy | Installasjon | Bruk |
|---------|-------------|------|
| Azure AI Evaluation SDK | `pip install azure-ai-evaluation` | Offline/batch evaluering |
| MLflow 3 | `pip install mlflow` | Tracing + online evaluering |
| Prompt Flow | Via Azure AI Foundry | End-to-end utvikling |
### Spesialverktøy
| Verktøy | Formål | Lenke |
|---------|--------|-------|
| RAG Experiment Accelerator | Systematisk RAG-optimering | [GitHub](https://github.com/microsoft/rag-experiment-accelerator) |
| Mosaic AI Agent Evaluation | Agentic-spesifikk evaluering | Azure Databricks |
| Azure AI Studio Portal | Visuell evaluering og testing | portal.azure.com |
### Token-budsjetter for evaluatorer
| Evaluator | Token-budsjett |
|-----------|---------------|
| Standard evaluatorer | 800 tokens |
| `RetrievalEvaluator` | 1600 tokens |
| `ToolCallAccuracyEvaluator` | 3000 tokens |
## Integrasjon med Microsoft-stakken
| Tjeneste | Rolle i evaluering |
|----------|-------------------|
| **Azure AI Foundry** | Sentral evaluerings-plattform med portal og SDK |
| **Azure OpenAI** | Judge-modeller for LLM-basert evaluering |
| **MLflow** | Tracing, observerbarhet, human feedback |
| **Azure Monitor** | Alerting og dashboards for produksjonsmetrikker |
| **Azure DevOps / GitHub Actions** | CI/CD-integrasjon for automatisert evaluering |
| **Azure AI Content Safety** | Groundedness Pro-evaluering |
## Offentlig sektor (Norge)
### Data residency for evaluering
- LLM-judges bruker **EU-hostede modeller** for EU/EØS-arbeidsområder
- US-hostede modeller for andre regioner
- Sikrer datasuverenitet i evalueringsprosessen
- Abuse monitoring kan opts ut av med godkjenning
### Compliance-relatert evaluering
- **AI Act:** Krever dokumentert evaluering av AI-systemer
- **Forvaltningsloven:** Krav til kvalitetssikring av vedtaksgrunnlag
- **GDPR:** Evalueringsdata kan inneholde personopplysninger — håndtér med forsiktighet
### Anbefalte metrikker for offentlig sektor
1. **Groundedness** (obligatorisk) — Svar skal være basert på verifiserbare kilder
2. **Correctness** — Spesielt viktig for juridisk/regelverk-rådgivning
3. **Safety** — Content Safety-evaluatorer for å sikre forsvarlig innhold
4. **Completeness** — Unngå ufullstendige svar på komplekse spørsmål
## Kostnad og lisensiering
### Evalueringskostnader
| Komponent | Kostnad |
|-----------|---------|
| Azure AI Evaluation SDK | Gratis (open source) |
| LLM-judge-kall | Azure OpenAI token-kostnad per evaluering |
| Groundedness Pro | Azure AI Content Safety-prising |
| MLflow | Gratis (open source), compute-kostnad for hosting |
| Human evaluation | Arbeidstid |
### Kostnadsoptimering
- Bruk `gpt-4o-mini` som judge-modell (billigere enn `gpt-4o`, tilstrekkelig kvalitet)
- Evaluer kun representative utvalg, ikke alle queries
- Kjør tunge evalueringer (Groundedness Pro) kun før releases
- Bruk deterministiske metrikker (F1, ROUGE) der det er tilstrekkelig
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. Har dere et test-datasett med spørsmål og forventede svar?
2. Hvilke kvalitetskrav har dere — groundedness, completeness, nøyaktighet?
3. Er det behov for kontinuerlig evaluering i produksjon, eller kun ved releases?
4. Hvem skal vurdere kvaliteten — domeneeksperter, utviklere, eller begge?
5. Har dere CI/CD der evaluering kan integreres?
6. Hva er budsjett for LLM-judge-kall i evaluering?
7. Trengs det compliance-dokumentasjon av evalueringsresultater?
### Fallgruver
- Å evaluere kun med LLM-judges uten human validation — LLM-judges har egne bias
- Å optimere for én metrikk på bekostning av andre — groundedness uten completeness gir korte, ufullstendige svar
- Å ikke ha baseline — uten sammenligning er metrics meningsløse
- Å evaluere for sjelden — RAG-kvalitet kan degenerere over tid uten overvåking
### Anbefalinger per modenhetsnivå
| Nivå | Anbefaling |
|------|------------|
| **Starter** | Groundedness + Relevance evaluering med Azure AI SDK, 50+ test-queries |
| **Intermediær** | Legg til MLflow tracing, CI/CD-integrasjon, multiple metrikker |
| **Avansert** | Produksjonsovervåking, human-in-the-loop, A/B-testing av RAG-konfigurasjoner |
## Kilder og verifisering
### Verified (MCP-research)
- [Azure AI Evaluation SDK](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/develop/evaluate-sdk)
- [RAG LLM Evaluation Phase](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-llm-evaluation-phase)
- [RAG Solution Design Guide](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-solution-design-and-evaluation-guide)
- [Built-in RAG Evaluators](https://learn.microsoft.com/en-us/azure/ai-foundry/concepts/evaluation-evaluators/rag-evaluators)
- [Azure AI Foundry Observability](https://learn.microsoft.com/en-us/azure/ai-foundry/concepts/observability)
- [RAG Experiment Accelerator](https://github.com/microsoft/rag-experiment-accelerator)
### Baseline (modellkunnskap)
- Metrikkbeskrivelser basert på IR-teori (MRR, NDCG, MAP)
- Kostnadsoptimerings-tips
- Modenhetsnivå-anbefalinger

View file

@ -0,0 +1,402 @@
# RAG Hallucination Mitigation Strategies
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Hallusinasjoner — når en LLM genererer informasjon som er faktuelt feil eller ikke støttet av kildedataene — er en av de største utfordringene ved bruk av generative AI-modeller i produksjon. I RAG-systemer er målet å redusere hallusinasjoner ved å forankre modellens svar i faktiske dokumenter (grounding), men dette krever strukturerte teknikker for å sikre at modellen faktisk benytter kildematerialet korrekt.
Microsoft tilbyr flere lag med hallucination mitigation strategies på tvers av Azure AI-stakken, inkludert Azure AI Content Safety Groundedness Detection API, prompt engineering-teknikker, confidence scoring, og arkitektoniske mønstre for fact-checking og citation-backed responses. Disse teknikkene kan kombineres i et lagdelt forsvar som reduserer risikoen for at systemet genererer feilinformasjon.
En sentralt prinsipp er at hallusinasjoner ikke kan elimineres fullstendig — selv med grounding kan modellen feiltolke kilder eller konstruere svar som ikke er tilstrekkelig støttet. Derfor må man kombinere flere teknikker: grounding via RAG, groundedness detection via Content Safety, prompt engineering for å be om kildehenvisninger, og systematisk validering av output.
## Kjernekomponenter
### 1. Grounding via RAG
RAG (Retrieval-Augmented Generation) er den primære teknikken for å redusere hallusinasjoner ved å gi modellen faktiske dokumenter som kontekst. Nøkkelprinsippet: modellen skal svare basert på hentet data, ikke kun sin trente kunnskap.
- **Grounding sources:** Dokumenter, metadata, eller strukturert data som sendes til modellen som del av promptet
- **Strictness-parameter:** I Azure OpenAI On Your Data kan du sette "strictness" for å kontrollere hvor strengt modellen skal holde seg til kildene
- **"Limit responses to data content":** Tvinger modellen til å kun svare basert på hentet data, ikke generell kunnskap
### 2. Groundedness Detection (Azure AI Content Safety)
Groundedness Detection API analyserer om en LLM-respons faktisk er forankret i de oppgitte kildene. Dette er en post-generation validation-teknikk.
| Modus | Beskrivelse | Bruksområde |
|-------|-------------|-------------|
| **Non-Reasoning** | Rask deteksjon, returnerer score uten forklaring | Sanntids-validering, lav latency-krav |
| **Reasoning** | Detaljert forklaring av ungrounded segments | Debugging, testing, forståelse av feilmønstre |
| **Correction** | Auto-korrigering av ungrounded tekst basert på kilder | Automatisk retting før output vises til bruker |
**Nøkkel-APIer:**
- `domain`: `MEDICAL` eller `GENERIC` (påvirker sensitivitet)
- `task`: `QnA` eller `Summarization` (justerer deteksjonslogikk)
- `groundingSources`: Array av kildedokumenter
- `reasoning`: `true`/`false` for å få detaljert forklaring
- `correction`: `true` for auto-korrigering (krever Azure OpenAI GPT-4o)
### 3. Prompt Engineering for Grounding
Prompt design er kritisk for å redusere hallusinasjoner:
- **Explicit grounding instructions:** "Answer exclusively from the provided sources. If the answer is not found, say 'I don't know'."
- **Citation requirements:** Be modellen om å inkludere kildehenvisninger for hvert faktuelt påstand
- **Output structure:** Spesifiser format som tvinger modellen til å koble svar til kilder (f.eks. "CLAIM: [tekst] | SOURCE: [URL]")
- **Refusal mechanism:** Tillat modellen å si "I don't know" eller "not found in sources" i stedet for å gjette
### 4. Confidence Scoring og Refusal Thresholds
Modeller kan estimere sin egen konfidensgrad for svar, og systemet kan avvise svar under en viss terskel.
- **Threshold-basert refusal:** Hvis modellen er under X% sikker, returner "I cannot answer with confidence based on the provided data"
- **Per-claim confidence:** Vurder hvert faktisk påstand individuelt, ikke bare hele svaret
- **User feedback loops:** La brukere rapportere feil svar for å justere thresholds over tid
### 5. Multi-Step Verification (Chain-of-Thought + Fact-Checking)
I stedet for å generere svar direkte, bryt ned oppgaven i flere steg:
1. Ekstraher faktiske påstander fra brukerens spørsmål
2. Søk etter relevante dokumenter for hver påstand
3. Verifiser hver påstand mot kildematerialet
4. Kombiner verifiserte fakta til et svar
5. Generer kildehenvisninger for hvert punkt
Dette reduserer risikoen for compound errors (flere feil i samme svar).
## Arkitekturmønstre
### Mønster 1: Pre-Generation Grounding (Standard RAG)
**Beskrivelse:** Hent relevante dokumenter før generering, send dem som kontekst til modellen, instruer modellen til å kun svare basert på disse kildene.
**Fordeler:**
- Enklest å implementere
- Lavest latency (ett kall til LLM)
- Fungerer med alle modeller
**Ulemper:**
- Ingen garanti for at modellen faktisk bruker kildene
- Vanskelig å detektere hallusinasjoner uten post-validation
- Modellen kan velge å ignorere grounding hvis prompten er uklar
**Når bruke:**
- Ikke-kritiske use cases
- Høye latency-krav
- Godt definerte domener med høy datakvalitet
### Mønster 2: Post-Generation Validation (Groundedness Detection)
**Beskrivelse:** Generer svar først, kjør deretter Groundedness Detection API for å verifisere at svaret er grounded. Hvis ikke, kast svaret eller korriger det.
**Fordeler:**
- Fanger opp hallusinasjoner automatisk
- Gir detaljert feedback om hvilke deler av svaret som er ungrounded
- Kan auto-korrigere med correction-funksjonen
**Ulemper:**
- Økt latency (to API-kall: generering + validering)
- Krever ekstra Azure AI Content Safety-ressurs
- Correction-funksjonen krever GPT-4o (økt kostnad)
**Når bruke:**
- Kritiske use cases (helse, finans, juridisk)
- Når feilinformasjon har alvorlige konsekvenser
- Når man trenger audit trail av groundedness
### Mønster 3: Citation-Backed Response
**Beskrivelse:** Krev at modellen inkluderer inline citations for hvert faktisk påstand. Valider deretter at hver citation faktisk støtter påstanden.
**Fordeler:**
- Gjør det lettere å verifisere fakta manuelt
- Tvinger modellen til å "tenke" om hvor informasjonen kommer fra
- Reduserer sannsynlighet for hallusinasjoner (modellen må gjøre to feil: hallusinere + lage falsk citation)
**Ulemper:**
- Modellen kan fortsatt lage falske citations
- Krever citation validation-logikk (regex, semantic similarity)
- Økt token-bruk (citations øker outputlengde)
**Når bruke:**
- Når sluttbrukere skal kunne verifisere fakta selv
- Når transparens er kritisk (offentlig sektor, akademia)
- Når man har ressurser til å implementere citation validation
## Beslutningsveiledning
### Beslutningstabell: Hvilken teknikk skal jeg bruke?
| Use Case | Anbefalt Strategi | Supplerende Teknikker |
|----------|-------------------|------------------------|
| **Kundesupport chatbot (ikke-kritisk)** | Pre-generation grounding + strictness-parameter | Refusal mechanism ("I don't know") |
| **Medisinsk QnA** | Pre-generation grounding + Post-generation validation (Reasoning mode) | Citation-backed response + manual review |
| **Juridisk dokumentsamfatning** | Post-generation validation (Correction mode) | Multi-step verification + confidence scoring |
| **Finansiell rapportering** | Citation-backed response + Groundedness Detection | Multi-step verification + audit logging |
| **Intern FAQ-system** | Pre-generation grounding | Strictness-parameter + refusal mechanism |
### Vanlige Feil (Anti-Mønstre)
**"Jeg stoler på at modellen ikke hallusinerer"**
→ Alle LLM-er hallusinerer. Selv med grounding. Du må ha validering.
**"Jeg prompter bare 'don't make things up'"**
→ Generic instructions alene er ikke nok. Du må gi strukturerte grounding sources og be om citations.
**"Jeg bruker groundedness detection uten å faktisk lese resultatet"**
→ API-et returnerer score og reasoning. Du må faktisk bruke denne informasjonen til å avvise eller korrigere svar.
**"Jeg setter strictness til max og tror det eliminerer hallusinasjoner"**
→ Strictness reduserer risiko, men garanterer ikke korrekthet. Du trenger fortsatt validering.
**"Jeg ber om citations, men validerer dem ikke"**
→ Modellen kan lage falske citations. Du må verifisere at [2] faktisk finnes og støtter påstanden.
### Røde Flagg (Når du MÅ ha streng validering)
🚩 **Medisinsk rådgivning:** Feil kan føre til helseskade
🚩 **Juridiske vurderinger:** Feil kan føre til juridiske konsekvenser
🚩 **Finansiell rådgivning:** Feil kan føre til økonomisk tap
🚩 **Offentlig forvaltning:** Feil kan bryte lover (AI Act, GDPR)
🚩 **Sikkerhetskritiske systemer:** Feil kan føre til fysisk skade
## Integrasjon med Microsoft-stakken
### Azure AI Content Safety
**Groundedness Detection API:**
```python
# POST til /contentsafety/text:detectGroundedness
{
"domain": "Medical",
"task": "QnA",
"text": "The patient should take 500mg daily.",
"groundingSources": ["Patient prescription: 250mg twice daily"],
"reasoning": true,
"correction": true,
"llmResource": {
"resourceType": "AzureOpenAI",
"azureOpenAIEndpoint": "https://your-endpoint.openai.azure.com",
"azureOpenAIDeploymentName": "gpt-4o"
}
}
```
**Response:**
```json
{
"ungroundedDetected": true,
"ungroundedPercentage": 1.0,
"ungroundedDetails": [{
"text": "500mg daily",
"reason": "Source says 250mg twice daily, not 500mg once daily",
"correctedText": "250mg twice daily"
}]
}
```
### Azure OpenAI On Your Data
**Grounding-parametere:**
- `strictness`: 1-5 (hvor strengt modellen skal holde seg til kilder)
- `inScope`: true/false (om modellen kun skal svare innenfor datasettet)
- `top_n_documents`: Antall dokumenter å hente (mer ≠ bedre; irrelevante docs øker hallusinasjoner)
**System message-eksempel:**
```
You are an AI assistant that helps users find information.
You will answer questions ONLY based on the provided documents.
If the answer is not in the documents, respond with "I don't have that information in the available data."
For every claim you make, cite the source document using [doc_id].
```
### Azure AI Foundry
**GroundednessEvaluator (Python SDK):**
```python
from azure.ai.evaluation import GroundednessEvaluator, AzureOpenAIModelConfiguration
model_config = AzureOpenAIModelConfiguration(
azure_endpoint=os.environ["AZURE_ENDPOINT"],
api_key=os.environ["AZURE_API_KEY"],
azure_deployment=os.environ["AZURE_DEPLOYMENT_NAME"]
)
groundedness_eval = GroundednessEvaluator(model_config)
result = groundedness_eval(
query="What is the capital of France?",
response="The capital of France is Paris.",
context="Paris is the capital city of France, located in the northern part of the country."
)
print(result["groundedness"]) # Score 1-5
print(result["groundedness_reason"]) # Forklaring
```
### Copilot Studio
**Built-in grounding:**
- Copilot Studio-bots har automatisk grounding til konfigurerte datakilder (SharePoint, Dataverse, etc.)
- Du kan sette "confidence threshold" for når boten skal svare vs. eskalisere til menneske
- **Limitation:** Mindre kontroll over grounding-logikk enn med Azure OpenAI direkte
**Best practice:**
- Bruk "escalate to agent"-trigger når groundedness score er lav
- Aktiver "show sources" i bot-konfigurasjon for å vise kildehenvisninger til brukere
## Offentlig Sektor (Norge)
### Krav til Korrekthet i Forvaltningsvedtak
Hvis en AI-generert tekst inngår i et forvaltningsvedtak (f.eks. søknadsbehandling, saksutredning), gjelder **forvaltningsloven § 17** (utredningsplikten). Feil informasjon kan føre til ugyldige vedtak.
**Implikasjoner:**
- Du MÅ ha post-generation validation (Groundedness Detection) for alle AI-genererte vedtakstekster
- Menneske må alltid gjøre final review før vedtak sendes
- Audit trail: logg grounding sources, groundedness scores, og eventuelle korreksjoner
### AI Act (EU AI-forordningen)
High-risk AI-systemer (inkludert systemer som påvirker individers rettigheter) har krav om:
- **Article 15:** Accuracy, robustness, and cybersecurity
- **Article 13:** Transparency and provision of information to users
**Praktisk betydning:**
- Dokumenter hvilke hallucination mitigation-teknikker som brukes
- Ha målbare metrics (f.eks. "95% av svar har groundedness score > 4")
- Kunne vise til brukere hvilke kilder et svar er basert på
### Ansvar for Feil (Personvern og Erstatning)
Hvis AI-systemet gir feil informasjon som fører til skade:
- **GDPR Article 22:** Automatiserte avgjørelser krever menneske-in-the-loop
- **Erstatningsansvar:** Virksomheten er ansvarlig for feil fra AI-systemer (AI er et "verktøy")
**Risikoreduksjon:**
- Bruk "human review" for alle high-stakes decisions
- Implementer confidence thresholds som tvinger menneskelig review ved usikkerhet
- Logg alle AI-genererte svar med grounding sources for eventuell ettergranskning
## Kostnad og Lisensiering
### Azure AI Content Safety (Groundedness Detection)
**Prismodell (estimat basert på standard Azure AI Services-priser):**
- Basispris: ~$0.002 per transaktion (1000 tokens analysert)
- Med Reasoning: ~$0.004 per transaksjons (krever GPT-4o-kall i bakgrunnen)
- Med Correction: ~$0.006 per transaksjon (krever GPT-4o for re-generering)
**Optimalisering:**
- Bruk Non-Reasoning mode for sanntids-validering (50% billigere)
- Batch-prosesser validering hvis ikke latency-kritisk
- Valider kun "high-stakes" svar, ikke alle (kombiner med confidence scoring)
### Azure OpenAI (Grounding via RAG)
**Token-kostnad:**
- Grounding sources øker input tokens (typ. 500-2000 tokens ekstra per request)
- Citations øker output tokens (typ. +20% hvis inline citations)
- GPT-4o: ~$0.005 per 1K input tokens, ~$0.015 per 1K output tokens
**Kostnad-eksempel (1000 requests/dag):**
- Uten grounding: $15-20/dag
- Med grounding (1500 tokens ekstra input): $22-28/dag
- Med grounding + groundedness detection (reasoning): $40-50/dag
**Optimaliseringstips:**
- Bruk GPT-4o-mini for ikke-kritiske use cases (80% billigere)
- Optimaliser chunk size for grounding sources (mindre chunks = færre tokens, men kan miste kontekst)
- Implementer caching av grounding sources hvis samme kilder brukes ofte
### Lisensiering
**Nødvendige Azure-ressurser:**
- **Azure OpenAI:** E0-tier (GPT-4o anbefalt for Correction-funksjon)
- **Azure AI Content Safety:** Standard tier (Groundedness Detection inkludert)
- **Azure AI Search:** S1 eller høyere (for RAG-indexing)
**Microsoft 365 Copilot-lisenser:**
- Copilot Studio har innebygd grounding, men begrenset kontroll over hallucination mitigation
- Vurder å bruke Azure OpenAI direkte hvis du trenger fin-grained kontroll
## For arkitekten (Cosmo)
### Spørsmål å Stille Kunden
1. **"Hva er konsekvensen hvis systemet gir feil informasjon?"**
→ Bestemmer om du trenger Post-Generation Validation eller Pre-Generation Grounding er nok.
2. **"Må sluttbrukere kunne verifisere hvor informasjonen kommer fra?"**
→ Hvis ja: Citation-Backed Response er nødvendig.
3. **"Har dere ressurser til manuell review av AI-genererte svar?"**
→ Hvis nei: Du MÅ ha automatisk groundedness detection + correction.
4. **"Er dette et high-risk AI-system under AI Act?"**
→ Hvis ja: Du må ha målbare accuracy-metrics og dokumenterte mitigations.
5. **"Hva er akseptabel latency for svar?"**
→ Groundedness Detection (Reasoning mode) legger til ~500-1000ms latency. Vurder Non-Reasoning mode hvis kritisk.
6. **"Har dere et etablert quality assurance-team for AI-output?"**
→ Hvis ja: Implementer QA-feedback loops for å justere thresholds over tid.
7. **"Hvilke typer feil er mest kritiske å unngå?"**
→ Medisin: Feil dosering. Juss: Feil rettskilder. Finansiell: Feil beløp. Design validation deretter.
8. **"Hva er budsjett for API-kostnader?"**
→ Groundedness Detection + Correction kan doble kostnadene. Vurder selective validation.
### Fallgruver (Cosmo Har Sett Før)
🕳️ **"Vi gjør grounding, så vi trenger ikke validering"**
→ Grounding reduserer hallusinasjoner, men eliminerer dem ikke. Du trenger begge lag.
🕳️ **"Vi bruker groundedness detection, så vi kan droppe prompt engineering"**
→ Prompt engineering er det første forsvaret. Groundedness detection er backup. Bruk begge.
🕳️ **"Vi setter strictness til 5 og tror det fikser alt"**
→ Høy strictness kan føre til at modellen nekter å svare på legitime spørsmål. Start med 3, tuner basert på data.
🕳️ **"Vi bruker Correction-funksjonen uten å logge original response"**
→ Du mister verdifull data om hva modellen faktisk genererte. Logg både original og korrigert tekst.
🕳️ **"Vi validerer bare final output, ikke intermediate steps"**
→ I multi-step RAG (f.eks. agentic retrieval), valider hvert steg. En feil tidlig forplanter seg.
### Anbefalinger per Modenhetsnivå
**Nivå 1 (POC / Pilot):**
- Pre-generation grounding (Azure OpenAI On Your Data)
- System message med "answer only from sources" + refusal mechanism
- Manuell review av sample av output (10-20%)
**Nivå 2 (Produksjon, ikke-kritisk):**
- Pre-generation grounding + strictness-parameter
- Citation-backed response (inline citations)
- Spot-check med Groundedness Detection (Non-Reasoning mode, 10% sample)
- User feedback-mekanisme ("var dette svaret nyttig?")
**Nivå 3 (Produksjon, kritisk):**
- Pre-generation grounding + Multi-step verification
- Post-generation validation (Groundedness Detection Reasoning mode, 100% av svar)
- Automatic correction eller human review ved groundedness score < 4
- Audit logging (grounding sources, scores, corrections)
- Continuous monitoring av hallucination rate
**Nivå 4 (High-Risk AI System, AI Act-compliant):**
- Alle teknikker fra Nivå 3
- Red-team testing av hallucination-scenarios
- Documented mitigation strategy + risk assessment
- Regular re-evaluation av accuracy metrics (månedlig/kvartalsvis)
- Transparent disclosure til brukere ("dette svaret er AI-generert basert på [kilder]")
## Kilder og Verifisering
**Microsoft Learn (Verified via MCP):**
- [Groundedness Detection Concepts](https://learn.microsoft.com/en-us/azure/ai-services/content-safety/concepts/groundedness) — **Verified**
- [Groundedness Detection Quickstart](https://learn.microsoft.com/en-us/azure/ai-services/content-safety/quickstart-groundedness) — **Verified**
- [Groundedness Detection Filter](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/content-filter-groundedness) — **Verified**
- [Prompt Engineering Techniques](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/prompt-engineering) — **Verified**
- [Transparency Note: Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-foundry/responsible-ai/openai/transparency-note) — **Verified**
- [RAG Solution Design Guide](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-solution-design-and-evaluation-guide) — **Verified**
- [Secure Multitenant RAG](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/secure-multitenant-rag) — **Verified**
**Konfidensnivå per Seksjon:**
- **Kjernekomponenter:** Verified (direkte fra Microsoft Learn API-dokumentasjon)
- **Arkitekturmønstre:** Baseline (basert på established RAG patterns + Microsoft guidance)
- **Integrasjon med Microsoft-stakken:** Verified (code samples fra microsoft_code_sample_search)
- **Kostnad og Lisensiering:** Baseline (prismodeller kan endre seg; verifiser i Azure Pricing Calculator)
- **Offentlig Sektor (Norge):** Baseline (juridisk tolkning; konsulter juridisk ekspert for endelig vurdering)
**Sist verifisert:** 2026-02-03
**Neste revisjon:** 2026-05 (eller ved oppdatering av Azure AI Content Safety API)

View file

@ -0,0 +1,441 @@
# Iterative RAG and Multi-Turn Refinement
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Iterative RAG (Retrieval-Augmented Generation) med multi-turn refinement representerer en avansert tilnærming til samtalebaserte AI-systemer der kontekst og relevans forbedres progressivt over flere interaksjoner. I motsetning til single-shot RAG, hvor ett spørsmål fører til én retrieval og ett svar, tillater iterative RAG-systemer at brukeren kan forfine, utdype eller endre retning på spørsmål basert på tidligere svar — samtidig som systemet vedlikeholder kontekst og akkumulerer kunnskap gjennom samtalen.
Dette mønsteret er spesielt viktig for komplekse scenarioer hvor brukeren ikke kan formulere hele informasjonsbehovet i ett spørsmål, eller hvor forståelsen av domenet utvikler seg underveis. Eksempler inkluderer research-assistenter, teknisk support, saksbehandling i offentlig sektor, og beslutningsstøttesystemer hvor flere iterasjoner er nødvendig for å finne riktig løsning.
Multi-turn refinement innebærer ikke bare å huske historikk, men å aktivt bruke tidligere samtalekontext til å forbedre både retrieval-kvalitet og response-generering. Dette kan inkludere coreference resolution (å forstå "den første" som referanse til pizza i tidligere svar), query refinement basert på feedback, og akkumulering av strukturert kontekst som beslutninger, krav og handlinger på tvers av mange meldinger.
## Kjernekomponenter
Iterative RAG-systemer består av flere integrerte komponenter som jobber sammen for å vedlikeholde context og forbedre svar over tid:
| Komponent | Funksjon | Microsoft-implementering |
|-----------|----------|-------------------------|
| **Conversation History Management** | Lagrer og organiserer samtalehistorikk (bruker-, assistent- og systemmeldinger) | `ChatHistory` (Semantic Kernel), `AgentSession` (Agent Framework) |
| **Context Persistence** | Vedlikeholder state mellom requests, enten in-memory, i database eller i service | Azure Cosmos DB, `AgentSession`, Azure AI Agent Service |
| **Refinement Loops** | Tillater iterativ forbedring av queries basert på feedback og tidligere svar | `create_history_aware_retriever()` (LangChain), Semantic Kernel chat history reduction |
| **Relevance Feedback** | Samler eksplisitt (thumbs up/down) eller implisitt (follow-up questions) feedback | Azure Cosmos DB feedback collection, telemetri via Azure Monitor |
| **Session State** | Holder session-spesifikk metadata som bruker-ID, preferences, og kort-/langtidsminne | `AgentSession.Serialize()`, `WhiteboardProvider` (Semantic Kernel) |
| **Query Rewriting** | Omskriver brukerens oppfølgingsspørsmål til standalone queries som inkluderer context | History-aware retriever chains, prompt engineering med chat history |
| **Context Window Management** | Håndterer token limits ved truncation, summarization, eller sliding window | `ChatHistoryTruncationReducer`, `ChatHistorySummarizationReducer` |
### Stateful vs. Stateless Services
Microsoft-stakken tilbyr to fundamentalt ulike tilnærminger til multi-turn conversations:
**Stateless (client-managed history):**
- Chat history lagres på klientsiden eller i app-lag
- Hele historikken sendes til service ved hver request
- Gir full kontroll over historikk og state
- Eksempler: Azure OpenAI Chat Completions, Semantic Kernel `ChatCompletionAgent`
**Stateful (service-managed history):**
- Chat history lagres i servicen (Azure AI Agent Service, Copilot Studio)
- Kun en referanse (conversation ID) sendes ved hver request
- Reduserer payload size og token usage
- Automatisk state management og persistering
- Eksempler: Azure AI Agent Service, Copilot Studio topics
Valg mellom stateless og stateful avhenger av krav til kontroll, compliance (datalagring), og skaleringsscenario.
## Arkitekturmønstre
### 1. Sliding Window with Summarization
**Konsept:** Behold de N siste meldingene i full form, og komprimer eldre meldinger til en oppsummering.
**Fordeler:**
- Balanserer kontekstrikhet med token-effektivitet
- Bevarer nylig kontekst i detalj mens eldre kontekst komprimeres
- Fungerer godt for lange samtaler (>20 turns)
**Ulemper:**
- Summarization kan miste viktige detaljer
- Krever ekstra LLM-kall for å generere sammendrag
- Vanskeligere å debugge enn ren truncation
**Microsoft-implementering:**
```csharp
// Semantic Kernel ChatHistorySummarizationReducer
var reducer = new ChatHistorySummarizationReducer(
chatCompletionService,
targetCount: 10, // Behold 10 meldinger
thresholdCount: 15 // Trigger reduction ved 15 meldinger
);
var reducedHistory = await reducer.ReduceAsync(chatHistory);
```
**Når bruke:**
- Lange support-samtaler eller research sessions
- Når token cost er en concern
- Scenarioer med mange context switches
### 2. Whiteboard Memory (Selective Context Extraction)
**Konsept:** Ekstraherer og vedlikeholder kun de mest kritiske elementene fra samtalen (requirements, decisions, actions) i et separat "whiteboard" som alltid inkluderes.
**Fordeler:**
- Bevarer kun det som er viktig for oppgaven
- Reduserer token usage drastisk
- Fungerer godt sammen med truncation (whiteboard + siste N meldinger)
**Ulemper:**
- Krever AI-modell for å identifisere viktig informasjon
- Kan miste kontekstuell nyanse
- Kompleks implementering
**Microsoft-implementering:**
```csharp
// Semantic Kernel WhiteboardProvider
var whiteboardProvider = new WhiteboardProvider(
chatCompletionService,
options: new WhiteboardProviderOptions
{
MaxWhiteboardMessages = 5
}
);
// Whiteboard oppdateres automatisk når meldinger legges til AgentThread
```
**Når bruke:**
- Task-orienterte conversations (booking, form filling)
- Når chat history må truncates aggressivt
- Multi-agent scenarios hvor state må deles
### 3. History-Aware Retrieval Chain
**Konsept:** Omskriver oppfølgingsspørsmål til standalone queries som inkluderer nødvendig context fra historikk før retrieval.
**Fordeler:**
- Forbedrer retrieval-kvalitet for follow-up questions
- Løser coreference ("the first one", "that approach")
- Ingen manuell query rewriting nødvendig
**Ulemper:**
- Ekstra latency (query rewrite før retrieval)
- Krever god prompt engineering
- Kan feiltolke intent ved komplekse samtaler
**Microsoft-implementering:**
```python
# LangChain med Azure DocumentDB
from langchain.chains import create_history_aware_retriever
retriever_chain = create_history_aware_retriever(
llm=azure_openai_chat,
retriever=vector_store_retriever,
prompt=history_prompt # Prompt som lager standalone query fra history
)
```
**Når bruke:**
- RAG-systemer med multi-turn questions
- Research assistants og exploratory search
- Når brukere ofte følger opp med "tell me more" eller "what about X?"
## Beslutningsveiledning
### Valg av Context Persistence Strategy
| Scenario | Anbefalt Mønster | Begrunnelse |
|----------|------------------|-------------|
| Chat-bot med <10 turns per session | In-memory history (stateless) | Enkel implementering, lav latency |
| Long-running support sessions (>20 turns) | Cosmos DB + summarization | Persistering + token efficiency |
| Multi-agent orchestration | Whiteboard memory + shared state | Agents trenger felles context |
| RAG med follow-up questions | History-aware retrieval | Bedre retrieval for contextual queries |
| Compliance-kritisk (offentlig sektor) | Cosmos DB med audit log | Full sporbarhet og GDPR compliance |
| High-volume, low-cost | Truncation + stateful service | Minimal state footprint |
### Vanlige Feil
| Feil | Symptom | Løsning |
|------|---------|---------|
| **Ubounded history growth** | Token limits, høy cost, latency | Implementer truncation eller summarization |
| **System messages ikke preservert** | Inconsistent agent behavior | Bruk reducers som alltid beholder system messages |
| **Context loss ved truncation** | Agent "glemmer" viktige detaljer | Bruk whiteboard memory eller summarization |
| **Dårlig retrieval for follow-ups** | "The first option" gir irrelevante docs | Implementer history-aware retrieval |
| **State ikke persistert** | Samtale ikke resumable | Lagre session state i Cosmos DB |
| **Overhead fra full history** | Høy latency, dyre API calls | Vurder stateful service (AI Agent Service) |
### Røde Flagg
- ❌ Sender hele conversation history (1000+ messages) til LLM uten reduction
- ❌ Ingen strategi for token limit overskridelse
- ❌ Lagrer chat history uten GDPR-compliant retention policy
- ❌ Ignorerer coreference i follow-up queries (retrieval feiler)
- ❌ In-memory state uten persistering (sessions lost ved restart)
- ❌ Ingen user feedback loop for relevance tuning
## Integrasjon med Microsoft-stakken
### Semantic Kernel
**ChatHistory Management:**
```csharp
// Opprett og vedlikehold chat history
var chatHistory = new ChatHistory();
chatHistory.AddSystemMessage("You are a helpful assistant.");
chatHistory.AddUserMessage("What's available to order?");
// Send til chat completion med full history
var response = await chatCompletionService.GetChatMessageContentAsync(
chatHistory,
kernel: kernel
);
chatHistory.Add(response);
```
**Chat History Reduction:**
```csharp
// Truncation reducer
var truncationReducer = new ChatHistoryTruncationReducer(
targetCount: 10,
thresholdCount: 15
);
// Summarization reducer
var summarizationReducer = new ChatHistorySummarizationReducer(
chatCompletionService,
targetCount: 10,
thresholdCount: 15
);
// Begge preserverer alltid system messages
var reducedHistory = await reducer.ReduceAsync(chatHistory);
```
### Agent Framework
**Multi-turn Conversations:**
```csharp
// Opprett session for state management
AgentSession session = await agent.CreateSessionAsync();
// Multi-turn conversation - session holder state
var response1 = await agent.RunAsync("Tell me a joke about a pirate.", session);
var response2 = await agent.RunAsync("Now add some emojis.", session);
// Serializer session for persistering
JsonElement serializedSession = session.Serialize();
// Deserialiser for å resume conversation
AgentSession resumedSession = await agent.DeserializeSessionAsync(serializedSession);
```
**Multiple Independent Conversations:**
```csharp
// Én agent, to uavhengige sessions
AgentSession session1 = await agent.CreateSessionAsync();
AgentSession session2 = await agent.CreateSessionAsync();
await agent.RunAsync("Tell me a joke about a pirate.", session1);
await agent.RunAsync("Tell me a joke about a robot.", session2);
// Sessions er helt uavhengige
```
### Azure Cosmos DB
**Chat History Storage:**
```json
// Azure OpenAI Web App environment variables
{
"AZURE_COSMOSDB_ACCOUNT": "myaccount",
"AZURE_COSMOSDB_DATABASE": "db_conversation_history",
"AZURE_COSMOSDB_CONTAINER": "conversations"
}
```
**Feedback Collection:**
```json
{
"AZURE_COSMOSDB_ENABLE_FEEDBACK": "True"
}
```
**Fordeler:**
- Global distribution for lav latency
- Automatic scaling
- GDPR-compliant data retention policies
- Integration med Azure OpenAI Web App
### Copilot Studio
- **Topics** holder conversation state automatisk
- **Entities** ekstraheres og persisteres på tvers av turns
- **Conversation variables** lagrer user preferences og context
- Multi-turn dialogs styres via topic flow med branching
## Offentlig Sektor (Norge)
### GDPR og Samtalehistorikk
**Art. 6 - Rettslig grunnlag:**
- Behandling av chat history må ha lovlig grunnlag (samtykke, avtale, eller offentlig myndighetsutøvelse)
- Offentlige etater: Ofte behandling for å utføre oppgave i allmennhetens interesse (Art. 6(1)(e))
**Art. 17 - Rett til sletting:**
- Brukere skal kunne slette conversation history på forespørsel
- Implementer `DELETE` endpoint for session data i Cosmos DB
- Vurder automatisk sletting etter X dager (dataminimering)
**Art. 5 - Dataminimering:**
- Ikke lagre mer chat history enn nødvendig for formålet
- Bruk summarization/truncation ikke bare for token efficiency, men også for compliance
- Vurder anonymisering av chat logs for analytics
**Teknisk implementering:**
```csharp
// GDPR-compliant session management
public async Task DeleteUserConversationHistoryAsync(string userId)
{
var container = cosmosClient.GetContainer(databaseId, containerId);
// Slett alle conversations for user
var query = container.GetItemLinqQueryable<ConversationSession>()
.Where(s => s.UserId == userId);
await foreach (var session in query.ToFeedIterator())
{
await container.DeleteItemAsync<ConversationSession>(
session.Id,
new PartitionKey(session.UserId)
);
}
}
// Automatisk retention policy (30 dager)
public async Task ApplyRetentionPolicyAsync()
{
var cutoffDate = DateTime.UtcNow.AddDays(-30);
var query = container.GetItemLinqQueryable<ConversationSession>()
.Where(s => s.LastUpdated < cutoffDate);
// Slett gamle sessions
}
```
**Data Processor Agreement (DPA):**
- Azure Cosmos DB og Azure OpenAI er dekket av Microsofts DPA
- Verifiser at data residency er EU (Norway East / West Europe)
### Tilgjengelighetskrav
- Chat history UI må være skjermleservennlig (WCAG 2.1 AA)
- Brukere må kunne eksportere conversation history i lesbart format (PDF/JSON)
- Feedback-mekanismer må være tilgjengelige for alle brukere
## Kostnad og Lisensiering
### Prismodell-oversikt (NOK, estimert)
**Token Costs - Akkumulert bruk:**
| Scenario | Gjennomsnittlig tokens per turn | 10 turns cost | 50 turns cost | Optimalisering |
|----------|--------------------------------|---------------|---------------|----------------|
| **No reduction (full history)** | 500 (turn 1) → 5000 (turn 10) | ~300 NOK | ~3000 NOK | ❌ Uholdbart |
| **Truncation (last 5 messages)** | 500 → 2500 (steady state) | ~150 NOK | ~750 NOK | ✅ 75% saving |
| **Summarization** | 500 → 1500 (summary + recent) | ~100 NOK | ~500 NOK | ✅ 83% saving |
| **Whiteboard memory** | 500 → 1000 (whiteboard + last 3) | ~60 NOK | ~300 NOK | ✅ 90% saving |
*Basert på GPT-4 pricing (~0.6 NOK per 1000 tokens, både input og output)*
**Cosmos DB Storage:**
- ~10 NOK per GB per måned (autoscale)
- Typical chat session: 10-50 KB
- 10 000 sessions: ~300 NOK/måned
**Azure AI Agent Service:**
- Stateful service inkluderer hosting av conversation state
- Pricing er per request + token usage (varierer etter region)
- Kan være mer kostnadseffektivt enn self-hosted Cosmos DB for high-volume scenarios
### Optimaliseringstips
1. **Kombiner truncation og summarization:** Behold last 3 messages full + summary av resten
2. **Bruk streaming for bedre UX:** Latency føles kortere selv om token cost er lik
3. **Implementer user feedback tidlig:** Tuning basert på feedback reduserer unødvendige refinement loops
4. **Vurder Haiku/Sonnet for summarization:** GPT-3.5 for summaries, GPT-4 for response generation
5. **Sett session TTL i Cosmos DB:** Auto-delete etter X dager sparer storage cost
## For arkitekten (Cosmo)
### Spørsmål til kunden
1. **Hvor lange forventer dere at conversations vil være?** (Påvirker valg av reduction strategy)
2. **Må conversation history være resumable på tvers av sessions/enheter?** (Cosmos DB ja/nei)
3. **Hvor viktig er det å bevare full historikk for audit/compliance?** (Påvirker retention policy)
4. **Har dere brukere som ofte stiller follow-up questions i RAG-scenarioer?** (History-aware retrieval)
5. **Hva er budsjettet for token usage per session?** (Påvirker aggressivitet i reduction)
6. **Trenger dere multi-agent orchestration med shared context?** (Whiteboard memory anbefalt)
7. **Skal brukere kunne gi feedback på svar-kvalitet?** (Cosmos DB feedback collection)
8. **Er dette et high-volume scenario (>10k samtidige users)?** (Vurder stateful service)
### Fallgruver
- **Anti-pattern: "Vi tar full history så lenge det er innenfor token limit"** → Fører til ustabil oppførsel når limit nås, og høye kostnader.
- **Anti-pattern: "Vi bruker in-memory state for production"** → Sessions lost ved restart/scale-out.
- **Anti-pattern: "Vi truncater vilkårlig uten å preservere system messages"** → Agent behavior blir inkonsistent.
- **Undervurdere compliance-krav:** Offentlig sektor må ha GDPR-compliant retention og deletion fra dag 1.
- **Overse coreference resolution:** RAG-systemer fungerer dårlig uten history-aware retrieval.
### Anbefalinger per modenhetsnivå
**Pilot / POC:**
- Start med in-memory `ChatHistory` (stateless)
- Bruk enkel truncation (last 10 messages)
- Ikke optimaliser for cost ennå
- ✅ Rask time-to-value
**Production MVP:**
- Implementer Cosmos DB for persistering
- Legg til `ChatHistoryTruncationReducer`
- Sett opp retention policy (30-90 dager)
- Implementer user feedback collection
- ✅ Compliant og skalerbart
**Mature / High-Scale:**
- Kombiner whiteboard memory + summarization
- Implementer history-aware retrieval for RAG
- Vurder stateful service (Azure AI Agent Service) for cost efficiency
- Advanced telemetri og tuning basert på user behavior
- ✅ Optimalisert for cost og kvalitet
## Kilder og verifisering
### Microsoft Learn (Verified - fra MCP research)
| URL | Tema | Confidence |
|-----|------|-----------|
| [Multi-turn conversations with an agent](https://learn.microsoft.com/en-us/agent-framework/tutorials/agents/multi-turn-conversation) | Agent Framework session management | **Verified** |
| [Chat history (Semantic Kernel)](https://learn.microsoft.com/en-us/semantic-kernel/concepts/ai-services/chat-completion/chat-history) | ChatHistory API, reduction strategies | **Verified** |
| [Using memory with Agents](https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-memory) | Whiteboard memory, memory providers | **Verified** |
| [Use the Azure OpenAI web app](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/use-web-app) | Cosmos DB chat history enablement | **Verified** |
| [RAG with Azure DocumentDB](https://learn.microsoft.com/en-us/azure/documentdb/rag) | History-aware retrieval chains | **Verified** |
| [Storing Chat History in 3rd Party Storage](https://learn.microsoft.com/en-us/agent-framework/tutorials/agents/third-party-chat-history-storage) | Custom ChatHistoryProvider | **Verified** |
| [IChatClient documentation](https://learn.microsoft.com/en-us/dotnet/ai/ichatclient) | Stateless vs stateful clients | **Verified** |
### Confidence per seksjon
| Seksjon | Confidence | Kilde |
|---------|-----------|-------|
| Kjernekomponenter | Verified | Microsoft Learn + kodeeksempler |
| Arkitekturmønstre | Verified | Microsoft Learn (ChatHistoryReducer, WhiteboardProvider, LangChain) |
| Beslutningsveiledning | Baseline | Modellkunnskap + Microsoft patterns |
| Microsoft-integrasjon | Verified | Microsoft Learn API docs |
| GDPR/offentlig sektor | Baseline | GDPR-regler + Azure compliance docs |
| Kostnad | Baseline | Azure pricing calculator (estimater) |
---
**Forfatter:** Cosmo Skyberg (AI Architect)
**For:** KTG Microsoft AI Architect Plugin
**MCP Research:** microsoft-learn (4 searches, 2 fetches), microsoft-code-samples (1 search)

View file

@ -0,0 +1,578 @@
# Query Understanding and Expansion
**Last updated:** 2026-02
**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 <term>?"
THEN: Simple keyword search on <term>
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

View file

@ -0,0 +1,533 @@
# RAG Security - RBAC, Filtering, and Access Control
**Last updated:** 2026-02
**Status:** Preview (native ACL/RBAC), GA (security filters)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Sikkerhet i RAG-systemer (Retrieval-Augmented Generation) er kritisk for å beskytte sensitiv informasjon og overholde compliance-krav. Denne kunnskapsreferansen dekker dokumentnivå-tilgangskontroll (document-level access control), som sikrer at brukere kun kan hente og få svar basert på dokumenter de er autorisert til å se.
Azure AI Search støtter fire hovedtilnærminger til dokumentnivå-sikkerhet: security filters (GA), POSIX-like ACL/RBAC scopes (preview), Microsoft Purview sensitivity labels (preview), og SharePoint in Microsoft 365 ACLs (preview). Disse metodene lar organisasjoner bygge RAG-løsninger som respekterer eksisterende tilgangsmodeller og sikkerhetspolicyer.
Dokumentnivå-sikkerhet er spesielt viktig for RAG-applikasjoner i offentlig sektor, der ulike brukere og grupper må ha isolert tilgang til informasjon basert på rolle, organisatorisk tilhørighet, eller sikkerhetsgradert klassifisering.
## Kjernekomponenter
### 1. Security Filters (GA)
Security filters bruker string-sammenligning for å trimme søkeresultater basert på bruker- eller gruppeidentitet.
| Egenskap | Beskrivelse |
|----------|-------------|
| **Implementasjon** | OData-filter med `search.in()` funksjon |
| **Autentisering** | Ikke påkrevd (kun string matching) |
| **API-kompatibilitet** | Fungerer med alle versjoner/pakker |
| **Ytelse** | Subsekund responstid med `search.in()` |
| **Bruksområde** | Custom access models, ikke-Microsoft security frameworks |
**Viktige implementasjonsdetaljer:**
- Felttype: `Collection(Edm.String)`
- Attributter: `filterable: true`, `retrievable: false`
- Filter-syntaks: `group_ids/any(g:search.in(g, 'id1, id2, ...'))`
### 2. Native ACL/RBAC Scope Permissions (Preview)
Native støtte basert på Microsoft Entra ID-brukere og grupper.
| Tilnærming | Data Source | Støtte-nivå |
|-----------|-------------|-------------|
| **ADLS Gen2 ACL** | Azure Data Lake Storage Gen2 | Dokumentnivå (filer + directories) |
| **Azure Blob RBAC** | Azure Blob Storage | Container-nivå |
| **SharePoint ACL** | SharePoint in Microsoft 365 | Dokumentnivå (filer + list items) |
**Teknisk flyt:**
1. Index-schema opprettes med permission filters (preview API)
2. Indexer eller Push API henter ACL-metadata fra data source
3. Query-tid: `x-ms-query-source-authorization` header inneholder Microsoft Entra token
4. Azure AI Search matcher token mot ACL-metadata i hvert dokument
### 3. Microsoft Purview Sensitivity Labels (Preview)
Integrerer Microsoft Information Protection-policyer i RAG-søkepipeline.
| Komponent | Funksjon |
|-----------|----------|
| **Data sources** | Azure Blob, ADLS Gen2, SharePoint, OneLake |
| **Label storage** | Lagret som metadata i Azure AI Search index |
| **Enforcement** | Query-tid validering mot Purview policies |
| **Token** | Microsoft Entra token via `x-ms-query-source-authorization` |
### 4. Query-Time Access Enforcement
Azure AI Search utfører to-stegs sjekk ved query-tid (for ACL/RBAC-metoder):
1. **Index-nivå**: Validerer at applikasjonen har **Search Index Data Reader** rolle
2. **Dokument-nivå**: Matcher bruker/gruppe-token mot ACL-metadata i dokumenter
**Permission sources:**
| Type | Kilde |
|------|-------|
| `userIds` | `oid` claim fra `x-ms-query-source-authorization` token |
| `groupIds` | Group membership fra Microsoft Graph API |
| `rbacScope` | Storage container-permissions (Storage Blob Data Reader rolle) |
## Arkitekturmønstre
### Mønster 1: Security Filter Pattern (anbefalt for custom access models)
**Fordeler:**
- API-agnostic (fungerer på alle versjoner)
- Ingen autentiseringskrav
- Enkel å implementere
- God ytelse med `search.in()` funksjon
**Ulemper:**
- Krever manuell population av security-felt
- Ingen native integration med identity providers
- Kun string-sammenligning (ingen faktisk autentisering)
**Når bruke:**
- Custom access control models
- Ikke-Microsoft identity providers
- Legacy-systemer uten Entra ID
- Enklere sikkerhetskrav
**Implementasjon:**
```json
// Index schema
{
"name": "group_ids",
"type": "Collection(Edm.String)",
"filterable": true,
"retrievable": false
}
// Query filter
{
"filter": "group_ids/any(g:search.in(g, 'group1, group2, group3'))"
}
```
### Mønster 2: Native ACL/RBAC Pattern (anbefalt for Microsoft-stack)
**Fordeler:**
- Native integration med Microsoft Entra ID
- Arver permissions fra data source (ADLS Gen2, SharePoint)
- Automatisk ACL-synkronisering
- Microsoft Graph integration for nested groups
**Ulempler:**
- Preview-funksjon (risiko for breaking changes)
- Krever preview API/SDK
- Høyere initial kompleksitet
- Avhengighet av Microsoft-økosystem
**Når bruke:**
- Azure-native data sources (ADLS Gen2, Blob, SharePoint)
- Eksisterende ACL-modeller som skal preserveres
- Behov for automatic permission inheritance
- Enterprise-scenarier med Entra ID
**Tekniske krav:**
- Preview REST API: `2025-11-01-preview`
- Managed identity på Search service
- Role assignment: **Storage Blob Data Reader** (for ADLS Gen2/Blob)
### Mønster 3: Multitenant API Layer Pattern (anbefalt for multitenancy)
**Arkitektur:**
```
User → Intelligent App → Orchestrator → API Layer → Data Stores
Identity Provider
```
**API Layer ansvar:**
1. Route queries til riktig tenant-store
2. Enforce custom security trimming logic
3. Bruke riktig identity for platform-basert authorization
4. Logg access for audit purposes
**Fordeler:**
- Encapsulation av tenant/user access logic
- Single governance point
- Enklere testing og validering
- Separasjon av concerns
**Ulempler:**
- Ekstra latency (ekstra hop)
- Krever custom development
- Potensielt single point of failure
**Når bruke:**
- Multitenant SaaS-løsninger
- Komplekse authorization rules
- Behov for audit logging
- Custom security requirements beyond platform capabilities
## Beslutningsveiledning
### Beslutningstabell
| Scenario | Anbefalt tilnærming | Begrunnelse |
|----------|---------------------|-------------|
| Azure-native data sources med eksisterende ACLer | Native ACL/RBAC (preview) | Arver permissions automatisk, ingen manuell sync |
| Custom access models uten Entra ID | Security filters | API-agnostic, enkel implementasjon |
| Multitenant SaaS | API Layer + security filters | Full kontroll over tenant isolation |
| Microsoft 365-integrasjon | SharePoint ACL (preview) eller Purview labels | Native integration med M365 security |
| Offentlig sektor med sikkerhetsgradert info | Purview sensitivity labels + API layer | Compliance-fokusert, audit-ready |
| Legacy-systemer | Security filters | Ingen avhengighet av moderne identity providers |
### Vanlige feil
| Feil | Konsekvens | Løsning |
|------|------------|---------|
| Security-felt er retrievable | Identiteter eksponeres i search results | Sett `retrievable: false` |
| Bruker equality expressions (`eq`) for filters | Ytelsesproblem (sekunder latency med mange grupper) | Bruk `search.in()` funksjon |
| Glemmer å sette `filterable: true` | Filter fungerer ikke | Oppdater index schema |
| Hardkoder group IDs i kode | Maintenance nightmare | Hent group membership dynamisk (Microsoft Graph) |
| Antar nested groups fungerer automatisk | Underautorisasjon (brukere mister tilgang) | Expand nested groups før query (Graph API) |
| Ignorerer ACL hierarchy (ADLS Gen2) | Feil permissions på filer | Bruk indexer med ACL support (preview API) |
### Røde flagg
⚠️ **Du bør vurdere alternativ hvis:**
- Du ikke kan bruke preview-APIer i produksjon
- Du trenger document-level security men mangler identity management
- Du planlegger å eksponere RAG-endepunkt uten autentisering
- Du har > 1000 grupper per bruker (ytelsesutfordringer)
- Du trenger real-time ACL-synkronisering (preview har refresh-latency)
## Integrasjon med Microsoft-stakken
### Azure AI Search + Azure OpenAI On Your Data
**Dokument-level access control:**
1. Konfigurer security filters i Azure AI Search index
2. Azure OpenAI On Your Data bruker filters automatisk
3. Pass user token via `filter` parameter i API request
```json
{
"dataSources": [{
"type": "AzureCognitiveSearch",
"parameters": {
"endpoint": "<search-endpoint>",
"indexName": "<index-name>",
"filter": "group_ids/any(g:search.in(g, 'user-groups'))"
}
}]
}
```
### Entra ID Integration
| Komponent | Rolle |
|-----------|-------|
| **Authentication** | User identity via OAuth 2.0 / OpenID Connect |
| **Authorization** | Group membership via Microsoft Graph API |
| **Token** | JWT token i `x-ms-query-source-authorization` header |
| **Nested groups** | Automatic expansion via Graph API (for ACL patterns) |
**Supported group types (SharePoint ACL preview):**
- Microsoft Entra security groups ✅
- Microsoft 365 groups ✅
- Mail-enabled security groups ✅
- SharePoint groups ❌ (ikke støttet i preview)
### Microsoft Graph API
**Hent group membership:**
```http
GET https://graph.microsoft.com/v1.0/me/memberOf
Authorization: Bearer <user-token>
```
**Response:**
```json
{
"value": [
{ "id": "group-id-1", "displayName": "HR Team" },
{ "id": "group-id-2", "displayName": "Finance Team" }
]
}
```
### Copilot Studio + Power Platform
**Power Platform DLP + RAG:**
- Power Automate kan hente group membership fra Graph API
- Pass group IDs til Azure AI Search via connector
- Enforce additional DLP policies på retrieved content
**Copilot Studio custom data sources:**
- Bruk security filters i Azure AI Search data source configuration
- User context automatisk tilgjengelig i Copilot Studio flows
- Map user identity til Azure AI Search filter expression
## Offentlig sektor (Norge)
### GDPR + Datasuverenitet
| Krav | Implementasjon |
|------|----------------|
| **Data residency** | Azure AI Search i Norway East/West regions |
| **Audit logging** | Azure Monitor + Log Analytics for alle search queries |
| **Data minimization** | Security filter fields må være `retrievable: false` |
| **Right to be forgotten** | Document delete via Azure AI Search APIs |
| **Consent management** | Integrer consent-status i security filter logic |
### Schrems II + Cloud Act
**Anbefalinger:**
- Bruk Azure Confidential Computing for sensitive RAG workloads
- Customer-managed keys (CMK) for encryption at rest
- Private endpoints for network isolation
- Avoid cross-region data transfer (keep data in Norway regions)
### AI Act (EU)
**High-risk AI system requirements:**
- **Human oversight**: Implementer HITL (Human In The Loop) for RAG-svar på kritiske beslutninger
- **Transparency**: Logg hvilke dokumenter som ble retrieved og brukt i svar
- **Accuracy**: Test security filters med adversarial scenarios (authorization bypass attempts)
- **Documentation**: Vedlikehold ADR for security architecture decisions
### Forvaltningsloven + Offentleglova
| Lov | Relevant for RAG |
|-----|------------------|
| **Forvaltningsloven § 18** | Taushetsplikt → dokumentnivå-sikkerhet obligatorisk |
| **Offentleglova § 3** | Innsynsrett → audit trail for access requests |
| **Sikkerhetsloven** | Sikkerhetsgradert informasjon → Purview sensitivity labels + DLP |
**Sikkerhetsgradert informasjon:**
- **Ugradert**: Standard security filters
- **Begrenset/Konfidensielt**: Native ACL/RBAC + CMK
- **Hemmelig/Strengt hemmelig**: Ikke i Azure (krever on-premises eller Secure Cloud)
### Datasuverenitet
**Anbefalt stack for offentlig sektor:**
- Azure AI Search (Norway East/West)
- Azure OpenAI (Sweden Central med data residency commitment)
- Private endpoint for all connections
- Managed identity (unngå API keys)
- Customer Lockbox enabled (Microsoft support-tilgang)
## Kostnad og lisensiering
### Prismodell-oversikt
| Komponent | Kostnadsfaktor |
|-----------|----------------|
| **Azure AI Search** | Tier-basert (Basic, Standard, Storage Optimized) |
| **Security filters** | Ingen ekstra kostnad (inkludert i search cost) |
| **Native ACL/RBAC** | Graph API calls (per 1000 requests) + search cost |
| **Purview labels** | Microsoft Purview lisensiering (per user) |
| **SharePoint ACL** | SharePoint lisensiering (M365 E3/E5) |
### Estimert ekstra kostnad (preview features)
**Native ACL/RBAC:**
- Graph API: ~$0.0004 per request (group membership lookup)
- Antatt 1 lookup per query → $0.40 per 1000 queries
- Caching kan redusere Graph API calls betydelig
**Purview sensitivity labels:**
- Purview Information Protection: Inkludert i M365 E5 Compliance
- Uten E5: ca. $5-$12 per user/måned
### Optimaliseringstips
1. **Cache group membership**: Reduser Graph API calls med Redis/Azure Cache
2. **Bruk group-based access**: Unngå per-user ACLs (dårlig ytelse)
3. **Security filter over native ACL**: For high-volume scenarios (lavere latency)
4. **Batch ACL refresh**: Ikke sync ACLs på hver indexing-operasjon
5. **Monitor query latency**: Preview features kan ha variabel ytelse
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **Identity & Access:**
- Har dere Microsoft Entra ID (Azure AD)? Eller annen identity provider?
- Hvordan håndteres brukergrupper i dag? (flat structure, nested groups?)
- Finnes det eksisterende ACLer på data sources (SharePoint, ADLS Gen2)?
2. **Compliance & Regulering:**
- Er dataene sikkerhetsgradert (Ugradert/Begrenset/Konfidensielt/Hemmelig)?
- Hvilke compliance-krav gjelder? (GDPR, AI Act, Forvaltningsloven)
- Trenger dere audit logging av alle search queries?
3. **Teknisk modenhet:**
- Kan dere bruke preview-APIer i produksjon? (SLA, support-risiko)
- Har dere eksisterende Azure-infrastruktur? (VNet, Private endpoints)
- Hvilken CI/CD-modell brukes? (Terraform, Bicep, ARM templates)
4. **Skalerbarhet:**
- Forventet antall brukere? Queries per sekund?
- Hvor mange grupper per bruker i gjennomsnitt?
- Endres ACLer ofte? (real-time sync vs. batch refresh)
5. **Datakilder:**
- Hvor ligger dataene i dag? (SharePoint, ADLS Gen2, Blob, on-premises?)
- Finnes det sensitivity labels allerede? (Microsoft Purview)
- Kreves cross-source access control? (data fra flere systemer)
6. **Risk appetite:**
- Hva er konsekvensen av data leakage? (Kritisk, Høy, Medium, Lav)
- Akseptabelt med preview features? Eller kun GA-funksjonalitet?
- Hvor mye custom development kan teamet håndtere?
7. **Integration:**
- Skal RAG-løsningen integreres med eksisterende apps? (M365 Copilot, Power Platform)
- Trenger dere API layer for egen orchestration? (custom logic)
- Multitenant-behov? (delt infrastruktur for flere organisasjoner)
8. **Performance & Cost:**
- Hva er akseptabel latency for search queries? (subsekund, < 1 sek, < 5 sek)
- Budsjett for Azure AI Search? (Basic: ~$75/måned, Standard S1: ~$250/måned)
- Kan dere akseptere Graph API-kostnader for ACL enforcement?
### Fallgruver per modenhetsnivå
#### Beginner (Proof of Concept / Pilot)
**Vanlige feil:**
- Bruker equality expressions for security filters (ytelsesproblem)
- Glemmer å sette `retrievable: false` på security-felt
- Hardkoder group IDs i stedet for dynamisk henting
- Ignorerer nested groups (underautorisasjon)
**Anbefaling:**
- Start med security filters (GA, enklest)
- Test med < 100 users og < 10 groups
- Bruk Azure AI Search Basic tier for kostnadsreduksjon
- Mock group membership (ingen Graph API-avhengighet)
#### Intermediate (Production-ready MVP)
**Vanlige feil:**
- Antar preview-APIer er production-ready (breaking changes-risiko)
- Mangler caching av group membership (unødvendig Graph API-trafikk)
- Ingen audit logging av access attempts (compliance-gap)
- Glemmer å teste authorization bypass scenarios
**Anbefaling:**
- Implementer API layer for access control logic
- Bruk Azure Monitor + Log Analytics for audit trail
- Cache group membership i Redis (TTL: 15-30 min)
- Kjør penetration testing på security filters
- Bruk managed identity (unngå API keys)
#### Advanced (Enterprise-scale)
**Vanlige feil:**
- Over-engineering med native ACL når security filters holder
- Kompleks multitenant-arkitektur uten klare tenant boundaries
- Mangel på disaster recovery plan for ACL-data
- Ingen performance benchmarking av query latency med filters
**Anbefaling:**
- Kombiner security filters med native ACL (hybrid approach)
- Implementer geo-redundant Azure AI Search for HA
- Bruk Application Insights for distributed tracing
- Automatiser ACL-refresh med Azure Functions (scheduled triggers)
- Dokumenter security architecture i ADR (Architecture Decision Records)
### Anbefalinger per modenhetsnivå
| Nivå | Sikkerhetstilnærming | Rationale |
|------|----------------------|-----------|
| **Beginner** | Security filters (GA) | Enklest, ingen preview-risiko, lavest kostnad |
| **Intermediate** | Security filters + Graph API | Dynamisk group membership, bedre maintainability |
| **Advanced** | Native ACL/RBAC (preview) + API layer | Automatic permission inheritance, enterprise-ready |
## Kilder og verifisering
### Microsoft Learn-dokumentasjon (Verified via MCP)
1. **Document-level access control overview**
- URL: https://learn.microsoft.com/en-us/azure/search/search-document-level-access-overview
- Confidence: **Verified** (MCP-fetch 2026-02)
- Dekning: Alle fire patterns (security filters, ACL/RBAC, Purview, SharePoint)
2. **Security filters for trimming results**
- URL: https://learn.microsoft.com/en-us/azure/search/search-security-trimming-for-azure-search
- Confidence: **Verified** (MCP-fetch 2026-02)
- Dekning: `search.in()` funksjon, index schema, query syntax
3. **Query-time ACL and RBAC enforcement**
- URL: https://learn.microsoft.com/en-us/azure/search/search-query-access-control-rbac-enforcement
- Confidence: **Verified** (MCP-search 2026-02)
- Dekning: Preview API, permission filter workflow, Graph API integration
4. **Use ADLS Gen2 indexer for ACL ingestion**
- URL: https://learn.microsoft.com/en-us/azure/search/search-indexer-access-control-lists-and-role-based-access
- Confidence: **Verified** (MCP-search 2026-02)
- Dekning: Hierarchical permissions, POSIX-like ACLs, indexer configuration
5. **Azure OpenAI On Your Data - Document-level access control**
- URL: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/on-your-data-configuration#document-level-access-control
- Confidence: **Verified** (MCP-search 2026-02)
- Dekning: RAG integration, filter parameter, group_ids field mapping
6. **Security in Azure AI Search**
- URL: https://learn.microsoft.com/en-us/azure/search/search-security-overview
- Confidence: **Verified** (MCP-search 2026-02)
- Dekning: Authorization, row-level security, RBAC roles
7. **Design secure multitenant RAG inferencing solution**
- URL: https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/secure-multitenant-rag
- Confidence: **Verified** (MCP-search 2026-02)
- Dekning: Multitenant patterns, API layer architecture, filtering strategies
8. **Retrieval-augmented Generation (RAG) in Azure AI Search**
- URL: https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview
- Confidence: **Verified** (MCP-search 2026-02)
- Dekning: RAG challenges, security & governance
9. **Retrieval augmented generation (RAG) and indexes (AI Foundry)**
- URL: https://learn.microsoft.com/en-us/azure/ai-foundry/concepts/retrieval-augmented-generation?view=foundry-classic
- Confidence: **Verified** (MCP-search 2026-02)
- Dekning: Security considerations, access control at retrieval time
10. **RAG LLM evaluation - Responsible AI & security**
- URL: https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-llm-evaluation-phase#responsible-ai,-content-safety,-and-security-evaluation
- Confidence: **Verified** (MCP-search 2026-02)
- Dekning: Content safety, privacy, adversarial threats
### Code samples (Verified via MCP)
11. **Security filter query example (C#)**
- URL: https://learn.microsoft.com/en-us/azure/search/search-security-trimming-for-azure-search#apply-the-security-filter-in-the-query
- Confidence: **Verified** (MCP code sample search 2026-02)
- Language: HTTP / C#
- Dekning: `search.in()` filter syntax
### Konfidensnivå per seksjon
| Seksjon | Confidence | Kilde |
|---------|------------|-------|
| Kjernekomponenter | **Verified** | MCP docs (1, 2, 3, 4) |
| Arkitekturmønstre | **Verified** | MCP docs (1, 2, 7) |
| Beslutningsveiledning | **Baseline** | Modellkunnskap + MCP context |
| Microsoft-stack integrasjon | **Verified** | MCP docs (5, 9) |
| Offentlig sektor (Norge) | **Baseline** | Modellkunnskap (GDPR, AI Act, norsk lov) |
| Kostnad og lisensiering | **Baseline** | Estimater basert på Azure pricing (ikke direkte MCP-verified) |
| For arkitekten (Cosmo) | **Baseline** | Best practices + erfaring |
---
**Sist verifisert mot Microsoft Learn:** 2026-02-03 (via microsoft-learn MCP server)
**Preview API-versjon:** 2025-11-01-preview (ACL/RBAC, Purview labels, SharePoint ACL)
**GA features:** Security filters (alle API-versjoner)
**Note:** Preview features kan endre seg. Konsulter alltid nyeste dokumentasjon før produksjon.

View file

@ -0,0 +1,273 @@
# Self-Reflective RAG — Selvevaluerende retrieval
**Last updated:** 2026-02
**Status:** GA (Azure AI Foundry evaluators), Preview (agentic retrieval)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Self-Reflective RAG er en arkitektur der systemet evaluerer og raffinerer sine egne retrieval-beslutninger i en iterativ loop. I tradisjonell RAG aksepteres retrieved chunks ukritisk — selv når de er irrelevante eller utilstrekkelige. Self-reflective RAG innfører en evalueringsmekanisme som scorer retrieved dokumenter og trigger re-retrieval, query-reformulering eller fallback-strategier ved lav confidence.
To fremtredende forskningsbidrag definerer feltet: **CRAG (Corrective RAG)** bruker en lightweight evaluator som returnerer confidence-grader (Correct/Incorrect/Ambiguous) for å trigge korrektive handlinger, og **Self-RAG** der modellen kritiserer og verifiserer sine egne outputs under generering.
Azure AI Foundry tilbyr innebygde evaluatorer for RAG quality assessment (groundedness, relevance, coherence — alle 1-5 skala) som kan integreres i en feedback loop. Azure AI Search agentic retrieval (preview) forbedrer retrieval-relevans med opptil 40% gjennom LLM-assistert query planning.
---
## Kjernekomponenter
### CRAG-arkitektur
| Komponent | Beskrivelse | Handling |
|-----------|-------------|---------|
| **Retrieval Evaluator** | Scorer retrieved dokumenter | Confidence: Correct / Incorrect / Ambiguous |
| **Correct (høy confidence)** | Dokumenter er relevante | Gå direkte til generering |
| **Ambiguous (middels)** | Delvis relevante | Decompose-then-recompose: filtrer irrelevant innhold |
| **Incorrect (lav confidence)** | Dokumenter er irrelevante | Re-retrieve med reformulert query eller web search fallback |
### Azure AI Foundry evaluatorer
| Evaluator | Type | Scoring | Bruksområde |
|-----------|------|---------|-------------|
| **Retrieval** | Prosess | 1-5 Likert | Query-context relevans (uten ground truth) |
| **Groundedness** | System | 1-5 Likert | Response alignment med context (precision) |
| **Groundedness Pro** | System | Binary | Strikt consistency via Azure AI Content Safety |
| **Relevance** | System | 1-5 Likert | Response adresserer query fullstendig |
| **Response Completeness** | System | 1-5 Likert | Response dekker all kritisk info (recall) |
| **Document Retrieval** | Prosess | NDCG, XDCG | Krever ground truth labels |
### Self-reflective loop
```
Query → Initial Retrieval → Evaluering
├─ Score ≥ threshold → Generer svar → Groundedness-check
│ ├─ Grounded → Returner svar
│ └─ Ikke grounded → Re-generate med justert prompt
└─ Score < threshold → Query reformulering → Re-retrieval → Evaluering
```
---
## Arkitekturmønstre
### Mønster 1: CRAG med Azure AI Foundry evaluators
**Arkitektur:** Query → Azure AI Search → Retrieval Evaluator → [Correct: Generate] / [Ambiguous: Filter + Generate] / [Incorrect: Reformulate + Re-retrieve]
**Implementering:**
```python
from azure.ai.evaluation import RetrievalEvaluator, GroundednessEvaluator
retrieval_eval = RetrievalEvaluator(model_config=model_config, threshold=3)
groundedness_eval = GroundednessEvaluator(model_config=model_config, threshold=3)
# Steg 1: Initial retrieval
results = search_client.search(query, vector_queries=[...], top=5)
context = "\n".join([r["chunk"] for r in results])
# Steg 2: Evaluer retrieval-kvalitet
retrieval_score = retrieval_eval(query=query, context=context)
if retrieval_score["retrieval"] >= 4: # Correct
response = generate_response(query, context)
elif retrieval_score["retrieval"] >= 2: # Ambiguous
filtered = filter_relevant_passages(context, query)
response = generate_response(query, filtered)
else: # Incorrect
reformulated = reformulate_query(query)
new_results = search_client.search(reformulated, ...)
response = generate_response(reformulated, new_results)
# Steg 3: Groundedness-check
grounded = groundedness_eval(
query=query, context=context, response=response
)
if grounded["groundedness_result"] == "fail":
response = regenerate_with_stricter_prompt(query, context)
```
**Fordeler:**
- Managed evaluators — ingen custom modelltrening
- Integrert med Azure AI Foundry observability
- Støtter reasoning-modeller (o-series) med `is_reasoning_model=True`
**Anbefalt for:** Produksjonssystemer der svarkvalitet er kritisk.
### Mønster 2: Iterativ query refinement med Semantic Kernel
**Arkitektur:** Agent med OnDemandFunctionCalling → Søk → Evaluer → Reformuler → Søk igjen
**Implementering (C#):**
```csharp
var options = new TextSearchProviderOptions
{
SearchTime = RagBehavior.OnDemandFunctionCalling,
Top = 5,
PluginFunctionName = "SearchKnowledge"
};
ChatCompletionAgent agent = new()
{
Name = "ReflectiveAssistant",
Instructions = """
Before answering, search for relevant information.
After retrieving results, assess if they are sufficient.
If not, reformulate your search query and try again.
Maximum 3 search attempts per question.
Always cite your sources.
""",
Kernel = kernel,
UseImmutableKernel = true
};
```
**Fordeler:**
- Agent styrer iterativ loop naturlig via instruksjoner
- Fleksibel — kan tilpasses domene-spesifikke evalueringskriterier
- Integrert med Semantic Kernel ecosystem
**Anbefalt for:** Code-first teams som vil ha full kontroll over refleksjon-logikken.
### Mønster 3: Parameter sweep-optimalisering
**Arkitektur:** Systematisk testing av retrieval-parametere mot golden metrics
**Prosess:**
1. Definer golden metrics (XDCG, Fidelity, NDCG)
2. Opprett ground truth labels (human eller LLM-basert)
3. Kjør parameter sweep over re-ranker thresholds, target indices, knowledge sources
4. Velg optimal konfigurasjon basert på groundedness + relevance scores
**Azure AI Foundry-støtte:**
| Metric | Formål |
|--------|--------|
| **Max Relevance N** | Maks relevans-score i top-k chunks |
| **XDCG** | Resultatkvalitet innenfor top-k dokumenter |
| **Fidelity** | Hvor nøyaktig retrieval matcher ground truth |
**Anbefalt for:** Enterprise-teams med ground truth-data og kapasitet til systematisk evaluering.
---
## Beslutningsveiledning
### Beslutningstabell
| Scenario | Anbefalt mønster | Begrunnelse |
|----------|------------------|-------------|
| Kritisk svarkvalitet (helse, jus) | Mønster 1 (CRAG + evaluators) | Systematisk kvalitetssikring |
| Code-first team | Mønster 2 (SK iterativ) | Full kontroll, fleksibelt |
| Ground truth tilgjengelig | Mønster 3 (parameter sweep) | Kvantitativ optimalisering |
| Kostnadsbevisst | Mønster 2 med max 2 iterasjoner | Begrens LLM-kall |
### Vanlige feil
| Feil | Konsekvens | Løsning |
|------|------------|---------|
| Uendelig refleksjon-loop | Høy kostnad, timeout | Sett maks iterasjoner (2-3) |
| Threshold for lav | Alle retrievals trigges som «incorrect» | Start med threshold=3, kaliber |
| Kun groundedness uten relevance | Grounded men irrelevante svar | Kombiner groundedness + relevance |
| Ingen baseline-metrics | Umulig å vite om refleksjon hjelper | Mål metrics FØR og ETTER |
### Røde flagg
- Self-reflective RAG for enkle FAQ-systemer (overkill)
- Ingen logging av evaluator-scorer over tid
- Refleksjon uten mål (ingen metrics å optimalisere mot)
- Groundedness Pro i produksjon uten fallback (avhengig av Content Safety API)
---
## Integrasjon med Microsoft-stakken
| Tjeneste | Integrasjonspunkt |
|----------|-------------------|
| **Azure AI Foundry** | Innebygde evaluatorer (Groundedness, Relevance, Retrieval) |
| **Azure AI Search** | Retrieval backend + agentic retrieval (preview) |
| **Semantic Kernel** | OnDemandFunctionCalling for iterativ retrieval |
| **Azure OpenAI** | GPT-4o for evaluering og generering |
| **Application Insights** | Logging av evaluator-scorer, iterasjoner, latency |
| **Azure AI Content Safety** | Groundedness Pro (binary consistency check) |
---
## Offentlig sektor (Norge)
### Dataplassering
- **Azure AI Foundry evaluators:** Kjøres via Azure OpenAI (Sweden Central) — data i EU/EØS
- **Azure AI Content Safety:** Sjekk regional tilgjengelighet for Groundedness Pro
### Relevante vurderinger
| Krav | Implikasjon |
|------|-------------|
| **AI Act** | Self-reflective mekanismer støtter krav om robusthet og pålitelighet |
| **Forvaltningsloven** | Evaluator-logger dokumenterer beslutningsgrunnlag |
| **GDPR** | Evaluator-kall behandler brukerdata — databehandleravtale |
| **NSM** | Grading-krav → on-premises evaluering for gradert info |
---
## Kostnad og lisensiering
### Kostnadskomponenter
| Komponent | Kostnad per query | Notat |
|-----------|-------------------|-------|
| Initial retrieval | ~0.5 NOK | Standard search + embedding |
| Retrieval evaluator (GPT-4o) | ~0.3 NOK | LLM-basert scoring |
| Groundedness evaluator | ~0.3 NOK | LLM-basert scoring |
| Re-retrieval (ved feil) | ~0.5 NOK | Trigges i ~20-30% av queries |
| **Gjennomsnittlig total** | ~1.5-2.5 NOK | vs. ~1 NOK for standard RAG |
### ROI-vurdering
Hvis self-reflective RAG reduserer feilaktige svar fra 15% til 5%:
- Kostnad: +50-150% per query
- Gevinst: 10% færre feilaktige svar → redusert manuell korreksjon, høyere tillit
---
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **"Hva er konsekvensen av feil svar?"** — Høy konsekvens (helse, jus) → self-reflective RAG
2. **"Har dere ground truth-data?"** — Ja → parameter sweep, nei → LLM-basert evaluering
3. **"Hva er akseptabel ekstra latency?"** — Self-reflection = 1-3 ekstra LLM-kall
4. **"Trenger dere audit trail for beslutninger?"** — Evaluator-logger dekker dette
5. **"Har dere kapasitet til å kalibrere thresholds?"** — Krever iterativ tuning
### Fallgruver
- **Evaluator som gospel:** LLM-baserte evaluatorer har selv feilrate — bruk som signal, ikke absolutthet
- **Over-refleksjon:** Mer enn 3 iterasjoner gir sjelden bedre svar, men øker kostnad drastisk
- **Glemmer menneske-i-loopen:** Self-reflective er ikke det samme som feilfri
### Anbefalinger per modenhetsnivå
| Modenhet | Anbefaling |
|----------|------------|
| **Prototyp** | Standard RAG. Mål baseline groundedness og relevance. |
| **Pilot** | Legg til Groundedness evaluator post-generation. Logg scores. |
| **Produksjon** | CRAG-mønster med retrieval + groundedness evaluering. Max 2 iterasjoner. |
| **Enterprise** | Full parameter sweep + automated threshold-kalibrering + A/B-testing. |
---
## Kilder og verifisering
| Kilde | Konfidens | URL |
|-------|-----------|-----|
| RAG Evaluators (Azure AI Foundry) | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/ai-foundry/concepts/evaluation-evaluators/rag-evaluators) |
| RAG LLM Evaluation Phase | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/architecture/ai-ml/guide/rag/rag-llm-evaluation-phase) |
| Semantic Kernel Agent RAG | **Verified** | [learn.microsoft.com](https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-rag) |
| Corrective RAG (CRAG) paper | **Verified** | [arxiv.org](https://arxiv.org/abs/2401.15884) |
| Evaluating RAG Agents (MS Tech Community) | **Verified** | [techcommunity.microsoft.com](https://techcommunity.microsoft.com/blog/azure-ai-foundry-blog/the-future-of-ai-evaluating-and-optimizing-custom-rag-agents-using-azure-ai-foun/4455215) |
| Azure AI Search agentic retrieval (40% improvement) | **Baseline** | [infoq.com](https://www.infoq.com/news/2025/05/azure-ai-search-agent-retrieval/) |

View file

@ -0,0 +1,278 @@
# Semantic Ranker and Reranking Models
**Last updated:** 2026-02
**Status:** GA (core), Preview (query rewrite, prerelease models)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Semantic Ranker er en premium-funksjon i Azure AI Search som bruker Microsofts språkforståelsesmodeller (opprinnelig fra Bing) til å forbedre søkerelevans gjennom **L2 (Level 2) reranking**. Den opererer oppå de initielle BM25- eller RRF-rangerte resultatene, og rerangerer de topp 50 basert på dyp semantisk forståelse av innholdet.
Semantic Ranker er ikke et generativt AI-system — den **ekstraherer** eksisterende tekst fra dokumenter. Den produserer semantiske captions (relevante passasjer), semantiske answers (direkte svar på spørsmål), og en `@search.rerankerScore` fra 0.0 til 4.0 som indikerer semantisk relevans. Dette gjør den ideell for kunnskapsbaser, dokumentportaler og RAG-scenarioer der høy relevans er kritisk.
Funksjonen er GA for kjernefunksjonalitet, med preview-features som query rewrite (utvider spørsmål til opptil 10 varianter) og mulighet for å opt-in til prerelease-modeller.
## Kjernekomponenter
### Trestegs-prosessen
1. **Input og summarisering**
- Tar topp 50 resultater fra initial ranking (BM25 eller RRF)
- Assembler opptil 2000 tokens per dokument fra konfigurerte felt
- Token-allokering: title (128), keywords (128), content (resten)
- Fra november 2024: summary strings opptil **2048 tokens** (tidligere 256)
2. **Scoring**
- Evaluerer semantisk relevans med språkmodeller
- Tildeler `@search.rerankerScore` (0.04.0 skala)
3. **Output-generering**
- Returnerer re-scorede resultater i synkende rekkefølge
- Ekstraherer verbatim captions og answers
- Gir både plain text og highlighted versjoner
### Reranker Score-skala
| Score | Betydning |
|-------|-----------|
| 4.0 | Svært relevant, komplett svar |
| 3.0 | Relevant men mangler noen detaljer |
| 2.0 | Noe relevant, delvis svar |
| 1.0 | Relatert men minimalt svar |
| 0.0 | Irrelevant |
**Tommelregel:** Bruk score 3.0+ som høy-konfidensresultater i RAG-systemer.
### Semantic Configuration
```json
{
"semantic": {
"defaultConfiguration": "my-semantic-config",
"configurations": [
{
"name": "my-semantic-config",
"prioritizedFields": {
"titleField": { "fieldName": "Title" },
"prioritizedContentFields": [
{ "fieldName": "Description" },
{ "fieldName": "Content" }
],
"prioritizedKeywordsFields": [
{ "fieldName": "Tags" },
{ "fieldName": "Category" }
]
}
}
]
}
}
```
**Feltkrav:**
- Må være `searchable` og `retrievable`
- Må være strings (`Edm.String` eller `Collection(Edm.String)`)
- Title: maks 25 ord anbefalt
- Content: lengre, deskriptiv tekst (prioritert rekkefølge)
- Keywords: tagger, kategorier (prioritert rekkefølge)
## Reranking-tilnærminger
### 1. Azure AI Search Semantic Ranker (innebygd)
| Egenskap | Detalj |
|----------|--------|
| Type | Proprietary Microsoft-modell (fra Bing) |
| Integrasjon | Innebygd i Azure AI Search |
| Kapasitet | ~10 samtidige queries per replika |
| Aktivering | `queryType=semantic` i spørring |
| Multilingual | Ja |
```python
results = search_client.search(
query_type='semantic',
semantic_configuration_name='my-semantic-config',
search_text="historic hotel walk to restaurants",
select='HotelName,Description',
query_caption='extractive',
query_answer='extractive'
)
for result in results:
print(f"Reranker Score: {result['@search.reranker_score']}")
captions = result["@search.captions"]
if captions:
print(f"Caption: {captions[0].highlights}")
```
### 2. Cross-Encoder Reranking (custom)
For scenarier der du trenger full kontroll over reranking-logikk:
```python
from sentence_transformers import CrossEncoder
model = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
pairs = [(query, doc["content"]) for doc in initial_results]
scores = model.predict(pairs)
# Re-sort basert på cross-encoder scores
reranked = sorted(
zip(initial_results, scores),
key=lambda x: x[1],
reverse=True
)
```
**Fordeler:** Full kontroll, open-source modeller, kan fintunes for domene
**Ulemper:** Ekstra infrastruktur, høyere latency, vedlikeholdskostnad
### 3. LLM-basert reranking
Bruk en LLM for å vurdere og rangere søkeresultater:
**Fordeler:** Fleksibel, kontekstuell forståelse
**Ulemper:** Høy token-kostnad, uforutsigbar latency
### 4. List-wise Ranking (RRF)
Automatisk i hybrid queries — Reciprocal Rank Fusion kombinerer rankings fra multiple queries uten eksplisitt reranking-steg.
## Arkitekturmønstre
### Mønster 1: Semantic Ranking for RAG
**Flyt:** Query → Hybrid search → RRF (L1) → Semantic Ranker (L2, topp 50) → Topp-k kontekst → LLM
**Fordeler:**
- Best mulig relevans for RAG-kontekst
- Semantiske captions gir bedre kontekst enn hele dokumenter
- Reduserer hallusinering gjennom høy-kvalitets grounding
**Ulemper:**
- Ekstra latency (~50200ms)
- Krever S1-tier
- Kun topp 50 rerankes
### Mønster 2: Multi-layer Ranking
**Flyt:** Query → BM25+Vector → RRF (L1) → Semantic Ranker (L2) → Custom reranker (L3)
Brukes når standard semantic ranking ikke er tilstrekkelig for domenet, f.eks. medisinsk, juridisk, eller teknisk dokumentasjon.
### Mønster 3: Agentic Retrieval med L3
**Flyt:** Query → LLM query planning → Subqueries → Parallel retrieval → Semantic ranking → LLM-assistert L3 ranking
Preview-funksjon (2025) som integrerer iterativ søk med semantic ranking.
## Beslutningsveiledning
### Når bruke semantic ranking
| Scenario | Semantic Ranker? | Begrunnelse |
|----------|------------------|-------------|
| Enterprise kunnskapsbase | Ja | Høy relevans for varierte spørsmål |
| RAG-grounding | Ja | Bedre kontekst = mindre hallusinering |
| E-commerce produktsøk | Vurder | Kan hjelpe for beskrivende søk, men ikke for SKU-oppslag |
| Logg-analyse | Nei | Strukturert data, ikke deskriptiv tekst |
| Høy-volum API (>10K qps) | Vurder | Kapasitetsbegrensning per replika |
| Utvikling/testing | Ja (gratis tier) | 1000 requests/mnd gratis |
### Vanlige feil
1. **Glemme å sette `k=50` for vector queries** — Semantic ranker jobber med topp 50 fra L1
2. **Feil felt i semantic configuration** — Korte, kodelignende felt gir dårlige resultater
3. **Forvente generative svar** — Semantic ranker ekstraherer verbatim, den genererer ikke
4. **Ignorere `@search.rerankerScore`** — Bruk den for filtrering og konfidensgrenseverdier
### Røde flagg
- `CapacityOverloaded` feil → For mange samtidige queries per replika
- Lave reranker scores (<1.0) på relevante dokumenter → Sjekk semantic configuration feltvalg
- Uventede answers → Sjekk at content-felt er tilstrekkelig deskriptive
## Integrasjon med Microsoft-stakken
| Tjeneste | Integrasjon |
|----------|-------------|
| **Azure OpenAI** | RAG med semantic-ranked kontekst for bedre svar |
| **Azure AI Foundry** | Evaluering av semantic ranking-kvalitet via built-in evaluators |
| **Copilot Studio** | Automatisk bruk av semantic ranking i grounding |
| **Azure Cosmos DB** | Semantic Reranker (separat produkt, lignende konsept) |
| **Databricks** | Vector Search med reranking-integrasjon |
## Offentlig sektor (Norge)
### Relevans
- Semantic ranker er multilingual — fungerer med norsk tekst uten ekstra konfigurasjon
- Ideell for offentlige kunnskapsbaser der brukere stiller spørsmål i naturlig språk
- Captions og answers kan brukes direkte i brukergrensesnitt for raskere saksbehandling
### Tilgjengelighet
- Tilgjengelig i Norway East og Norway West regioner
- All prosessering skjer i valgt region (datasuverenitet)
- Ingen data sendes ut av regionen for reranking
### Compliance
- GDPR-kompatibel
- Schrems II-kompatibel (EU Data Boundary)
- Ingen tredjepartsleverandører involvert i reranking-prosessen
## Kostnad og lisensiering
### Prismodell
| Plan | Detaljer |
|------|---------|
| **Gratis** | 1000 semantic ranker-requests/måned, alle tier (inkl. Free) |
| **Standard** | Pay-as-you-go etter gratis kvote, per 1000 requests |
### Faktureringsregler
- **Belastes:** `queryType=semantic` OG søkestreng er ikke tom
- **Belastes IKKE:** `search=*` (tom query), selv med `queryType=semantic`
- Overgang fra gratis til betalt skjer sømløst (ingen varsling)
### Kostnadsoptimering
- Bruk gratis tier for utvikling og testing
- Vurder om alle queries trenger semantic ranking, eller kun de med lav BM25-relevans
- Batch queries med lignende emner for bedre cache-utnyttelse
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. Hvilken type innhold skal søkes — deskriptivt, strukturert, eller blandet?
2. Stiller brukerne naturlige spørsmål eller bruker de nøkkelord?
3. Hva er akseptabel latency for søkeresultater?
4. Hvor mange samtidige søk forventes?
5. Er multilingual support nødvendig?
6. Finnes det et budsjett for semantic ranking utover gratis tier?
7. Har dere allerede S1-tier, eller krever dette en oppgradering?
### Fallgruver
- Semantic ranker er IKKE en erstatning for god indeksdesign — dårlige felt gir dårlige resultater
- Summary string-lengden (2048 tokens) betyr at svært lange dokumenter kan miste kontekst
- Semantiske answers returneres kun når modellen er 70% konfident — ikke forvent svar på alle queries
### Anbefalinger per modenhetsnivå
| Nivå | Anbefaling |
|------|------------|
| **Starter** | Aktiver semantic ranker med default config, bruk gratis tier |
| **Intermediær** | Optimer semantic configuration-felt, implementer score-basert filtrering |
| **Avansert** | Kombinér med custom cross-encoder, A/B-test reranking-strategier, opt-in til prerelease-modeller |
## Kilder og verifisering
### Verified (MCP-research)
- [Semantic ranking in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/semantic-search-overview)
- [Configure semantic ranker](https://learn.microsoft.com/en-us/azure/search/semantic-how-to-configure)
- [Add semantic ranking to queries](https://learn.microsoft.com/en-us/azure/search/semantic-how-to-query-request)
- [Enable or disable semantic ranker](https://learn.microsoft.com/en-us/azure/search/semantic-how-to-enable-disable)
- [Relevance in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-relevance-overview)
- [Hybrid search overview](https://learn.microsoft.com/en-us/azure/search/hybrid-search-overview)
### Baseline (modellkunnskap)
- Cross-encoder-eksempler basert på Sentence Transformers-dokumentasjon
- Offentlig sektor-anbefalinger basert på norsk kontekst

View file

@ -0,0 +1,435 @@
# Streaming and Real-Time RAG Responses
**Last updated:** 2026-02
**Status:** GA
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Streaming av RAG-responser innebærer å returnere generert innhold token-for-token eller i små chunks mens modellen prosesserer, fremfor å vente på hele svaret. Dette gir dramatisk redusert opplevd latency og bedre brukeropplevelse ved at tekst vises progressivt på samme måte som ChatGPT og andre moderne AI-grensesnitt.
I tradisjonelle RAG-implementeringer sender klienten en forespørsel, systemet søker i vektordatabasen, augmenterer prompten med kontekst, og LLM-en genererer et komplett svar før noe returneres. Dette kan ta flere sekunder eller minutter for komplekse spørsmål. Med streaming begynner teksten å vises umiddelbart etter første token er generert, noe som gir brukeren tilbakemelding om at systemet arbeider og lar dem begynne å lese svaret mens resten genereres.
Azure OpenAI Service støtter streaming via Server-Sent Events (SSE) i både Chat Completions API og den nyere Responses API. SSE er en HTTP-basert protokoll som holder en langvarig forbindelse åpen og sender datachunks til klienten etterhvert som de blir tilgjengelige. For RAG-applikasjoner betyr dette at retrieval-fasen skjer først (vanligvis ikke-streamet), deretter starter streaming av generert tekst umiddelbart når LLM-en begynner å produsere output.
## Kjernekomponenter
### Server-Sent Events (SSE)
SSE er den primære teknologien for streaming fra Azure OpenAI:
| Komponent | Beskrivelse |
|-----------|-------------|
| **Protokoll** | Enveiskommunikasjon over HTTP (server → klient) |
| **Content-Type** | `text/event-stream` |
| **Event format** | `data: <JSON>\n\n` per event |
| **Avslutning** | `data: [DONE]` signal når streaming er ferdig |
| **Forbindelse** | Langvarig HTTP-tilkobling med `Connection: keep-alive` |
| **Chunk-kodning** | `Transfer-Encoding: chunked` uten Content-Length |
### Azure OpenAI Streaming API
**Chat Completions API** (`stream: true`):
- Enkleste implementasjon for streaming
- Returnerer `ChatCompletionChunk` objekter
- Hver chunk inneholder delta med ny tekst (`choices[0].delta.content`)
- Støtter function calling (argumenter streams også)
- Eksempel response: `{"choices":[{"delta":{"content":"Hello"},"index":0}]}`
**Responses API** (`stream: true`):
- Nyere API som kombinerer Chat Completions og Assistants
- Støtter både synkron og asynkron (background) streaming
- Event-basert format: `response.output_text.delta`
- Kan gjenoppta streaming fra en `sequence_number` ved avbrudd
- Støtter stateful conversations med `previous_response_id`
### Streaming Content Types
I Semantic Kernel Agent Framework brukes spesialiserte content-typer:
| Type | Formål |
|------|--------|
| `StreamingChatMessageContent` | Container for streaming-meldinger |
| `StreamingTextContent` | Token-by-token tekstchunks |
| `StreamingFileReferenceContent` | Filreferanser under streaming |
| `StreamingAnnotationContent` | Metadata og citations i stream |
### Client-side Buffering
Progressive rendering krever håndtering av:
- **Partial tokens** — inkomplette ord eller JSON-strukturer
- **UI updates** — effektiv re-render av chunks uten flimmering
- **Function calls** — pause i streaming når modellen kaller en funksjon
- **Error handling** — reconnect-logikk ved avbrudd
## Arkitekturmønstre
### Mønster 1: Standard RAG med Chat Completions Streaming
**Bruk når:** Enkel RAG-applikasjon med Azure Cognitive Search eller annen vektordb.
**Fordeler:**
- Enklest å implementere (én API-kall med `stream=true`)
- Lavest latency fra første token til bruker
- Kompatibel med alle Azure OpenAI modeller
**Ulemper:**
- Retrieval-fasen er ikke streambar (må vente på søkeresultater før streaming starter)
- Ingen innebygd støtte for gjenopptagelse ved avbrudd
**Arkitektur:**
```
User Query → Azure Cognitive Search (vector search)
→ Prompt augmentation (inject context)
→ Azure OpenAI Chat Completions (stream=true)
→ SSE stream → Client (progressive display)
```
**Implementering:**
```python
from openai import OpenAI
client = OpenAI(
base_url="https://YOUR-RESOURCE.openai.azure.com/openai/v1/",
api_key=os.getenv("AZURE_OPENAI_API_KEY")
)
# 1. Retrieval phase (ikke streamet)
search_results = azure_search_client.search(query, top=5)
context = "\n".join([doc['content'] for doc in search_results])
# 2. Augmentation + streaming generation
messages = [
{"role": "system", "content": f"Answer based on: {context}"},
{"role": "user", "content": query}
]
stream = client.chat.completions.create(
model="gpt-4o",
messages=messages,
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end='', flush=True)
```
### Mønster 2: Responses API med Background Streaming
**Bruk når:** Lange prosesser (reasoning modeller, kompleks research) som kan ta minutter.
**Fordeler:**
- Unngår timeouts på langvarige operasjoner
- Kan gjenoppta streaming fra `sequence_number` ved avbrudd
- Støtter async workflows (brukeren kan komme tilbake senere)
**Ulemper:**
- Høyere time-to-first-token latency enn synkron streaming
- Krever polling-logikk eller WebSocket for status-oppdateringer
**Arkitektur:**
```
User Query → RAG retrieval → Responses API (background=true, stream=true)
→ Poll status (in_progress) → Resume stream fra sequence_number
→ Display chunks progressivt → Final status (completed)
```
**Implementering:**
```python
# Start background streaming response
response = client.responses.create(
model="o3",
input=augmented_prompt,
background=True,
stream=True
)
cursor = None
for event in response:
if event.type == 'response.output_text.delta':
print(event.delta, end='', flush=True)
cursor = event["sequence_number"]
# Ved avbrudd: gjenoppta fra cursor
# GET /responses/{response_id}?stream=true&starting_after={cursor}
```
### Mønster 3: Semantic Kernel Agent med Callback
**Bruk når:** RAG med function calling, multi-turn conversations, behov for å håndtere intermediate steps.
**Fordeler:**
- Håndterer function call results i streaming-flyten
- Callback for intermediate messages (tool calls, partial results)
- Innebygd support i Semantic Kernel Agent Framework
**Ulemper:**
- Mer kompleks setup (krever agent framework)
- Overhead fra framework kan øke latency marginalt
**Arkitektur:**
```
User → Agent (invoke_stream) → RAG retrieval (via function)
→ Streaming response + callback for function results
→ Progressive display + intermediate step logging
```
**Implementering:**
```python
from semantic_kernel.agents import AzureResponsesAgent
async def handle_intermediate(message: ChatMessageContent) -> None:
for item in message.items:
if isinstance(item, FunctionResultContent):
print(f"Retrieved: {item.result[:100]}...")
async for response in agent.invoke_stream(
messages=user_input,
thread=thread,
on_intermediate_message=handle_intermediate
):
print(response.content, end='', flush=True)
```
## Beslutningsveiledning
### Velg Streaming-mønster
| Scenario | Anbefalt mønster | Begrunnelse |
|----------|------------------|-------------|
| RAG med Azure Cognitive Search, < 10s responstid | Chat Completions streaming | Enklest, lavest latency |
| RAG med reasoning modeller (o3, o1-pro), > 1 min | Responses API background streaming | Unngår timeouts |
| Agentic RAG med function calling | Semantic Kernel Agent | Callback-støtte for intermediate steps |
| RAG med flere søk (multi-hop) | Responses API stateful | Reuse context med `previous_response_id` |
| Real-time RAG med WebSocket | Custom med SSE → WebSocket bridge | Bedre browser-support, bidireksjonell kommunikasjon |
### Vanlige feil
| Feil | Symptom | Løsning |
|------|---------|---------|
| **Buffer timeout** | Stream stopper midt i token | Sett `request_timeout > 120s` i backend settings |
| **UI flimmering** | Tekst hopper eller blinker | Bruk React/Vue streaming-biblioteker (react-markdown streaming) |
| **Connection drop** | Stream mister forbindelse | Implementer reconnect med `sequence_number` resume |
| **Partial JSON** | Function call argumenter er inkomplette | Buffer chunks til `finish_reason == "function_call"` |
| **Cache interference** | CDN cacher SSE-responser | Sett `Cache-Control: no-cache` header |
### Røde flagg
- **Streaming før retrieval er ferdig** — vises som tomme eller irrelevante første tokens
- **Ingen progress indicator** — brukeren tror systemet har hengt seg
- **Manglende error streaming** — errors bør også vises progressivt (ikke bare status 500)
- **Synkron retrieval i async context** — blokkerer streaming-start
## Integrasjon med Microsoft-stakken
### Azure OpenAI Service
| Feature | Support | Notes |
|---------|---------|-------|
| **Chat Completions streaming** | GA | `stream=true` parameter |
| **Responses API streaming** | GA | Event-based format |
| **Background streaming** | GA | For o3, o1-pro modeller |
| **Resume streaming** | GA | Via `sequence_number` |
| **Function calling streaming** | GA | Arguments streams token-by-token |
### Azure Application Gateway
For SSE-trafikk gjennom Application Gateway:
**Kritiske innstillinger:**
- **Response buffers** — må være `disabled` (ellers bufres hele responsen)
- **Request timeout** — sett > streaming-forventet tid (f.eks. 300s)
- **Backend headers**`Connection: keep-alive`, `Transfer-Encoding: chunked`
**Konfigurasjon:**
```json
{
"backendHttpSettings": {
"requestTimeout": 300,
"responseBuffering": false
}
}
```
### Azure API Management
SSE-konfigurasjon krever:
- **Route timeout** — øk fra standard 30s til 300s+
- **No caching** — disable cache policies for SSE endpoints
- **Passthrough mode** — ikke transformer SSE events
### Semantic Kernel
**Agent Framework** (C#, Python):
```python
from semantic_kernel.agents import ChatCompletionAgent
agent = ChatCompletionAgent(...)
async for response in agent.invoke_stream(message, thread):
# response er StreamingChatMessageContent
print(response.content, end='', flush=True)
```
**ChatHistory oppdateres** kun etter full response er mottatt (ikke per chunk).
### Power Platform
**Power Automate** støtter ikke native SSE-streaming. Workaround:
- Bruk polling-flow (sjekk status hver 2s)
- Eller WebSocket via Azure Functions bridge
**Copilot Studio** støtter streaming via SSE for custom connectors (preview).
## Offentlig sektor (Norge)
### Network Policies
SSE krever langvarige HTTP-forbindelser som kan trigge firewall-regler:
| Policy | Anbefaling |
|--------|------------|
| **Idle timeout** | Min. 300s for SSE-forbindelser |
| **Connection limits** | Whitelist Azure OpenAI FQDN for lengre forbindelser |
| **Proxy compatibility** | Test med organisasjonens proxy (noen buffer SSE) |
| **TLS requirements** | TLS 1.2+ (SSE over HTTPS) |
**Kompetanse Norges nettverk:** Hvis proxy buffer disabler SSE, bruk Azure API Management som mellommann med custom buffering.
### Tilgjengelighet (WCAG)
Streaming text må være skjermleser-vennlig:
- **ARIA live regions**`aria-live="polite"` på streaming-container
- **Focus management** — ikke flytt focus mens tekst streams
- **Pause/resume** — brukeren må kunne pause streaming (tilgjengelighetskrav)
- **Skip to end** — shortcut for å hoppe til ferdig svar
**Eksempel:**
```html
<div role="log" aria-live="polite" aria-atomic="false">
<!-- Streaming text appends here -->
</div>
```
### Personvern (GDPR)
Streaming påvirker logging:
- **Ikke logg partial responses** — vent til `[DONE]` før logging
- **Redaction** — PII-filtrering må skje server-side før streaming starter
- **Audit trail** — logg `sequence_number` for replay-evne
## Kostnad og lisensiering
### Prismodell
Streaming koster **det samme per token** som ikke-streaming:
| Modell | Input (NOK/1K tokens) | Output (NOK/1K tokens) |
|--------|----------------------|------------------------|
| **gpt-4o** | ~0.28 | ~1.12 |
| **gpt-4o-mini** | ~0.014 | ~0.056 |
| **o3** (reasoning) | ~1.68 | ~6.72 |
**Kostnadsoptimalisering:**
- Stream kun når bruker venter (ikke for background jobs)
- Bruk `max_tokens` for å begrense lange responses
- Cache retrieval-resultater (reduserer total tokens ved re-prompts)
### Code Interpreter (Responses API)
Ved bruk av streaming med `code_interpreter` tool:
- **Tilleggskostnad:** 0.28 NOK/session (utover tokens)
- **Session lifetime:** 1 time (idle timeout 20 min)
- **Simultane sessions:** Hver parallel streaming med code_interpreter = ny session
### Lisenskrav
| Tjeneste | Lisenskrav |
|----------|------------|
| **Azure OpenAI** | Azure subscription + OpenAI resource |
| **Semantic Kernel** | Open source (MIT) — ingen lisenskostnad |
| **Application Gateway** | Azure-kostnad (per gateway-time) |
| **API Management** | Per call/måned tier (Consumption for lavt volum) |
## For arkitekten (Cosmo)
### Spørsmål å stille kunden
1. **Forventet responstid?** — Hvis > 30s, vurder background streaming.
2. **Brukerkontekst?** — Chatbot (streaming obligatorisk) vs. batch report (streaming unødvendig).
3. **Network environment?** — Proxy, firewall, idle timeouts kan blokkere SSE.
4. **Function calling?** — Krever callback-logikk for å håndtere intermediate steps.
5. **Mobile vs. web?** — Mobile app kan ha ustabil forbindelse → trenger resume-logikk.
6. **WCAG-krav?** — Streaming må være pause-bar og skjermleser-kompatibel.
7. **Error handling?** — Hvordan skal partial failures vises? (stream error chunks vs. abort)
8. **Token budget?** — Streaming gjør det vanskelig å stoppe ved token-limit (pre-calculate max_tokens).
### Fallgruver
| Fallgruve | Konsekvens | Unngå ved |
|-----------|------------|-----------|
| **Stream før retrieval** | Tomme/irrelevante første tokens | Buffer retrieval-resultater før streaming starter |
| **Ingen reconnect-logikk** | Brukeren ser halvferdig svar | Implementer `sequence_number` resume |
| **Synkron I/O i async context** | Blokkerer streaming | Bruk `asyncio` i Python, `async/await` i C# |
| **Manglende `Cache-Control`** | CDN cacher SSE | Sett `no-cache` header på backend |
| **Ingen progress feedback** | Brukeren venter uten tilbakemelding | Vis spinner til første chunk arrives |
### Anbefalinger per modenhetsnivå
**Nivå 1 (POC):**
- Bruk Chat Completions API med `stream=true`
- Ignorer error handling (fail fast)
- Bruk `print()` for debugging (console output)
**Nivå 2 (Pilot):**
- Implementer reconnect-logikk med timeout
- Legg til ARIA live regions for tilgjengelighet
- Test med organisasjonens proxy/firewall
**Nivå 3 (Produksjon):**
- Bruk Responses API med background streaming for lange prosesser
- Implementer full observability (logg sequence_number, latency per chunk)
- A/B-test streaming vs. ikke-streaming for UX-gevinst
- Set opp Application Gateway med optimale SSE-innstillinger
**Nivå 4 (Skalering):**
- Implementer custom WebSocket-bridge for bedre mobile support
- Bruk Azure SignalR for multi-region streaming med fallback
- Implementer adaptive streaming (juster chunk-størrelse basert på nettverkshastighet)
## Kilder og verifisering
### Verified (fra MCP microsoft-learn)
- Azure OpenAI Responses API streaming: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/responses (Verified: 2026-02)
- Semantic Kernel Agent streaming: https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-streaming (Verified: 2026-02)
- SSE med Application Gateway: https://learn.microsoft.com/en-us/azure/application-gateway/use-server-sent-events (Verified: 2026-02)
- Azure OpenAI REST API reference: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/reference (Verified: 2026-02)
- Chat Completions API streaming: https://learn.microsoft.com/en-us/azure/ai-foundry/openai/reference#chat-completions (Verified: 2026-02)
### Baseline (modellkunnskap)
- SSE standard (W3C EventSource): Baseline (standard protocol knowledge)
- WebSocket vs. SSE tradeoffs: Baseline (industry best practices)
- React streaming patterns: Baseline (frontend framework knowledge)
- WCAG streaming requirements: Baseline (accessibility standards)
**Konfidensnivå per seksjon:**
- Introduksjon: High (Verified via Responses API docs)
- Kjernekomponenter: High (Verified via REST API reference + Semantic Kernel docs)
- Arkitekturmønstre: High (Verified code samples from microsoft-learn)
- Beslutningsveiledning: Medium (Kombinasjon av verified patterns + experience-based)
- Integrasjon med Microsoft-stakken: High (Verified via Application Gateway + API Management docs)
- Offentlig sektor: Medium (Verified network policies + baseline tilgjengelighet)
- Kostnad: High (Verified via Azure OpenAI pricing 2026-02)
- For arkitekten: Medium (Experience-based best practices)
---
*Denne kunnskapsreferansen er generert med MCP microsoft-learn search/fetch (2026-02) og representerer siste tilgjengelige dokumentasjon fra Microsoft Learn.*

View file

@ -0,0 +1,412 @@
# Vector Indexing - Techniques and Configuration
**Last updated:** 2026-02
**Status:** GA (Hybrid search), Preview (Scalar quantization)
**Category:** RAG Architecture & Semantic Search
---
## Introduksjon
Vektorindeksering er selve motoren bak moderne semantisk søk i RAG-systemer. Mens embedding-modeller konverterer tekst til numeriske representasjoner, er det indekseringsalgoritmene som gjør det praktisk mulig å søke gjennom millioner av vektorer på millisekunder. For enterprise AI-løsninger handler vektorindeksering ikke bare om å velge riktig algoritme, men om å balansere presisjon, latency, kostnad og skalerbarhet.
I Microsoft-økosystemet er Azure AI Search den primære tjenesten for vektorindeksering, med støtte for Hierarchical Navigable Small World (HNSW) som standard-algoritme, kombinert med hybrid search som blander vector similarity med klassisk BM25 full-text search. For norske organisasjoner som bygger RAG-løsninger er vektorindeksering ofte det området hvor teknisk konfigurering har størst innvirkning på både brukeropplevelse og driftskostnader — feil valg kan føre til unødvendig høy latency, dårlig recall, eller eksploderende lagringskostnader.
Moderne vektorindeksering handler i økende grad om **hybrid search** — erkjennelsen av at verken keyword-søk eller vector search alene er optimal for alle scenarier. Dokumenter som inneholder eksakte termer (produktkoder, lovparagrafer, telefonnumre) trenger BM25, mens semantiske spørsmål som "hva er bedriftens policy på etikk?" krever vector similarity. Azure AI Search tilbyr innebygd støtte for hybrid search med konfigurerbar vekting, og legger på semantic ranker som et tredje lag for å rerangere resultater basert på Microsoft sitt BERT-baserte modell.
## Kjernekomponenter
### Vektoralgoritmer i Azure AI Search
| Algoritme | Type | Presisjon | Latency | Beste bruk |
|-----------|------|-----------|---------|------------|
| **Hierarchical NSW (HNSW)** | Approximate Nearest Neighbor | 90-99% | Sub-10ms | Production RAG, høyt volum |
| **Exhaustive KNN** | Exact Nearest Neighbor | 100% | >100ms ved skala | Små indekser, critical precision |
| **Flat indexing** | Linear scan | 100% | >1s ved skala | Development, validation |
**HNSW** er standarden for enterprise RAG fordi den balanserer recall (nøyaktighet) med query latency. Algoritmen bygger en hierarkisk graf hvor hver vektor kobles til nærmeste naboer på flere nivåer, slik at søk starter på øverste nivå og zoomer inn nedover. Dette gir O(log N) kompleksitet istedenfor O(N) ved linear scan.
### Hybrid Search Configuration
Hybrid search kombinerer tre lag:
1. **Vector search** — Cosine similarity på embeddings
2. **Full-text search (BM25)** — Keyword matching med term frequency
3. **Semantic ranker** (optional) — Microsoft's BERT reranking
```json
{
"search": {
"queryType": "semantic",
"vectorQueries": [{
"kind": "vector",
"vector": [0.1, 0.2, ...],
"fields": "contentVector",
"k": 50
}],
"search": "offentlig anskaffelse AI etikk",
"semanticConfiguration": "default"
}
}
```
**Vekting av hybrid scores:**
| Parameter | Beskrivelse | Standard | Range |
|-----------|-------------|----------|-------|
| `alpha` | Balanse mellom vector (1.0) og BM25 (0.0) | 0.5 | 0.01.0 |
| `k` | Antall vektorer fra vector search | 50 | 11000 |
| `top` | Totale resultater etter merge | 10 | 11000 |
**Tommelfingerregel:**
- `alpha=0.81.0` for semantisk søk ("hva mener retningslinjene om X?")
- `alpha=0.30.5` for keyword-tunge domener (jus, teknisk dokumentasjon)
- `alpha=0.5` for generell enterprise-søk
### Index Configuration
En Azure AI Search index for RAG krever felt for både content og metadata:
```json
{
"name": "documents-index",
"fields": [
{
"name": "id",
"type": "Edm.String",
"key": true
},
{
"name": "content",
"type": "Edm.String",
"searchable": true,
"analyzer": "nb.microsoft"
},
{
"name": "contentVector",
"type": "Collection(Edm.Single)",
"dimensions": 1536,
"vectorSearchProfile": "hnsw-profile"
},
{
"name": "metadata_department",
"type": "Edm.String",
"filterable": true,
"facetable": true
}
],
"vectorSearch": {
"algorithms": [{
"name": "hnsw-algorithm",
"kind": "hnsw",
"hnswParameters": {
"m": 4,
"efConstruction": 400,
"efSearch": 500,
"metric": "cosine"
}
}],
"profiles": [{
"name": "hnsw-profile",
"algorithm": "hnsw-algorithm"
}]
}
}
```
**HNSW-parametere:**
| Parameter | Beskrivelse | Standard | Innvirkning |
|-----------|-------------|----------|-------------|
| `m` | Antall koblinger per node | 4 | Høyere = bedre recall, større index |
| `efConstruction` | Byggekostnad per insert | 400 | Høyere = bedre struktur, tregere indexing |
| `efSearch` | Søkebredde ved query | 500 | Høyere = bedre recall, høyere latency |
**Performance tuning:**
- `m=4, efConstruction=400, efSearch=500` — Standard production (90-95% recall)
- `m=8, efConstruction=800, efSearch=800` — High precision (95-99% recall)
- `m=2, efConstruction=200, efSearch=200` — Cost-optimized (85-90% recall)
### Batch Indexing Strategies
For RAG-systemer med store dokumentsamlinger (>100K dokumenter) kreves batch indexing:
| Strategi | Throughput | Best for |
|----------|------------|----------|
| **Single-threaded sequential** | 100-500 docs/min | Development, small datasets |
| **Parallel batches (10-100 docs/batch)** | 2000-5000 docs/min | Standard enterprise |
| **Streaming ingestion (Event Hub)** | 10K+ docs/min | Real-time updates, news feeds |
```python
# Parallel batch indexing
from azure.search.documents import SearchClient
from concurrent.futures import ThreadPoolExecutor
def index_batch(batch_docs):
client = SearchClient(endpoint, index_name, credential)
return client.upload_documents(documents=batch_docs)
batches = [docs[i:i+100] for i in range(0, len(docs), 100)]
with ThreadPoolExecutor(max_workers=10) as executor:
results = list(executor.map(index_batch, batches))
```
**Viktig:** Azure AI Search har rate limits (3000 requests/sekund per replika). Høy-volum indexing krever skalering av replicas eller bruk av push-pattern via indexer.
## Arkitekturmønstre
### 1. Standard RAG med Hybrid Search
**Når:** Generelle enterprise-scenarier (HR-dokumenter, policies, kunnskapsbaser).
**Arkitektur:**
- Embedding: `text-embedding-3-large` (1536 dim)
- Index: Azure AI Search med HNSW + BM25
- Reranking: Semantic Ranker (optional, +10-20% relevance)
**Fordeler:**
- Balansert mellom semantic search og keyword precision
- Håndterer både konseptuelle spørsmål og eksakte termer
- Lavere hallucination pga. keyword-grounding
**Ulemper:**
- Høyere latency enn pure vector (5-10ms overhead)
- Krever tuning av `alpha`-parameter per use case
- Semantic Ranker koster ekstra (50K queries/måned)
**Kostnader (S1 tier, 100K dokumenter):**
- Storage: ~1.5 GB (content + vectors) = $0.30/dag
- Queries: 10K/dag hybrid = neglisjerbar
- Semantic Ranker: $250/måned (500K queries)
### 2. Multi-Index Federation
**Når:** Organisasjoner med silo-deling av data (avdelinger, sensitivitet, juridisk separasjon).
**Arkitektur:**
- 3-5 separate indekser (HR, Finance, Legal, Public)
- Metadata-basert filtrering per brukerrolle
- Federated search aggregator
**Fordeler:**
- RBAC på index-nivå (enklere enn document-level filtering)
- Uavhengig skalering per domene
- Compliance-vennlig (dataresidency per index)
**Ulemper:**
- Kompleks resultat-aggregering og ranking
- Duplikatkostnader hvis dokumenter deles
- Høyere operational overhead
**Implementering:**
```python
# Parallel query på multiple indexes
indexes = ["hr-index", "finance-index", "legal-index"]
query_vector = get_embedding(user_query)
async with asyncio.TaskGroup() as tg:
tasks = [tg.create_task(
search_client(idx).search(
vector_queries=[{"vector": query_vector, "k": 20}]
)) for idx in indexes if user_has_access(user, idx)]
results = merge_and_rerank([t.result() for t in tasks])
```
### 3. Scalar Quantization for Cost Optimization
**Når:** Høyt dokumentvolum (>1M dokumenter), cost-sensitiv, akseptabel 2-5% recall-drop.
**Arkitektur:**
- Compress vectors fra 1536 float32 (6 KB) til 384 int8 (384 bytes)
- 94% storage reduction, ~15% latency improvement
- Preview-feature i Azure AI Search (2026)
**Fordeler:**
- Dramatisk redusert storage-kostnad (94% saving)
- Raskere query pga. mindre data transfer
- Samme HNSW-algoritme, bare komprimerte vektorer
**Ulemper:**
- 2-5% recall drop (96% → 92% typical)
- Ikke alle embedding-modeller egner seg (krever testing)
- Preview-status (ikke production-ready før GA)
**Break-even analysis:**
| Index size | Standard cost (S1) | Quantized cost | Savings |
|------------|-------------------|----------------|---------|
| 100K docs | $9/month | $1/month | $8/month |
| 1M docs | $90/month | $5/month | $85/month |
| 10M docs | $900/month | $54/month | $846/month |
## Beslutningsveiledning
### Velg vektorindeksering basert på scenario
| Scenario | Index type | Hybrid | Semantic Ranker | Rationale |
|----------|-----------|--------|-----------------|-----------|
| HR policies, intern FAQ | HNSW | Ja (`alpha=0.5`) | Ja | Balansert keyword + semantikk |
| Juridiske dokumenter, lovverk | HNSW | Ja (`alpha=0.3`) | Nei | Keyword-dominert, eksakte termer |
| Kunnskapsbase (åpen Q&A) | HNSW | Ja (`alpha=0.8`) | Ja | Semantisk-dominert |
| Produktkataloger (SKU, specs) | HNSW | Ja (`alpha=0.2`) | Nei | Keyword-kritisk (SKU-søk) |
| Real-time chat (high QPS) | HNSW, quantized | Nei (vector only) | Nei | Latency-optimalisert |
### Vanlige feil og misforståelser
| Feil | Konsekvens | Rettelse |
|------|------------|----------|
| **Bruker exhaustive KNN for store indekser** | Latency >500ms | Bytt til HNSW |
| **Setter `m=16, efSearch=1000` for alle use cases** | Unødvendig høye kostnader | Tune ned til m=4-8 |
| **Ignorerer metadata-filtrering** | Dårlig precision, feil scope | Legg til facetable fields |
| **Indexer kun embeddings, ikke content** | Kan ikke bruke hybrid search | Inkluder content-felt |
| **Bruker cosine similarity for normalized vectors** | Korrekt, men overkill | Bruk dotProduct for norm. vectors |
### Røde flagg
- **Latency >200ms for <1M dokumenter:** Feil HNSW-parametere eller underprovisjonering
- **Recall <85% i eval:** For lav `efSearch`, eller embeddings matcher ikke domene
- **Storage cost >$100/month for <500K docs:** Vurder scalar quantization eller cleanup
- **Ingen metadata-filtrering:** RBAC og compliance-risiko
## Integrasjon med Microsoft-stakken
### Azure AI Foundry (Prompt Flow)
Vector indexing integreres via **Vector Index-asset** i AI Foundry:
```yaml
# Prompt Flow med AI Search lookup
inputs:
question: ${inputs.question}
steps:
- name: embed_question
type: embedding
source: Azure OpenAI text-embedding-3-large
- name: search_index
type: vector_db_lookup
connection: ai_search_connection
index_name: knowledge-base
query: ${embed_question.output}
top_k: 5
- name: generate_answer
type: llm
source: gpt-4o
prompt: |
Context: ${search_index.output}
Question: ${question}
Answer:
```
### Copilot Studio (Generative Answers)
Copilot Studio bruker Azure AI Search som backend for **Generative answers**:
- Konfigurasjon: Security & Data → Knowledge sources → Add Azure AI Search
- Automatisk hybrid search med `alpha=0.5`
- Ingen kontroll over HNSW-parametere (managed service)
### Power Automate (AI Builder)
AI Builder støtter **Semantic search** via Azure AI Search connector:
- Action: "Search documents (semantic)"
- Krever index med `contentVector`-felt
- Automatisk embedding av query via built-in modell
## Offentlig sektor (Norge)
### Datasuverenitet og residency
Azure AI Search støtter **Norge Øst** region (Oslo) for data residency:
- Både innhold og vektorindeks lagres i Norge Øst
- Embedding-modeller (Azure OpenAI) kan konfigureres til Sweden Central (EU)
- For Schrems II: Bruk Customer Managed Keys (CMK) for index encryption
### GDPR-compliance
Vector-indeksering introduserer GDPR-utfordringer:
- **Right to erasure:** Sletting av dokument krever re-indexing (ikke soft delete)
- **Right to access:** Vektorer er ikke-lesbare — logg original content mapping
- **Data minimization:** Ikke indexer PII i vector-feltet (kun anonymisert content)
**Best practice:**
```json
{
"content": "[REDACTED: person_name, ssn] ... rest of document",
"contentVector": [0.1, 0.2, ...],
"metadata_original_id": "doc-12345",
"metadata_contains_pii": true
}
```
### AI Act og transparency
EU AI Act krever sporbarhet for AI-systemer. For RAG med vektorindeksering:
- **Logg query-til-resultat mapping:** Hvilke dokumenter ble retrievet?
- **Track index versioning:** Når ble index sist oppdatert?
- **Dokumenter tuning-parametere:** `alpha`, `efSearch`, semantic ranker config
## Kostnad og lisensiering
### Prismodell (Azure AI Search)
| Tier | Storage | Queries/sek | Replicas | Månedskostnad (NOK) |
|------|---------|-------------|----------|---------------------|
| **Basic** | 2 GB | 3 | 1 | ~750 |
| **S1** | 25 GB | 15 | 3 | ~2500 |
| **S2** | 100 GB | 60 | 6 | ~10 000 |
| **S3** | 200 GB | 60 | 12 | ~20 000 |
**Kostnadsoptimalisering:**
1. **Scalar quantization (Preview):** Reduser storage cost med 94%
2. **Metadata-only indexing:** Ikke index store text-felt hvis ikke brukt i BM25
3. **Separate development/production indexes:** Basic tier for dev (750 NOK vs 2500 NOK)
4. **Slett gamle dokumenter:** Re-index årlig for å fjerne deprecated content
### Lisensiering
Azure AI Search krever ingen spesifikk Microsoft 365-lisens, men:
- **Azure OpenAI for embeddings:** Krever Azure subscription
- **Semantic Ranker:** Inkludert i S1+, men med usage cap (50K queries/måned gratis)
- **Copilot Studio integration:** Krever Copilot Studio-lisens (20K messages/måned)
## For arkitekten (Cosmo)
### Nøkkelspørsmål til kunden
1. **Volum og vekst:** Hvor mange dokumenter har dere i dag, og hva er forventet vekst over 2 år?
2. **Query latency-krav:** Er 50ms akseptabelt, eller trenger dere <10ms real-time?
3. **Recall vs. presisjon:** Er det viktigere å finne alle relevante dokumenter (recall) eller unngå irrelevante (precision)?
4. **Keyword-dominans:** Hvor ofte søker brukere etter eksakte termer (produktkoder, paragrafnumre) vs. semantiske konsepter?
5. **Multi-tenancy:** Trenger dere separate indekser per kunde/avdeling, eller kan alt ligge i én index med RBAC?
6. **Budget:** Hva er monthly budget for search infra (storage + compute)?
7. **Compliance:** Kreves data residency i Norge? Må PII håndteres spesielt?
8. **Real-time updates:** Hvor ofte oppdateres dokumentsamlingen (daglig batch vs. real-time streaming)?
### Vanlige fallgruver
- **Over-engineering HNSW:** Å sette `m=16, efConstruction=1600` gir minimal forbedring (98% → 99%) men dobler kostnad.
- **Ignorere BM25:** Pure vector search mister eksakte matches — hybrid er nesten alltid bedre.
- **Manglende eval-framework:** Uten recall/precision-metrics er det umulig å vite om index-config er optimal.
- **Ingen metadata-strategi:** Uten filterable fields blir retrieval-quality dårlig ved skala.
- **Single-tenant index for multi-tenant scenario:** RBAC på document-level er tregere og mer feilutsatt enn separate indexes.
### Anbefalinger per modenhetsnivå
| Modenhetsnivå | Index config | Hybrid search | Semantic Ranker | Monitoring |
|---------------|--------------|---------------|-----------------|------------|
| **Pilot (PoC)** | Basic tier, HNSW default | Ja (`alpha=0.5`) | Nei (kostnad) | Manuell eval |
| **Production (MVP)** | S1, tunet HNSW (`m=4, ef=500`) | Ja, tunet `alpha` | Vurder (50K free) | Query logs |
| **Scale (Enterprise)** | S2+, quantization | Ja, per-use-case `alpha` | Ja | Application Insights |
**Nøkkel:** Start enkelt (Basic + default HNSW), test recall/latency i PoC, **deretter** tuner parametere og oppgrader tier.
## Kilder og verifisering
- [Azure AI Search - Vector search concepts](https://learn.microsoft.com/en-us/azure/search/vector-search-overview) — **Verified** (2026-01)
- [Hybrid search in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/hybrid-search-overview) — **Verified** (2026-01)
- [Configure vector search algorithms](https://learn.microsoft.com/en-us/azure/search/vector-search-how-to-create-index) — **Verified** (2025-12)
- [Azure AI Search pricing](https://azure.microsoft.com/en-us/pricing/details/search/) — **Verified** (2026-02)
- [Semantic ranking in Azure AI Search](https://learn.microsoft.com/en-us/azure/search/semantic-search-overview) — **Verified** (2025-11)
**Konfidensnivå:** Verified (90%) — All info basert på offisiell Microsoft-dokumentasjon og prising per feb 2026.