# Multi-Modal Prompt Engineering Techniques

**Last updated:** 2026-02
**Status:** GA
**Category:** Multi-Modal AI

---

## Introduksjon

Multimodal prompt engineering er kunsten å skrive effektive instruksjonar som kombinerer tekst og bilete for å utnytte kapabilitetane til vision-enabled modellar som GPT-4o, GPT-4o mini og GPT-4 Turbo with Vision. Desse modellane aksepterer både tekst og bilete som input, og kan utføre oppgåver som bildeanalyse, visuelt resonnement, dokumentforståing og diagramtolking.

Microsoft sin offisielle rettleiing for image prompt engineering identifiserer seks grunnprinsipp: kontekstuell spesifisitet, oppgåveorienterte prompts, handtering av nekting (refusals), eksempelbruk, oppdeling av komplekse oppgåver, og definering av output-format. Desse prinsippa er like relevante for norsk offentleg sektor, der multimodale modellar kan nyttast til alt frå byggesaksanalyse til kvalitetssikring av veginfrastruktur.

Azure AI Foundry Playground tilbyr eit interaktivt miljø for å eksperimentere med multimodale prompts, og GPT-4o sin image tokenization-mekanisme påverkar både kostnader og ytelse. Forståing av korleis bilete vert konvertert til tokens er kritisk for kostnadsoptimalisering i produksjonssystem.

---

## Kjernekomponentar

| Komponent | Formål | Teknologi |
|-----------|--------|-----------|
| GPT-4o / GPT-4o mini | Multimodal chat med tekst + bilete | Azure OpenAI Service |
| Image Tokenization | Konvertering av bilete til tokens | Intern GPT-4o-mekanisme |
| System Messages | Kontekstsetting for visuelle oppgåver | Chat Completions API |
| Structured Output | JSON/schema-basert output frå visuell analyse | Response format |
| Vision Fine-tuning | Tilpassing av visuell forståing | GPT-4o (2024-08-06) |
| Content Filtering | Sikkerheitsfilter for bilete-input/output | Azure AI Content Safety |

---

## Visual Grounding og Spatial Reasoning i Prompts

### Grunnleggjande image prompt-prinsipp

1. **Kontekstuell spesifisitet** — Gi modellen kontekst om kva biletet representerer
2. **Oppgåveorientering** — Fokuser på ei spesifikk oppgåve
3. **Handle refusals** — Reformuler ved nekting
4. **Bruk eksempel** — Vis ønska output-type
5. **Del opp komplekse oppgåver** — Steg-for-steg
6. **Definer output-format** — JSON, Markdown, tabell osv.

### Spatial reasoning-prompts

```python
from openai import AzureOpenAI

client = AzureOpenAI(
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    api_key=os.environ["AZURE_OPENAI_API_KEY"],
    api_version="2024-10-21"
)

# Spatial reasoning: Posisjon og relasjonar i biletet
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {
            "role": "system",
            "content": """Du er ein vegingeniør-assistent. Analyser
            biletet av vegkrysset og beskriv:
            1. Kva som er i NORD (øvst i biletet)
            2. Kva som er i SØR (nedst)
            3. Kva som er i ØST (høgre)
            4. Kva som er i VEST (venstre)
            5. Eventuelle trafikkproblem du observerer
            Returner som strukturert JSON."""
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "Analyser dette vegkrysset for trafikkplanlegging:"
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://example.com/intersection.jpg",
                        "detail": "high"
                    }
                }
            ]
        }
    ],
    max_tokens=1000,
    response_format={"type": "json_object"}
)
```

### Visual grounding med bounding box-referansar

```python
# Be modellen referere til spesifikke regionar
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {
            "role": "system",
            "content": """Når du analyserer bilete, referer til
            posisjonar med relative koordinatar:
            - Øvste venstre = (0,0)
            - Nedste høgre = (1,1)
            Bruk format: [objekt] ved ca. (x, y)"""
        },
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Identifiser alle trafikkskilt "
                                          "og deira posisjon i biletet."},
                {"type": "image_url", "image_url": {"url": image_url}}
            ]
        }
    ]
)
```

