CS2680 Modern AI Systems: Agents and Systems Optimizations
Lecture 3 — Agents from a user's perspective

Lecture 2 priced a single model invocation. Today we look at the thing that spends those invocations by the hundred: the agent. We take it deliberately from the outside — what it is once the marketing is stripped away, what it feels like to use, what a session costs token by token, and the four distinct ways it fails. Assignment 1 goes out today, and its write-up turns on one skill this class teaches: telling the difference between the model failing and the system around the model failing. By the end you should be able to build a token ledger for a session, price it, and classify any failure you observe with a defensible diagnostic.

Date: Thursday, September 10, 2026 · Assignment 1 goes out today (due Sep 29, 11:59pm)

Readings — both optional.

  • OptionalMemGPT: Towards LLMs as Operating Systems — assigned because it maps the context window onto a memory hierarchy with paging, an analogy that lands immediately if you have taken an OS course. Read the sections that lay out the memory tiers first; the analogy is most of the value, and so is the place it breaks.
  • OptionalRetrieval-Augmented Generation for Knowledge-Intensive NLP Tasks — the paper behind the acronym RAG. Read it to see what retrieval was originally for, and to recognize that what it describes is a caching-and-indexing system.

Where this sits

Lecture 2 built the model and then built the cost model around it: prefill and decode as two phases with different bottlenecks, a bandwidth-bound decode floor, KV-cache sizing, and cost per million tokens as a function of throughput. Today that machinery meets its dominant customer. An agent turns one user request into a long sequence of invocations, and the shape of that sequence — not the model — determines what the session costs and how it fails. The next two classes (Lectures 4 and 5) open the loop and make its design decisions yours; today the loop is a sealed box we observe, measure, and bill.

Instructor notes — Timing plan

75-minute class (Tue/Thu, 11:15am–12:30pm, SEC LL2.221).

TimeSegmentNotes
0–3Framing"You priced a call; today, the thing that makes four hundred of them." Announce Assignment 1 in one sentence; details in §3.9.
3–11§3.1 What an agent isStatelessness is the load-bearing fact. Everything later descends from it.
11–17§3.2 What agents are used forThe taxonomy plus the 0.95^20 = 36% compounding number.
17–29§3.3 The token ledgerCentrepiece. Build the table live, row by row.
29–35§3.4 What it costsPrice the ledger; the 74% re-send share is the punchline.
35–42§3.5 Context is the scarce resourceThe 55% tool-output share, then why a bigger window is not a fix.
42–52§3.6 Retrieval and memoryRAG as caching, MemGPT as paging, and where each analogy breaks.
52–59§3.7 Tools, and why they failThe empty-but-plausible result is the one to dramatize.
59–71§3.8 Evaluation and the failure taxonomyFour case sketches, one diagnostic question each. This is the Assignment 1 payload.
71–75§3.9 Assignment 1Dates, the write-up-over-artifact point, AI policy.

If running long: compress §3.2 to the compounding number and cut one of the four case sketches in §3.8 (drop the specification one — it is the most self-explanatory). Never cut the ledger or the taxonomy; the assignment depends on both.

Learning objectives

By the end of this class you should be able to:

  1. Describe an agent as a control loop around a stateless model, and explain why every apparent memory across turns is a token that some part of the system re-sent.
  2. Construct a token ledger for an n-turn session from stated component sizes, and show that cumulative input tokens grow quadratically in n while output tokens grow linearly.
  3. Price a session at a stated per-million-token rate and compute the fraction of the bill attributable to re-sent, unchanged prefix.
  4. Itemize what occupies a context window mid-session and rank the components by size — and say why a larger window does not remove the constraint.
  5. Design a small defensible evaluation — fixed task set, repeated runs, reported spread — and compute cost per completed task from success rate and per-run cost.
  6. Classify an observed agent failure as a model, harness, tool, or specification failure, and state the diagnostic question that justifies the classification.

3.1 What an agent is, minimally

Strip away the product names and an agent is three parts. A model: a stateless function that maps a context — one long token sequence — to a distribution over the next token, exactly the object Lecture 2 priced. A set of tools: functions outside the model that the surrounding system executes when the model emits a request for them, feeding the result back in as more tokens. And a loop: something that keeps calling the model, executing what it asks for, and decides when to stop. That is the whole architecture. Next Tuesday we write it; today we only need to know it is there.

The one property to internalize is statelessness. The model retains nothing between calls — no weights change, no hidden state persists, nothing is "remembered". If the agent appears to recall the file it read four steps ago, that is because the surrounding system put the file's contents back into the context and paid to have them processed again. Every apparent memory is a re-sent token. This is not an implementation detail; it is the fact from which today's cost arithmetic, the context-window pressure of §3.5, the retrieval and memory systems of §3.6, and half of the failure taxonomy in §3.8 all descend. When an agent "forgets" an instruction, the interesting question is never "why did the model forget" — the model never knew, in the sense of storing anything. The question is whether the token carrying that instruction was in the context of the failing call.

