ms-ai-architect/skills/ms-ai-security/references/performance-scalability/model-distillation-performance.md
Kjell Tore Guttormsen 3a73eeafdc refactor(ms-ai-architect): R13 del 1 — nøytraliser Cosmo-personaen i ref-korpusets headinger, etter å ha rettet en gate som var målt usann to ganger
Ordre 20260912T193441Z-7358817909. Steg 1 var ikke transformen, men å rette
roadmapens R13-gate og få den ratifisert. Gaten `grep -rl "Cosmo"
skills/*/references -> 0` var usann på to uavhengige måter:

1. Ordren fanget den første: 451 av forekomstene er Azure Cosmos DB, ekte
   produktinnhold. Diskriminatoren er ikke bokstaven «s» — `Cosmos <norsk
   substantiv>` er genitiv av personaen (`### Cosmos tonalitet`), mens
   `Cosmos DB`/`CosmosClient`/`cosmos_ru` er produkt.
2. Denne økten fant den andre: 132 persona-forekomster ligger i prosa,
   tabeller, dialog-replikker og proveniens-linjer. Heading-nøytralisering
   kan ikke nå dem, så «0 persona» er uoppnåelig også under den ratifiserte
   formen. Operatøren ratifiserte alternativ A: gaten speiler formen, og de
   132 bokføres til R13b/R14.

Tre korreksjoner av premisser som sto i ordren og STATE:
  «ca 320 produkt»   -> 451 (case-sensitivt nett manglet 327 lowercase
                        TOC-ankre + 99 identifikatorer; sann nevner 1 638)
  «169 headinger»    -> 401. 169 var `^## For Cosmo`-prefikset (168) og var
                        internt inkonsistent med sin egen topp-variant (204)
  «417 matcher ingen
   populasjon»       -> 417 er cosmo-headinger utenfor kodefences; briefens
                        nevner var reell hele tiden

Fence-bevissthet er målt skadelig, ikke nødvendig: begge toggle-regler er
gale på dette korpuset (naiv toggle skjuler en ekte heading i
chain-of-thought-prompting.md, CommonMark-regelen ubalanserer
service-level-documentation-dr.md). Fence-agnostisk deteksjon finner 401
heading-linjer i nøyaktig de samme 40 variantene som fence-bevisst finner
400 i — ingen kodeblokk-linje er byte-identisk til en persona-heading. Derfor
nøkles transformen på 40 enumererte heading-tekster og ignorerer fences. En
ukjent variant kaster; en slug-kollisjon kaster. Ingenting auto-fikses.

TOC-en regenereres ikke, den rettes kirurgisk: alle 327 persona-lenker hadde
lenketekst lik én av de 40 heading-tekstene og anker lik slugify av den
(327/327, 0 avvik), så heading og TOC-entry skrives i samme operasjon og
ingen mellomtilstand etterlater en død lenke.

Ratifisert målform: `For Cosmo`, `For Cosmo Skyberg` og `For arkitekten
(Cosmo)` konvergerer på `For arkitekten`. To filer kolliderte og er adjudisert
ved å lese dem, ikke ved regel.

Verifisering (alle 7 kriterier fra ordren):
  G1 persona på heading-linjer   401 -> 0
  G2 døde fragmentlenker         1 -> 1 (pre-eksisterende, unntatt)
  G3 produkt-forekomster         451 -> 451; `Cosmos DB|Azure Cosmos` 308 = 308
  de 3 kun-produkt-filene        byte-identiske
  nettet validert begge veier    injisert persona feller G1; genitiv feller G1;
                                 produkt-heading og de 3 filene passerer
  hele diffen                    802 heading-linjer + 654 TOC-linjer, ANNET = 0
  linjeantall                    728 lagt til = 728 slettet
  suite                          1120/1120 (1097 + 23 nye)
  validate-plugin                250 PASS / 0 FAIL
  stikkprøve                     10 filer, alle 5 skills, inkl. de 3 mest
                                 produkt-tunge (26/20/19) — kun heading+TOC

Utenfor scope, urørt: de 4 SKILL.md, de 23 commands, CLAUDE.md, README.md,
NOTICE.md, docs/ (alt R14).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 22:12:28 +02:00

18 KiB

Model Distillation for Performance