---

## Few-shot Examples with Images

### Mønster: Klassifisering med bilete-eksempel

```python
def classify_with_examples(target_image_url: str,
                           examples: list[dict]) -> str:
    """
    Klassifiser med few-shot bilete-eksempel.

    examples = [
        {"url": "...", "label": "HULLROT", "forklaring": "..."},
        {"url": "...", "label": "SPREKK", "forklaring": "..."},
    ]
    """
    messages = [
        {
            "role": "system",
            "content": "Du er ein vegskade-klassifiseringsekspert. "
                       "Bruk dei gitte eksempla som referanse."
        }
    ]

    # Legg til eksempel-bilete som user/assistant-par
    for ex in examples:
        messages.append({
            "role": "user",
            "content": [
                {"type": "text", "text": "Klassifiser denne vegskaden:"},
                {"type": "image_url",
                 "image_url": {"url": ex["url"], "detail": "low"}}
            ]
        })
        messages.append({
            "role": "assistant",
            "content": f"Klassifisering: {ex['label']}\n"
                       f"Forklaring: {ex['forklaring']}"
        })

    # Legg til målbiletet
    messages.append({
        "role": "user",
        "content": [
            {"type": "text", "text": "Klassifiser denne vegskaden:"},
            {"type": "image_url",
             "image_url": {"url": target_image_url, "detail": "high"}}
        ]
    })

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        max_tokens=500
    )

    return response.choices[0].message.content
```

### Token-budsjett for few-shot med bilete

| Detalj-nivå | Tokens per bilete | Kostnadsimplikasjon |
|-------------|-------------------|---------------------|
| `low` | 85 tokens (GPT-4o) | Optimal for eksempel-bilete |
| `high` (1024x1024) | ~765 tokens (GPT-4o) | Bruk for mål-biletet |
| `high` (2048x2048) | ~2805 tokens | Reduser til 1024 om mogleg |
| `auto` | Varierer | Standard — modellen vel |

**Best practice for few-shot:**
- Bruk `"detail": "low"` for eksempel-bilete (85 tokens kvar)
- Bruk `"detail": "high"` for mål-biletet (full analyse)
- Avgrens til 3-5 eksempel for å spare tokens
- Plasser biletet **før** tekst for single-image prompts

---

## Chain-of-Thought Reasoning with Visuals

### Visuell CoT-teknikk

```python
# Steg-for-steg visuelt resonnement
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {
            "role": "system",
            "content": """Du er ein byggesak-ekspert for norsk
            offentleg sektor. Analyser biletet steg for steg:

            STEG 1: Beskriv kva du ser i biletet i detalj
            STEG 2: Identifiser relevante byggtekniske element
            STEG 3: Vurder samsvar med gjeldande forskrifter
            STEG 4: Gi din konklusjon med grunngjeving

            Vis resonneringskjeda tydeleg."""
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "Vurder om dette byggeprosjektet "
                            "ser ut til å følgje TEK17 krav "
                            "til universell utforming:"
                },
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://example.com/building-entrance.jpg",
                        "detail": "high"
                    }
                }
            ]
        }
    ],
    max_tokens=2000
)
```

### Multi-image CoT-samanlikning

```python
# Samanlikn to bilete med resonnement
messages = [
    {
        "role": "system",
        "content": """Samanlikn dei to bileta steg for steg:
        1. Beskriv bilete A
        2. Beskriv bilete B
        3. Identifiser forskjellar
        4. Gi vurdering basert på forskjellane"""
    },
    {
        "role": "user",
        "content": [
            {"type": "text",
             "text": "Bilete A (før tiltak):"},
            {"type": "image_url",
             "image_url": {"url": before_url, "detail": "high"}},
            {"type": "text",
             "text": "Bilete B (etter tiltak):"},
            {"type": "image_url",
             "image_url": {"url": after_url, "detail": "high"}},
            {"type": "text",
             "text": "Vurder om vedlikehaldstiltaket er utført korrekt."}
        ]
    }
]
```

### "Describe first"-teknikken

Når modellen nektar å utføre ei oppgåve, be den først beskrive biletet:

