1 of 102

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 of 102

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 of 102

3

4 of 102

4

how to fix “context rot”

(in our AI tutor)

5 of 102

5

3

The next 80 minutes

  • Part 1 — Compaction, memory, retrieval, skills…

Louis-François — the techniques + why the tutor needs them

  • Part 2 — The architecture + the eval harness, on Gemini 3.5 Flash

Omar — system design + measuring tokens, cost, latency, caching…

  • Part 3 — How to match the quality at a fraction of the cost

Samridhi — open & local models, experiments, compaction and how we chose

6 of 102

6

4

Hi — From Towards AI

  • Louis-François Bouchard

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)

  • Samridhi Vaid

Senior ML Engineer @ Towards AI

M.Sc Computer Science

  • Omar Solano

Senior ML Engineer @ Towards AI

B.Eng. in Automated Production Engineering

7 of 102

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 of 102

8

6

The case study: our AI tutor

We had five requirements…

  • answers grounded in our content, not general knowledge
  • stay in student's current lesson, not from any course we have
  • hold long help sessions: debugging, follow-ups, “explain that again”
  • handle code, read the student's, generate working examples
  • stream fast, latency is UX for a tutor

context engineering (in 2026)

9 of 102

9

7

Problems…

  • the context window is finite — everything the model sees competes for one attention budget
    • Instructions, retrieved lessons, tool use, code…
  • the model is stateless — every call starts from zero; between sessions, nothing persists

within a session: context management across sessions: memory

10 of 102

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 of 102

11

9

Long context hurts — quality

  • quality degrades as the window fills — models lose the middle: “context rot
  • lost in the middle — recall sags for facts buried deep in the window

12 of 102

12

11

Long context hurts — cost & latency

  • the whole history is re-sent every turn — you re-pay for every token, every turn
  • TTFT (time to first token) climbs with input size — the model reprocesses the entire window each call (latency)

→ manage it for spend & speed — not because quality drops

13 of 102

13

12

Compaction:

keep what still matters.

Drop or relocate the rest.

14 of 102

14

13

Start cheap — no LLM call required

  • Observation truncation (outliers) — cut one huge tool output to head + tail before it enters historywhen: one result is huge but only the input and outcome matter — a student's 300-line stack trace (fires the moment one huge output arrives)
  • Trim / sliding window — drop the oldest turns — or keep the last N, with overlap for continuitywhen: old turns no longer matter — previous, unrelated bugs or questions (continuous)
  • Tool-result clearing (for specific verbatim tools) — swap old outputs for a re-fetchable placeholder, keep the call recordwhen: lots of temporary outputs dominate — stale course-chunk retrievals; the safest first move (fires later, once an output is stale)

Trivial tools → Spend to save → Offload

15 of 102

15

14

Then: spend tokens to save tokens (LM-based)

  • Selective retention — keep constraints, decisions, open tasks; drop exploration & duplicateswhen: you can judge what matters — keep the student's goal & env, drop dead ends
  • Summarizationcontinuously replace old history with a running gist — lossy by designwhen: the gist is enough — what the student already understood, not every word
  • Compaction (summary + reset)collapse the whole history into one fresh summary, then start over from it (e.g. when claude code reaches context limit)careful: spend-to-save can backfire

Trivial tools → Spend to save → Offload

16 of 102

16

15

Spend tokens to save tokens — the full catalog (1/2)

Trivial tools → Spend to save → Offload

17 of 102

17

16

…or move tokens out of the window (2/2)

→ GraphRAG $$/course index — ties plain RAG

Trivial tools → Spend to save → Offload

18 of 102

18

17

Or don't delete — relocate

  • Offload to files / memory — persist details to disk or a memory tool; keep a pointer in context
  • reversible — nothing is lost; retrieval pulls it back in just-in-time
  • Karpathy’s "LLM wiki" — a file tree the agent maintains & re-reads: CLAUDE.md, AGENTS.md, a growing KB
    • + RAG DB!

→ the file system becomes cheap, durable, inspectable context

Trivial tools → Spend to save → Offload

19 of 102

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 of 102

20

35

Skills Parenthesis: load instructions like code

  • more small, focused skills — explain-concept · evaluation · review-my-code — not one giant file
  • progressive disclosure — names/small desc. always visible, bodies load only on use

Trivial tools → Spend to save → Offload

21 of 102

21

12

Compaction:

keep what still matters.

Drop or relocate the rest.

22 of 102

22

20

