Be explicit and specific about the task
Models do not infer unstated intent reliably; ambiguity is filled with the most probable continuation, which is often not what you wanted. State the goal, the audience, the constraints, the format, and the success criteria directly. Do: "Summarize the contract in 5 bullet points for a non-lawyer, citing the clause number for each." Don't: "Summarize this" and hope the length, audience, and format come out right.
Put instructions and data in separate, labeled sections
Mixing instructions with the content to be processed invites the model to confuse the two and opens the door to prompt injection. Use explicit delimiters - for Claude, XML-style tags such as and - to mark each region. Do: wrap user-supplied text in a tag and instruct the model to treat its contents as data only. Don't: paste a user message directly after your instructions with no boundary.
Show, don't just tell: use few-shot examples for format and edge cases
When you need a specific output shape or a domain convention, a few correct examples teach the pattern more reliably than prose alone. Make the examples diverse and include the tricky cases you care about. Do: include one example showing how to handle a missing field. Don't: rely on a single happy-path example and assume the model generalizes to edge cases.
Give the model an explicit way to say "I don't know"
A model asked to always answer will fabricate when it lacks grounds; an explicit abstention path turns that into an honest non-answer. Instruct it to respond with a fixed phrase when the context is insufficient. Do: "If the answer is not in the provided context, reply exactly: 'Not found in the provided sources.'" Don't: ask only for the answer and then act surprised at confident hallucinations.
Ground factual answers in retrieved context, not memory
For anything time-sensitive, private, or precise, supply the source material in the prompt and instruct the model to answer only from it and to cite it. Parametric memory is stale and unverifiable; grounded answers are auditable. Do: retrieve the relevant passages and require a citation per claim. Don't: ask a general model for current prices, versions, or internal policy from memory.
Match decoding parameters to the task
Sampling settings change behavior as much as wording: deterministic tasks want low randomness, creative tasks want more. Do: set temperature near zero for extraction, classification, and structured output. Don't: leave a high default temperature on a JSON-extraction endpoint and then debug "random" formatting failures - and don't tune temperature and top-p simultaneously.
Prefer structured output features over free-text parsing
Asking for JSON in prose and regexing the result is brittle; schema-constrained generation or tool/function calling is robust. Define the schema and let the platform enforce it, then still validate. Do: use the API's structured-output or tool-use mechanism with an explicit schema. Don't: parse JSON out of a chatty response and assume it will always be well-formed.
Always validate model output in code
The model is an untrusted component: its output can be malformed, unsafe, or adversarially manipulated. Validate types, ranges, and schema, and never feed raw output into a privileged action. Do: parse and schema-check JSON, allow-list tool arguments, and reject anything that fails. Don't: execute, render, or persist model output without a validation layer.
Decompose complex tasks into chained prompts
A single prompt that must classify, extract, reason, and format at once is hard to get right and harder to debug. Split it into steps where each output feeds the next, giving you checkpoints to validate. Do: chain "extract entities" then "validate" then "format" as separate calls. Don't: cram every requirement into one mega-prompt and bisect failures blindly.
Treat prompts as versioned, tested artifacts
Prompts are production code: they should live in version control, change through review, and be measured against an eval before shipping. Eyeballing one example is not testing. Do: keep prompts in the repo, change them via pull request, and gate on an eval score. Don't: edit the production prompt in a dashboard and judge the change by a single hand-picked input.
Build an evaluation set before optimizing
You cannot improve what you cannot measure; "this feels better" does not survive a model upgrade. Curate representative inputs with expected outputs or graded criteria and score every change against it. Do: assemble a golden set, including failure cases, and track faithfulness and task metrics over time. Don't: iterate on wording by vibes and discover regressions only in production.
Manage the context window as a scarce budget
Every token of instruction, history, and retrieved data competes for the same window and dilutes signal when it is irrelevant. Curate ruthlessly: fewer, higher-quality passages and pruned history beat dumping everything in. Do: retrieve top-k relevant chunks and summarize old turns. Don't: stuff the whole knowledge base or full chat history into context and assume more is better - that invites context rot.
Exploit prompt caching for stable prefixes
When a long system prompt, schema, tool set, or document repeats across calls, caching its processed form cuts latency and cost dramatically. Order the prompt so stable content comes first and variable content last. Do: place cache_control breakpoints after the stable block and keep per-request input after it. Don't: interleave variable data into the stable prefix, which defeats the cache.
Defend against prompt injection by design, not just instructions
Telling the model to "ignore malicious instructions" is necessary but not sufficient, because injection can override it. Constrain the blast radius: least-privilege tools, output validation, and human approval for high-impact actions. Do: label untrusted content as data, restrict what tools an agent can call, and require confirmation before irreversible operations. Don't: give an agent broad credentials and trust a single guardrail sentence to keep it safe.