A systems reader has seen this shape before. A stateless worker behind a loop that re-supplies all state on every request is a familiar design — it is how you build things that scale and recover — and it has the familiar cost: the state must move, every time. Here the state is the transcript, moving it means processing it token by token through the model, and Lecture 2 told us what processing tokens costs. The rest of this lecture is that observation made quantitative.

Instructor notes

Minutes: 8. Board: Three boxes — model, tools, loop — with one arrow cycle. Under the model box write "stateless: context in, next token out" and underline stateless. Leave this up; §3.3 and §3.8 both point back at it. Ask the room: "The agent read a file in step 3 and uses its contents in step 9. Where did the contents live in between?" The answer — in the transcript, re-sent and re-processed on every intervening call — is the lecture in one sentence. Expect confusion: Students who have used chat products believe the model has session memory. Say: "The product has memory. The model does not. The product's memory is a system that decides which tokens to send again — and you pay for every one." If short on time: The statelessness paragraph must survive intact; the systems-analogy paragraph can go.

3.2 What people actually use agents for

Coding is the workload that works best, and the reason is structural rather than a fact about models: the environment pushes back. Compilers, type checkers, and test suites give the loop a cheap, fast, mostly reliable verifier, so a wrong step gets caught and the agent gets another try with the error message in context. The demand on the system underneath is long context — repositories are big — and many calls per task. Research and synthesis — read these sources, produce a comparison — works moderately and fails expensively, because the failure mode is confident wrongness with no compiler to object; verification falls entirely on the user, which is where §3.8's evaluation discipline comes from. It demands large context windows and retrieval. Data wrangling — reshape this CSV, reconcile these two exports — works well when the output schema is checkable and poorly when "looks plausible" is the only test. Operational automation — file the ticket, send the email, update the record — is where the least forgiveness lives: tools with side effects, and §3.7 explains why retrying them is dangerous. It demands reliability above all. Multi-step tool workflows — the general case of "do this whole task" — inherit every demand at once: long context, many dependent calls, tool latency on the critical path, and reliability that compounds.

Compounding deserves its own number, because it is the single most under-appreciated fact about agents. Suppose each step of a task succeeds independently with probability 0.95 — a step being one model decision plus one tool execution. Over a 20-step task the chance every step goes right is 0.95^20 ≈ 0.36. A per-step success rate that sounds excellent produces a task that fails two times in three. At 0.99 per step, 0.99^20 ≈ 0.82 — still one failure in five or six. The independence assumption is generous besides: real errors cascade, since a wrong step poisons the context for every later one. This is why "the model is 95% accurate" and "the agent completes the task" are nearly unrelated claims, and why the tasks that work are the ones where a step can be checked and retried before its error compounds.

Instructor notes

Minutes: 6. Board: The five categories in a column, and next to them just one line of arithmetic: 0.95^20 ≈ 0.36. Circle it. Ask the room: "Why does coding work so much better than research synthesis, when the model is the same?" Push past "training data" to "the compiler is a free verifier in the loop; the essay has none." Expect confusion: Students expect agent capability to be a property of the model. The fix: "it is a property of the pair — the task's verifiability matters as much as the model." Common wrong answer: "Make the model 99% and the problem goes away." 0.99^20 ≈ 0.82; it does not.

3.3 Anatomy of a session, token by token

Watch one session as the sequence of API calls it actually is. Call 1: the system sends a system prompt (instructions and persona), the tool schemas (descriptions of the available tools — themselves tokens, processed like any others), and the user's request. The model replies with a tool call. The system executes the tool, appends the result to the transcript, and makes call 2 — which contains everything call 1 contained, plus the model's reply, plus the tool result. Statelessness leaves no choice: the model cannot see what it is not sent, so every call resends the whole transcript so far. Each call therefore does a prefill over an almost entirely repeated prefix, then a short decode. Across the session, the tokens produced grow linearly in the number of turns, and the tokens processed grow quadratically, because turn k re-processes everything turns 1 through k−1 accumulated.

Make it concrete. Take a 10-turn session — a turn being one model call — with round, illustrative sizes: a 1,500-token system prompt plus 500 tokens of tool schemas (a 2,000-token fixed preamble) and a 200-token user request, so call 1 sends 2,200 tokens. Each turn produces a 150-token model reply (a tool call or, on the last turn, an answer), and every turn but the last appends a 500-token tool result, so the transcript grows by 650 tokens between consecutive calls and input at turn k is 2,200 + 650·(k−1). Write n for the number of turns. The table is the argument:

TurnInput tokens this callNew since last callCumulative inputCumulative output
12,2002,2002,200150
22,8506505,050300
33,5006508,550450
44,15065012,700600
54,80065017,500750
65,45065022,950900
76,10065029,0501,050
86,75065035,8001,200
97,40065043,2001,350
108,05065051,2501,500

Reading the ledger

