TECH STACK · Playbook — Tips, Tricks & Best Practices

Phase-3 draft, 2026-07-12. The practical wing: the stuff people bookmark, return to, and send to a colleague with "read section 3 before you touch that agent." Engineer-nod bar throughout — every tip is something you can do today, and the "mistakes everyone makes" blocks are all failures we have watched happen. Stage only.
How to read this
Seven sections, ordered the way problems arrive in real projects: first you prompt, then you manage context, then you hand work to agents, then you bolt on retrieval, then you try to prove any of it works, then the bill arrives, then someone attacks it. Each section gives you the principles, the numbered moves, and the mistakes block. Skip to the section that's currently on fire.
1. Prompting that actually works
Most prompting advice is folklore. The practices below are the ones with real, repeatable effect sizes — the ones that survive when you actually measure output quality instead of eyeballing it. The unifying idea: the model does exactly what you specify and guesses at everything you don't. Every prompting technique that works is a way of shrinking the guessing surface.
The moves
- Structure every serious prompt as role → context → task → constraints → format. Not because the order is magic, but because it forces you to actually supply all five. Most bad prompts are missing two of them — usually constraints and format — and the model fills the holes with defaults you didn't choose.
- Show, don't describe: few-shot examples beat instructions. Two or three input/output examples of exactly what you want will outperform a paragraph describing it, almost every time. If you can't produce an example of the output you want, you don't know what you want yet — and neither will the model. Make the examples cover the edge cases, not just the happy path: include one weird input and the output you expect for it.
- Use chain-of-thought where it helps — and know where it doesn't. Asking the model to reason step by step reliably improves math, logic, multi-constraint planning, and anything with intermediate state. It does not reliably improve — and can degrade — simple classification, retrieval-style lookups, and creative writing, where "reasoning" becomes the model talking itself into a hedge. And note: modern reasoning models do this internally; bolting "think step by step" onto a model that already deliberates mostly burns tokens. ⚑ unverified
- Ask for the reasoning first, then the answer — in that order. Models generate left to right. If the answer comes first, the "reasoning" after it is a post-hoc justification of whatever it already committed to. Reasoning-then-answer lets the conclusion actually depend on the work. Corollary: when you want machine-parseable output, have the model put the final answer in a delimited block at the end so you can extract it and throw the reasoning away.
- Control the output format explicitly, with a skeleton. "Respond in JSON" is a wish. Giving the exact schema — keys, types, an example object, and "no prose outside the JSON" — is a specification. Better still, use the structured-output / JSON-schema mode your provider offers and stop parsing with regex and prayer.
- Tell it what to do, not what to avoid. "Don't be verbose" gives the model a picture of verbosity to steer by. "Answer in at most 3 sentences" gives it a target. Negative instructions are weak; positive constraints with numbers are strong.
- Give it an out. The single cheapest hallucination fix in existence: "If the information isn't in the provided text, say 'not found' — do not guess." Without an explicit escape hatch, the model treats every question as answerable, because in its training data, questions get answered.
- Iterate like an engineer, not a gambler. Change one thing per run. Keep the prompt in version control next to the code it serves. Test each revision against the same fixed set of inputs (see section 5), not against whatever example you typed last. "I reworded it and it seems better" is the prompting equivalent of shotgun debugging.
Before / after — eight pairs
Pair 1 — the vague ask.
- Before: "Summarize this document."
- After: "Summarize this document for a busy executive in 5 bullet points, max 20 words each. Lead
with the financial impact. Include no recommendations — findings only."
Pair 2 — missing role and audience.
- Before: "Explain how OAuth works."
- After: "You are onboarding a junior backend developer who knows HTTP but has never done auth.
Explain the OAuth 2.0 authorization-code flow in under 400 words, then list the 3 mistakes juniors make implementing it."
Pair 3 — extraction without an out.
- Before: "What is the customer's account number in this email?"
- After: "Extract the customer's account number from the email below. Return only the number. If no
account number appears, return exactly: NONE. Do not infer or construct one."
Pair 4 — format by wish vs. format by schema.
- Before: "List the products mentioned and their prices as JSON."
- After: "Return JSON matching exactly: {\"products\": [{\"name\": string, \"price_usd\": number |
null}]}. Use null when a price isn't stated. No text outside the JSON. Example — input: 'the X100 runs $40, the X200 price is TBD' → {\"products\": [{\"name\": \"X100\", \"price_usd\": 40}, {\"name\": \"X200\", \"price_usd\": null}]}."
Pair 5 — reasoning order.
- Before: "Is this contract clause enforceable? Answer yes or no, then explain."
- After: "Analyze this contract clause step by step: (1) identify the obligation it creates, (2)
identify any conditions or ambiguities, (3) note anything that commonly makes similar clauses fail. Then, on a final line, write VERDICT: followed by ENFORCEABLE, QUESTIONABLE, or UNENFORCEABLE."
Pair 6 — negative instruction vs. positive constraint.
- Before: "Rewrite this, and don't make it sound like marketing."
- After: "Rewrite this in the voice of an engineer writing internal documentation: plain declarative
sentences, no adjectives of enthusiasm, no calls to action, present tense, max 150 words."
Pair 7 — instructions vs. few-shot.
- Before: "Classify these support tickets by urgency."
- After: "Classify each ticket as P1, P2, or P3. Examples — 'Site is down for all users' → P1;
'Export button gives an error, workaround exists' → P2; 'Feature request: dark mode' → P3; 'CEO demo in an hour and login is broken' → P1. Ticket: {ticket}. Reply with only the label."
Pair 8 — the pile-of-context prompt.
- Before: [12,000 words of pasted email thread] "What should I do?"
- After: "Below is an email thread about a delayed vendor delivery. Read it, then answer three
questions: (1) What has actually been agreed, with quotes? (2) What is still open? (3) Draft my 200-word reply that closes the open items without conceding a new deadline. Thread: [...]"
Mistakes everyone makes
- The mega-prompt. One prompt asked to extract, translate, summarize, and format in a single pass.
Chain small prompts; each link becomes testable and each failure becomes findable.
- Polishing the prompt while the input is the problem. If the source document is garbage, no
wording fixes it. Look at what you're actually sending — most people never print the final assembled prompt even once.
- Treating the first answer as the model's best answer. It's the most probable answer to an
underspecified question. One round of "here's what's wrong with that, revise" is the highest-ROI move in interactive use.
- Prompt superstition. Keeping incantations ("take a deep breath", threats, tips) that were never
A/B tested against your task. Measure or delete.
2. Context engineering
Prompting is what you say. Context engineering is deciding everything the model sees — instructions, documents, history, tool outputs — and, just as important, everything it doesn't. It's the discipline that separates demos from systems, because in production, the prompt is maybe 5% of the tokens and the context is the other 95%. The model has no idea which parts of that window matter. You do. Act like it.
The core physics: attention is finite. As the window fills, the model's grip on any single fact weakens — retrieval accuracy degrades with distance and with clutter, and material buried mid-window is recalled worse than material at the start or end (the "lost in the middle" effect, documented in the research literature ⚑ unverified). Practitioners call the degradation context rot: the longer a session runs and the more debris accumulates — dead ends, superseded plans, giant tool dumps — the dumber the model gets, not because it changed but because its window is now mostly noise.
The moves
- Curate in, not just out. For every candidate item ask: does the model need this to do the next step? A 400-line log file when 12 lines show the error; a whole API spec when it needs one endpoint; three previous drafts when only the latest matters — all of it is rot fuel. Send the extract, note where the full source lives.
- Put durable instructions at the top, task material in the middle, the immediate question at the end. Ends of the window get the strongest attention. Never bury the actual ask under 30k tokens of reference material.
- Summarize-and-refresh on long sessions. When a working session gets long, stop and have the model write a compact state summary: decisions made, current plan, open items, key file paths. Start a fresh context seeded with that summary. Ten minutes of ritual buys back the model you had an hour ago. Do it at natural phase boundaries — after exploration, before implementation — not only when things visibly degrade.
- Lay out repos and documents for AI consumption. This is the new hygiene bar. A
CLAUDE.md/AGENTS.mdat the repo root — build commands, architecture in ten lines, conventions, the forbidden zones — is read automatically by coding agents and pays for itself the first session. Keep it under a few hundred lines; it's context on every request, so every stale line in it is a tax. Same principle for documents: front-load a real summary, use meaningful headings, keep files small enough to load whole.
- Prefer pointers over payloads. Give the model the map — file tree, doc index, table schema — and the ability (or instruction) to request specifics, rather than pre-loading everything you might need. Agents with tools make this natural: the model pulls what the task turns out to require.
- Know when RAG beats stuffing. Under roughly 50–100k tokens of stable, always-relevant material, stuffing (with prompt caching — section 6) is simpler and often better: no retrieval misses. RAG wins when the corpus is bigger than the window, when it changes often, when queries touch a small slice of a large whole, or when per-request token cost matters at volume. The crossover is economic and qualitative, not just about fitting. ⚑ unverified
- Isolate contexts per concern. Don't run your code review, your marketing draft, and your infra debugging in one immortal session. Each task gets a context containing only its own world.
Mistakes everyone makes
- Confusing "fits in the window" with "usable." A model can accept 200k tokens and still
reason well over only a fraction of them. Capacity is not comprehension.
- The append-only session. Never pruning, never refreshing, then blaming the model when hour
three goes sideways. Context rot is your fault, not the model's.
- CLAUDE.md as a junk drawer. Every one-off note pasted in "for later" degrades every future
session. Instructions files need pruning like code needs refactoring.
- Letting tool output flood the window. One unfiltered
curlof a big JSON response can be
20k tokens of rot. Truncate, extract, or route large outputs to files.
- Repeating yourself instead of restructuring. If the model keeps ignoring an instruction,
it's usually drowned, contradicted, or mid-window — moving it beats shouting it twice.
3. Working with agents
An agent is a model in a loop with tools: it acts, observes the result, acts again. That loop is the whole power and the whole risk — errors compound across steps, and the agent will keep going, confidently, long after step 3 went wrong. Working well with agents is mostly scoping (giving them tasks the loop can actually verify) and containment (making the blast radius of a bad step small).
The scoping test that matters most: can success be checked mechanically? "Make the tests pass," "migrate these call sites and keep the build green," "convert these 40 files to the new format" — an agent can grind on these because every iteration gets a true/false signal from reality. "Improve the architecture," "make the copy better" — no feedback signal, so the loop is just vibes at machine speed.
The moves
- Scope tasks with a definition of done. Not "fix the auth bug" but "the three failing tests in
auth.test.tspass, no other tests break, no public API changes." The agent needs the same acceptance criteria a contractor would — and unlike the contractor, it won't push back on a vague spec; it will just invent one.
- Plan first, execute second. For anything non-trivial, have the agent produce a plan and read it before it touches anything. Thirty seconds of plan review catches the misunderstanding at step 0 instead of at step 40. Most agent disasters were visible in the plan.
- Verify work products, not narration. Agents report success in the same confident tone whether or not they succeeded. Never accept "all tests pass" — run the tests. Read the diff, not the summary of the diff. The agent's self-report is a claim; the artifact is the evidence.
- Sandbox and permission hygiene. Run agents with the least access that lets them do the job: scoped directories, no production credentials, no destructive commands without a prompt, network egress only where needed. Git worktrees or containers per agent task are cheap insurance. The uncomfortable truth: an agent will occasionally do something you'd never predict —
git push --force,rmon the wrong path, "helpfully" editing a config you never mentioned. Permissions are the difference between an anecdote and an incident.
- Budget the review burden before you start. Reviewing agent output is real work, and it's harder than reviewing a human's, because the code looks plausible everywhere and the mistakes are unhumanly weird. An agent that generates in 10 minutes what takes 2 hours to review is a productivity claim that needs auditing. Corollary: keep agent diffs small enough to actually review — many small verified tasks beat one heroic sprawl.
- Cut losses fast. When an agent is flailing — same error twice, "fixing" by deleting the test, growing changes to shrink the problem — stop it. Reset context, improve the task spec, restart. Three failed iterations means the spec is broken; iteration four won't save it.
- Know when NOT to use an agent. Skip the agent when: the task is faster to do than to specify (30-second edits); success can't be verified mechanically and the stakes are high; the domain knowledge lives in your head and isn't written anywhere the agent can read; the operation is irreversible (prod migrations, sending external email, anything legal or financial) — agents draft, humans fire; or you can't afford the review time, because unreviewed agent output is deferred debt, not saved work.
Mistakes everyone makes
- Delegation as abdication. "The agent wrote it" is not a review process. You own everything you
ship, including the parts you didn't read.
- The immortal session. One agent context reused across days of unrelated tasks, dragging every
previous confusion along. Fresh task, fresh context.
- Trusting green checkmarks without reading the tests. Agents under pressure to "make tests
pass" sometimes make tests pass — by weakening asserts, skipping cases, or special-casing the test input. Check what got tested, not just the exit code.
- Full permissions for convenience.
--dangerously-skip-permissionson day one because prompts
are annoying. The prompts are the safety system. Earn the loosening per-environment, in a sandbox.
- Anthropomorphic patience. Coaching a failing agent through 10 rounds of feedback like a junior
hire. It doesn't learn within your project the way a person does; fix the instructions file or the task spec — the things that persist.
4. RAG best practices
Section 2 covered when to reach for RAG. This is how — and the honest headline is that RAG quality is decided at the boring end of the pipeline. Everyone wants to tune the model; the wins are in chunking, search, and reranking, in that order. The model just narrates whatever retrieval hands it: garbage retrieved, garbage generated — now with citations.
The moves
- Chunk along the document's own structure. Split on sections, headings, paragraphs — never blind fixed-length cuts that sever sentences and tables mid-thought. Typical working range is a few hundred to ~1,000 tokens per chunk with 10–20% overlap ⚑ unverified. Smaller chunks retrieve more precisely; bigger chunks carry more context. Tune on your corpus, against the eval in tip 5.
- Enrich chunks with their provenance. Prepend title, section path, and date to each chunk ("Q3 2025 Handbook › Leave Policy › Parental"). A paragraph that says "the limit is 20 days" is useless without knowing which document and which year it came from — to the retriever and to the model. For chunks that read badly out of context, contextual enrichment (a one-line LLM-written situating sentence per chunk) measurably cuts retrieval failures ⚑ unverified.
- Hybrid search, not embeddings alone. Dense vector search catches meaning; keyword search (BM25) catches exact strings — part numbers, error codes, names, legal citations — where embeddings are weakest. Run both, fuse the results (reciprocal rank fusion is the standard trick). Pure-vector RAG fails hilariously on "what does error E4402 mean," and every real corpus is full of E4402s.
- Rerank before you generate. First-stage retrieval is built for speed, not precision. Pull a generous candidate set (top 25–50), then run a reranker — a cross-encoder that actually reads query and chunk together, e.g. Cohere Rerank or an open-source equivalent — and keep the top handful. Reranking is the single highest ROI-per-line-of-code upgrade in the pipeline.
- Evaluate retrieval before you scale anything. Before tuning, before the vector-DB bake-off, build a golden set: 50–100 real questions, each mapped to the chunks that should answer it. Measure whether the right chunk lands in the top-k (recall@k, plus a rank-weighted score like MRR). This costs an afternoon and tells you the truth about every change you make afterward. Teams that skip it tune blind, forever. Managed platforms — Pinecone, Weaviate, Qdrant Cloud — remove ops burden, but no database choice fixes bad chunks.
- Instrument the "I don't know" path. The worst RAG failure mode is silent: answer not in corpus, model answers anyway from frozen memory, user believes it. Require citations from retrieved text, give the model an explicit not-found response, and log retrieval scores so you can see when the system is answering from thin evidence.
The failure-modes checklist
Run down this list when RAG output is wrong — it's ordered by how often each one is the culprit:
- Bad chunks — answer straddles a chunk boundary, or the chunk lost its heading/context.
- Retrieval miss — right chunk exists, doesn't reach top-k (vocabulary mismatch, exact-term
query hitting vector-only search).
- Rot in the middle — right chunk retrieved, buried under 20 mediocre ones, model missed it.
- Stale corpus — retrieved chunk is true-but-outdated; no date filtering, no versioning.
- Unanswerable question — corpus never contained it; model freelanced instead of declining.
- Conflicting sources — two documents disagree, model blends them into one confident fiction.
- Query-shape mismatch — user asked a comparison/aggregation question; top-k passage lookup
structurally can't answer it (needs multi-query decomposition or a different tool entirely).
Mistakes everyone makes
- Starting with the vector database evaluation. Weeks on Pinecone-vs-Weaviate before anyone has
looked at a single retrieved chunk with their own eyes.
- Never reading the retrievals. The single best debugging habit in RAG: print what was
retrieved for ten real queries. It's almost always worse than you assumed.
- top-k as a religion. k=5 forever, never tested, never dynamic. If the reranker says only two
chunks are relevant, send two.
- Indexing garbage. OCR debris, boilerplate headers, duplicated docs — indexed, retrieved, and
faithfully cited. Corpus hygiene precedes everything.
- Demo-driven confidence. It answered five hand-picked questions in the meeting, so it ships.
The golden set exists precisely because those five questions are the ones it was tuned on.
5. Evals & shipping
"It seemed better" is the phrase that precedes most LLM production incidents. Model outputs are non-deterministic, quality is multi-dimensional, and humans anchor on the last three examples they read — which means unmeasured iteration is random walk with extra confidence. Evals are how you turn "we think the new prompt is better" into "the new prompt is +9 points on extraction accuracy and −2 on tone; ship it." Nobody regrets building evals early. Everybody regrets building them after the incident.
The moves
- Build the golden set before you tune anything. 50–200 real inputs (pull from logs, not imagination) with expected outputs or grading criteria. Include the ugly cases: ambiguous inputs, adversarial phrasing, empty fields, the weird customer. Version it in git next to the prompts it tests. A golden set of 50 beats a vibe check of 5,000.
- Grade three ways, matched to the claim. Exact/programmatic checks for anything with a right answer (extraction, classification, format validity — cheapest, run on every commit). Model-graded rubrics (LLM-as-judge) for qualities like faithfulness and tone — useful at scale, but calibrate the judge against a sample of human ratings before trusting it, and never let a model grade its own homework without spot checks. Human review for the high-stakes slice — it doesn't scale, so spend it where it counts.
- Regression-test prompts like code. Any change to prompt, model version, temperature, or retrieval config triggers the eval suite. Prompt edits are code changes with invisible diffs — the two-word tweak that fixed the CEO's pet example just broke nine cases nobody retried. Wire the suite into CI; tools like Promptfoo, Braintrust, or Langfuse make this an afternoon's setup, not a platform project.
- Pin model versions; treat upgrades as migrations. Point at a dated model snapshot, not a floating alias — providers update those silently, and your carefully tuned behavior drifts under you. New model version = run full evals = conscious decision, same discipline as a database migration.
- A/B on real traffic before full rollout. Offline evals tell you it's not worse; only live traffic tells you it's better, because real users are stranger than your golden set. Route a small slice (5–10%) to the new variant, compare on outcome metrics — task completion, retry rate, thumbs-down rate, escalation-to-human rate — not just output-quality scores. Canary, then ramp, with a rollback path that's one config flip.
- Keep evaluating after launch. Sample production outputs weekly for review; feed every production failure back into the golden set as a permanent regression case. The eval suite should grow monotonically — it's the accumulated scar tissue of everything that ever went wrong.
Mistakes everyone makes
- Demo-set evaluation. Testing on the same 10 examples the prompt was tuned on. That's not an
eval; that's a memorization check.
- One score to rule them all. A single "quality: 7.8" hides that accuracy went up while safety
went down. Track dimensions separately; regressions live in the disaggregation.
- Uncalibrated judges. Deploying LLM-as-judge without ever checking it against human judgment,
then optimizing toward the judge's biases (verbosity bias is the classic — judges reward length).
- Evals as launch theater. Run once before shipping, never again. Model drift, data drift, and
prompt edits all continue after launch day; so must the suite.
- Measuring quality but not outcomes. The response scored 9/10 and the user still couldn't
complete the task. Outcome metrics are the ground truth; quality scores are the proxy.
6. Cost control
LLM spend has a specific pathology: it's invisible per-call and shocking per-month. Every unit is "fractions of a cent," so nobody watches, and then the invoice lands. The good news — LLM costs are unusually controllable, because the three biggest levers (caching, routing, batching) are pricing features your provider already built. Most teams that actually pull them cut spend 50–90% ⚑ unverified with zero quality loss.
The moves
- Prompt caching first — it's the biggest single lever. If your requests share a long stable prefix (system prompt, tool definitions, reference docs), the provider can reuse the processed prefix instead of recomputing it. Anthropic: cache reads are ~90% off input price, writes cost ~25% over base ⚑ unverified. OpenAI: automatic caching at ~50% off cached input tokens ⚑ unverified. Gemini offers both implicit and explicit caching ⚑ unverified. The design consequence: structure prompts stable-first — everything constant at the top, volatile material (user query, timestamp) at the bottom, because one changed token invalidates the cache from that point on. A timestamp in your system prompt's first line can silently disable caching for your entire fleet.
- Route cheap-first, escalate on failure. Frontier models are often 10–60× the price of small ones per token ⚑ unverified — and a large share of production traffic is classification, extraction, and short transforms that small models handle fine. Pattern: classify request complexity (a rules pass or a tiny-model pass), send easy traffic to the cheap model, escalate to the frontier model when confidence is low or validation fails. Even a "dumb" two-tier split typically moves the majority of calls to the cheap tier. Gateways like OpenRouter make multi-model routing a config change. Prove routing safety with your eval suite (section 5), not optimism.
- Batch everything that isn't interactive. Anthropic's Batch API and OpenAI's Batch API both run asynchronous jobs at ~50% off, results within 24 hours (usually much faster) ⚑ unverified. Nightly enrichment, backfills, bulk classification, eval runs — none of it needs a real-time endpoint. If no human is waiting on the response, you're voluntarily paying double.
- Trim context relentlessly — you pay for every token, every call. Output tokens also cost several times input ⚑ unverified, so cap response length ("max 3 sentences,"
max_tokens) as a cost control, not just a style choice. Summarize old conversation turns instead of resending full history; send document extracts, not documents; strip retrieved chunks the reranker scored low. In chat products, unbounded history means each conversation gets linearly more expensive the longer it runs — usually the silent majority of the bill.
- Monitor spend per feature, per user, per request — from day one. You can't fix what you can't attribute. Log tokens in/out, model, cache hit/miss on every call; tag by feature; alert on anomalies (a retry loop against a frontier model is a classic four-figure weekend). Gateways and observability layers — Helicone, Langfuse, LiteLLM — give you this in an afternoon. Set billing alerts at the provider level as the backstop.
- Set unit economics before scaling. Know your cost per task ("a support resolution costs $0.04") and its acceptable ceiling. That number decides routing thresholds, cache strategy, and context budgets — and whether the feature makes commercial sense at 100× volume, before you're at 100× volume.
Mistakes everyone makes
- Frontier-model-for-everything. The best model as the default for traffic that's 80%
yes/no questions. Defaults are where the money leaks.
- Caching-hostile prompt layout. Volatile tokens (timestamps, request IDs, user names) near the
top of the prompt, invalidating the cache on every call. Free money, declined.
- Uncapped retries. Error → retry → error → retry, at full price, all night. Retry with backoff,
a cap, and an alert.
- Resending the world every turn. Full conversation history plus full document set on every
message of a 50-turn chat. Nobody noticed because each call was "cheap."
- Discovering the bill monthly. No per-feature attribution, no alerts, just an invoice
autopsy every month. By the time finance asks, the pattern is 30 days old.
7. Security & safety hygiene
One sentence of threat model: anything that enters the model's context can steer the model. The model cannot reliably distinguish your instructions from instructions embedded in a document, email, web page, or tool result it processes — that's prompt injection, and it is not solved. There is no patch; there is only architecture that assumes it will land. Design accordingly and most of the scary scenarios become contained instead of catastrophic.
The moves
- Treat all external content as hostile input. Emails, PDFs, web pages, user uploads, API responses — any of them can contain "ignore your instructions and…" text, visible or hidden (white-on-white text, HTML comments, metadata). Delimit external content clearly in the prompt and instruct the model that it's data, not commands — this raises the bar but does not secure anything on its own. The real defense is the next tip.
- Cap the blast radius, not just the probability. Ask: if an injection fully controls the model's next action, what's the worst it can do? That's a permissions question, not a prompting question. Least-privilege tools, read-only by default, scoped credentials per agent, no destructive or irreversible action (sending, deleting, paying, publishing) without human confirmation. The dangerous triad to avoid wiring together in one autonomous loop: access to private data + exposure to untrusted content + ability to communicate externally. Any two is manageable; all three is an exfiltration machine waiting for its instruction.
- Keep secrets out of context entirely. No API keys, credentials, or connection strings in prompts or instruction files — context gets logged, cached, and can be extracted by injection or by asking nicely. Secrets live in the execution layer (env vars, secret managers); tools use them without the model ever seeing them. And scrub or minimize PII before it enters prompts, especially with third-party providers — check your data-retention and training-use terms ⚑ unverified.
- Validate outputs like user input — because that's what they are. Model output rendered into HTML is an XSS vector; model-generated SQL is an injection vector; model-suggested shell commands are arbitrary code execution; hallucinated package names are a real supply-chain attack (attackers register commonly hallucinated names — slopsquatting). Parse against schemas, allowlist commands/tables/URLs, sanitize before render, and gate anything executable on review.
- Log everything; red-team on a schedule. Full audit trail of prompts, retrieved content, tool calls, and outputs (secrets excluded) — injections will eventually land, and the difference between an incident and a mystery is the log. Then attack your own system before strangers do: run known injection corpora and your own targeted attempts against every significant release, the same cadence as your evals.
Mistakes everyone makes
- Prompt-only defense. "You must never reveal the system prompt" as the entire security model.
Instructions are suggestions to a language model; permissions are enforced by code. Enforce in code.
- Trusting the model's judgment of its inputs. "The model will notice something's suspicious."
Injection attacks are engineered precisely so it doesn't.
- The over-privileged demo that shipped. Full-access credentials granted "temporarily" during
the prototype, still there in production a year later.
- Secrets in the instructions file. A database URL pasted into CLAUDE.md for convenience — now
in every context window, every log line, and every transcript export.
- Assuming the provider handles it. Provider safety filters target universal harms, not your
data boundaries, your tenant isolation, or your customer's PII. That layer is yours.
Cross-cutting close
If the seven sections compress to one habit each: specify instead of hoping (1); curate the window (2); verify the artifact, not the narration (3); read your retrievals (4); measure before believing (5); cache, route, batch (6); and cap the blast radius (7). None of it is glamorous. All of it is the difference between teams that ship LLM systems and teams that demo them.
Anchored links (per the Layered Autopsy): → Layer IV · ORCHESTRATION — How RAG Actually Works · → Layer IV — Agents & Tool Use · → Layer VI · APPLICATION — What Shipping Really Takes.
Some links on this page are affiliate links. If you sign up or buy through one, TheCatch.AI earns a commission at no extra cost to you. We list what we would use; the commission never decides the ranking, and nothing in Bubble Watch or Economics carries an affiliate link — analysis stays clean.