BUT, there’s a problem with compaction methods…

23 of 102

23

20

BUT, there’s a problem with compaction methods…

24 of 102

24

20

Caching: why it works (and what you pay)

25 of 102

25

19

Caching: a game-changer

  • implicit: automatic, default-on — Gemini 2.5+ (~90% off), DeepSeek ($0.14→$0.0028/M ≈50×)...
  • explicit: you pin it — Anthropic cache_control / Gemini cache: guaranteed, but TTL + storage rent

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 of 102

26

21

2026: every serious harness converged here

  • Claude Code — five mechanisms: microcompact (no LLM) trims tool outputs every turn; near ~95% a 9-section structured summary replaces history; files/skills/plan re-injected afterthe summary is readable & editable — and CLAUDE.md survives compaction
  • Codex — one move, summarize → replace: a local LLM writes a 'handoff summary' (prompt is in the codex-rs repo); for OpenAI models /responses/compact returns an encrypted blob insteadfires pre-turn AND mid-turn — and tries structured session memory first, a full LLM summary only if that's not enough
  • the APIs themselvesAnthropic & OpenAI both ship it server-side: set context_management → a compaction block comes back, old turns dropped, system prompt stays cachedsame model writes the summary — accurate recall matters more than speed or cost

27 of 102

27

21

2026: every serious harness converged here

They all don't just compact, so shouldn’t you.

  • Start fresh sessions when switching tasks.
  • Scope file context narrowly.
  • Disconnect unused tools.
  • Compact.
  • Optimize for cache hits. (Model providers improve their feature set for prompt caching frequently)
  • User a model router based on task complexity.

Log everything (e.g. LangSmith, Opik…) and monitor what’s happening (cache hit rate, user frustration, abnormally long outputs…)

28 of 102

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 of 102

29

30

The pattern we engineer toward

keep in the window (optimized with caching)

  • the student's goal, their environment (current course, lesson, current code setup/repo), decisions made, the current error…

drop or compact (using various techniques)

  • old stack traces → truncate · dead-end attempts → selective retention · chit-chat → trim…

persist across sessions (memory)

  • level & progress · the session's gist…

Follow along!

30 of 102

30

PART 2

The tutor, built & measured

system design · the eval harness · Gemini 3.5 baseline

Follow along!

31 of 102

31

One request, end to end

ONE AGENT

LangChain create_agent + InMemorySaver

Gemini 3.5 Flash

32 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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?

https://arxiv.org/pdf/2605.05242

42 of 102

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 of 102

43

Grounding tool 2: run_kb_command, browse the KB

  • A read-only shell over the corpus: rg, grep, find, ls, sed, head, cat, wc.

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 of 102

44

Grounding tool 2: run_kb_command, browse the KB

  • A read-only shell over the corpus: rg, grep, find, ls, sed, head, cat, wc.
  • Limits: 8-second timeout, output capped at 40,000 chars, max 20 commands/turn, sandboxed to data/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 of 102

45

Grounding tool 2: run_kb_command, browse the KB

  • A read-only shell over the corpus: rg, grep, find, ls, sed, head, cat, wc.
  • Limits: 8-second timeout, output capped at 40,000 chars, max 20 commands/turn, sandboxed to data/kb/.
  • Built offline, read at runtime: an agent maintains the wiki via data/kb/MAINTAINER.md when sources change; the tutor only reads it.

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 of 102

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).

  • A read-only shell over the corpus: rg, grep, find, ls, sed, head, cat, wc.
  • Limits: 8-second timeout, output capped at 40,000 chars, max 20 commands/turn, sandboxed to data/kb/.
  • Built offline, read at runtime: an agent maintains the wiki via data/kb/MAINTAINER.md when sources change; the tutor only reads it.

47 of 102

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.

  • A read-only shell over the corpus: rg, grep, find, ls, sed, head, cat, wc.
  • Limits: 8-second timeout, output capped at 40,000 chars, max 20 commands/turn, sandboxed to data/kb/.
  • Built offline, read at runtime: an agent maintains the wiki via data/kb/MAINTAINER.md when sources change; the tutor only reads it.

48 of 102

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 of 102

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 of 102

50

Demo: the tutor, live

51 of 102

51

Demo: the tutor, live

What we log per turn (telemetry)

input / output tokens · cached

  • estimated $ · time-to-first-token
  • model calls · did compaction fire?

52 of 102

52

Why measure at all?

  • The field's advice is confident, but as we discovered, under modern prompt caching the obvious move can invert.