Cumulative input: 10 · 2,200 + 650 · (0 + 1 + … + 9) = 22,000 + 650 · 45 = 51,250 tokens. Tokens produced: 10 · 150 = 1,500 tokens — 34× fewer than were processed. Final transcript (preamble + user + 10 replies + 9 tool results): 2,200 + 1,500 + 4,500 = 8,200 tokens. Ratio of tokens processed to tokens in the final transcript: 51,250 / 8,200 = 6.25×. Distinct input tokens ever sent equal the final call's input, 8,050; everything above that is repetition: 51,250 − 8,050 = 43,200 re-sent tokens, or 84% of all input.

Interpretation: the provider processed the session six times over, and five of every six input tokens were tokens it had already seen.

The general form, for a preamble of P tokens, an initial user message of u, and g tokens appended per turn:

cumulative input over n turns = n · (P + u) + g · n(n−1)/2

Quadratic in n, while output is linear. With our sizes that is 325·n² + 1,875·n, and the quadratic term takes over fast: at n = 20 the total is 325 · 400 + 1,875 · 20 = 167,500 tokens, 3.27× the 10-turn figure for 2× the turns, and the re-sent share rises to (167,500 − 14,550) / 167,500 ≈ 91%. Doubling the session length more than triples what gets processed. The high re-sent share is not an artifact of these particular sizes: Lecture 5 runs the same arithmetic over a leaner session — a 2,000-token preamble growing by 300 a step — and gets 92% over 20 steps.

The redundancy has structure: the repeated tokens form an exact prefix of every call, and exact repeated prefixes are what a cache exploits. That mechanism is prefix caching, the Oct 15 lecture; today's job is only to see the redundancy and measure it, which §3.9 asks you to do in your own logs.

Instructor notes

Minutes: 12. The centrepiece — protect it. Board: Do not project the table. Write the column headers and build rows 1, 2, 3 live, then jump to row 10 and ask the room for the cumulative total before writing it. Then the three derived numbers: 6.25×, 84%, and the n = 20 figure. Box "processed = quadratic, produced = linear". Ask the room: "Turn 10 sends 8,050 tokens. How many of them has the provider never seen before?" Answer: 650. Let that sink in before deriving the 84%. Expect confusion: Students assume the API "keeps the conversation" server-side and only the new message travels. Say: "Some products cache; the model cannot. The transcript is in the request, every request — open your Assignment 1 logs and look." Common wrong answer: "So send only the new tokens." The model attends over the whole context to produce the next token; withhold the transcript and the model has never heard of your task. If short on time: Rows 1, 2, 10 and the three derived numbers; skip the general formula (it returns in the exercises).

3.4 What a session costs

Now price the ledger. Lecture 2 turned throughput and a GPU-hour rate into cost per million tokens; take that result as given rather than rebuilding it. What a user sees is a rate card built on top of it — separate per-million-token rates for input and for output, with output several times dearer. Lecture 2 says why: one quantity governs both phases, tokens processed per pass over the weights, and prefill has thousands of them while decode has one per sequence in the batch. Its sizing example puts a figure on the gap — a 2,000-token prompt costs 58.8 ms of GPU time and the 300-token response 31.6 ms, so 29 µs per prompt token against 105 µs per generated token, a factor of 3.6. Take $3 per million input tokens and $15 per million output tokens — round illustrative figures chosen for arithmetic, not any vendor's price; substitute the rates you are actually charged and the structure of the conclusion survives.

Pricing the 10-turn session

Input: 51,250 tokens × $3 / 1e6 = $0.154 Output: 1,500 tokens × $15 / 1e6 = $0.023 Total ≈ $0.18, of which input is 0.154 / 0.176 ≈ 87% — despite output's 5× higher rate, because 34× more tokens were processed than produced.

Of the input, 43,200 tokens were re-sends of unchanged prefix: 43,200 × $3 / 1e6 = $0.130, which is 0.130 / 0.176 ≈ 74% of the entire bill.

Interpretation: roughly three-quarters of what this session costs is payment for re-reading text the provider has already read.

Eighteen cents sounds like nothing until you multiply. The 20-turn session from §3.3 costs 167,500 × $3/1e6 + 3,000 × $15/1e6 ≈ $0.55 — doubling the turns tripled the bill, because the bill inherits the ledger's quadratic. An agent you run 100 times a day at 20 turns is order $55/day and $1,650 a month at these illustrative rates, for one user and one workflow. Hold on to the 74%. It is what Assignment 3 goes after in October — an agent that stops re-sending unchanged context is attacking three-quarters of its own bill.

Instructor notes

Minutes: 6. Board: The three lines of the worked block, then "74% of the bill = re-reading". Write the $0.18 → $0.55 doubling-of-turns comparison beside it. Ask the room: "Output costs 5× more per token. Why is 87% of the bill input?" Because the token counts differ by 34×; the ledger beats the rate. Expect confusion: Students anchor on output price because it is the bigger number on the pricing page. The fix is the 34× volume ratio. If short on time: State $0.18 and 74% with one line of arithmetic each; drop the monthly extrapolation.

3.5 Context is the scarce resource