```python
# Steg 1: Be modellen beskrive biletet detaljert
describe_response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text",
             "text": "Beskriv dette biletet i detalj, inkludert "
                     "alle synlege element, tekst, tal og merking."},
            {"type": "image_url",
             "image_url": {"url": image_url, "detail": "high"}}
        ]
    }]
)

description = describe_response.choices[0].message.content

# Steg 2: Utfør analyse basert på skildringa
analysis = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system",
         "content": "Analyser følgjande bildeskilding for "
                    "reguleringsplan-samsvar."},
        {"role": "user",
         "content": f"Bildeskilding:\n{description}\n\n"
                    "Vurder om det skildra bygget er i samsvar "
                    "med reguleringsplanen."}
    ]
)
```

---

## System Messages for Multi-Modal Tasks

### Template-struktur for visuelle system messages

```python
VISUAL_SYSTEM_TEMPLATE = """
ROLLE: {rolle}
KONTEKST: {kontekst}
OPPGÅVE: {oppgåve}

ANALYSEINSTRUKSJONAR:
{steg_for_steg_instruksjonar}

OUTPUT-FORMAT:
{format_spesifikasjon}

AVGRENSINGAR:
- {avgrensing_1}
- {avgrensing_2}
- Om du er usikker, sei eksplisitt kva du er usikker på
- Ikkje gjett — be om tilleggsinformasjon om nødvendig
"""

# Eksempel: Vegskade-vurdering
system_message = VISUAL_SYSTEM_TEMPLATE.format(
    rolle="Fagingeniør med 20 års erfaring frå norsk offentleg sektor",
    kontekst="Årlege fagvise inspeksjonar i Noreg",
    oppgåve="Vurder vegskade og anbefal vedlikehaldstiltak",
    steg_for_steg_instruksjonar="""
1. Identifiser skadetypen (sprekk, hullrot, setning, kantskade)
2. Vurder alvorlegheit på skala 1-5
3. Estimer utbreiing i m2
4. Anbefal tiltak (lappearbeid, fresing, full omlegging)
5. Prioriter (akutt, innan 3 mnd, neste sesong)""",
    format_spesifikasjon="""JSON med felt:
{
  "skadetype": "string",
  "alvorlegheit": 1-5,
  "utbreiing_m2": number,
  "tiltak": "string",
  "prioritet": "akutt|3mnd|neste_sesong",
  "grunngjeving": "string"
}""",
    avgrensing_1="Ikkje anslå kostnad utan prisgrunnlag",
    avgrensing_2="Merk alle vurderingar der confidence er låg"
)
```

### Rollebaserte system messages

| Rolle | System message-fokus | Typisk output |
|-------|---------------------|---------------|
| Byggesak-konsulent | TEK17-samsvar, reguleringsplan | Avviksliste med referanse |
| Vegingeniør | Skadeklassifisering, NVDB-kategori | Vedlikehaldsprioritering |
| Kulturminne-rådgjevar | Tilstandsvurdering, freding | Tilstandsrapport |
| Miljørådgjevar | Artsidentifisering, habitatvurdering | Konsekvensutgreiing |

---

## Image Tokenization og Kostnadsoptimalisering

### Token-forbruk per bilete

**GPT-4o token-kalkulering (high detail):**

1. Skaler biletet slik at lengste side er maks 2048px
2. Skaler så kortaste side er maks 768px
3. Del biletet i 512x512-tiles
4. Kvar tile = 170 tokens
5. Legg til 85 base tokens

```python
import math

def estimate_image_tokens(width: int, height: int,
                          detail: str = "high",
                          model: str = "gpt-4o") -> int:
    """Estimer token-forbruk for eit bilete."""
    if detail == "low":
        return 85 if model == "gpt-4o" else 2833

    # High detail: Skaler ned
    max_long = 2048
    max_short = 768

    # Steg 1: Skaler lengste side til 2048
    ratio = min(max_long / max(width, height), 1.0)
    w, h = int(width * ratio), int(height * ratio)

    # Steg 2: Skaler kortaste side til 768
    ratio2 = min(max_short / min(w, h), 1.0)
    w, h = int(w * ratio2), int(h * ratio2)

    # Steg 3: Tell tiles
    tiles_x = math.ceil(w / 512)
    tiles_y = math.ceil(h / 512)
    total_tiles = tiles_x * tiles_y

    # Steg 4: Kalkuler tokens
    return 85 + (170 * total_tiles)

# Eksempel
tokens = estimate_image_tokens(4096, 3072, "high")
print(f"Estimerte tokens: {tokens}")  # 85 + (170 * 6) = 1105
```