53 of 102

53

Why measure at all?

  • The field's advice is confident, but as we discovered, under modern prompt caching the obvious move can invert.
  • The space is too big to eyeball: ~many configurations across quality, memory, tokens, cost, latency.

54 of 102

54

Why measure at all?

  • The field's advice is confident, but as we discovered, under modern prompt caching the obvious move can invert.
  • The space is too big to eyeball: ~many configurations across quality, memory, tokens, cost, latency.

so we built a harness that runs the real agent and grades it offline. First, the vocabulary.

55 of 102

55

The vocabulary

→ for the Gemini study: multiple presets, all on gemini-3.5-flash. What do we test on?

  • Preset: a specific setup for the AI tutor we tested, everything else held fixed
  • Task type: one test set for one specific task.
    • We use two in this study: single-turn, sessions
  • run: one preset × one model × one task type
    • E.g. hybrid search x Gemini 3.5 x single-turn
  • bundle: the saved JSON for one turn: answer, tools, sources, tokens, timing, did-compaction-fire.

56 of 102

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 of 102

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 of 102

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 of 102

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 of 102

60

The harness: run → grade → gate → report

run_battery (task) function drives the production agent code.

61 of 102

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 of 102

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 of 102

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 of 102

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 of 102

65

What we ran: 11 presets, one variable

  • 2 reference points: full_history (keep everything in context) and production (the live default).
  • 6 one-change variants: sliding-window, prompt-compression, selective-retention, context-reset, in-context-history-retrieval, profile_memory
  • everything else held fixed: model, prompt, retrieval, sources, dataset. 660 turns, 0 API errors.
  • ~590$ across the whole gemini study (all the batteries)

So which arm actually won?

66 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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.

  • But these are the results in these conditions, with 11 to 13-turn sessions we can’t justify compaction.

That sets up Part 3 where we test under different conditions

72 of 102

72

PART 3

So when does compaction actually matter?

cached chat → documents + tools → local & at scale

73 of 102

73

Should you ever compact?

  • On Gemini 3.5 Flash, keep-everything won
  • But full history on a frontier model is expensive.
  • So when is compaction actually worth it?

every number here is from our own eval runs on the tutor's corpus.

74 of 102

74

First, what fills the context?

  • Long chat history → the one detail that matters gets buried
  • Pasted document → too big to fit the window
  • Big tool output → pages of useless verbatim logs
  • Each type needs a different fix.

75 of 102

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 of 102

76

But does it still remember?

Keep-all 95% vs summarize 32%, summarizing drops the detail a later question needs.

77 of 102

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 of 102

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 of 102

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 of 102

80

Going local: can we just cache?

  • At scale, the bill pushes us to run our own model instead of paying per token.
  • But our own hardware means a small model, only a ~32k context window.
  • The cloud's move was keep-everything plus caching. Can we do that locally?

81 of 102

81

We can't: it doesn't fit

  • No, the context doesn't fit in 32k.
  • Our lessons are already bigger than that, and students paste long logs that blow past it.
  • And if it doesn't fit, there's nothing to cache, so locally we have to compress or retrieve.

82 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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 of 102

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 of 102

89

PART 3

So when does compaction actually matter?

cached chat · document/tool context · local and at scale

90 of 102

90

Should you ever compact?

  • We saw keep-everything win on Gemini, and it cost us $600
  • So: can a cheaper or local model match it?
  • The real question isn't whether to compact, it's : the window, the cost, or the rot.

every number here is from our own eval runs on the tutor's corpus.

91 of 102

91

First, what kind of context is it?

  • Context isn't one thing.
    • A chat history, a document, and a tool output each break for different reasons.
  • A chat history grows every turn; a document or a big tool output can fill the window in one shot.
  • The right method depends on the shape, identify it first.

92 of 102

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 of 102

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 of 102

94

But does it still remember?

Keep-all 95% vs summarize 32% (DeepSeek sessions, n=22).

95 of 102

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 of 102

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 of 102

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 of 102

98

If you retrieve, use hybrid

Dense retrieval collapsed at 400k; keyword (BM25) held 100%. The tutor's hybrid keeps a keyword path.

99 of 102

99

At scale, compaction is economics

Cheap per turn isn't cheap at scale: $18k-180k/mo. RAG ~5x throughput.

100 of 102

100

Compaction is the exception, not the rule

If you can cache, the cheapest thing is to keep everything.

101 of 102

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 of 102

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.