What is actually in the window mid-session? End of our 10-turn session, the 8,200-token transcript breaks down: tool outputs 4,500 tokens (55%), fixed preamble 2,000 (24%), the model's own replies 1,500 (18%), the user's request 200 (2%). The user — the only participant with intent — occupies two percent of the context. Tool outputs are usually the surprise, and real sessions are worse than our tidy 500-token illustration: a single file read, a verbose API response, or an unfiltered search result can be thousands of tokens, none of which the model needed and all of which every subsequent call re-processes. When a long session degrades, the first thing to inspect is not the model; it is what has accumulated in the window.

The tempting fix is a bigger window, and models now advertise windows into the hundreds of thousands of tokens. It is not a free fix, for three reasons that are all Lecture 2 wearing different clothes. Cost: every resident token is re-billed on every call — the ledger's quadratic has the window size as its ceiling, so raising the ceiling raises the bill. Latency: time to first token (TTFT) is prefill time, and prefill work grows with context length, so a 100,000-token context makes every turn's think-time longer. Bandwidth: during decode, attention reads the key/value (KV) cache — which grows linearly with context — on every generated token, and Lecture 2 established both that decode is bandwidth-bound and that the KV cache is the capacity that runs out. Take its numbers rather than rebuilding them: the reference 7B costs 512 KiB of cache per token, so a 32,768-token context needs 17.2 GB for a single sequence, and Lecture 2's 62.5 GB of usable KV budget on an 80 GB GPU holds three of them. A long context competes for exactly the resource Lecture 2 showed was binding. There is also a quality observation, honestly labelled as empirical folklore rather than a derived result: models use information at the edges of a long context more reliably than information buried in the middle, so stuffing the window is not even guaranteed to make the answer better.

Something must therefore decide what deserves to be resident — an admission and eviction policy, in the vocabulary you already own. Designing that policy is Lecture 4's job; the rest of today looks at the systems that move information out of the window and fetch it back on demand.

Instructor notes

Minutes: 7. Board: A horizontal bar for the 8,200-token transcript, segmented and labelled with the four percentages. Write "user: 2%" last and pause. Ask the room: "Your agent gets dumber around turn 15. Name the first thing you would look at." Steer toward "print the context and see what is in it" — most rooms say "the model got confused." Expect confusion: "The window is 200k now, so this is solved." Run the three costs: re-billed occupancy, TTFT, KV bandwidth — the constraint moved, it did not vanish. If short on time: Keep the breakdown bar and the cost/latency/bandwidth trio; drop the middle-of-context folklore.

3.6 Retrieval and memory, from the outside

Both of this week's readings are answers to §3.5, and both are systems ideas wearing ML clothing.

Retrieval-augmented generation. RAG (Lewis et al., 2020) established the pattern: instead of hoping the model's weights contain a fact, keep a corpus outside the model, retrieve the passages most relevant to the query — the paper used a dense retriever over a Wikipedia index, fine-tuned jointly with the generator while the document encoder stayed fixed — and place the retrieved text in the context, where the model can condition on it. From the outside, that is the whole idea. It helps when the knowledge is too large, too private, or too fresh to be in the weights; it turns "the model does not know X" from a retraining problem into an indexing problem.

Call it what it is: a caching-and-indexing system. There is a corpus (backing store), an index over embeddings, a top-k lookup (admission of the working set into the window), and a freshness problem. Its failure modes are therefore the failure modes of every such system. The retrieval miss: the answer exists in the corpus but the query embedding lands elsewhere, and the model answers without it — from the outside this looks identical to a model failure, which is exactly why §3.8's diagnostics start from the context, not the model. The stale index: the document changed, the index did not, and the agent confidently cites last quarter's number. The bad chunk boundary: corpora are split into fixed-size chunks before indexing, and a chunk boundary that cuts an answer in half retrieves a passage that says "the limit is" and stops. And the confidently-cited distractor: retrieval returns something topically adjacent but wrong, the model weaves it in, and the citation makes the wrong answer look more trustworthy than an uncited one. A citation proves retrieval happened; it does not prove the retrieved thing was right.

Memory as a hierarchy. MemGPT (Packer et al., 2023) supplies the frame for the rest: treat the context window as main memory — small, fast, expensive per resident token, as §3.5 priced — and external storage as disk: large, slow, cheap. The system pages between them: summaries and salient facts move into the window when relevant, history moves out when not, and the title's OS analogy is earned, since this is virtual memory's move — present the illusion of a larger resource than physically exists by managing movement between tiers.

Be honest about where it breaks, because the break is the interesting part. In an OS, a page fault is raised by hardware: touch an unmapped page and the MMU traps, deterministically, every time. Here there is no fault. Nothing detects that the model needed a page that was not resident — the model itself must decide to fetch, by emitting a tool call, and it decides based on a context that by construction does not contain the thing it would need in order to know the thing is missing. A wrong page-in decision does not trap; it produces a fluent answer composed without the evicted fact, indistinguishable from the outside from a right one. The OS analogy gives you the architecture; it does not give you the fault, and the missing fault is a theme we are about to see again with tools.

Instructor notes