### Kostnadsoptimaliseringsstrategiar

| Strategi | Besparingsestimat | Avveging |
|----------|-------------------|----------|
| Bruk `detail: low` for eksempel-bilete | 80-95% per bilete | Lågare oppløysing |
| Resize til 1024x1024 før sending | 40-60% | Tap av findetaljar |
| Crop til relevant region | 60-80% | Krev forhandskjennskap |
| Cache analyseresultat | 100% på gjenbruk | Stale data-risiko |
| Batch liknande bilete | Redusert overhead | Meir kompleks logikk |

---

## Norsk offentleg sektor

### Bruksområde for multimodal prompt engineering
- **Byggesak**: Visuell vurdering av samsvar med reguleringsplanar
- **Vegforvaltning**: Automatisk skadeklassifisering frå dronefoto
- **Kulturarv**: Tilstandsvurdering av kulturminne frå bilete
- **Plan og kart**: Analyse av reguleringsplanar og kartutsnitt
- **Miljø**: Artsidentifisering og habitatvurdering

### Prompt-design for norsk kontekst
- Skriv system messages på norsk for domene-spesifikk terminologi
- Referer til norske standardar (TEK17, NVDB, NS-EN-standardar)
- Inkluder norske einskapar (NOK, m2, km/t)
- Bruk norske stadnamn og referansar

### Personvern i multimodale prompts
- Bilete av personar: Aldri be modellen identifisere personar
- Nummerplatar: Sladd før analyse om ikkje nødvendig
- Brev/dokument: Fjern personnummer frå bilete-input
- Azure OpenAI content filtering aktiv som standard

---

## Beslutningsrammeverk

| Scenario | Anbefaling | Grunngjeving |
|----------|------------|--------------|
| Enkel bildeklassifisering | Zero-shot med god system message | Raskast, lågast kostnad |
| Konsistent klassifisering | Few-shot med 3-5 eksempel-bilete | Betre konsistens, høgare kostnad |
| Kompleks vurdering | Chain-of-thought med steg-instruksjonar | Transparent resonnement |
| Kostnadsoptimalisering | `detail: low` + resize + caching | Drastisk token-reduksjon |
| Nekting/refusal-problem | "Describe first"-teknikk | Omgå overivrig filtering |
| Multi-bilete-samanlikning | Sekvensielle bilete med tydelege labels | Unngå forvirring |
| Produksjonssystem | Structured output (JSON) + validering | Påliteleg parsing |

---

## For Cosmo

- **Seks grunnprinsipp for image prompts**: Kontekstuell spesifisitet, oppgåveorientering, refusal-handtering, eksempelbruk, oppgåvedeling og output-formatering — følg Microsoft sin offisielle rettleiing for GPT-4o vision.
- **Few-shot med bilete brukar `detail: low` (85 tokens) for eksempel** og `detail: high` for mål-biletet — dette gir konsistent klassifisering utan å sprengje token-budsjettet.
- **Chain-of-thought med visuelt resonnement** gir transparente vurderingar — kritisk for offentleg sektor der avgjerder må grunngjevast, be modellen vise resonneringskjeda steg for steg.
- **Image tokenization avgjer kostnad**: Eit 4096x3072 bilete i `high detail` kostar ~1105 tokens med GPT-4o — resize til 1024x1024 reduserer til ~765 tokens, og `low detail` er flat 85 tokens.
- **System messages på norsk med domene-terminologi** gir betre resultat enn engelske generelle prompts — referer til norske standardar, einskapar og kontekst for presise fagvurderingar.
