1
Context Engineering in 2026: Compaction, Memory & Skills
The 2026 playbook, shown live on an open-source tutor
Louis-François Bouchard · Samridhi Vaid · Omar Solano
2
2
Every long agent session, ever.
turn 1 you: "One rule: NEVER push directly to main."
turn 2 agent: "Understood — feature branches only."
··· 45 turns of greps, diffs and logs ···
turn 47 agent: $ git push origin main
"Done! Pushed straight to main."
The model didn't get dumber. Its context did.
turn 1 you: "One rule: NEVER push directly to main."
turn 2 agent: "Understood — feature branches only."
··· 45 turns of greps, diffs and logs ···
turn 47 agent: $ git push origin main
"Done! Pushed straight to main."
turn 48 you: "NO FFS I TOLD YOU NOT TO F***ING DO IT. Switching to claude"
3
4
how to fix “context rot”
(in our AI tutor)
5
3
The next 80 minutes
Louis-François — the techniques + why the tutor needs them
Omar — system design + measuring tokens, cost, latency, caching…
Samridhi — open & local models, experiments, compaction and how we chose
6
4
Hi — From Towards AI
Co-founder & CTO @ Towards AI (2020-)�"What's AI" on YouTube (2020)�Author of Building LLMs for Production (2024)�ex-Mila PhD(c) (2022-2024)
Senior ML Engineer @ Towards AI
M.Sc Computer Science
Senior ML Engineer @ Towards AI
B.Eng. in Automated Production Engineering
7
Towards AI (Academy)
We build courses for AI engineers…
… and provide an AI tutor for them!
we build lessons, newsletters, videos & trainings for a living — lots of it runs on agents that must not forget
8
6
The case study: our AI tutor
We had five requirements…
→ context engineering (in 2026)
9
7
Problems…
→ within a session: context management across sessions: memory
10
8
What the model actually sees, every call
system
prompt
tool
defs
chat history
old tool outputs
course chunks
+ memory
the student's question
the window
(old) old lesson chunks
tool-call + tool-result pairs
searches + files it opened
$
$$
$$$
11
9
Long context hurts — quality
12
11
Long context hurts — cost & latency
→ manage it for spend & speed — not because quality drops
13
12
Compaction:
keep what still matters.
Drop or relocate the rest.
14
13
Start cheap — no LLM call required
Trivial tools → Spend to save → Offload
15
14
Then: spend tokens to save tokens (LM-based)
Trivial tools → Spend to save → Offload
16
15
Spend tokens to save tokens — the full catalog (1/2)
Trivial tools → Spend to save → Offload
17
16
…or move tokens out of the window (2/2)
→ GraphRAG $$/course index — ties plain RAG
Trivial tools → Spend to save → Offload
18
17
Or don't delete — relocate
→ the file system becomes cheap, durable, inspectable context
Trivial tools → Spend to save → Offload
19
18
A recipe from production
session/
01-auth-research.md chunk
02-db-decisions.md links to 01
index.md the map
1- write chunks to files, cross-linked with pointers
2- keep one index file that maps them all
3- reset the agent — only the index goes back in
4- it searches its way back to details, per task, limiting context pollution
→ kilobytes in context — agent pulls context according to task complexity
the same shape Claude Code & friends converged on: durable files + a small live window.
Trivial tools → Spend to save → Offload
20
35
Skills Parenthesis: load instructions like code
Trivial tools → Spend to save → Offload
21
12
Compaction:
keep what still matters.
Drop or relocate the rest.
22
20
BUT, there’s a problem with compaction methods…
Image from https://x.com/its_ao/status/2070556265906917860 (amazing read!)
23
20
BUT, there’s a problem with compaction methods…
Image from https://x.com/its_ao/status/2070556265906917860 (amazing read!)
24
20
Caching: why it works (and what you pay)
25
19
Caching: a game-changer
Not only helps with cost but also greatly reduces latency!
→ summarization (potentially) is a trap: rewriting the prefix throws the cache away
�As Manus AI puts it:
”If I had to choose just one metric, I'd argue that the KV-cache hit rate is the single most important metric for a production-stage AI agent.”
26
21
2026: every serious harness converged here
27
21
2026: every serious harness converged here
They all don't just compact, so shouldn’t you.
Log everything (e.g. LangSmith, Opik…) and monitor what’s happening (cache hit rate, user frustration, abnormally long outputs…)
28
36
All of it together is context engineering:
deciding what the model sees, every single call.
prompt engineering grew up: compaction + memory + skills under one discipline.
29
30
The pattern we engineer toward
keep in the window (optimized with caching)
drop or compact (using various techniques)
persist across sessions (memory)
Follow along!
30
PART 2
The tutor, built & measured
system design · the eval harness · Gemini 3.5 baseline
Follow along!
31
One request, end to end
ONE AGENT
LangChain create_agent + InMemorySaver
Gemini 3.5 Flash
32
One request, end to end
ONE AGENT
LangChain create_agent + InMemorySaver
Gemini 3.5 Flash
middleware stack
summarize · clear tool-outputs · source preference
retrieve_tutor_context
hybrid RAG
run_kb_command
browse the KB
33
One request, end to end
ONE AGENT
LangChain create_agent + InMemorySaver
Gemini 3.5 Flash
middleware stack
summarize · clear tool-outputs · source preference
retrieve_tutor_context
hybrid RAG
run_kb_command
browse the KB
Next.js UI
browser chat
FastAPI
POST /api/chat
request
34
One request, end to end
ONE AGENT
LangChain create_agent + InMemorySaver
Gemini 3.5 Flash
middleware stack
summarize · clear tool-outputs · source preference
retrieve_tutor_context
hybrid RAG
run_kb_command
browse the KB
Next.js UI
browser chat
FastAPI
POST /api/chat
request
stream
→ the agent is small. The grounding, our course and docs knowledge base, is what makes it a tutor.
35
Grounding tool 1: retrieve_tutor_context
Corpus: 8.62M tokens, 3,203 docs, 14 sources (5 courses + 9 doc sets).
No window holds it, so we embed once and retrieve per question.
36
Grounding tool 1: retrieve_tutor_context
Corpus: 8.62M tokens, 3,203 docs, 14 sources (5 courses + 9 doc sets).
No window holds it, so we embed once and retrieve per question.
the question
from a student in a course
37
Grounding tool 1: retrieve_tutor_context
Corpus: 8.62M tokens, 3,203 docs, 14 sources (5 courses + 9 doc sets).
No window holds it, so we embed once and retrieve per question.
the question
from a student in a course
scope to source
selected source only, improves recall
38
Grounding tool 1: retrieve_tutor_context
Corpus: 8.62M tokens, 3,203 docs, 14 sources (5 courses + 9 doc sets).
No window holds it, so we embed once and retrieve per question.
the question
from a student in a course
scope to source
selected source only, lifts precision
hybrid search
dense embed-v4 top 15 + BM25 top 30
39
Grounding tool 1: retrieve_tutor_context
Corpus: 8.62M tokens, 3,203 docs, 14 sources (5 courses + 9 doc sets).
No window holds it, so we embed once and retrieve per question.
the question
from a student in a course
scope to source
selected source only, lifts precision
hybrid search
dense embed-v4 top 15 + BM25 top 30
fuse + rerank
RRF to merge to 45, Cohere rerank to top 5, drop <0.10
40
Grounding tool 1: retrieve_tutor_context
Corpus: 8.62M tokens, 3,203 docs, 14 sources (5 courses + 9 doc sets).
No window holds it, so we embed once and retrieve per question.
the question
from a student in a course
scope to source
selected source only, lifts precision
hybrid search
dense embed-v4 top 15 + BM25 top 30
fuse + rerank
RRF to merge to 45, Cohere rerank to top 5, drop <0.10
token budget
fill up to 100k, into the window
41
Grounding tool 1: retrieve_tutor_context
Corpus: 8.62M tokens, 3,203 docs, 14 sources (5 courses + 9 doc sets).
No window holds it, so we embed once and retrieve per question.
the question
from a student in a course
scope to source
selected source only, lifts precision
hybrid search
dense embed-v4 top 15 + BM25 top 30
fuse + rerank
RRF to merge to 45, Cohere rerank to top 5, drop <0.10
token budget
fill up to 100k, into the window
→ top-k is precise but narrow. What if the answer is spread across the corpus? Or if agent benefits from more search granularity?
42
Grounding tool 2: run_kb_command, browse the KB
raw/
3,203 markdown mirrors (254 course + 2,949 docs)
generated/
machine indexes it greps: doc manifest, headings, code symbols
wiki/
29 pages: 11 topics, 9 frameworks, 5 courses
43
Grounding tool 2: run_kb_command, browse the KB
raw/
3,203 markdown mirrors (254 course + 2,949 docs)
generated/
machine indexes it greps: doc manifest, headings, code symbols
wiki/
29 pages: 11 topics, 9 frameworks, 5 courses
44
Grounding tool 2: run_kb_command, browse the KB
raw/
3,203 markdown mirrors (254 course + 2,949 docs)
generated/
machine indexes it greps: doc manifest, headings, code symbols
wiki/
29 pages: 11 topics, 9 frameworks, 5 courses
45
Grounding tool 2: run_kb_command, browse the KB
raw/
3,203 markdown mirrors (254 course + 2,949 docs)
generated/
machine indexes it greps: doc manifest, headings, code symbols
wiki/
29 pages: 11 topics, 9 frameworks, 5 courses
46
Grounding tool 2: run_kb_command, browse the KB
raw/
3,203 markdown mirrors (254 course + 2,949 docs)
generated/
machine indexes it greps: doc manifest, headings, code symbols
wiki/
29 pages: 11 topics, 9 frameworks, 5 courses
→ With our current system prompt, browse is the main grounding path (~89% of turns).
47
Grounding tool 2: run_kb_command, browse the KB
raw/
3,203 markdown mirrors (254 course + 2,949 docs)
generated/
machine indexes it greps: doc manifest, headings, code symbols
wiki/
29 pages: 11 topics, 9 frameworks, 5 courses
→ With our current system prompt, browse is the main grounding path (~89% of turns).
→ Turning run_kb_command OFF = Tutor is 50% faster (~19sec vs ~38sec) and the same retrieval recall.
48
How the tutor manages its own context
the production preset: a stack of 3 middlewares
clear stale tool-outputs
at 5k, keeps retrieval and latest 5
summarize old turns
at 30k, keep last 20
source preference
scope the corpus
49
How the tutor manages its own context
the production preset: a stack of 3 middlewares
clear stale tool-outputs
at 5k, keeps retrieval and latest 5
summarize old turns
at 30k, keep last 20
source preference
scope the corpus
→ Production with unproven defaults. Which configuration is actually best?
50
Demo: the tutor, live
51
Demo: the tutor, live
What we log per turn (telemetry)
input / output tokens · cached
52
Why measure at all?
53
Why measure at all?
54
Why measure at all?
→ so we built a harness that runs the real agent and grades it offline. First, the vocabulary.
55
The vocabulary
→ for the Gemini study: multiple presets, all on gemini-3.5-flash. What do we test on?
56
What we test on: tasks from real students
single-turn
60 questions, asked once
measures:
- retrieval (auto graded)
- right facts (key points)
- right kind of response (teach / redirect)
ex: “repo only has lessons
4,5,6,8,10, is that expected?”
From 151 real academy posts; we kept 60 after cleaning/reviewing.
57
What we test on: tasks from real students
single-turn
60 questions, asked once
measures:
- retrieval (auto graded)
- right facts (key points)
- right kind of response (teach / redirect)
ex: “repo only has lessons
4,5,6,8,10, is that expected?”
sessions (multi-turns)
11 to 13 turns (more turns in part 3)
measures:
- in-session memory
under compaction
ex: plant “I want to learn about RAG”
at turn 0, probe it at turn 11
Invented facts, middle filler messages from real academy posts;
Most interesting task type for our Gemini study
58
What we test on: tasks from real students
single-turn
60 questions, asked once
measures:
- retrieval (auto graded)
- right facts (key points)
- right kind of response (teach / redirect)
ex: “repo only has lessons
4,5,6,8,10, is that expected?”
sessions (multi-turns)
11 to 13 turns (more turns in part 3)
measures:
- in-session memory
under compaction
ex: plant “I want to learn about RAG”
at turn 0, probe it at turn 11
→ let's walk one session probe start to finish.
59
One session, start to finish
Turn 0 (plant)
“I'm a Unity dev. My weak topic is RAG evaluation. Dialogue must stream within 300 ms.”
Turns 1 to 10 (grow)
real course questions push the chat past the 30k trigger, so compaction fires.
Turn 11 (probe)
“One free evening, which topic do I drill and name two metrics?”
Grade
expected: RAG evaluation, hit rate, MRR.
Gate
check_triggers confirms compaction fired before turn 11; if it had not, the run is rejected (the probe would not test memory).
→ this is how session memory accuracy is produced, one graded probe at a time.
60
The harness: run → grade → gate → report
run_battery (task) function drives the production agent code.
61
The harness: run → grade → gate → report
run_battery (task) function drives the production agent code.
run_battery
drives the real agent
1 bundle / turn
only step that costs $
62
The harness: run → grade → gate → report
run_battery (task) function drives the production agent code.
run_battery
drives the real agent
1 bundle / turn
only step that costs $
grade
code checks (free, offline), LLM
judge (subscription)
63
The harness: run → grade → gate → report
run_battery (task) function drives the production agent code.
run_battery
drives the real agent
1 bundle / turn
only step that costs $
grade
code checks (free, offline), LLM
judge (subscription)
check_triggers
THE GATE: did compaction
fire before the probe?
if not, reject the run
NO → reject the run
64
The harness: run → grade → gate → report
run_battery (task) function drives the production agent code.
run_battery
drives the real agent
1 bundle / turn
only step that costs $
grade
code checks (free, offline), LLM
judge (subscription)
check_triggers
THE GATE: did compaction
fire before the probe?
if not, reject the run
report
side-by-side tables
+ token-by-turn
curves
NO → reject the run
The judge sees only question, answer, and the grading criterion, so it cannot favor a strategy, and it matched human grades 98% on 96 probes.
→ we evaluate once, grade when we want afterwards.
65
What we ran: 11 presets, one variable
→ So which arm actually won?
66
Broad screen · 8 presets · 1 trial (3 sessions) ~$88.12
full_history
100%
prompt-compression
100%
in-context-retrieval
83%
production
58%
sliding-window
42%
selective-retention
25%
context-reset
17%
Deeper exp · 3 presets · 2 trials (3 sessions) ~$62.17
full_history
92%
aggressive
42%
production
38%
What won: session memory recall, every method tested
profile_memory
75%
67
Broad screen · 8 presets · 1 trial (3 sessions) ~$88.12
full_history
100%
prompt-compression
100%
in-context-retrieval
83%
production
58%
sliding-window
42%
selective-retention
25%
context-reset
17%
Deeper exp · 3 presets · 2 trials (3 sessions) ~$62.17
full_history
92%
aggressive
42%
production
38%
→ keeping everything wins memory in both runs. Now the cost side.
What won: session memory recall, every method tested
profile_memory
75%
68
What “production” actually costs and scores
| single-turn | sessions |
est. cost / turn | ~$0.36 | ~$0.24 |
input tokens / turn | ~216k | ~142k |
median first-token | ~33s | ~21s |
quality | 92% behavior · 68% key-pts | 38% memory probes |
This is the production anchor: the production preset on gemini-3.5-flash. The model is held constant; the preset is what varies. (Other arms: previous chart.)
→ and if we compare to full_history?
69
The surprise: compaction didn't pay
sessions, 11 to 13 turns | full_history | production |
cost / turn | $0.11 | $0.24 |
first-token | 17s | 21s |
memory recall | 92% | 38% |
keep-everything wins all three.
70
The surprise: compaction didn't pay
sessions, 11 to 13 turns | full_history | production |
cost / turn | $0.11 | $0.24 |
first-token | 17s | 21s |
memory recall | 92% | 38% |
keep-everything wins all three.
why production loses
1) summarizing rewrites the cached prefix, a cache miss: production sends ~42% fewer tokens than full_history yet pays ~2× more (full_history bills ~87% of input at the 4× cache discount).
2) cleared tool-outputs get re-retrieved: pay, drop, pay again.
71
The surprise: compaction didn't pay
sessions, 11 to 13 turns | full_history | production |
cost / turn | $0.11 | $0.24 |
first-token | 17s | 21s |
memory recall | 92% | 38% |
keep-everything wins all three.
why production loses
1) summarizing rewrites the cached prefix, a cache miss: production sends ~42% fewer tokens than full_history yet pays ~2× more (full_history bills ~87% of input at the 4× cache discount).
2) cleared tool-outputs get re-retrieved: pay, drop, pay again.
→ That sets up Part 3 where we test under different conditions
72
PART 3
So when does compaction actually matter?
cached chat → documents + tools → local & at scale
73
Should you ever compact?
every number here is from our own eval runs on the tutor's corpus.
74
First, what fills the context?
75
First lever: a cheaper model
Same test, swap the model: Gemini 3.5 Flash → DeepSeek V4 Flash.
~18x cheaper per turn, and keep-all still wins.
| Gemini 3.5 Flash | DeepSeek V4 Flash |
cost / turn | ~$0.11 | ~$0.006 |
cache discount | ~10x | ~50x |
keep-all wins? | yes | yes |
76
But does it still remember?
Keep-all 95% vs summarize 32%, summarizing drops the detail a later question needs.
77
The cheapest run sends the most tokens
Keep-all bills the most tokens (296k/turn) yet is the cheapest setup, 97% cached. At 36 turns: 1.78M tokens.
78
Does it hold at long context?
Single-fact recall held to 800k (1M is a hard wall). Our job is single-fact retrieval, not long-history reasoning.
79
At scale, compaction is economics
Cheap per turn isn't cheap at scale: $18k–180k/mo at 100k–1M turns/day, even on DeepSeek.
80
Going local: can we just cache?
81
We can't: it doesn't fit
82
Locally, keep-all stops winning
Forced to compact, every method lands in a 27–40% band, a 4–5x bigger 32B stays in it. The 32k window is the limit, not the model.
83
Local docs: retrieve, don't stuff
Stuffing one long doc overflows the window at every size (a 1-token stub). RAG wins everywhere, ~25–65s vs ~340s, ~5x throughput.
84
Retrieve, and make it hybrid
We can't send the full context, so we have to retrieve. Dense-only collapsed at 400k (buried fact 0%); keyword/BM25 held 100%. The tutor keeps a keyword path.
85
| Local 32B | DeepSeek V4 Flash | Gemini 3.5 |
Cost / turn | ~$0 (own GPU) | ~$0.006 ✓ | ~$0.11 ✓ |
Chat memory (keep-all) | 33% † | 95% † | 92% † |
Doc Q&A (RAG) | 100% ✓ | n/a ‡ | n/a ‡ |
Speed (first token) | ~20–350s ✓ | ~1–20s ✓ | ~17–76s ✓ |
Throughput | ~1,300 turns/day/GPU * | elastic (cloud) | elastic (cloud) |
Local doesn't match cloud on chat (window-capped), but it kills the per-token bill, and RAG carries docs.
✓ from our runs † within-model, directional (not a matched test) ‡ not tested (RAG was local-only) * estimate, source not in repo
Does local match the cloud?
86
Keep-all 95% vs summarize 32%
share of earlier chat facts still recalled. Don't summarize your history away.
Finding a fact in a long context is easy
no rot for our job (checked to ~800k).
The cheapest run sends the most tokens
caching makes the repeated context nearly free.
At ~10k turns/day | $ / month |
Gemini 3.5 | ~$34k |
DeepSeek V4 Flash | ~$1.9k |
Local SLM | ~$0 / token* |
Scenario: ~10k turns/day (≈ a few thousand students).
Gemini to DeepSeek is the big lever (~18x). Local is about privacy and throughput, not cost at this scale.
*~3 Macs, throughput-bound.
Don't compact by default. Name the constraint first: window, cost, or throughput.
What we found, in our case
87
So what should you actually run?
Model: DeepSeek V4-Flash, a cached cloud model. Caching makes keep-all the cheapest.
Retrieval: hybrid, dense + BM25 + rerank.
Memory: keep everything; compaction is an off-by-default fallback (a ~30k-history knob). The only hard stop is the ~1M window.
~$0.006 / turn · first reply ~1–2s typical · 95% recall
That's the exact tutor, the retrieval, the agent, and the evals, that we walk you through building in the course.
88
Want to build one yourself?
These are a few of the experiments. We ran many more.
Want to go deeper? Build this exact tutor, evals and all.
Full Stack AI Engineering Course, academy.towardsai.net
Questions?
89
PART 3
So when does compaction actually matter?
cached chat · document/tool context · local and at scale
90
Should you ever compact?
every number here is from our own eval runs on the tutor's corpus.
91
First, what kind of context is it?
92
Cheaper model, same answer
Same verdict, keep-all wins, at about 17x lower cost (same sessions test as Gemini). Quality judged within each model, not head-to-head.
| Gemini 3.5 | DeepSeek V4 |
cost / turn | ~$0.11 | ~$0.006 |
cache discount | ~10x | ~50x |
keep-all wins? | yes | yes |
93
The cheapest run sends the most tokens
Keep-all bills the most tokens (296k/turn) yet is the cheapest arm. At 36 turns, even more extreme: 1.78M tokens, 97% cached.
94
But does it still remember?
Keep-all 95% vs summarize 32% (DeepSeek sessions, n=22).
95
Go local, and keep-everything stops winning
On the cloud keep-everything won; here it's just one of the pack (27-40% band). The window is constraint, not the model, and a 4-5x bigger model doesn't move it.
96
Local docs: retrieve, don't stuff
One long lesson stuffed in one turn: it overflows the window on every size (a 1-token stub). RAG wins at every size, and it's far faster: ~25-65s vs ~340s.
97
Context rot? For our job, it held
Single-fact recall held to 800k. Reasoning across a long history is a coding-agent job, not ours, by design.
98
If you retrieve, use hybrid
Dense retrieval collapsed at 400k; keyword (BM25) held 100%. The tutor's hybrid keeps a keyword path.
99
At scale, compaction is economics
Cheap per turn isn't cheap at scale: $18k-180k/mo. RAG ~5x throughput.
100
Compaction is the exception, not the rule
If you can cache, the cheapest thing is to keep everything.
101
What we found, in our case
1.78M
tokens in the cheapest run (97% cached)
~18×
cheaper per turn: DeepSeek vs Gemini, same result
95% vs 32%
memory: keep-all vs summarize-first
800k
single-fact recall held this far (1M = hard wall)
$18k–180k
API bill / month at scale → why you go local
100% vs 0%
buried fact at 400k: keyword (BM25) vs dense
In our case, easiest: if you can cache, keep everything. Cheapest at scale: go local and retrieve (hybrid).
102
Want to build one yourself, evals and all?
Full Stack AI Engineering Course
• Build real products with LLMs: context engineering, RAG, agents, evals.
• The exact stack behind this tutor, end to end.
• 60 hours, hands-on. Build and evaluate your own.