Minutes: 10. Board: Two-tier memory diagram: "context (KB–100s of KB of text, $, fast)" over "store (GB, cheap, slow)", arrows labelled page-in/page-out. Then write "no MMU" beside the up-arrow and let it hang. Ask the room: "In an OS, what happens when a process touches a page that is not resident? And what happens here?" The contrast — deterministic trap versus silent fluent wrongness — is the section. Expect confusion: RAG is perceived as an ML technique requiring ML background. Reframe: corpus, index, top-k lookup, staleness — they have built this before, for bytes instead of facts. Common wrong answer: "The citation means it is grounded." A citation proves a lookup happened, not that the lookup returned the right thing. If short on time: Compress RAG to the definition plus the retrieval-miss failure; the MemGPT no-fault point must survive.

3.7 Tools, and why they fail

From the model's point of view a tool result is just more text. Sit with that: the model does not observe the tool executing, does not see a status code unless someone chose to serialize one, and applies no schema validation on what comes back. Whatever string enters the transcript is the truth the next call conditions on. Every tool failure mode below is a corollary.

Schema mismatch. The model emits a call with arguments the tool does not accept — a misspelled field, a string where a number belongs, a rejected date format. A legible error message is usually survivable, because the model reads it like any other text and reformulates; a stack trace or an empty response is not, which brings us to the worst case.

The silent failure returning a plausible empty result. A search back-end times out and the wrapper returns {"results": []} with a success status. The model cannot distinguish "the search found nothing" from "the search did not run" — the two are the same tokens. So it concludes the thing does not exist and reports that, confidently, with no error anywhere in the transcript. This is the single most damaging tool failure, precisely because it produces no evidence of itself: a bad result is indistinguishable from a good one unless something checks, and by default nothing checks.

Non-idempotent operations retried after a timeout. A tool call to send an email times out. Did it send? The timeout carries no information about whether the side effect happened before or after the deadline, so retrying either recovers from a failure or sends the email twice — the classic distributed-systems ambiguity, landing on agents with full force because retrying is the loop's most natural response to failure. What to do about it is Lecture 4's problem; what to do as a user is to look for it, because a duplicated side effect in a transcript almost always has a timeout just before it.

Latency. Tools run on the wall clock, and in many real agents the tools, not the model, dominate end-to-end time: a session of a dozen model calls at a second or two each can sit for minutes inside a slow API, a test-suite run, or a cold data query. An agent that feels slow is more often waiting than thinking, so measure before blaming the model — Assignment 1's habit, and the subject of Lecture 5's instrumentation section.

Instructor notes

Minutes: 7. Board: Write {"results": []} in large letters. Ask what it means. Collect both readings — "nothing matched" and "nothing ran" — then write "same tokens" under it. Ask the room: "A tool call timed out. Name a tool where retrying is safe, and one where it is not." Read versus send-email; the difference is idempotency, a word Lecture 4 designs around. Expect confusion: Students assume the platform validates tool results the way a type system would. Nothing does; the transcript is untyped text end to end. If short on time: The empty-result failure is the keeper; latency compresses to one sentence.

3.8 Evaluating an agent, and the four ways it fails

You have watched a demo. What do you actually know? Almost nothing, and the point can be made quantitative. Agent runs are stochastic — sampling in the model, timing in the tools — so a single successful run is one draw from a distribution you have not seen. An agent that succeeds 30% of the time hands you a flawless demo nearly one time in three. Even repeated success is weaker evidence than it feels: if the true failure rate is f, the chance of 10 clean runs is (1−f)^10, and setting that to 0.05 gives f = 1 − 0.05^(1/10) ≈ 0.26. Ten consecutive successes are consistent, at 95% confidence, with an agent that fails a quarter of the time.

A defensible small evaluation is not much more work. Fix a task set — even five or ten tasks, written down before you start, so success is judged against a spec rather than against whatever happened. Run each several times. Report four numbers: success rate against the pre-stated criterion; cost per completed task — total spend divided by successes, because failed runs cost money too; wall-clock to first useful output, which is what using the agent feels like; and variance across repeated runs of the same task, because an agent that succeeds differently every time is telling you something a mean hides. Cost per completed task deserves its arithmetic: take ten runs of one task where seven succeed at the §3.4 session cost of ≈$0.18 and three fail — and failures run long, since not-succeeding usually means looping until a budget fires, say to the 20-turn $0.55. Total 7 · 0.18 + 3 · 0.55 = $2.91 over seven completions ≈ $0.42 per completed task, 2.3× the cost of a successful run. The failures dominate the price of the successes.

When a run fails, classify it. Four classes, and the entire skill is asking the diagnostic questions in the right order.

Model failure. Everything the model needed was in the context, correct and intact, and it still did the wrong thing. Hypothetical sketch: the transcript shows the file's contents in context, the real function parse_config plainly visible — and the model calls parse_config_fast, which does not exist. Diagnostic: read the failing call's input. Was everything needed present and correct? Only if yes is the model to blame — which is why this class must be diagnosed last, not first.

