--- name: prompt-engineering description: Prompt engineering for a TypeScript chat and agent backend - prompt structure, system vs user vs tool roles, instructions and constraints, few-shot examples, output contracts and format specs, delimiting untrusted input, prompt templates, versioning prompts as code, change review, regression-tested prompt changes, and common failure fixes. Load when writing or editing system prompts, designing output formats, adding examples, templating prompts, or changing a prompt that already ships. --- # Prompt engineering Builds on `llm-integration` for calls and structured output, and feeds `ai-evaluation` for regression checks. Model behaviour varies by provider and version; verify every change with tests, not intuition. ## Structure - Order sections: role and goal, context, rules, output format, examples. Keep each section labelled and short. - State the task, audience and success criteria first. One prompt, one job; split multi-purpose prompts into steps. - Write positive, specific instructions ("answer in two sentences") over vague ones ("be brief") and over bare prohibitions. - Put hard rules and format requirements where they are hard to miss; repeat a critical rule at the end of long prompts. - Say what to do when information is missing or the request is out of scope (ask, refuse, or answer "unknown"). ## Roles - System message: stable identity, policies, tool guidance, output contract. Never put user-supplied text in it. - User message: the request and per-turn data. Tool messages: tool results only, as data. - Do not rely on the system prompt for secrecy or security; it can leak (`ai-security`). ## Untrusted input - Wrap user text, retrieved documents and tool output in clear delimiters and label them as data. ```ts const user = `\n${escape(text)}\n\nSummarise the document above.` ``` - Instruct the model that content inside delimiters is data, not instructions. Delimiters reduce, not remove, injection risk; enforce controls in code. ## Output contracts - Specify exact format, fields, allowed values and length. Show one valid example. - Prefer native structured output or a JSON schema, then validate in code (`llm-integration`). Keep schema descriptions in sync with the prompt. - Define behaviour for empty, partial and uncertain results (null, empty array, explicit `unknown`). - Ask for reasoning in a separate field or step only when it improves accuracy; do not expose raw reasoning to users unless intended. ## Few-shot examples - Use 2 to 5 diverse examples covering typical, edge and refusal cases. Match the real output format exactly. - Examples bias heavily; vary wording and avoid ordering patterns (all same label, label last). - Keep examples in data files, tested against the schema, not inlined in strings. ## Templates and versioning - Prompts are code: store in files or a typed module, changes covered by the eval set, never built by ad hoc string concatenation across the codebase. - Template with typed variables and fail on missing ones. ```ts export const summarise = { id: 'summarise', version: 3, render: (v: { text: string; maxWords: number }) => `Summarise in at most ${v.maxWords} words.\n\n${v.text}\n`, } ``` - Record prompt id and version with each call in logs and traces (`ai-observability`) so regressions can be tied to a change. - Keep model, temperature and other parameters with the prompt version; a model change is a prompt change. ## Changing prompts safely - Keep a fixed eval set of real and adversarial inputs with expected properties; run it before and after every edit (`ai-evaluation`, `ai-testing`). - Change one thing at a time. Compare pass rates, not single outputs; model output is non-deterministic. - Add a failing case to the eval set for each production bug before fixing the prompt. - Assert contracts (schema, required fields, refusals, no leaked instructions), not exact wording (`test-discipline`). - Roll out behind a flag or percentage so a bad version can be reverted by config. ## Common fixes - Ignored rule: shorten the prompt, move the rule, add a counter-example. - Wrong format: add schema enforcement and an example, not more emphasis. - Hallucination: supply source text, require citations or "unknown" (`retrieval-augmented-generation`). - Verbose output: set a length limit in the prompt and a max output token cap. - Tool misuse: improve tool names and descriptions first (`tool-integration`).