# Disconnected AI Scenarios **Last updated:** 2026-02 **Status:** GA **Category:** Hybrid Cloud & Edge AI --- ## Introduksjon Frakoblede (disconnected) AI-scenarioer er situasjoner der AI-arbeidsbelastninger ma kjore uten internettilkobling — enten permanent, periodisk eller i beredskapssituasjoner. For norsk offentlig sektor er dette svart relevant: Forsvaret opererer i omrader uten nettdekning, helsesektoren trenger AI-stotte i ambulanser og utposter, og kritisk infrastruktur (energi, transport) ma fungere uavhengig av skytjenester. Microsoft tilbyr flere losninger for frakoblet AI: Azure AI Foundry Tools disconnected containers for tradisjonelle AI-tjenester (tale, tekst, bilde), Azure Stack Edge for hardware-basert edge-inferens, Azure Local med disconnected operations for storre Kubernetes-miljoer, og ONNX Runtime for helt lokale modellkjoringer uten skyavhengigheter. Denne referansen dekker de viktigste moensterne for offline modell-deployment, datarekonsiliering, lokal caching/synkronisering og fallback-strategier — alle med fokus pa palit drift nar nettverkstilkoblingen er ustabil eller fravarende. --- ## Spekter av tilkobling AI-scenarioer fordeler seg langs et tilkoblingsspektrum: ``` ┌─────────────────────────────────────────────────────┐ │ Alltid Sporadisk Periodisk Helt │ │ tilkoblet tilkoblet tilkoblet frakoblet │ │ ●──────────●────────────●────────────● │ │ | | | | │ │ Standard Connected Batch sync Air-gapped │ │ Azure containers + lokale │ │ services (billing) offline ops modeller │ └─────────────────────────────────────────────────────┘ ``` | Modus | Nettverkskrav | Azure-tjenester | Billing | |-------|---------------|-----------------|---------| | Alltid tilkoblet | Stabilt internett | Alle | Pay-as-you-go | | Connected containers | Periodisk (billing) | Begrensede | Bruksbasert | | Periodisk synk | Timer/dager mellom tilkoblinger | Batch-synk | Commitment tier | | Helt frakoblet | Ingen | Kun lokale | Forhndsbetalt lisens | --- ## Offline Model Deployment ### Azure AI Foundry Tools Disconnected Containers Microsofts primaere losning for AI-tjenester uten nettverkstilkobling: | Tjeneste | Container | Disconnected | Status | |----------|-----------|--------------|--------| | Speech to Text | speech-to-text | Ja | GA | | Custom Speech to Text | custom-speech-to-text | Ja | GA | | Neural Text to Speech | neural-text-to-speech | Ja | GA | | Translator | text-translation | Ja | GA | | Language Detection | text-language-detection | Ja | GA | | Key Phrase Extraction | text-keyphrase | Ja | GA | | Named Entity Recognition | text-ner | Ja | GA | | PII Detection | text-pii | Ja | GA | | Sentiment Analysis | text-sentiment | Ja | GA | | CLU | clu | Ja | GA | | Summarization | text-summarization | Ja | Preview | | Read OCR | vision-read | Ja | GA | | Document Intelligence | document-intelligence | Ja | GA | | Content Safety (Text) | contentsafety-text | Ja | Preview | | Content Safety (Image) | contentsafety-image | Ja | Preview | | Prompt Shields | contentsafety-promptshields | Ja | Preview | ### Prosess for disconnected deployment ``` ┌─────────────────────────────────────────┐ │ 1. Soknad og godkjenning │ │ ├── Enterprise Agreement kreves │ │ ├── Gyldig business case │ │ └── Godkjenning innen 10 dager │ │ │ │ 2. Lisensnedlasting │ │ ├── Kjop commitment tier │ │ ├── Last ned lisensfil │ │ └── Lisensfil har utlopsdato │ │ │ │ 3. Container-nedlasting │ │ ├── Pull fra MCR (online) │ │ ├── Eksporter til tar │ │ └── Overfar til offline-miljo │ │ │ │ 4. Offline deployment │ │ ├── Importer container │ │ ├── Mount lisensfil │ │ └── Kjor uten nettverkstilkobling │ └─────────────────────────────────────────┘ ``` ### Lisensnedlasting og container-oppsett ```bash # Steg 1: Last ned lisens (online maskin) docker run --rm -it \ -v /host/license:/license \ mcr.microsoft.com/azure-cognitive-services/speechservices/speech-to-text \ eula=accept \ billing=https://my-resource.cognitiveservices.azure.com \ apikey= \ DownloadLicense=True \ Mounts:License=/license # Steg 2: Eksporter container image docker save \ mcr.microsoft.com/azure-cognitive-services/speechservices/speech-to-text \ -o speech-to-text.tar # Steg 3: Overfar til offline-miljo (USB, etc.) # Kopier speech-to-text.tar og lisensfil # Steg 4: Importer pa offline-maskin docker load -i speech-to-text.tar # Steg 5: Kjor uten nettverkstilkobling docker run --rm -it -p 5000:5000 \ -v /host/license:/license \ mcr.microsoft.com/azure-cognitive-services/speechservices/speech-to-text \ eula=accept \ Mounts:License=/license \ Mounts:Output=/output ``` ### ONNX Runtime — helt lokale modeller For scenarioer uten Docker- eller lisensbehov: ```python # Helt lokal inferens med ONNX Runtime # Ingen skyavhengighet, ingen lisens, ingen Docker import onnxruntime as ort import numpy as np # Last modell fra lokal disk session = ort.InferenceSession( "/models/document-classifier.onnx", providers=['CPUExecutionProvider'] ) # Kjor inferens input_name = session.get_inputs()[0].name result = session.run(None, { input_name: np.array(preprocessed_data) }) ``` --- ## Azure Stack Edge i disconnected modus ### Nkkelforskjeller offline vs online | Funksjon | Online | Disconnected | |----------|--------|-------------| | Azure Portal management | Ja | Nei — kun lokal UI | | Kubernetes workloads | Full Arc-stotte | Lokal kubectl | | Container registry | Azure Container Registry | Edge Container Registry | | Overvaking | Azure Monitor | Lokalt Kubernetes dashboard | | Azure Arc | Full integrasjon | Ikke tilgjengelig | | VM-styring | Arc-enabled VMs | Lokalt PowerShell/UI | | GPU workloads | Full stotte | Full stotte (forklargjort) | ### Forberedelse for disconnected drift ```powershell # Forbered Azure Stack Edge for offline-bruk # (Gjores mens enheten fortsatt er online) # 1. Aktiver enhet via Azure Portal # 2. Enable Kubernetes Set-AzureDataBoxEdgeRole -Name "Kubernetes" -Activated # 3. Deploy alle nodvendige container workloads kubectl apply -f ai-inference-deployment.yaml # 4. Push container images til Edge Container Registry docker tag my-model:v1 ecr.edgehostname:31001/my-model:v1 docker push ecr.edgehostname:31001/my-model:v1 # 5. Verifiser at alt kjorer kubectl get pods -A # 6. Koble fra nettverket ``` --- ## Data Reconciliation Strategies ### Utfordringer med frakoblet data Nar AI-systemer kjorer offline, oppstar det utfordringer med: - Data som genereres lokalt ma synkroniseres nar tilkobling gjenopprettes - Modellresultater fra offline-perioden ma valideres - Konflikter mellom lokale og sentrale data - Versjonshaandtering av modeller og konfigurasjoner ### Rekonsilieringsmoenstre | Moenster | Beskrivelse | Bruksomrade | |---------|-------------|-------------| | Store-and-Forward | Buffer lokalt, send nar tilkoblet | IoT-data, loggfiler | | Event Sourcing | Registrer alle hendelser, replay sentralt | Audit, compliance | | Last-Write-Wins | Siste endring vinner ved konflikt | Enkle konfigurasjoner | | Merge/CRDTs | Konfliktfri sammenslaing | Distribuerte datasett | | Manual Review | Menneske loeser konflikter | Kritiske beslutninger | ### Store-and-Forward med IoT Hub ```python # Lokal buffering og batch-synkronisering import json import os from datetime import datetime from pathlib import Path class OfflineBuffer: def __init__(self, buffer_dir="/data/offline-buffer"): self.buffer_dir = Path(buffer_dir) self.buffer_dir.mkdir(parents=True, exist_ok=True) def store_result(self, inference_result, metadata): """Lagre inferensresultat lokalt.""" entry = { "timestamp": datetime.utcnow().isoformat(), "result": inference_result, "metadata": metadata, "synced": False } filepath = self.buffer_dir / f"{entry['timestamp']}.json" filepath.write_text(json.dumps(entry)) return filepath def get_unsynced(self): """Hent alle usynkroniserte resultater.""" results = [] for f in sorted(self.buffer_dir.glob("*.json")): entry = json.loads(f.read_text()) if not entry.get("synced"): results.append((f, entry)) return results async def sync_to_cloud(self, iot_client): """Synkroniser bufferede resultater til sky.""" unsynced = self.get_unsynced() for filepath, entry in unsynced: try: await iot_client.send_message( json.dumps(entry) ) entry["synced"] = True entry["synced_at"] = datetime.utcnow().isoformat() filepath.write_text(json.dumps(entry)) except Exception as e: # Fortsett med neste — proev igjen senere print(f"Sync feilet for {filepath}: {e}") break ``` ### Modellversjon-rekonsiliering ```yaml # model-sync-config.yaml sync: strategy: "check-on-connect" model_registry: cloud: "https://ml-workspace.azureml.net/models" local: "/models/registry.json" conflict_resolution: "cloud-wins" validation: enabled: true test_dataset: "/data/validation/standard-test.json" min_accuracy: 0.95 rollback: enabled: true keep_previous: 3 ``` --- ## Local Cache and Sync ### Flerlags cache-arkitektur ``` ┌──────────────────────────────────────────┐ │ Lag 1: In-Memory Cache (Redis) │ │ TTL: 1 time │ Storrelse: 2 GB │ │ Hoyest prioritet, raskest tilgang │ ├──────────────────────────────────────────┤ │ Lag 2: Lokal Disk Cache (SSD) │ │ TTL: 7 dager │ Storrelse: 100 GB │ │ Modellvekter, embeddings, resultater │ ├──────────────────────────────────────────┤ │ Lag 3: Persistent Storage (S2D/NAS) │ │ Ingen TTL │ Storrelse: 1 TB+ │ │ Full modellhistorikk, treningsdata │ ├──────────────────────────────────────────┤ │ Lag 4: Cloud Sync (Azure Blob) │ │ Synk ved tilkobling │ │ Master-kopi av modeller og data │ └──────────────────────────────────────────┘ ``` ### Synkroniseringslogikk ```python # Intelligent sync-manager class SyncManager: def __init__(self, config): self.local_store = LocalModelStore(config.local_path) self.cloud_store = AzureBlobStore(config.connection_string) self.sync_log = SyncLog(config.log_path) async def check_connectivity(self): """Sjekk om skytilkobling er tilgjengelig.""" try: await self.cloud_store.ping() return True except Exception: return False async def sync_models(self): """Synkroniser modeller mellom lokal og sky.""" if not await self.check_connectivity(): return SyncResult(status="offline", synced=0) # Hent manifest fra sky cloud_manifest = await self.cloud_store.get_manifest() local_manifest = self.local_store.get_manifest() updates = [] for model_id, cloud_info in cloud_manifest.items(): local_info = local_manifest.get(model_id) if not local_info: # Ny modell — last ned updates.append(("download", model_id, cloud_info)) elif cloud_info['version'] > local_info['version']: # Oppdatert modell — last ned ny versjon updates.append(("update", model_id, cloud_info)) # Utfor oppdateringer med prioritering for action, model_id, info in sorted( updates, key=lambda x: x[2].get('priority', 99) ): try: await self._download_model(model_id, info) self.sync_log.record(action, model_id, "success") except Exception as e: self.sync_log.record(action, model_id, f"failed: {e}") # Last opp lokale resultater await self._upload_offline_results() return SyncResult( status="synced", synced=len(updates) ) ``` --- ## Fallback Inference Patterns ### Degraderingsstrategier | Strategi | Nar | Implementasjon | |----------|-----|---------------| | Full model → Lite model | GPU svikter | Fall tilbake til CPU-modell | | Cloud model → Edge model | Nettverk nede | Bruk lokal kvantisert modell | | ML-modell → Regler | Modell korrupt | Regelbasert fallback | | Real-time → Batch | Overbelastning | Buffer foresporsler | | AI → Manuell | Alt feiler | Eskalering til menneske | ### Implementasjon av fallback-kaskade ```python class ResilientInferenceEngine: def __init__(self): self.engines = [ CloudInference(endpoint="https://foundry.azure.com"), LocalGPUInference(model_path="/models/full-model.onnx"), LocalCPUInference(model_path="/models/quantized-int8.onnx"), RuleBasedFallback(rules_path="/config/rules.json") ] async def infer(self, input_data, timeout=5.0): """Prover inferensmotorer i prioritetsrekkefoolge.""" last_error = None for engine in self.engines: try: result = await asyncio.wait_for( engine.predict(input_data), timeout=timeout ) return InferenceResult( prediction=result, engine=engine.name, confidence=engine.confidence_level, degraded=(engine != self.engines[0]) ) except asyncio.TimeoutError: last_error = f"{engine.name}: timeout" timeout = min(timeout * 2, 30) # Okt timeout for neste except Exception as e: last_error = f"{engine.name}: {e}" continue # Alle motorer feilet — returner fallback return InferenceResult( prediction=None, engine="none", confidence=0, degraded=True, error=last_error ) ``` ### Health monitoring for offline-systemer ```yaml # health-check-config.yaml health_checks: model_health: interval: 60s checks: - name: model_loaded type: inference_test input: "test_input.json" expected_output_shape: [1, 10] - name: gpu_available type: nvidia_smi min_free_memory_mb: 1024 - name: disk_space type: disk min_free_gb: 10 degradation_rules: - condition: "gpu_available == false" action: "switch_to_cpu_model" - condition: "disk_space < 5GB" action: "cleanup_old_models" - condition: "model_loaded == false" action: "reload_from_cache" max_retries: 3 ``` --- ## Scenarioer for norsk offentlig sektor ### Forsvar og beredskap | Scenario | Tilkoblingsstatus | Losning | |----------|-------------------|---------| | Feltoperasjoner | Helt frakoblet | ONNX Runtime + kvantiserte modeller | | Kjoretoy/fartoy | Periodisk | Store-and-forward + modellsynk | | Kommandoplass | Begrenset | Azure Stack Edge disconnected | | Sambandssystemer | Ustabil | Fallback-kaskade med degradering | ### Helse | Scenario | Tilkoblingsstatus | Losning | |----------|-------------------|---------| | Ambulanse | Ustabil | Lokal bildeanalyse (ONNX) | | Distriktslege | Periodisk | Disconnected containers (tale, tekst) | | Sykehus DR | Beredskap | Azure Local med offline-kapasitet | | Feltsykehus | Frakoblet | Forhndslastede modeller | ### Transport og infrastruktur | Scenario | Tilkoblingsstatus | Losning | |----------|-------------------|---------| | Tunneler | Frakoblet | Edge-inferens med kamerasystem | | Fartsoyvervaking | Ustabil | Lokal objektdeteksjon | | Trafikkanalyse | Periodisk | Batch-analyse med synk | | Fergedrift | Variabel | Hybrid med sky-fallback | --- ## Lisens- og kostnadshensyn ### Disconnected containers prismodell | Prismodell | Beskrivelse | Krav | |-----------|-------------|------| | Commitment tier | Arlig forpliktelse | Enterprise Agreement | | Per-tjeneste | Betal per container-tjeneste | Godkjent soknad | | Kalenderars-binding | 12 mnd minimum | Automatisk fornyelse | ### Viktige begrensninger - Lisensfil har utlopsdato — krever periodisk fornyelse - Enterprise Agreement eller tilsvarende er obligatorisk - Godkjenningsprosess tar opptil 10 virkedager - Ingen SLA for disconnected containers (kunde eier infrastruktur) - Ikke tilgjengelig i sovereign clouds (kun public cloud for opprettelse) --- ## For Cosmo - **Azure tilbyr et komplett spekter for frakoblet AI** — fra Foundry Tools disconnected containers (tale, tekst, bilde) til helt lokale ONNX Runtime-modeller uten skyavhengighet. - **Disconnected containers krever Enterprise Agreement og godkjenning** — lisensfiler har utlopsdato og ma fornyes, men gir tilgang til de samme API-ene som sky-tjenestene. - **Fallback-kaskader er essensielt for paalitelig edge-AI** — design alltid med degraderingsstrategi: sky → lokal GPU → lokal CPU → regler → manuell. - **Store-and-forward med rekonsilieringslogikk** loser utfordringen med data som genereres offline — buffer lokalt, synkroniser ved tilkobling, hndter konflikter. - **For norsk offentlig sektor er frakoblet AI kritisk for beredskap, forsvar og helse** — Azure Stack Edge og ONNX Runtime gir funksjonskapasitet uten internett-avhengighet.