ktg-plugin-marketplace/plugins/ms-ai-architect/skills/ms-ai-infrastructure/references/hybrid-edge/on-premises-slm-phi-deployment.md
Kjell Tore Guttormsen 6a7632146e 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>
2026-04-07 17:17:17 +02:00

15 KiB

On-Premises SLM and Phi Model Deployment

Last updated: 2026-02 Status: GA Category: Hybrid Cloud & Edge AI


Introduksjon

Small Language Models (SLM) er kompakte AI-modeller med faerre enn 10 milliarder parametere som kan kjores effektivt pa lokal hardware uten skyavhengighet. Microsofts Phi-modellserie — fra Phi-2 (2.7B) til Phi-4 (14B) — representerer state-of-the-art for SLM, med ytelse som konkurrerer med modeller mange ganger storre.

For norsk offentlig sektor er lokal SLM-deployment sarlig attraktivt: full datakontroll uten at data forlater organisasjonens nettverk, forutsigbare kostnader uten per-token-prising, og mulighet for drift i miljoer med begrenset eller ingen internettilkobling. Phi-modellene er spesielt godt egnet fordi de er optimalisert for oppgaver som klassifisering, oppsummering, enhetstuttrekking og enkel sporsmalsbesvaring.

Microsoft tilbyr flere deploymentsveier for lokale SLM: Azure App Service sidecar, AKS Edge Essentials med KAITO, ONNX Runtime pa Windows/Linux, og Windows ML pa Copilot+ PC-er. Valget avhenger av skaleringsbehovet, tilgjengelig hardware og integrasjonskrav.


Kjernekomponenter

Komponent Formal Teknologi
Phi-3 Mini 3.8B parameter SLM for generelle oppgaver MIT-lisens
Phi-3 Small 7B parameter SLM for hoeyere kvalitet MIT-lisens
Phi-3 Medium 14B parameter SLM for komplekse oppgaver MIT-lisens
Phi-3.5 Mini Forbedret 3.8B med multilingual stoette MIT-lisens
Phi-4 Mini Nyeste 3.8B med forbedret resonnering MIT-lisens
ONNX Runtime Cross-platform inferensmotor Open source
KAITO Kubernetes AI Toolchain Operator Azure Arc
Olive Modelloptimalisering for deployment Microsoft
Windows ML Lokal inferens pa Windows Windows SDK

Phi-3/Phi-4 Deployment

Modelloversikt

Modell Parametere Kontekst RAM-krav GPU-krav Styrker
Phi-3 Mini 4K 3.8B 4K tokens 8 GB Valgfritt Enkel Q&A, klassifisering
Phi-3 Mini 128K 3.8B 128K tokens 8 GB Anbefalt Lange dokumenter
Phi-3 Small 7B 128K tokens 16 GB Anbefalt Flerspraklig, koding
Phi-3 Medium 14B 128K tokens 32 GB Pakrevd Kompleks resonnering
Phi-3.5 Mini 3.8B 128K tokens 8 GB Valgfritt Multilingual, forbedret
Phi-4 Mini 3.8B 128K tokens 8 GB Valgfritt Beste resonnering i klassen

Deployment med Azure App Service Sidecar

# App Service sidecar-konfigurasjon for Phi-3.5 Mini
apiVersion: apps/v1
kind: Deployment
metadata:
  name: phi-slm-app
spec:
  template:
    spec:
      containers:
        # Hoved-applikasjon
        - name: web-app
          image: myregistry.azurecr.io/myapp:latest
          ports:
            - containerPort: 8080
          env:
            - name: SLM_ENDPOINT
              value: "http://localhost:11434"

        # SLM sidecar
        - name: phi-sidecar
          image: mcr.microsoft.com/oss/ollama/ollama:latest
          ports:
            - containerPort: 11434
          resources:
            requests:
              memory: "8Gi"
              cpu: "4"
            limits:
              memory: "16Gi"
              cpu: "8"
          command: ["ollama", "serve"]
          lifecycle:
            postStart:
              exec:
                command: ["ollama", "pull", "phi3.5"]

Deployment med KAITO pa AKS Edge