Last updated: 2026-04 Status: GA Category: Performance & Scalability Type: reference Source: https://learn.microsoft.com/azure/foundry/openai/concepts/fine-tuning-considerations


Innhold

Introduksjon

Model distillation er prosessen der en stor, kraftig modell (teacher) brukes til å trene en mindre, raskere modell (student) som oppnår akseptabel kvalitet for en spesifikk oppgave. I Azure OpenAI-konteksten betyr dette typisk å samle produksjonsdata fra en premium-modell som GPT-4o eller o3, og bruke disse som treningsdata for å fine-tune en mindre modell som GPT-4o-mini eller GPT-4.1-nano.

Microsoft Foundry tilbyr en integrert distillation-pipeline via Stored Completions-funksjonen. Produksjonsforespørsler og -svar lagres automatisk, filtreres etter kvalitet, og konverteres direkte til fine-tuning datasett. Dette eliminerer manuell datakuratering og gir en strømlinjeformet vei fra stor modell til optimalisert, kostnadseffektiv deployment.

For norsk offentlig sektor er distillation spesielt verdifullt fordi det muliggjør lavere driftskostnader, raskere responstider og potensielt bedre kontroll over modellens oppførsel. En distillert modell trenger færre tokens per forespørsel (kortere prompts), noe som direkte reduserer både latens og kostnad.

Kjernekomponenter

Komponent Formål Teknologi
Stored Completions Automatisk lagring av produksjonsdata Microsoft Foundry
Fine-tuning API LoRA-basert tilpasning av base-modeller Azure OpenAI
Evaluation Framework Kvalitetsmåling av distillert modell Microsoft Foundry Evaluations
Teacher Model Stor modell som genererer treningsdata GPT-4o, o3, GPT-5
Student Model Mindre modell som trenes via distillation GPT-4o-mini, GPT-4.1-nano

Distillation Training Process

Steg 1: Aktiver Stored Completions

from openai import AzureOpenAI

client = AzureOpenAI(
    azure_endpoint="https://my-aoai.openai.azure.com",
    api_key="...",
    api_version="2024-12-01-preview"
)

# Aktiver stored completions for teacher-modellen
response = client.chat.completions.create(
    model="gpt-4o",  # Teacher model
    messages=[
        {"role": "system", "content": "Du er en norsk saksbehandler-assistent..."},
        {"role": "user", "content": "Oppsummer denne klagen: ..."}
    ],
    store=True,  # Lagre completion for distillation
    metadata={
        "task": "complaint-summary",
        "quality_score": "verified"
    }
)

Steg 2: Samle og kuratere treningsdata

# Samle tilstrekkelig med stored completions
# Minimum: 10 completions (anbefalt: 500-1000+)

def curate_distillation_dataset(
    completions: list[dict],
    min_quality_score: float = 0.8,
    target_size: int = 1000
) -> list[dict]:
    """Curate high-quality completions for distillation."""
    curated = []

    for completion in completions:
        # Filtrer basert på kvalitet
        if completion.get("quality_score", 0) < min_quality_score:
            continue

        # Konverter til fine-tuning format
        training_example = {
            "messages": [
                {"role": "system", "content": completion["system_prompt"]},
                {"role": "user", "content": completion["user_input"]},
                {"role": "assistant", "content": completion["assistant_output"]}
            ]
        }
        curated.append(training_example)

        if len(curated) >= target_size:
            break

    return curated

# Minimum 10 stored completions, anbefalt 500+
# Microsoft anbefaler hundrevis til tusenvis for best resultat

Steg 3: Fine-tune student-modellen

import json

# Opprett treningsfil
def create_training_file(dataset: list[dict], filename: str):
    with open(filename, "w") as f:
        for example in dataset:
            f.write(json.dumps(example) + "\n")

# Last opp og start fine-tuning
def start_distillation_finetuning(
    client: AzureOpenAI,
    training_file: str,
    student_model: str = "gpt-4o-mini"
):
    """Start fine-tuning of student model with teacher data."""
    # Last opp treningsdata
    file = client.files.create(
        file=open(training_file, "rb"),
        purpose="fine-tune"
    )

    # Start fine-tuning jobb
    job = client.fine_tuning.jobs.create(
        training_file=file.id,
        model=student_model,
        hyperparameters={
            "n_epochs": 3,
            "learning_rate_multiplier": 1.0,
            "batch_size": "auto"
        },
        suffix="distilled-complaint-summary"
    )

    return job

