Så bygger jag prompt templates med variabler och guardrails
När en prompt används en gång kan jag skriva den ganska fritt. När samma instruktion ska köras hundra gånger i ett system behöver jag något annat: ett kontrakt med stabila instruktioner, tydliga variabler och kontroller runt de delar som får ändras.
När en prompt används en gång kan jag skriva den ganska fritt. När samma instruktion ska köras hundra gånger i ett system behöver jag något annat: ett kontrakt med stabila instruktioner, tydliga variabler och kontroller runt de delar som får ändras.
Det är där prompt templates blir intressanta. För mig är de inte en textsträng med några {placeholders}. De är en liten gränsyta mellan applikationslogik och språkmodell.
Separera stabilt från variabelt
Jag börjar med att dela prompten i två typer av information.
Stabilt: uppgiftens regler, output-format, sanningskrav, policy, prioritering och vilka verktyg som får användas.
Variabelt: användarens input, dokument, målgrupp, produktdata, datum, sökfråga eller annan körningsspecifik kontext.
En enkel mall kan se ut så här:
Poängen är inte XML i sig. Poängen är att modellen kan skilja regler från input. Anthropic rekommenderar just tydlig separation av instruktioner, kontext, exempel och variabel input i sina prompting-riktlinjer, så som de såg ut när den här artikeln publicerades. Anthropic prompting best practices.
Variabler behöver typer och constraints
Jag vill inte ha variabeln {{context}} om den i praktiken kan innehålla vad som helst. Jag definierar hellre varje fält ungefär som ett API-kontrakt:
Det gör att fel kan fångas innan prompten renderas. Om market är tomt är det bättre att applikationen stoppar än att modellen försöker gissa.
Validera före modellen
Guardrails börjar därför utanför prompten. Jag delar in dem i tre lager.
1. Input validation
Kontrollera datatyp, längd, tillåtna värden och om obligatoriska fält finns.
2. Prompt boundary
Markera variabel data tydligt så att den inte blandas ihop med systeminstruktioner. Dokument från användare är data, inte nya regler för agenten.
3. Output validation
Kontrollera att svaret följer schema, innehåller obligatoriska fält och inte försöker returnera något verktyget inte ska göra.
Det är starkare än att skriva "följ alltid instruktionerna ovan" längst ned i prompten.
Gör inte template-motorn till ett programmeringsspråk
En fälla är att lägga för mycket logik i själva promptmallen:
När regler kan uttryckas exakt lägger jag dem hellre i kod. Applikationen kan bestämma vilken variant som ska användas och skicka modellen den relevanta kontexten.
LLM:n ska resonera där språk och osäkerhet kräver det. Den ska inte vara en dyr if/else-motor.
Templates behöver versionsnummer
När en prompt påverkar produktion vill jag veta exakt vilken version som skapade en viss output.
Det gör regressioner felsökningsbara. Om felprocenten plötsligt ändras efter en release kan jag jämföra template-versioner i stället för att leta i en prompt som skrivits över på plats.
OpenAI:s prompt management hade, när den här artikeln skrevs, samma riktning: prompts kan sparas, versionshanteras, använda variabler och kopplas till evals. OpenAI Prompt Management.
Examples är testdata, inte dekoration
Few-shot-exempel kan vara mycket effektiva, men jag behandlar dem som en del av kontraktet. De ska representera den faktiska uppgiften och inkludera edge cases.
Om alla exempel visar enkla lyckade fall lär sig modellen en falsk bild av domänen. Jag vill hellre ha exempel på:
- fullständig input,
- saknad obligatorisk information,
- motstridiga källor,
- input som innehåller instruktioner som ska behandlas som data,
- ett fall där korrekt svar är
UNRESOLVED.
Exemplen ska också versionshanteras och ingå i evals. Annars kan en "förbättring" av ett exempel ändra modellbeteendet utan att någon ser det.
Guardrails ska matcha risken
Alla templates behöver inte samma kontrollnivå. En mall som gör brainstorming kan vara relativt fri. En mall som avgör om en artikel får publiceras behöver betydligt hårdare output-kontrakt.
Jag använder ungefär:
Det här hindrar också en annan anti-pattern: att samma gigantiska systemprompt används överallt "för säkerhets skull".
Isolera instruktioner från okänd input
Om {{source_material}} kan innehålla webbsidor, e-post eller användardokument utgår jag från att texten kan innehålla prompt injection.
Jag skriver därför inte bara:
Jag gör rollen tydligare:
Det ersätter inte verktygsbehörigheter eller sandboxing, men minskar semantisk sammanblandning. Den viktigaste säkerheten ligger fortfarande i vad agenten faktiskt har rätt att göra.
Logga den renderade promptens byggstenar
Jag behöver inte alltid spara hela känsliga prompten, men jag vill kunna felsöka:
- template ID och version,
- vilka variabler som var satta,
- vilka optional blocks som aktiverades,
- modell och inställningar,
- eval-resultat,
- eventuell retry/fallback.
För känsliga inputs sparar jag hellre hash, metadata och säkra utdrag än råtext.
Testa renderingen före modelltestet
En förvånansvärt stor del av promptbuggar är egentligen templatebuggar. Variabeln är tom, XML-taggen blir felbalanserad eller ett optional block försvinner på fel villkor.
Jag har därför ett enkelt första teststeg:
Först därefter kommer LLM-evalen.
Det är samma princip jag använder i resten av mina AI-system: deterministiska fel ska fångas deterministiskt.
En återanvändbar template-struktur
Min standardmall tenderar att ha följande lager:
Jag stoppar inte automatiskt in alla delar. En enkel uppgift ska ha en enkel prompt. Men när uppgiften blir produktionskritisk vill jag att varje lager har ett tydligt ansvar.
Från prompt till systemkomponent
Det viktiga skiftet är att sluta se prompten som magisk copy. En produktionsprompt är en versionerad komponent med inputs, outputs, constraints, testfall och observability.
När jag bygger den så blir själva formuleringen mindre mystisk. Jag kan ändra en variabeldefinition utan att röra kärninstruktionen, A/B-testa ett exempel och stoppa ogiltig input redan innan den når modellen. Jag kan också se exakt vilken version som producerade ett givet fel.
Det är mycket närmare vanlig mjukvaruutveckling än traditionell "prompt engineering" – och det är precis därför det skalar bättre.