Skip to content

Context Engineering

CoreConceptJuly 20, 20269 min read

A support bot gets the ticket "Checkout returns ECONNRESET after 30s." The model replies with a confident billing FAQ. The prompt was fine. The context window was not — yesterday's chat history and a low-relevance FAQ crowded out the proxy-timeout doc that actually explained the error.

An LLM does not "know" your product at inference time. It predicts from whatever tokens you put in front of it. Context engineering is the discipline of packing that finite window so the right facts, tools, and history win — and the wrong ones get dropped. For how this sits beside prompt craft and agent loops, see Prompt vs Context vs Harness.

Context engineering: every token in the window shapes the output
Context engineering: every token in the window shapes the output

The model only sees what you pack

At generation time, the model's output is determined by its weights plus the input context you supply: system instructions, tools, retrieved docs, memory, prior turns, and the user message. Change the window and you change the answer — even with the same user question and the same model version. That is not marketing; it is how autoregressive decoding works.

"Getting this right is everything" is a useful slogan with a precise reading: for a fixed model, quality is bounded by what entered the window and in what order. Clever wording cannot invent a document you never retrieved. A polluted window can make a perfect prompt look broken.

At a glance

Quick reference

  • Context = every token the model sees this call (not only the user sentence).
  • Prompt engineering = how you phrase roles, tasks, examples, and format inside that window.
  • Context engineering = what you select, compress, order, and drop before the call.
  • Same ticket + wrong docs → wrong answer; same ticket + curated docs → useful answer.
  • Weights are fixed at inference; the controllable lever is the window.

Remember this

For a fixed model, answer quality is bounded by what you put in the context window — wording alone cannot invent missing facts.

Why the field renamed prompt engineering

Early LLM apps were mostly prompt engineering: one message with a role, a task, maybe a few examples, and a format. That still matters — see Prompt Engineering for Developers for zero-shot, few-shot, and structured outputs. As products added RAG, tool results, long chat history, and multi-step agents, the "prompt" stopped being a single paragraph. It became a assembled payload with competing chunks and a hard token budget.

Context engineering names that larger job: gather candidates, score them for the current goal, compress or summarize what must survive, drop noise, and leave headroom for the model's answer. Prompt craft is one slice of the window. Calling the whole problem "prompting" hid the real failure mode — retrieval and packing — behind endless rewrites of the instruction text.

The rename is not a claim that prompts are obsolete. It is a claim that inputs became multi-source and budget-constrained, so the engineering surface moved from sentence craft to window design.

Inputs grew from one message to a multi-source budget
Inputs grew from one message to a multi-source budget

Quick reference

  • Prompt era: one composed message, iterate on wording.
  • Context era: many sources share one finite budget every turn.
  • Rename signals: RAG, tools, memory, and agents — not a new model API.
  • Still write clear instructions; stop treating every miss as a wording bug.
  • When to skip the jargon: a one-shot transform with all facts inline is still "just a prompt."

Remember this

"Context engineering" names the job after inputs became multi-source and budget-constrained — prompt craft remains a slice, not the whole window.

What usually sits in the window

Treat the context window as ordered layers that compete for the same tokens. Typical production stacks look like this for our checkout ticket:

System / policy — role, safety rules, output schema. Tools — schemas and recent tool results (proxy check, order lookup). Retrieved knowledge — docs and tickets ranked for "ECONNRESET" and checkout. Working memory / history — summarized prior turns, not the raw transcript. User message — the ticket text. Some APIs also inject invisible tool-routing or cache prefixes; those still consume budget even when you did not write them.

Order and priority matter. Models show lost-in-the-middle effects: important facts buried between long flanks get used less reliably than facts near the edges. Stuffing "everything we have" is not generosity — it is a denial-of-signal attack on your own call. Prefer a hard char/token budget and an explicit ranking key (relevance × recency × authority) over appending another FAQ.

Layers compete for the same tokens — rank by this turn's goal
Layers compete for the same tokens — rank by this turn's goal

Quick reference

  • System: durable rules and schema — version like code.
  • Tools: schemas are cheap; raw tool dumps are expensive — summarize.
  • Retrieval: rank for this turn's goal, not for "might be useful someday."
  • History: compress old turns; keep decisions and open questions.
  • User message: keep last and unedited so intent stays visible.
  • Budget: leave room for the completion; a full window with no answer budget is a footgun.

Remember this

Every layer competes for one budget — rank and drop by this turn's goal, or mid-window noise will drown the signal.

One triage turn: gather, curate, call, update

Running example. Subject: checkout support triage. Input: Checkout returns ECONNRESET after 30s. Success: the answer cites the proxy-timeout doc and returns a structured category. Failure: the window keeps unrelated billing history and the model cites the billing FAQ.

Gather candidates: system triage prompt, top-k docs for the error string, last tool result (if any), compressed history. Curate with a max character budget — keep high-score proxy docs, drop billing history. Call the model with the curated messages. Update memory for the next turn with the decision and citations, not the full assistant essay.

This loop is context engineering in the small. Classic vs Graph vs Agentic RAG deepens retrieval; here the point is the curator — the code that decides what enters the window — not the model brand.

