# Iterative RAG and Multi-Turn Refinement **Last updated:** 2026-04 | Verified: MCP 2026-04 **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() .Where(s => s.UserId == userId); await foreach (var session in query.ToFeedIterator()) { await container.DeleteItemAsync( 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() .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) ### .NET AI IChatClient-interface (oppdatert 2026-04) `IChatClient` er .NET-standarden for interaksjon med AI chat services (Microsoft.Extensions.AI). Støtter stateless og stateful samtaler, tool calling, streaming, caching, og OpenTelemetry. ```csharp // Stateful iterativ RAG med IChatClient List history = []; while (true) { history.Add(new(ChatRole.User, userInput)); ChatResponse response = await client.GetResponseAsync(history); history.AddMessages(response); // akkumulerer kontekst } ``` **Viktige egenskaper:** - `ConversationId` støtter stateful tjenester (slipper å sende full historikk) - `FunctionInvokingChatClient` gir automatisk tool invocation for agentic loops - `DistributedCachingChatClient` wrapper cacher identiske historikker - `ChatHistoryTruncationReducer` / `ChatHistorySummarizationReducer` håndterer context window limits - Pipeline-komposisjon: `ChatClientBuilder` stacker cache, tool invocation, og telemetri