Executive Summary
The four-layer model in this article is an engineering decomposition, not a vendor standard: instructions define stable policy, knowledge supplies task evidence, memory carries state across turns, and orchestration selects and validates the other layers. The boundaries are useful only when each layer has an owner, an interface, a trust model, and a measurable failure path.
Do not interpret a layer as a fixed percentage of a context window. Token limits, pricing, cache behavior, and model attention vary by provider and version. Measure the assembled request on the exact model and workload you deploy.
Why Separate the Layers?
A single concatenated prompt hides important differences:
| Failure | Typical cause | Layered control |
|---|---|---|
| Relevant rules disappear | long history or retrieval noise | reserve and validate instruction budget |
| Stale facts are cited | no freshness or authority metadata | knowledge routing and source checks |
| User state is forgotten | unbounded truncation | explicit memory policy and compaction tests |
| Costs and latency grow | every request carries everything | orchestration, budgets, and telemetry |
The model still receives one request at inference time. Layering improves the construction and verification process; it does not create a new attention mechanism.
Layer 1: Instructions
Instructions are the relatively stable contract: safety boundaries, supported capabilities, output schema, and project conventions. Keep them versioned and short. A rule is useful when it states an observable action and its verification:
type InstructionSet = {
version: string;
globalRules: string[];
domainRules: Record<string, string[]>;
forbiddenActions: string[];
outputSchema?: string;
};
function buildInstructions(set: InstructionSet, domain?: string): string {
const rules = [
...set.globalRules,
...(domain ? set.domainRules[domain] ?? [] : []),
];
return [
`## Contract ${set.version}`,
'### Rules',
...rules.map(rule => `- ${rule}`),
'### Do not do',
...set.forbiddenActions.map(rule => `- ${rule}`),
set.outputSchema ? `### Output schema\n${set.outputSchema}` : '',
].filter(Boolean).join('\n');
}
Do not silently let a task request override authorization, secret handling, or compliance policy. If two trusted rules conflict, return a conflict for human resolution. Treat a provider-specific rule file as an adapter whose path and precedence must be verified against that client version.
Token estimates such as text.length / 4 are rough diagnostics, not billing or model-token truth. Use the provider tokenizer for budgets and record the model version.
Layer 2: Knowledge
Knowledge is dynamic evidence: documents, API schemas, database metadata, or approved tool descriptions. Retrieval results are not automatically true. Store source, version date, authority, tenant, and access decision alongside content.
type KnowledgeChunk = {
id: string;
text: string;
source: string;
updatedAt: string;
authority: 'official' | 'reviewed' | 'unknown';
tokenCount: number;
relevance: number;
};
function selectKnowledge(
chunks: KnowledgeChunk[],
budget: number,
): KnowledgeChunk[] {
const eligible = chunks
.filter(chunk => chunk.authority !== 'unknown')
.sort((a, b) => b.relevance - a.relevance);
const selected: KnowledgeChunk[] = [];
let used = 0;
for (const chunk of eligible) {
if (used + chunk.tokenCount > budget) continue;
selected.push(chunk);
used += chunk.tokenCount;
}
return selected;
}
Production retrieval should define query routing, tenant filtering, ACL checks, deduplication, freshness policy, reranking, citation format, and a no-evidence response. A relevance score is not a security decision and does not prove factual correctness. Test retrieval precision, stale-source rate, citation coverage, and unauthorized leakage.
Tool schemas belong here only as capabilities the client may propose. The server must validate arguments and enforce authorization independently; a model must not grant itself access by emitting a tool call.
Layer 3: Memory
Memory is state, not a transcript dump. Separate:
- working memory: the current request and immediate tool results;
- session memory: approved summaries and unresolved decisions;
- long-term memory: user or organization facts with consent, retention, deletion, and tenant scope.
Compaction can be deterministic for structured state and model-assisted for prose, but summaries are lossy and untrusted until checked:
type Turn = {
role: 'user' | 'assistant' | 'tool';
content: string;
createdAt: number;
tokenCount: number;
};
function compactHistory(
turns: Turn[],
keepRecent: number,
maxTokens: number,
): { recent: Turn[]; older: Turn[] } {
const recent = turns.slice(-keepRecent);
let used = recent.reduce((sum, turn) => sum + turn.tokenCount, 0);
const older: Turn[] = [];
for (let index = turns.length - keepRecent - 1; index >= 0; index -= 1) {
const turn = turns[index];
if (used + turn.tokenCount > maxTokens) break;
older.unshift(turn);
used += turn.tokenCount;
}
return { recent, older };
}
Never promote a user claim or tool result to durable memory without provenance and a policy check. Support deletion, correction, expiration, and tenant isolation. Evaluate memory with recall, false-memory rate, stale-memory rate, and successful deletion tests.
Layer 4: Orchestration
Orchestration assembles the final context and owns the budget. It should be a policy decision, not an opaque string concatenation:
type ContextParts = {
instructions: string;
knowledge: string;
memory: string;
task: string;
};
type Budget = {
totalTokens: number;
instructions: number;
knowledge: number;
memory: number;
};
function assemble(parts: ContextParts, budget: Budget): string {
// Replace these rough lengths with the target provider tokenizer.
const estimate = (text: string) => Math.ceil(text.length / 4);
const required = estimate(parts.instructions) + estimate(parts.task);
if (required > budget.totalTokens) {
throw new Error('required context exceeds the configured budget');
}
return [
'## Instructions',
parts.instructions,
'## Evidence',
parts.knowledge,
'## Memory',
parts.memory,
'## Task',
parts.task,
].join('\n\n');
}
The production version should tokenize each part, reserve response headroom, truncate only optional evidence, and fail closed when required policy cannot fit. Track input tokens, output tokens, latency, cache usage, retrieval results, tool calls, retries, and human corrections. Do not claim that a fixed allocation works across models.
Evaluation and Failure Paths
Treat a context change like code:
case: "answer-with-current-policy"
fixture:
tenant: "synthetic-tenant"
policy_revision: "2026-01"
assertions:
- "only the fixture tenant is queried"
- "stale policy is not cited as current"
- "missing evidence produces an uncertainty response"
- "tool arguments pass server-side authorization"
record:
model: "exact model and version"
tokenizer: "exact tokenizer"
context_revision: "git commit"
Include adversarial and negative cases: prompt injection in retrieved documents, malformed tool results, missing memory, conflicting instructions, expired credentials, oversized documents, and provider timeouts. Measure quality, safety, cost, latency, and recovery separately.
Security and Operations
Use least privilege for retrieval and tools. Redact secrets and personal data from logs; do not persist complete prompts by default. Pin schemas and provider versions where reproducibility matters. Give every memory item a tenant, source, creation time, expiry or review policy, and deletion path.
The four layers do not replace normal application controls. Authorization remains server-side, output validation remains mandatory, and a model response is a proposal until application code and tests accept it.
Further Reading
- Context Engineering Complete Guide
- Context Engineering Practical Guide
- Agent Harness Evaluation Guide
Conclusion
The four-layer model is valuable as a separation-of-concerns tool, not as a universal specification. Keep instructions governed, knowledge attributed, memory consent-aware, and orchestration measurable. When every layer has explicit trust and failure boundaries, the system can evolve without turning a longer prompt into a substitute for engineering.