# KAITO Workspace for Phi-3 Mini pa edge
apiVersion: kaito.sh/v1alpha1
kind: Workspace
metadata:
  name: phi3-edge
  annotations:
    kaito.sh/enablelb: "false"  # Ikke ekstern lastbalansering pa edge
spec:
  resource:
    instanceType: "Standard_NC4as_T4_v3"  # GPU-node
    labelSelector:
      matchLabels:
        apps: phi3-edge
  inference:
    preset:
      name: "phi-3-mini-128k-instruct"
    adapters:
      - source:
          name: "custom-norwegian-adapter"
          image: "myregistry/phi3-no-adapter:v1"

ONNX Runtime deployment (CPU)

# Phi-3 Mini deployment med ONNX Runtime (ingen GPU nodvendig)
import onnxruntime_genai as og

class PhiLocalDeployment:
    def __init__(self, model_path: str):
        """
        Initialiser Phi-3/4 lokal deployment.
        model_path: Sti til ONNX-optimalisert Phi-modell
        """
        self.model = og.Model(model_path)
        self.tokenizer = og.Tokenizer(self.model)
        self.search_options = {
            "max_length": 2048,
            "temperature": 0.7,
            "top_p": 0.9,
            "do_sample": True
        }

    def generate(self, prompt: str, system_message: str = None,
                 max_tokens: int = 1024) -> str:
        """Generer svar fra lokal Phi-modell"""
        if system_message:
            full_prompt = (
                f"<|system|>\n{system_message}<|end|>\n"
                f"<|user|>\n{prompt}<|end|>\n"
                f"<|assistant|>\n"
            )
        else:
            full_prompt = (
                f"<|user|>\n{prompt}<|end|>\n"
                f"<|assistant|>\n"
            )

        input_tokens = self.tokenizer.encode(full_prompt)

        params = og.GeneratorParams(self.model)
        params.set_search_options(**{
            **self.search_options,
            "max_length": max_tokens
        })
        params.input_ids = input_tokens

        generator = og.Generator(self.model, params)

        output_tokens = []
        while not generator.is_done():
            generator.compute_logits()
            generator.generate_next_token()
            new_token = generator.get_next_tokens()[0]
            output_tokens.append(new_token)

        return self.tokenizer.decode(output_tokens)

    def generate_streaming(self, prompt: str, system_message: str = None):
        """Streaming-generering for lavere opplevd latens"""
        full_prompt = self._format_prompt(prompt, system_message)
        input_tokens = self.tokenizer.encode(full_prompt)

        params = og.GeneratorParams(self.model)
        params.set_search_options(**self.search_options)
        params.input_ids = input_tokens

        generator = og.Generator(self.model, params)
        tokenizer_stream = self.tokenizer.create_stream()

        while not generator.is_done():
            generator.compute_logits()
            generator.generate_next_token()
            token = generator.get_next_tokens()[0]
            yield tokenizer_stream.decode(token)

Resource-Constrained Sizing

Hardware-dimensjonering

Scenario Modell CPU RAM GPU Disk Inferens-hastighet
Minimal (PC) Phi-3 Mini INT4 4 kjerner 8 GB Ingen 5 GB ~10 tokens/s
Standard (server) Phi-3 Mini FP16 8 kjerner 16 GB T4 16GB 10 GB ~40 tokens/s
Ytelse (GPU) Phi-3 Small FP16 8 kjerner 32 GB A10G 24GB 20 GB ~50 tokens/s
Enterprise Phi-3 Medium FP16 16 kjerner 64 GB A100 40GB 40 GB ~60 tokens/s
Edge (NPU) Phi-3 Mini INT4 Snapdragon X 16 GB NPU 5 GB ~20 tokens/s

Minnesoptimalisering

# Konfigurasjon for ressursbegrensede miljoer
import onnxruntime as ort