Steg 4: Evaluer distillert modell

async def evaluate_distillation(
    teacher_client: AzureOpenAI,
    student_client: AzureOpenAI,
    test_prompts: list[dict],
    teacher_model: str = "gpt-4o",
    student_model: str = "ft:gpt-4o-mini:distilled"
) -> dict:
    """Compare teacher vs student model quality."""
    results = {"teacher": [], "student": [], "quality_matches": 0}

    for prompt in test_prompts:
        # Teacher response (ground truth)
        teacher_resp = teacher_client.chat.completions.create(
            model=teacher_model,
            messages=prompt["messages"]
        )

        # Student response
        student_resp = student_client.chat.completions.create(
            model=student_model,
            messages=prompt["messages"]
        )

        teacher_text = teacher_resp.choices[0].message.content
        student_text = student_resp.choices[0].message.content

        results["teacher"].append({
            "output": teacher_text,
            "tokens": teacher_resp.usage.total_tokens,
            "latency_ms": teacher_resp.response_ms  # Hvis tilgjengelig
        })
        results["student"].append({
            "output": student_text,
            "tokens": student_resp.usage.total_tokens,
            "latency_ms": student_resp.response_ms
        })

    # Beregn metrics
    avg_teacher_tokens = sum(
        r["tokens"] for r in results["teacher"]) / len(results["teacher"])
    avg_student_tokens = sum(
        r["tokens"] for r in results["student"]) / len(results["student"])

    return {
        "test_size": len(test_prompts),
        "avg_teacher_tokens": round(avg_teacher_tokens),
        "avg_student_tokens": round(avg_student_tokens),
        "token_reduction_pct": round(
            (1 - avg_student_tokens / avg_teacher_tokens) * 100, 1),
    }

Model Size vs. Quality Tradeoffs

Sammenligning av Azure OpenAI-modeller

Modell Relativ størrelse Input TPM/PTU Latens-mål Kostnad (Standard) Typisk bruk etter distillation
GPT-5 Største 4,750 50 TPS Høyest Teacher model
GPT-4.1 Stor 3,000 80 TPS Høy Teacher / produksjon
GPT-4o Stor 2,500 25 TPS Høy Teacher model
GPT-4.1-mini Medium 14,900 90 TPS Medium Student — god balanse
GPT-4o-mini Medium 37,000 33 TPS Lav Student — kostnadsoptimal
GPT-4.1-nano Liten 59,400 100 TPS Lavest Student — latens-kritisk

Kvalitets-/kostnadsmatrise

# Sammenlign distillation-kandidater
distillation_candidates = {
    "gpt-4o → gpt-4o-mini": {
        "teacher_cost_per_1m_input": 2.50,
        "student_cost_per_1m_input": 0.15,
        "cost_reduction": "94%",
        "expected_quality_retention": "85-95%",
        "best_for": "General tasks, summarization"
    },
    "gpt-4.1 → gpt-4.1-mini": {
        "teacher_cost_per_1m_input": 2.00,
        "student_cost_per_1m_input": 0.40,
        "cost_reduction": "80%",
        "expected_quality_retention": "88-96%",
        "best_for": "Instruction following, structured output"
    },
    "gpt-4.1 → gpt-4.1-nano": {
        "teacher_cost_per_1m_input": 2.00,
        "student_cost_per_1m_input": 0.10,
        "cost_reduction": "95%",
        "expected_quality_retention": "75-90%",
        "best_for": "Classification, simple extraction"
    }
}

Token Reduction Benefits

Hvorfor distillerte modeller bruker færre tokens

Standard prompt (med few-shot examples):
┌─────────────────────────────────────────┐
│ System prompt: 200 tokens               │
│ Few-shot example 1: 150 tokens          │
│ Few-shot example 2: 150 tokens          │
│ Few-shot example 3: 150 tokens          │
│ User input: 500 tokens                  │
│ ─────────────────────────────────        │
│ TOTALT INPUT: 1,150 tokens              │
└─────────────────────────────────────────┘

Distillert modell (innebygd kunnskap):
┌─────────────────────────────────────────┐
│ System prompt: 50 tokens                │
│ User input: 500 tokens                  │
│ ─────────────────────────────────        │
│ TOTALT INPUT: 550 tokens (52% reduksjon)│
└─────────────────────────────────────────┘

