I en prototype er en prompt måske blot en streng, I skrev på en eftermiddag. I produktion bryder den tilgang sammen omkring den første måned.
I skal kunne ændre én del af instruktionerne uden at påvirke andre, variere adfærden mellem kundeanvendelser, A/B-teste versioner, rulle tilbage ved fejl og se, hvornår prompten sidst blev ændret og hvorfor.
Et produktionssystem til prompts håndterer alt dette. Det er ikke “skriv en streng”, men en arkitektur.
Denne artikel beskriver arkitekturen — de tre lag, disciplinen omkring skabeloner, versionsstyring, evaluering og den driftspraksis, der gør prompts til infrastruktur frem for løse artefakter.
Produktionsprompts består af to adskilte artefakter: genbrugelige skabeloner og data pr. forespørgsel. Versionér skabelonerne som kode. Behandl genererede prompts og modelsvar som følsomme logdata, når de indeholder bruger-, kunde- eller interne data.
De tre lag
Produktionsprompter har tre adskilte lag, hver med forskellige ansvarsområder:
Systemlag. Stabil adfærd, identitet og begrænsninger. Ændres sjældent. Ejes af teamet, der designer AI-adfærden.
Udviklerlag. Instruktioner pr. funktion, værktøjsbeskrivelser og krav til outputformat. Ændres sammen med funktionen og ejes af funktionsteamet.
Brugerlag. Brugerens konkrete anmodning samt dynamisk kontekst som data, samtalehistorik og hentet viden. Er forskelligt ved hvert kald.
At blande dem er den mest almindelige fejl. Systemprompten vokser til 5,000 ord med identitet, funktionsinstruktioner og dynamisk kontekst; en enkelt ændring får nu andre dele til at bryde sammen.
At adskille dem er grundlæggende:
┌─────────────────────────────────────┐
│ System prompt (stable) │ Identity, behavior, hard constraints
├─────────────────────────────────────┤
│ Developer prompt (per-feature) │ Feature instructions, tools, format
├─────────────────────────────────────┤
│ User prompt (per-call) │ User query, context, conversation
└─────────────────────────────────────┘
Model-API’erne understøtter dette eksplicit:
- OpenAI:
system,developer,userroller. - Anthropic:
system, dereftermessagesmeduserogassistantroller. Værktøjsbeskrivelser er en separat parameter. - Gemini:
systemInstruction, dereftercontentsmed roller.
Brug disse adskillelser bevidst.
Lag 1: Systemprompten
Systemprompten definerer, hvem AI’en er og hvordan den opfører sig. Den ændres sjældent.
En god systemprompt dækker:
Identitet. Hvem AI’en er. “Du er en AI-assistent for [Virksomhed], specialiseret i [domæne].”
Stemme og stil. Hvordan den skal lyde. Specifikke egenskaber, ikke vage beskrivelser.
Hårde begrænsninger. Ting, den aldrig må gøre. Output bestemt indhold, træf bestemte beslutninger, ignorer bestemte instruktioner.
Adfærdsmodeller. Hvordan den håndterer almindelige situationer. Afvisninger, eskaleringer, usikkerhed.
Sikkerhed og efterlevelse. Påkrævede oplysninger, regelbaserede regler, indholdspolitikker.
Det skal ikke indeholde:
- Funktionsspecifikke instruktioner (“til salgs e-mails, gør X”).
- Dynamisk kontekst (“brugerens bestillingshistorik er…”).
- Værktøjsbeskrivelser (disse går andre steder).
- Ting, der ændres ofte.
En god systemprompt er 300-1000 ord. Er den længere, bliver den svær at styre; er den kortere, bliver adfærden ofte utilstrækkeligt specificeret.
Et template, der fungerer:
You are [name], an AI assistant for [company / context].
## Your role
[2-3 sentences on what you do]
## Voice and style
- [Specific trait 1]
- [Specific trait 2]
- [Specific trait 3]
- Do not [anti-pattern 1]
- Do not [anti-pattern 2]
## Hard constraints
- Never [hard rule 1]
- Never [hard rule 2]
- Always [hard rule 3]
## How to handle uncertainty
- If you don't know something factual: say so explicitly.
- If a user asks for something outside scope: offer what you can help with.
- If a request might cause harm: refuse and explain why.
## Format expectations
- Plain text by default
- Use markdown when displaying code or structured data
- Be concise; do not pad responses with filler
Dette er ryggen. Enhver interaktion går gennem det. Ændringer er bevidste og sjældne.
Lag 2: Udviklerprompten
Udviklerprompten er funktionsspecifik. Forskellige funktioner har forskellige udviklerprompter.
En summeringsfunktionens udviklerprompt:
Task: produce a summary of the document below.
Requirements:
- 3-5 bullet points
- Each bullet is one complete sentence
- Focus on facts and concrete claims, not impressions
- If the document contains numbers, include the most important ones
- Do not include marketing language or speculation
- If the document is ambiguous about something important, note it
Format: plain markdown bullets, no preamble.
En udviklerprompt til en kodegennemgangsfunktion:
Task: review the code diff below.
Output a JSON object with:
- summary: 1-2 sentence overview of the change
- concerns: array of specific issues (each: file, line, severity, description)
- suggestions: array of improvements (each: file, line, suggestion)
- approved: boolean (true if no blocking concerns)
Severity levels:
- "blocker": must be fixed before merge
- "warning": should be addressed but not blocking
- "nit": stylistic, optional
Focus on:
- Logic errors
- Security issues
- Performance issues
- Missing test coverage
- Unclear naming or structure
Skip:
- Formatting (handled by formatter)
- Subjective style preferences
Hver funktion har sin egen udviklerprompt. De gemmes separat, versioneres separat og evalueres separat.
Lag 3: Brugerprompten
Brugerebene er dynamisk. Den indeholder typisk:
Brugerens faktiske anmodning. “Opsummér dette dokument for mig.”
Kontekst, systemet har hentet. Dokumenter fra RAG, kundehistorik og samtalehistorik.
Variabler pr. kald. Brugernavn, tidszone, sprogpræference og kontoniveau.
Denne lag bygges programmerisk ved kaldetidspunktet. Strukturen ser typisk sådan ud:
{conversation_history_summary}
{retrieved_context}
User's request: {user_query}
Additional context:
- User name: {name}
- User timezone: {timezone}
- User tier: {tier}
Den præcise struktur afhænger af funktionen. Principper: data går her, ikke i system- eller udviklerprompter.
Disciplin i brugen af skabeloner
Prompts i produktion bygges ud fra skabeloner. Sammenkædning af strenge direkte i koden er en prototypemetode, der ikke skalerer.
Et simpelt templatesystem:
from string import Template
SUMMARIZE_TEMPLATE = Template("""
$conversation_summary
Document to summarize:
$document
User's specific instructions: $user_instructions
""")
prompt = SUMMARIZE_TEMPLATE.substitute(
conversation_summary=summarize_conversation(history),
document=document_text,
user_instructions=user_query,
)
Mere avanceret: et skabelonbibliotek som Jinja2 eller Handlebars med betingelser og delskabeloner.
{% if user_tier == "enterprise" %}
You have access to advanced analysis features.
{% endif %}
{% if retrieved_context %}
Relevant context from your knowledge base:
{{ retrieved_context }}
{% endif %}
User's request: {{ user_query }}
Skabeloner reducerer risikoen for promptinjektion via variabler, når brugerinput afgrænses korrekt, muliggør betinget logik og holder promptstrukturen ensartet.
Versionsstyring
Prompts er kode. Gem dem i versionsstyring.
Et velfungerende mønster er en prompts/-mappe i repositoryet med én fil pr. prompt:
prompts/
system/
main.txt
customer-support.txt
code-assistant.txt
features/
summarize.txt
classify-ticket.txt
generate-email.txt
templates/
base.j2
Hver fil er en separat prompt med sin egen commit-historik. Ændringer gennemgås via pull requests, og produktionen henviser til konkrete versioner.
Hvorfor det betyder noget:
- Diff. Når en prompt ændres, vises forskellen i pull requesten. Kontrollanter kan se præcist, hvad der er ændret.
- Tilbagerulning. Hvis en ændring giver fejl, kan den forrige version gendannes.
- Historik. Spørgsmål som “Hvornår ændrede vi refunderingspolitikken?” og “Hvorfor findes dette afsnit?” kan besvares via git blame.
- Værktøjer. Linters, validatorer og evalueringssuiter kan integreres med filbaserede prompts.
Undgå prompts som strenge i kode, hvor de er svære at finde og sammenligne, prompts gemt alene i et UI-værktøj, hvor værktøjet ejer historikken, og prompts kopieret fra chatvinduer uden sporbarhed eller test.
Læg ikke produktionssamtaler, kundedata, supportsager, interne dokumenter eller genererede prompts med følsomme variabler i versionsstyring. Den er til genbrugelige skabeloner, fixtures og rensede evalueringseksempler. Virkelige spor hører til i et observerbarhedssystem med opbevaringsregler, adgangskontrol og redigering.
Prompt som data: ekstern lagring
Til prompts, der ændres ofte — A/B-test, kundevarianter og lokalitetsspecifikke prompts — er filbaseret versionsstyring for langsom.
Mønstret er en database eller tjeneste, der gemmer promptversioner med metadata.
prompt = prompt_service.get(
name="summarize",
version="v3",
locale="en",
user_tier="enterprise",
)
Tjenesten vedligeholder:
- Aktuelle og historiske versioner af hver prompt.
- Metadata: hvornår tilføjet, af hvem, hvorfor.
- Evalueringsscorer knyttet til hver version.
- Mulighed for tilbagerulning.
Værktøjer: PromptLayer, Helicone eller en egen løsning. For de fleste teams fungerer et enkelt internt system med et simpelt databaseskema fint.
Grænsefladen er afgørende. Både ingeniører og medarbejdere fra produkt og indhold skal kunne redigere prompts. Ændringerne skal dog gennemgås og bestå evalueringer, før de går i produktion.
Ændringer med evalueringsport
Alle promptændringer gennemgår evalueringer før udrulning. Det kan ikke fraviges i seriøse produktionssystemer.
Flow:
- Ingeniør eller ikke-ingeniør skriver en promptændring.
- Ændringen køres mod evalueringssættet.
- Evalueringsresultaterne gennemgås sammen med ændringen.
- Hvis evalueringerne består uden regression og helst med forbedring, kan ændringen godkendes.
- Godkendte ændringer udrulles.
- Overvågning efter udrulning opdager det, evalueringerne overså.
I praksis betyder det, at hver prompt har et eval-sæt, og sættet kører i CI på promptændringer.
Uden porten kan promptændringer få uventede konsekvenser. Med den kan teamet arbejde hurtigt og med tillid.
En praktisk frigivelsescheckliste
Før en promptversion går i produktion, kræves en kort tjekliste:
| Check | Krav |
|---|---|
| Ejer | Prompten har en navngiven ejer og kontrollant. |
| Instruktionslag | System-, udvikler- og bruger-/kontekstdata er adskilt. |
| Skema | Strukturerede output har et skema og fejlhåndtering. |
| Injektionshåndtering | Brugergenereret indhold er tydeligt afgrænset og behandles aldrig som instruktioner. |
| Evaluering | Kandidatprompten består regressionssættet og sikkerhedstilfældene. |
| Logning | Skabelonversion, model, svartid, omkostning og redigerede input/output kan observeres. |
| Tilbagerulning | Den seneste kendte gode version kan gendannes uden en kodeudrulning. |
Den tilhørende tjekliste gør kontrollerne til en gentagelig udgivelsesgennemgang.
A/B-testning i produktion
A/B-test nye prompts mod den eksisterende version på en lille del af produktionstrafikken for at få signaler fra virkeligheden ud over evalueringerne.
Mønster:
- 95% af trafikken bruger produktionsprompt v3.
- 5% får den nye kandidat v4.
- Måling: brugerfeedback, efterfølgende forretningsmål og evalueringsscorer på virkelig trafik.
- Når der er tilstrækkelige data, besluttes det, om v4 udrulles til 100%, eller v3 beholdes.
Værktøjer: feature flags som LaunchDarkly eller en egen løsning, promptversioneringstjenester som PromptLayer og specialbygget routing.
Advarsler:
- A/B-test opdager kun de signaler, I måler. Uden brugerfeedback eller efterfølgende konverteringsmål fortæller testen kun lidt.
- Statistisk betydning kræver volumen. For lavvolumens funktioner er A/B-testning svær.
- Kør ikke for mange A/B-test samtidig; samspillet gør resultaterne uklare.
Observerbarhed for prompts
Hvert produktionskald skal logge:
- Hvilken promptskabelon der blev brugt (navn, version).
- Hvilke variable der blev substitueret, ved brug af tilladte navne og redigerede værdier, hvor det er nødvendigt.
- Den endelige genererede prompt kun, når politikken tillader det; ellers en redigeret, stikprøvebaseret eller hashet repræsentation.
- Modellens svar, redigeret eller stikprøvebaseret ved følsomme arbejdsgange.
- Latens, tokens, omkostninger.
- Nedstrøms signaler (brugertilbagemeldinger, succesmål).
Disse data er nødvendige for at undersøge: “Hvorfor gav modellen denne bruger et mærkeligt svar?” Uden dem gætter teamet.
Lagring: en databasetabel eller et observerbarhedsværktøj. Omkostningen er reel, hvis alt logges (kaldsvolumen × tokenantal × lagring). Det samme gælder risikoen for følsomme data. Beslut pr. arbejdsgang, hvilke felter der må gemmes, redigér hemmeligheder og persondata som standard, og brug kort opbevaring, medmindre compliance kræver længere spor. Nogle teams bruger stikprøver.
Gennemsigtighed: en regelmæssig praksis (ugentligt) af at læse et eksempel på virkelige produktionsprompter og responser. Opdager problemer, evals ikke gør.
Prompt anti-mønstre
Få mønstre at undgå:
Anti-mønster 1: Megaprompten. En systemprompt på 10,000 ord, der forsøger at håndtere alle situationer. Den er svær at ændre og fejlfinde, og modellen overser ofte senere instruktioner.
Løsning: Opdel den i lagdelte, fokuserede prompts — én pr. funktion.
Anti-mønster 2: Inline strengkonkatenation.
prompt = "You are helpful. " + (
"The user is a paid customer. " if user.tier == "paid" else ""
) + f"Their name is {user.name}. " + ...
Skrøbelig, svær at læse og sårbar over for injektion.
Løsning: Brug et skabelonsystem.
Anti-mønster 3: Samme prompt til for mange anvendelser.
En enkelt prompt til en “generel assistent”, der bruges til mailskrivning, kodegennemgang, kundesupport og research. Det er forskellige opgaver; én prompt er ikke optimeret til nogen af dem.
Løsning: funktionsspecifikke udviklerprompter over en fælles systemprompt.
Anti-mønster 4: Hard-kodede prompter.
response = openai.chat.completions.create(
messages=[
{"role": "system", "content": "You are a helpful assistant..."},
{"role": "user", "content": query}
]
)
Promptet er skjult i koden. Kan ikke redigeres uden deploy. Kan ikke A/B-testes. Kan ikke versioneres uafhængigt.
Løsning: udtræk til en promptfil eller tjeneste.
Anti-mønster 5: Ingen evalueringsdækning.
En funktion leverer med et prompt, der aldrig har været testet systematisk. Kvaliteten er “vibes”. Drift er uopdagelig.
Løsning: hver prompt har et eval-sæt.
Anti-mønster 6: Dynamiske data i systemprompten.
You are an assistant for John, a premium customer who joined in 2023, lives in Tallinn, and has 47 open tickets.
Nu ændres systemprompten ved hvert kald. Caching brydes, og der opstår uklarhed.
Løsning: dynamisk data går i bruger/kontekstlag, ikke i systemprompten.
Anti-mønster 7: Instruktioner skjult midt i.
Help the user with their request. Be polite. Format output as JSON. Don't use markdown. The user is asking about pricing, so be careful about quoting numbers. Output should be 1-2 sentences. Now help them.
Vigtige instruktioner forsvinder. Modellen kan overse dem.
Løsning: struktur med klare sektioner, placér kritiske instruktioner i start og slut (nærværkseffekten hjælper).
Specifikke mønstre for almindelige funktioner
Få funktionsspecifikke mønstre:
Klassificering
Task: classify the following text into one of these categories:
- billing: payment, refund, subscription
- technical: bug, error, integration issue
- account: login, password, profile changes
- feature_request: new functionality requests
- complaint: general dissatisfaction without specific actionable issue
Output a JSON object: {"category": "<one of above>", "confidence": "<high|medium|low>", "reasoning": "<1 sentence>"}
Text to classify:
{text}
Mønstre: opstillet kategorier med definitioner, struktureret output, konfidens- og begrundelsesfelter.
Ekstraktion
Task: extract structured data from the document below.
Schema:
- vendor_name: company that issued the invoice
- invoice_number: as printed on the document
- date: ISO 8601 format
- line_items: array of {description, quantity, unit_price, total}
- subtotal, tax, total: numbers
Rules:
- If a field is not present, use null
- Numbers should be numeric, not strings
- For ambiguous cases, set "needs_review": true and explain
Document:
{document}
Mønstre: eksplicit skema, forventede typer, håndtering af manglende data og eskalering ved usikkerhed.
Generering med stil
Task: write a {format} on the topic of {topic}, targeting {audience}.
Style:
- {Specific style trait 1}
- {Specific style trait 2}
- Avoid: {anti-pattern 1}, {anti-pattern 2}
Constraints:
- Length: {N} words
- Include: {required elements}
- Exclude: {forbidden elements}
Voice reference:
[Provide a sample of the desired voice]
Output: the {format} only, with no preamble or post-script.
Mønstre: konkrete stiltræk frem for generiske, eksplicitte begrænsninger og et referenceeksempel som anker for tonen.
Agent-loop
You have access to the following tools:
{tool_descriptions}
For each turn:
1. Think about what you need to do.
2. Decide if you need a tool. If yes, call it.
3. After observing the result, decide if you need more tools or can answer.
4. When you have enough information, produce the final answer.
Constraints:
- Maximum 5 tool calls per request.
- If after 5 calls you can't complete, explain what's missing.
- Never invent tool names or arguments.
- Verify tool results before acting on them.
User request:
{user_query}
Mønstre: eksplicitte tænketrin, værktøjsbudget, anti-hallucination, refleksion.
Teamaspektet
Produktionsprompter involverer typisk flere personer:
- Ingeniører forbinder prompterne til systemet, vedligeholder skabelonerne og styrer udrulningen.
- Produkt definerer, hvad prompterne skal opnå.
- Indhold/markedsføring ejer stemme- og stilvejledning.
- Domæneeksperter ved, hvad der er korrekt til konkrete anvendelser som juridiske formuleringer og medicinske begreber.
Et nyttigt mønster er en promptgennemgang, der minder om kodegennemgang og inddrager de rette kontrollanter for hvert domæne. Toneændringer gennemgås af indholdsteamet, logikændringer af ingeniører og domænespecifikt indhold af faglige eksperter.
Ved følsomme juridiske, medicinske eller finansielle anvendelser kan prompts kræve formel gennemgang og godkendelse. Tilpas processen derefter.
En 90-dagesplan for promptmodenhed
Til teams, der går fra “prompts er strenge i kode” til “prompts er styret infrastruktur”:
Dage 1-30: Grundlag.
- Udtræk alle prompter til dedikerede filer i kildekontrol.
- Opstil 3-lag mønster (system / udvikler / bruger).
- Byg et enkelt skabelonlag.
- Opsæt grundlæggende logning af prompter og responser.
Dage 31-60: Evaluering.
- Byg eval-sæt for de øverste 5 prompter.
- Kør evals på promptændringer (manuelt først).
- Opsæt CI-integration for evals (automatisk kør på PR’er).
Dage 61-90: Operativt.
- Implementér promptversionering (database eller tjeneste).
- Tilføj A/B-testevirksomhed for mindst én kritisk prompt.
- Byg dashboards for produktionspromptkvalitet.
- Etablér en gennemgangsproces for promptændringer.
Efter 90 dage er prompts styret infrastruktur. Ændringer er bevidste, testbare, gennemgåede og reversible. Kvaliteten kan måles, og drift kan opdages.
Prompter som infrastruktur
Produktionsprompts er ikke strenge. De er et lagdelt system med disciplin omkring versionering, skabeloner, evaluering og observerbarhed.
Tre-lagsarkitekturen (system / udvikler / bruger) adskiller ansvarsområder og holder prompts vedligeholdelige. Skabeloner forebygger skrøbelighed. Versionsstyring eller en prompttjeneste giver historik. Evalueringsporte blokerer dårlige ændringer. Observerbarhed opdager det, evalueringerne overser.
Det er ikke valgfrit i seriøs produktion. Teams, der springer trinnene over, ender med promptkaos — strenge spredt i koden, ukendt produktionsversion, umålt kvalitet og konstante uventede adfærdsændringer.
Teams, der investerer i promptinfrastruktur, får AI-adfærd, der kan kontrolleres, måles og forbedres. Det er forskellen mellem en funktion, der holder over tid, og en, der bliver teknisk gæld.
Start med arkitekturen. Alt andet bliver nemmere.