Harness failure. The surrounding system fed the model a defective context or mishandled its output. Hypothetical sketch: the user says "keep it under $200" in turn 2; the harness truncates history to fit the window; by turn 14 the constraint is no longer in the context, and the agent books a $340 flight. From the chat surface this is indistinguishable from the model ignoring an instruction. Diagnostic: does the context actually sent at the failing call match what the session should have accumulated? Diff the transcript-as-designed against the transcript-as-sent; a §3.6 retrieval miss belongs here too, since the retriever is part of the harness.

Tool failure. A tool returned wrong, empty, or stale data while claiming success, and the model reasoned correctly from it. Hypothetical sketch: §3.7's timeout — {"results": []} from a search that never ran, and the agent reports the paper does not exist. The model's inference was sound; its premise was manufactured by a wrapper. Diagnostic: replay the tool call by hand, outside the agent. Does the result match reality? If not, stop — do not chase the model.

Specification failure. The system did what was asked; the ask was not what was wanted. Hypothetical sketch: "clean up the data directory" — the agent deletes files the user meant to archive. Every component behaved; the words underdetermined the intent. Diagnostic: would a competent human contractor, given exactly the same words and nothing else, have done what you wanted? If not, no component failed, and no component-level fix will help.

The order matters: check the tool's ground truth, then the context's integrity, then the specification, and only then blame the model — because the first three produce evidence you can point to, and "the model is dumb" is the explanation that requires no work and teaches nothing. Assignment 1's write-up is graded on making exactly these calls with the transcript as evidence.

Instructor notes

Minutes: 12. The Assignment 1 payload — do not squeeze it. Board: A 2×2 of the four classes. Under each, only its diagnostic question, verbatim. Then number them in diagnosis order: tool → harness → spec → model. Ask the room: Run the $340-flight sketch and ask "who failed?" Most will say the model. Then reveal the truncation and ask what evidence would have distinguished the two — the answer, "the actual context at turn 14", is the assignment's method. Expect confusion: "Model failure" is the default attribution for everything. Invert it: model failure is the diagnosis of last resort, reached by eliminating the other three with evidence. Common wrong answer: Classifying the empty-search case as a model failure "because the model believed it." The model reasoned correctly from a false premise; the premise is the failure. If short on time: Drop the specification sketch; keep all four diagnostic questions and the diagnosis order.

3.9 Assignment 1, briefed properly

Assignment 1 — build something with an agent — goes out today, due Sep 29, 11:59pm, worth 10%, individual. The spec is on the assignments page; use an existing agent framework to build something that does real work for you.

Read the emphasis correctly: the artifact is not the point — the write-up is. What is graded is whether you can observe an agent the way this lecture did. Keep the transcripts, because they are the evidence for every claim you make. Record token counts and wall-clock per run, because §3.3 and §3.4 are about your logs now. Note the model, its version, and the date, because these systems change under you and an unreproducible observation is close to no observation.

The most common failure mode of this assignment is not a broken agent. It is a working one: students build something that succeeds, write "it worked", and have nothing to say. The failures are the material. An agent that worked on the third prompt after two instructive failures, with transcripts showing why the first two failed and which class each failure was, is a strong submission; a flawless demo with no analysis is a weak one, and §3.8 told you how little a flawless demo proves. Budget accordingly: run your task repeatedly, not once. AI tools are permitted under the course's two conditions — disclose what you used, take responsibility for what it produced — spelled out on the policy page.

This is the first of three assignments that build on one another, each worth 10% and each individual. Assignment 2 — build an agent — follows in the next class, due Oct 8, 11:59pm, and has you write the loop yourself. Assignment 3 — make your agent 3× cheaper — comes after it, due Oct 20, 11:59pm, and hands your own agent back with instructions to profile it, predict which change will win, and then make it measurably cheaper. All three specs live on the assignments page. The instrumentation habits you start this week are the ones you will still be using in late October.

Instructor notes

Minutes: 4. Board: Three lines: "due Sep 29, 11:59pm · individual · 10%", "keep transcripts, tokens, wall-clock, model+version+date", "the failures are the material". Ask the room: Nothing. Say plainly that a submission with two well-diagnosed failures outscores a flawless demo with no analysis, and that this is a policy, not a mood. If short on time: This section is already minimal; the three board lines are the floor.

Key takeaways

  • An agent is a loop around a stateless model plus tools. The model remembers nothing between calls; every apparent memory is a token the system re-sent, and re-sent tokens are what you pay for.
  • Across an n-turn session, tokens processed grow quadratically while tokens produced grow linearly: the illustrative 10-turn session processes 51,250 input tokens to produce 1,500 — 6.25× the final transcript — and 84% of the input is re-sent prefix. At the illustrative rates, re-sends are 74% of the bill. That redundancy is what prefix caching (Oct 15) exploits.
  • The context window is a scarce resource even when large: tool outputs dominate it (55% in our session, the user 2%), and every resident token costs money on each call, TTFT at prefill, and KV-cache bandwidth at decode.
  • Retrieval is caching-and-indexing and fails like one — misses, staleness, bad chunk boundaries, confident distractors. Memory-as-paging (MemGPT) is virtual memory without the page fault: nothing traps when the needed page is absent; the model just answers without it.
  • Per-step reliability compounds: 0.95 per step is 0.36 over 20 steps. A single successful demo is close to no evidence — ten clean runs still admit a 26% true failure rate — so evaluate on a fixed task set, repeated runs, reported spread, and cost per completed task.
  • Diagnose failures in order — tool, harness, specification, model — using the transcript as evidence. Model failure is the diagnosis of last resort, and making these calls well is the whole of Assignment 1's write-up.