One triage turn: gather → curate → LLM → update memory
One triage turn: gather → curate → LLM → update memory

Quick reference

  • Gather broadly; curate narrowly for this ticket.
  • Score with retrieval + simple heuristics — do not rely on "append all."
  • Log which chunk ids entered the window for every production call.
  • After the call, store citations and decisions, not the full completion.
  • If the model cites a dropped id, your eval caught a packing bug — fix retrieval, not the slogan.
Curate by score within a budget
1type Chunk = { id: string; text: string; score: number };2 3function curate(chunks: Chunk[], maxChars: number): Chunk[] {4  let used = 0;5  return [...chunks]6    .sort((a, b) => b.score - a.score)7    .filter((chunk) => {8      if (used + chunk.text.length > maxChars) return false;9      used += chunk.text.length;10      return true;11    });12}13 14const ticket = "Checkout returns ECONNRESET after 30s";15const windowChunks = curate(16  [17    { id: "billing-faq", text: "Refunds take 5–7 days…", score: 0.2 },18    { id: "proxy-timeout", text: "ECONNRESET: raise proxy idle timeout…", score: 0.95 },19    { id: "old-chat", text: "User asked about invoice #441 last week…", score: 0.15 },20  ],21  80,22);23// Expected: proxy-timeout first; billing-faq and old-chat dropped
Assert the right doc won
1console.assert(windowChunks[0]?.id === "proxy-timeout");2console.assert(!windowChunks.some((c) => c.id === "billing-faq"));3console.assert(!windowChunks.some((c) => c.id === "old-chat"));4console.log(5  "packed:",6  windowChunks.map((c) => c.id),7  "for ticket:",8  ticket,9);

Remember this

One turn is gather → curate → call → update: the curator that drops low-score chunks is the product, not the chat UI.

When the window lies to the model

Trigger: the triage service appends the last 40 chat turns plus every FAQ whose embedding is "somewhat close," with no budget. Symptom: answers cite billing or shipping for network errors; citation ids do not match the ticket. Mechanism: low-relevance and stale tokens dilute attention; the model faithfully uses what it sees. Evidence: log chunk_ids and token counts per call; compare against a golden set of ticket → required doc id. Recovery: cut history to a summary, re-rank with a harder score floor, re-run the same ticket. Prevention: enforce max chars, require a minimum score, and fail closed to "I need a doc" when retrieval is empty — do not invent from polluted leftovers.

Other failure classes: stale memory (an old "resolved" note blocks a new outage), prompt injection via retrieved text (a malicious page says "ignore the system prompt"), and tool dump bloat (a 50KB JSON payload leaves no room for the schema). Context engineering owns these; rewriting "You are a helpful assistant" does not.

Pollution path: low-score history crowds out the right doc
Pollution path: low-score history crowds out the right doc

Quick reference

  • Pollution: low-score chunks win by volume — cap and floor scores.
  • Stale memory: summarize with timestamps; prefer fresh retrieval for incidents.
  • Empty retrieval: refuse or escalate — do not fill with random FAQ.
  • Injection: treat retrieved text as untrusted data, not instructions.
  • Measure: citation hit rate, empty-retrieval rate, tokens per turn.

Remember this

Wrong answers with a "good prompt" are usually packing failures — log chunk ids, enforce budgets, and treat retrieved text as untrusted.

Fix the layer that actually broke

Use the same ticket to choose the repair. If the proxy doc was in the window and the model still ignored the schema, fix the prompt (format, examples, temperature). If the proxy doc never entered the window, fix context (retrieval, ranking, budget). If you need live curl checks, retries, and a verifier before you trust the category, you need a harness — covered in the comparison guide — not a longer system message.

Most teams over-invest in prompt rewrites because they are visible in the IDE. Invest in context when quality moves with which docs you pack. Climb to a harness only when a single curated call cannot meet the risk bar.

Pick the repair layer from the same failing ticket
Pick the repair layer from the same failing ticket

Quick reference

  • Schema/format drift → prompt layer.
  • Missing or wrong citations → context layer.
  • Needs tools + verify + retry → harness layer.
  • Reuse one eval set of tickets across all three layers.
  • Do not build agents to hide empty retrieval.

Remember this

Repair the lowest layer that explains the miss: schema → prompt, missing docs → context, tools/verify → harness.

Key takeaway

Context engineering is the claim that output quality tracks the window you assemble. Prompt engineering still writes the message; context engineering budgets the memory; harnesses automate gather → act → verify when one call is not enough.

Practice (20 min): paste the two snippets into curate-ticket.ts and run npx tsx curate-ticket.ts. Pass when proxy-timeout is packed and billing-faq / old-chat are absent. Then raise maxChars to 500 and include all three chunks — confirm the assert fails, restore the budget, and note which layer you fixed (context, not prompt).

Share:

Related Articles

Teams often treat every LLM quality problem as a prompt problem. Often the real issue is what entered the context window

Read

AI literacy in 2026 is a stack, not ten unrelated hobbies. You need instructions models follow, tools that connect to re

Read

A support ticket that needs docs, a tool call, and a model reply does not need twelve equal "frameworks." It needs an or

Read

Explore this topic

Keep learning

Follow a structured path or browse all courses to go deeper.