Kostnadsberegning

def calculate_distillation_savings(
    monthly_requests: int,
    avg_input_tokens_before: int,
    avg_input_tokens_after: int,
    avg_output_tokens: int,
    teacher_input_price_per_1m: float,
    teacher_output_price_per_1m: float,
    student_input_price_per_1m: float,
    student_output_price_per_1m: float,
    finetuning_cost: float = 500  # Engangskostnad for fine-tuning
) -> dict:
    """Calculate monthly savings from model distillation."""
    # Teacher-kostnad
    teacher_input_cost = (
        monthly_requests * avg_input_tokens_before / 1_000_000
        * teacher_input_price_per_1m)
    teacher_output_cost = (
        monthly_requests * avg_output_tokens / 1_000_000
        * teacher_output_price_per_1m)
    teacher_total = teacher_input_cost + teacher_output_cost

    # Student-kostnad
    student_input_cost = (
        monthly_requests * avg_input_tokens_after / 1_000_000
        * student_input_price_per_1m)
    student_output_cost = (
        monthly_requests * avg_output_tokens / 1_000_000
        * student_output_price_per_1m)
    student_total = student_input_cost + student_output_cost

    monthly_savings = teacher_total - student_total
    roi_months = finetuning_cost / monthly_savings if monthly_savings > 0 else float('inf')

    return {
        "teacher_monthly_nok": round(teacher_total * 11, 2),  # USD → NOK
        "student_monthly_nok": round(student_total * 11, 2),
        "monthly_savings_nok": round(monthly_savings * 11, 2),
        "savings_pct": round((1 - student_total / teacher_total) * 100, 1),
        "roi_months": round(roi_months, 1)
    }

# Eksempel: Direktoratet for digital tjenesteutvikling dokumentanalyse
savings = calculate_distillation_savings(
    monthly_requests=100_000,
    avg_input_tokens_before=1200,  # Med few-shot
    avg_input_tokens_after=550,    # Distillert
    avg_output_tokens=300,
    teacher_input_price_per_1m=2.50,
    teacher_output_price_per_1m=10.00,
    student_input_price_per_1m=0.15,
    student_output_price_per_1m=0.60,
    finetuning_cost=500
)
print(f"Månedlig besparelse: {savings['monthly_savings_nok']} NOK")
print(f"ROI: {savings['roi_months']} måneder")

Use Case Suitability

Når distillation er egnet

Use case Egnethet Begrunnelse
Dokumentklassifisering Svært egnet Enkel oppgave, høy konsistens
Oppsummering Egnet Forutsigbart format, godt distillert
Sentiment-analyse Svært egnet Binær/tertsiær output
Kodeforklaring Moderat egnet Krever presisjon, men mønsterbart
Kreativ skriving Lite egnet Variasjon er ønskelig
Kompleks resonnering Lite egnet Mister nuanser ved distillation
Flerspråklig oversettelse Moderat egnet Avhenger av språkpar og domene

Når distillation IKKE bør brukes

❌ Oppgaven krever konstant oppdatert kunnskap (bruk RAG i stedet)
❌ Output-variabilitet er viktig (kreative oppgaver)
❌ Volumet er for lavt (< 1000 forespørsler/mnd) — besparelsen dekker ikke fine-tuning-kostnad
❌ Oppgaven endrer seg ofte — modellen må re-trenes
❌ Sikkerhetskritiske beslutninger der teacher-modellens resonnering er viktig

Norsk offentlig sektor

  • Personvern og GDPR: Stored Completions lagrer brukerdata — sørg for at databehandleravtale dekker fine-tuning-formål. Treningsdata kan ikke eksporteres fra Microsoft Foundry.
  • Utredningsinstruksen: Distillation bør dokumenteres som et tiltak for kostnadsoptimalisering i AI-utredninger. Beregn besparelser over 3-5 år for å rettferdiggjøre initial investering.
  • Forvaltningsloven: Hvis den distillerte modellen brukes til vedtaksstøtte, dokumenter at kvaliteten er validert og at den oppfyller krav til forsvarlig saksbehandling.
  • Anskaffelser: Fine-tuning hosting koster per time (uavhengig av bruk). Sammenlign totalkostnad inkludert hosting mot standard pay-per-token.

Beslutningsrammeverk