def create_optimized_session(model_path: str, max_memory_gb: float = 4.0):
    """Opprett ONNX-session optimalisert for begrenset minne"""
    session_options = ort.SessionOptions()

    # Reduser minnebruk
    session_options.enable_mem_pattern = True
    session_options.enable_mem_reuse = True

    # Begrens trader basert pa tilgjengelige kjerner
    import os
    available_cores = os.cpu_count() or 4
    session_options.intra_op_num_threads = max(1, available_cores // 2)
    session_options.inter_op_num_threads = max(1, available_cores // 4)

    # Velg execution provider basert pa tilgjengelig hardware
    providers = []
    if ort.get_device() == "GPU":
        providers.append(('CUDAExecutionProvider', {
            'device_id': 0,
            'arena_extend_strategy': 'kSameAsRequested',
            'gpu_mem_limit': int(max_memory_gb * 1024 * 1024 * 1024),
            'cudnn_conv_algo_search': 'HEURISTIC'
        }))
    providers.append('CPUExecutionProvider')

    return ort.InferenceSession(
        model_path,
        sess_options=session_options,
        providers=providers
    )

Prompt Optimization for SLM

SLM-spesifikke prompt-teknikker

SLM-er har begrenset kontekstvindu og resonneringskapasitet sammenlignet med LLM-er. Prompt-optimalisering er kritisk:

Teknikk Beskrivelse Effekt
Konsist system-melding Kort, presis rolledefinisjon (< 100 tokens) Bedre oppgavefokus
Strukturert output Be om JSON/tabell-format Mer palitelig parsing
Few-shot eksempler 1-3 konkrete eksempler Hoyere noyaktighet
Decomposition Del opp komplekse oppgaver Bedre resultater
Constraint-basert Eksplisitte begrensninger Unnga hallusinasjoner

Prompt-maler for norsk offentlig sektor

# Optimaliserte prompt-maler for SLM i offentlig sektor
SLM_PROMPTS = {
    "klassifisering": """<|system|>
Du klassifiserer dokumenter. Svar KUN med en av kategoriene.
Kategorier: {categories}
<|end|>
<|user|>
Klassifiser folgende tekst:
"{text}"
Kategori:<|end|>
<|assistant|>""",

    "oppsummering": """<|system|>
Du oppsummerer tekst pa norsk. Maks {max_words} ord.
<|end|>
<|user|>
Oppsummer folgende:
"{text}"
<|end|>
<|assistant|>
Oppsummering:""",

    "uttrekking": """<|system|>
Du trekker ut strukturert informasjon. Svar i JSON-format.
<|end|>
<|user|>
Trekk ut folgende felter fra teksten: {fields}

Tekst: "{text}"

JSON:<|end|>
<|assistant|>
{{""",

    "qa_med_kontekst": """<|system|>
Du svarer pa sporsmal basert pa konteksten. Svar KUN basert pa informasjonen gitt.
Hvis svaret ikke finnes i konteksten, si "Ikke tilstrekkelig informasjon."
<|end|>
<|user|>
Kontekst:
{context}

Sporsmal: {question}
<|end|>
<|assistant|>"""
}

Fine-Tuning at Edge

Lokal fine-tuning av Phi-modeller

# LoRA fine-tuning av Phi-3 for norsk offentlig sektor
from transformers import (
    AutoModelForCausalLM, AutoTokenizer,
    TrainingArguments, Trainer
)
from peft import LoraConfig, get_peft_model
import torch

def finetune_phi_lora(
    base_model: str = "microsoft/phi-3-mini-4k-instruct",
    dataset_path: str = "training_data.jsonl",
    output_dir: str = "./phi3-finetuned"
):
    """Fine-tune Phi-3 med LoRA for norsk offentlig sektor"""

    # Last modell med 4-bit kvantisering for a spare minne
    model = AutoModelForCausalLM.from_pretrained(
        base_model,
        torch_dtype=torch.bfloat16,
        load_in_4bit=True,
        device_map="auto"
    )
    tokenizer = AutoTokenizer.from_pretrained(base_model)

    # LoRA-konfigurasjon (minimal for edge)
    lora_config = LoraConfig(
        r=16,              # Lav rank for edge-deployment
        lora_alpha=32,
        target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
        lora_dropout=0.05,
        bias="none",
        task_type="CAUSAL_LM"
    )

    model = get_peft_model(model, lora_config)

    # Treningsargumenter optimalisert for begrenset hardware
    training_args = TrainingArguments(
        output_dir=output_dir,
        num_train_epochs=3,
        per_device_train_batch_size=2,
        gradient_accumulation_steps=8,
        learning_rate=2e-4,
        fp16=True,
        logging_steps=10,
        save_strategy="epoch",
        optim="paged_adamw_8bit",  # Minneeffektiv optimizer
        max_grad_norm=0.3,
        warmup_ratio=0.03
    )

    trainer = Trainer(
        model=model,
        args=training_args,
        train_dataset=load_dataset(dataset_path),
        tokenizer=tokenizer
    )

    trainer.train()

    # Lagre kun LoRA-adapteret (liten filstorrelse)
    model.save_pretrained(output_dir)
    # Adapter-storrelse: typisk 20-50 MB vs 7+ GB for full modell

ONNX-eksport for deployment

# Konverter fine-tuned Phi-3 til ONNX for deployment
python -m olive run \
  --config olive-config.json \
  --model-id ./phi3-finetuned \
  --output-dir ./phi3-onnx-optimized \
  --precision int4 \
  --target-device cpu
// olive-config.json
{
  "input_model": {
    "type": "HfModel",
    "model_path": "./phi3-finetuned"
  },
  "passes": [
    {"type": "OnnxConversion"},
    {"type": "OnnxQuantization", "quant_mode": "dynamic", "weight_type": "QInt4"},
    {"type": "OrtTransformersOptimization", "model_type": "gpt2"}
  ],
  "engine": {
    "target": "onnxruntime",
    "execution_providers": ["CPUExecutionProvider"]
  }
}

Norsk offentlig sektor

Hvorfor lokal SLM for offentlig sektor?

  • Datakontroll: Ingen data forlater organisasjonens nettverk — viktig for personopplysninger og gradert informasjon
  • Kostnadskontroll: Fast infrastrukturkostnad uten per-token-prising — enklere budsjettforvaltning
  • Tilgjengelighet: Fungerer uten internettilkobling — relevant for felt, krisesituasjoner, og isolerte miljoer
  • Etterlevelse: Enklere a demonstrere compliance med Schrems II, GDPR, og NSM-krav

Anbefalte bruksomrader for SLM

Bruksomrade Modell Beskrivelse
Dokumentklassifisering Phi-3 Mini INT4 Klassifiser innkommende post/henvendelser
Oppsummering Phi-3.5 Mini Oppsummer lange utredninger og hoeringsnotater
Informasjonsuttrekking Phi-3 Mini Trekk ut nokkeldata fra skjemaer
Intern Q&A Phi-4 Mini + RAG Svar pa sporsmal fra regelverk
Tekstgenerering Phi-3 Small Utkast til brev og standardsvar

Beslutningsrammeverk

Scenario Anbefaling Begrunnelse
Enkel klassifisering/uttrekking Phi-3 Mini INT4 pa CPU Minimal hardware, rask inferens
Norsk sprakbehandling Phi-3.5 Mini eller Phi-4 Mini Bedre multilingual stoette
Kompleks resonnering Phi-3 Medium pa GPU Nodvendig kapasitet
Edge-deployment (IoT) Phi-3 Mini INT4 ONNX Minst fotavtrykk
Windows-klient Windows ML + Phi-4 Mini Automatisk hardware-optimalisering
Copilot+ PC Windows ML med NPU Best ytelse/watt
Server-deployment KAITO pa AKS Edge Skalerbart, Kubernetes-managed

For Cosmo

  • Phi-3 Mini INT4 er det naturlige startpunktet for de fleste offentlige sektors SLM-bruk — 3.8B parametere gir overraskende god kvalitet for klassifisering, uttrekking og enkel Q&A, og krever kun 8 GB RAM uten GPU
  • Fine-tuning med LoRA er nodvendig for doenmespesifikke oppgaver — en LoRA-adapter pa 20-50 MB er mye enklere a distribuere til edge enn en full modell, og gir dramatisk forbedring for norsk fagsprak
  • Prompt-optimalisering er viktigere for SLM enn for LLM — korte, strukturerte prompts med eksplisitte output-formater og 1-3 few-shot-eksempler oker kvaliteten betydelig
  • ONNX Runtime + Olive er den foretrukne deployment-pipeline — konverter til ONNX, kvantiser til INT4, og deploy pa CPU for maksimal portabilitet og ytelse
  • For norsk offentlig sektor: Lokal SLM-deployment eliminerer de fleste Schrems II-utfordringer — data forlater aldri nettverket, noe som forenkler personvernkonsekvensvurdering og compliance-dokumentasjon