Context Architecture¶
Context architecture is the design of what information reaches the model, in what form, from which sources, with what trust level and under what budget.
A context window is not a database, memory system or source of truth. It is a temporary working set assembled for one model decision.
A useful mental model is:
Canonical Sources
├── run state
├── user/task input
├── policies
├── skill definition
├── retrieved evidence
├── tool observations
└── memory
↓
Context Builder
├── select
├── normalize
├── rank
├── compact
├── label trust/provenance
└── fit budget
↓
Model Context
The context builder is therefore closer to a compiler than to a string concatenation helper.
Context is a projection, not canonical state¶
The runtime state may contain far more information than the model needs.
Canonical Run State
↓ projection
Current Model Context
The projection may include:
- current goal,
- relevant success conditions,
- current plan fragment,
- recent authoritative observations,
- available capabilities,
- selected business rules,
- retrieved evidence,
- unresolved questions.
It should not automatically include every historical message, tool result and artifact.
Context layers¶
A useful conceptual stack is:
1. platform/system constraints
2. application policy/instructions
3. active skill instructions
4. task and goal
5. canonical state projection
6. observations and evidence
7. relevant memory
8. user interaction/history needed now
The exact API representation differs by provider, but the architecture should know which layer owns which information.
Stable instructions vs runtime data¶
Separate relatively stable behavior from changing task data.
Stable:
- application role,
- hard interaction rules,
- skill contract,
- output schema guidance,
- domain terminology.
Dynamic:
- current customer/order,
- latest tool result,
- current plan,
- retrieved documents,
- remaining budget,
- current failure.
Do not rewrite stable system behavior into every piece of retrieved text or user content.
Context ownership¶
A dedicated ContextBuilder or equivalent component should own assembly rules.
Example interface:
class ContextBuilder(Protocol):
def build(self, run: AgentRun, purpose: ContextPurpose) -> ModelContext: ...
The purpose matters because planning, tool selection, verification and summarization may require different projections.
PLANNING context
goal + constraints + coarse state
ACTION_SELECTION context
current state + fresh observations + capabilities
VERIFICATION context
claimed result + evidence + success conditions
One giant universal context template usually becomes noisy and expensive.
Context as a budgeted resource¶
A larger context is not automatically better.
Costs include:
- more input tokens,
- higher latency,
- more irrelevant distractors,
- increased chance of conflicting instructions,
- harder provenance tracking,
- stale information remaining visible.
Think in terms of a budget:
context_budget
├── instructions
├── task/state
├── evidence
├── tool schemas
└── reserve for output
The builder should know approximate priorities and truncation policy before the provider rejects the request.
Relevance over chronology¶
Chat-style applications often default to chronological history. Agent runtimes usually need relevance-oriented state projection.
Weak:
last 100 messages
Better:
current goal
current plan step
fresh relevant observations
required constraints
selected evidence
important unresolved facts
Chronology can still matter, but it is not the primary organizing principle for many agent decisions.
Observation normalization¶
Raw tool output should usually be normalized before being inserted into model context.
Raw:
{
"status": 200,
"headers": {...},
"internal_metadata": {...},
"payload": {...}
}
Model-facing observation:
{
"source": "order_service",
"observed_at": "...",
"order_id": "123",
"payment_status": "PAID",
"shipment_status": "NOT_SHIPPED"
}
Keep the raw artifact separately if it is needed for audit/debugging.
The normalized form should preserve the facts necessary for reasoning without flooding context with transport noise.
Fact vs hypothesis¶
The context should make it possible to distinguish:
FACT
authoritative observation from a source
INFERENCE
interpretation derived from facts
HYPOTHESIS
unverified assumption used for planning
If these blur together, the model may treat its own earlier guesses as authoritative state.
A structured record can help:
{
"claim": "customer may be eligible for refund",
"kind": "hypothesis",
"evidence_refs": ["obs-41", "policy-7"]
}
Provenance¶
Evidence should carry source information.
Useful metadata:
source_id
source_type
retrieved_at / observed_at
tenant / access scope
trust classification
content version
citation/artifact reference
Provenance enables:
- grounding,
- audit,
- freshness checks,
- tenant isolation,
- verification,
- re-fetching canonical data.
Freshness¶
Some facts decay quickly.
Examples:
repository HEAD changes often
order status may change
flight status changes
policy document versioned, slower
static product spec relatively stable
The runtime should define freshness policy by source/capability.
cached observation
↓
older than freshness threshold?
↓ yes
re-observe canonical source
Do not leave freshness entirely to model judgement when code can enforce it.
Trusted vs untrusted context¶
Not all tokens are equally trustworthy.
Typical sources:
HIGHER TRUST
system/application policy
signed/internal configuration
authoritative structured service data
VARIABLE TRUST
internal documents
retrieved knowledge
external webpages
emails/messages
user-uploaded files
UNTRUSTED INSTRUCTION SOURCE
arbitrary retrieved text claiming "ignore previous instructions"
Retrieved content may contain instructions, but those instructions should be treated as data, not as authority over the runtime.
This is one of the core defenses against indirect prompt injection.
Data trust vs instruction authority¶
A subtle but important distinction:
A source may be trusted as data without being trusted to issue instructions.
Example:
GitHub README
It may be authoritative documentation for the repository, but text inside it should not automatically be allowed to redefine agent permissions.
Represent these dimensions separately where useful:
content_trust = internal_repository
instruction_authority = none
Retrieval as context acquisition¶
RAG is one way to acquire relevant context.
question / state
↓
retrieval query
↓
search
↓
rerank/filter
↓
evidence
↓
context builder
The context builder should not treat top-k retrieval results as inherently correct or relevant.
Possible filters:
- tenant authorization,
- document version,
- freshness,
- source type,
- relevance score,
- duplication,
- trust classification.
Tool results as context acquisition¶
Tool calling is another context source.
Difference:
Retrieval
finds stored knowledge/evidence
Tool observation
queries current operational state or performs action
For a question such as "Has invoice 42 been paid?", the current billing service is usually stronger evidence than an embedded document snapshot.
Memory as optional context source¶
Persistent memory should not be dumped wholesale into the context.
Memory Store
↓ relevant memory retrieval
Context Builder
Memory records should have provenance, timestamps and confidence/ownership where appropriate.
Remembered user preference and current authoritative account state are different categories and should not be conflated.
Summarization and compaction¶
When context grows, summarize lower-value history while preserving canonical records separately.
Bad:
summarize everything
replace original state
Better:
canonical state/artifacts remain stored
↓
context-specific summary generated
↓
used only as projection
A summary is a lossy representation and should not silently become the source of truth.
What should be re-fetched instead of summarized?¶
Prefer re-fetching when the data is:
- operational/current,
- cheap to query,
- safety-critical,
- authorization-sensitive,
- likely to have changed.
Examples:
- current bank balance,
- current order state,
- current repository branch HEAD,
- current user permissions.
Prefer summarization for:
- long discussion history,
- completed plan segments,
- large evidence sets whose raw artifacts remain available,
- previous reasoning outcomes that are not authoritative external facts.
Context versioning and reproducibility¶
For debugging, record enough metadata to reconstruct what the model saw.
Possible trace fields:
context_template_version
skill_version
policy_version
state_version
observation_ids
retrieval_result_ids
model configuration
You may not store every rendered prompt forever, especially with sensitive data, but you need a strategy for reproducibility and privacy.
Context caching¶
Caching can reduce cost and latency for stable prefixes or repeated retrieval.
But cached context must respect:
- tenant isolation,
- authorization changes,
- source version,
- expiry/freshness,
- privacy requirements.
Never reuse a context fragment across tenants merely because the text looks identical unless its access scope is truly shared.
Example: code review agent¶
Possible context for one step:
SYSTEM
review policy + security constraints
SKILL
PR review instructions + finding schema
TASK
review PR #123 for correctness issues
STATE
files reviewed: 8/11
open findings: 2
OBSERVATIONS
current diff for file X
failing test Y
TOOLS
read_file
fetch_diff
run_tests
BUDGET
6 tool calls remaining
It does not need every file in the repository, every previous model response and every CI log on each step.
Context anti-patterns¶
Dump everything¶
More tokens are treated as more intelligence.
Chat history as state¶
The runtime expects the model to infer canonical progress from messages.
Unlabelled evidence¶
Retrieved text has no source, time or trust metadata.
Stale operational data¶
Old tool results remain in context and are used for irreversible actions.
Summary becomes truth¶
A lossy model summary replaces canonical state.
Retrieval can override policy¶
External documents are inserted at the same instruction authority as application rules.
One context template for every reasoning task¶
Planning, acting and verification receive the same bloated prompt.
Practical context-building pipeline¶
1. Load canonical run state
2. Determine context purpose
3. Select required instructions/policy
4. Select relevant state projection
5. Refresh stale critical observations
6. Retrieve optional evidence/memory
7. Apply authorization/trust filters
8. Normalize and deduplicate
9. Rank by relevance/priority
10. Compact to token budget
11. Attach provenance metadata
12. Invoke model
Takeaways¶
- Context is a temporary projection, not canonical state.
- Treat context construction as an architectural subsystem, not string concatenation.
- Build different projections for planning, action selection and verification.
- Prefer relevance and freshness over simply replaying chronological history.
- Distinguish facts, inferences and hypotheses.
- Preserve provenance and trust classification.
- Treat retrieved/external instructions as untrusted data unless explicitly authorized.
- Re-fetch current authoritative state when correctness matters more than saving a tool call.
- Keep raw/canonical artifacts outside summaries so context can stay compact without losing truth.