Numbers worth memorizing

QuantityValueSource
10-turn session, tokens processed vs produced51,250 vs 1,500 (34×)ledger, §3.3
Processed-to-final-transcript ratio, 10 turns6.25× (51,250 / 8,200)§3.3
Re-sent share of input tokens84% at 10 turns → 91% at 20§3.3
Cumulative input, our sizes325·n² + 1,875·n (quadratic in turns)§3.3
Session cost at illustrative $3/$15 per Mtok≈$0.18; 74% of it re-sent prefix§3.4
Tool outputs' share of the final transcript55% (user: 2%)§3.5
20-step task success at 0.95 per step0.95^20 ≈ 36%§3.2
What 10 clean runs provetrue failure rate may still be 26% (95% conf.)§3.8

Self-check

  1. A session has a 3,000-token preamble, a 300-token user request, and appends 900 tokens per turn (200 model + 700 tool result). Over 12 turns, cumulative input and the re-sent fraction?Total = 12 · 3,300 + 900 · (0+…+11) = 39,600 + 900 · 66 = 99,000. Distinct = final input = 3,300 + 900 · 11 = 13,200. Re-sent = 85,800 / 99,000 ≈ 87%.
  2. In §3.3's ledger, doubling the turns from 10 to 20 multiplied cumulative input by 3.27. Why more than 2×, and what does the multiplier tend to as n grows?The 325·n² term quadruples when n doubles while the linear term only doubles; as n grows the quadratic dominates and the multiplier tends to per doubling.
  3. Your agent reports "no papers match" — but the paper exists. First diagnostic step, and which failure class do you suspect?Replay the search call by hand outside the agent. If it returns results, suspect a tool failure (a silent empty result); the model reasoned correctly from a manufactured premise.
  4. Why is a 10× larger context window not a 10× fix for the problems of §3.5?Every resident token is re-billed on each call (the quadratic's ceiling rises), prefill and therefore TTFT grow with context, and the KV cache read on every decode step grows linearly — the constraint moves to cost, latency, and bandwidth rather than disappearing.
  5. Eight runs of a task: six succeed at $0.20 each, two fail after burning $0.60 each. Cost per completed task?(6 · 0.20 + 2 · 0.60) / 6 = 2.40 / 6 = $0.40 — double the cost of a successful run, because the failures are amortized over the successes.
  6. An agent books a hotel over the user's stated budget. Give one story per failure class that produces this exact symptom.Model: the budget was in context and it chose a pricier hotel anyway. Harness: truncation evicted the budget before the booking turn. Tool: the search tool returned prices in the wrong currency while claiming success. Specification: the user said "a nice hotel near the venue" and never stated the budget in the session at all.

Exercises

  1. The ledger, symbolically. With preamble P = 2,000, user message u = 200, per-turn growth g = 650, and per-turn output o = 150 (all tokens): (a) write cumulative input C(n) and final transcript length X(n) as functions of the turn count n; (b) find the first turn count at which C(n) exceeds 10 × X(n). Solution sketch: (a) C(n) = 2,200·n + 650·n(n−1)/2 = 325·n² + 1,875·n; X(n) = 2,200 + 150·n + 500·(n−1) = 1,700 + 650·n (check at n = 10: 8,200, the transcript of §3.3). (b) Solve 325·n² + 1,875·n ≥ 17,000 + 6,500·n, i.e. 13·n² − 185·n − 680 ≥ 0 → n ≈ 17.3, so n = 18 (check: C(18) = 139,050 > 10 · 13,400 = 134,000; C(17) = 125,800 < 10 · 12,750 = 127,500).
  2. A summarization policy, priced. Modify §3.3's session: at the end of turn 5, the harness replaces all accumulated dialogue (5 replies + 5 tool results = 3,250 tokens) with a 500-token summary, keeping the preamble and the user request. The summarization itself is a model call that reads the full 5,450-token transcript and writes the 500-token summary. Recompute cumulative input over the 10 turns, the saving versus 51,250, and state the non-monetary risk. Then decide whether the percentage saved keeps rising as the session runs longer. Solution sketch: Turns 1–5 unchanged: 17,500. Turn 6 restarts at 2,000 + 200 + 500 = 2,700, then +650/turn: 2,700 + 3,350 + 4,000 + 4,650 + 5,300 = 20,000. Add the summarizer's 5,450 input → total 42,950, a 16% saving (8,300 tokens). Risk: the summary is lossy — a discarded detail (a numeric constraint, an error message) is a silent context miss. Growth: after the reset each turn submits exactly 2,750 fewer tokens than it would have (5,450 against 2,700 at turn 6, and the gap stays constant), so the absolute saving is 2,750·(n−5) − 5,450 — linear in n against a total that is quadratic. The percentage saved therefore peaks at about 22% near n = 16 and decays afterwards (15% by n = 40). A single compaction shifts the curve down; only repeated compaction changes its shape.
  3. Reliability, compounded and priced. This one needs §3.2 and §3.4 together. A task takes 15 tool-using steps, each succeeding independently with probability 0.96. Assume a completed run costs §3.4's 10-turn price of ≈$0.18 and a failed run loops until its budget fires, at the 20-turn price of ≈$0.55. (a) What fraction of runs complete? (b) What is the cost per completed task if you retry until one succeeds? (c) You can spend engineering effort either raising per-step reliability to 0.98 or halving the cost of a failed run. Which buys more? Solution sketch: (a) 0.96^15 = 0.542 — barely half, from a per-step rate that reads as excellent. (b) Cost per completed task = $0.18 + $0.55 · (1−p)/p = 0.18 + 0.55 · 0.845 ≈ $0.64, 3.6× the price of the successful run itself. (c) At p = 0.98^15 = 0.739 the same formula gives 0.18 + 0.55 · 0.354 ≈ $0.37; halving the failure cost instead gives 0.18 + 0.275 · 0.845 ≈ $0.41. Reliability wins, because it cuts both what each wasted run costs and how many of them you pay for.
  4. Classify and defend. Assign a failure class to each, and name the evidence that would confirm it. (a) An agent asked to refactor a module renames a function everywhere except in one test file it was never shown; the harness's file-listing tool excluded tests/ by default. (b) An agent with the full API documentation in context calls an endpoint with a parameter the documentation does not mention. (c) Asked to "archive old logs", an agent compresses logs from the last week that the on-call engineer still needed. Solution sketch: (a) Tool failure, by §3.8's test: the listing tool returned a filtered view while its contract implied completeness, and the model then reasoned correctly from a false premise. The harness owns the default that did the filtering, which is where the fix lands — but the failing component is the one that lied about its own result. Confirm by replaying the listing by hand and diffing against the real tree; if the listing comes back complete, the classification was wrong and the model is back in scope. (b) Model failure: the correct information was present and intact, and the output contradicts it; confirm by locating the parameter list in the failing call's input. (c) Specification failure: "old" was never defined; a human contractor given the same words could have done the same; confirm that no component deviated from its contract — the fix is in the ask, not the agent.
  5. Redo the ledger under a tool-output cap. The harness now truncates every tool result to 200 tokens (per-turn growth drops to 350). For the 10-turn session, recompute (a) cumulative input, (b) session cost at the illustrative $3/$15 rates, and (c) the tool outputs' share of the final transcript. What did the cap cost, qualitatively? Solution sketch: (a) 10 · 2,200 + 350 · 45 = 37,750 tokens (−26%). (b) 37,750 × 3e−6 + 1,500 × 15e−6 = 0.113 + 0.023 ≈ $0.14, a 23% saving on $0.18. (c) Transcript = 2,200 + 1,500 + 9 · 200 = 5,500; tool share 1,800 / 5,500 ≈ 33%, down from 55%. Cost of the cap: truncation is an eviction — if the needed fact was in the cut 300 tokens, you have converted a billing problem into a harness failure (§3.8), and nothing will report it.

Reading guide

MemGPT — optional, recommended if you have taken an OS course. Read the introduction and the section describing the memory hierarchy and its tiers; the figure showing the analogy between context/external storage and main memory/disk is the one to internalize. Skim the evaluation. Hold this question while reading: in an OS, what triggers a page-in, and what plays that role here? The answer — the model itself, deciding from a context that lacks the very information it would need — is where the analogy breaks, and noticing exactly where an analogy breaks is worth more than the analogy. It returns as a reading for the Nov 10 agent-serving lecture on session state and memory.

RAG — optional. Read the introduction and the model description for the pattern — retrieve passages, condition generation on them, fine-tune the query encoder and the generator together while the document index stays fixed; skip the remaining training details and the benchmark tables. Read it as a systems paper wearing an ML costume: there is a backing store, an index, a top-k lookup, and a staleness problem. Hold this question: which of §3.6's four failure modes does the paper's design anticipate, and which did deployment discover later?

Looking ahead

The next two classes open the box. Lecture 4 (Sep 15) writes the loop, designs the tool interfaces, and turns §3.5's scarcity into an explicit context policy — an admission and eviction problem with a budget — and Assignment 2 goes out. Lecture 5 (Sep 17) turns the same session around and asks what this workload does to the serving system underneath, and how to instrument an agent well enough to find out; that is the bridge into Part II. The ledger's redundancy becomes recoverable machine time on Oct 15, the prefix-cache lecture, and the cache competition is where you write the policy that recovers it — take its dates and rules from that page. Tool latency and stalled sessions return as scheduling problems in the batching lectures (Oct 6, Oct 8), and the whole user-side picture — many dependent calls, shared prefixes, tools on the critical path — gets served properly in five agent-serving classes running Nov 3 through Nov 17. Between now and Sep 29, generate transcripts: Assignment 1 is this lecture, run against something you actually want done.