# 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: \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
``` ### 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.*