Scenario Anbefaling Begrunnelse
Høyt volum, enkel oppgave Distiller til nano/mini Størst kostnadsbesparelse
Middels volum, moderat kompleksitet Distiller til mini God balanse kvalitet/kostnad
Lavt volum (<1K/mnd) Behold teacher Fine-tuning-kostnad > besparelse
Hyppig endring i oppgave Unngå distillation Re-training overhead
Latens-kritisk (<500ms) Distiller til nano + PTU Lavest mulig responstid

Modellvalg og routing-strategi (oppdatert 2026-04)

Microsoft dokumenterer nå 10 seleksjonskriterier ved valg av AI-modell for distillasjon:

Kriterium Relevans for distillasjon
Task fit Velg teacher og student basert på oppgavens art
Routing strategy Definer routing FØR distillasjon — påvirker teacher-modellvalg
Cost Studentmodellens kostnad er primær motivasjon
Context window Student må håndtere samme kontekst som teacher
Security Studentmodell arver ikke teachers sikkerhetstiltak — re-evaluer
Region Student deployes i samme region som teacher for dataresidency
Deployment PTU vs Standard — student er oftest Standard til start
Domain Domene-spesifikk teacher gir bedre student
Performance Latens- og throughput-krav til student (se modellmatrise)
Tunability Studentmodellen MÅ støtte fine-tuning (f.eks. GPT-4o-mini, GPT-4.1-nano)

Modell-routing som distillasjonsstrategi

# Model routing strategy i distillasjonskontekst
# Teacher: GPT-4.1 (høyeste kvalitet)
# Router: Klassifiser oppgavekompleksitet → velg modell dynamisk
# Student: GPT-4.1-mini eller GPT-4.1-nano (basert på klassifisering)

from openai import AzureOpenAI
import json

client = AzureOpenAI(
    azure_endpoint="https://my-foundry.openai.azure.com",
    api_key="...",
    api_version="2024-10-21"
)

def classify_task_complexity(user_input: str) -> str:
    """Klassifiser oppgavekompleksitet for routing."""
    response = client.chat.completions.create(
        model="gpt-4.1-nano",  # Rask og billig til routing
        messages=[{
            "role": "system",
            "content": "Klassifiser denne brukerforespørselen: 'simple' (fakta, svar, klassifisering) eller 'complex' (resonnering, kreativt, multi-steg). Svar med ett ord."
        }, {"role": "user", "content": user_input}]
    )
    return response.choices[0].message.content.strip().lower()

def route_to_model(user_input: str) -> str:
    """Route til riktig modell basert på kompleksitet."""
    complexity = classify_task_complexity(user_input)
    
    if complexity == "simple":
        model = "ft:gpt-4.1-nano:distilled-v1"  # Distillert nano for enkle oppgaver
    else:
        model = "gpt-4.1"  # Teacher for komplekse oppgaver
    
    response = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": user_input}]
    )
    return response.choices[0].message.content

# Routing strategy gir: lavere kostnad for enkle oppgaver + høy kvalitet for komplekse

Oppdatert modellmatrise for distillasjon

Modell Tunability TPM (PTU, input) Anbefalt student-rolle
GPT-4.1-nano Ja 59,400 Enkle oppgaver, latens-kritisk
GPT-4o-mini Ja 37,000 Generelle oppgaver, kostnadsoptimal
GPT-4.1-mini Ja 14,900 Moderate oppgaver, god balanse
GPT-4.1 Nei (direkte) 3,000 Teacher (ikke student)
GPT-4o Nei (direkte) 2,500 Teacher (ikke student)

Referanser

For arkitekten

  • Bruk denne referansen når kunden har høyt volum av repetitive AI-oppgaver og ønsker å redusere kostnader uten å miste kvalitet.
  • Stored Completions → Distill-flyten i Microsoft Foundry er den enkleste veien — ingen manuell datakuratering nødvendig.
  • Anbefal alltid evaluering med reelle testdata før produksjonsdeployment av distillert modell — kvalitetstap varierer sterkt per oppgave.
  • GPT-4.1-nano gir 59,400 input TPM per PTU vs. 3,000 for GPT-4.1 — en 20x throughput-økning for enkle oppgaver.
  • Fine-tuned modeller har hosting-kostnad per time — beregn break-even punkt basert på forventet volum.