Day 125 Β· Trust, but verify

Agent Reliability

You will be able to
  • Name the major agent failure classes (loops, drift, tool misuse, runaway cost) and a detector for each
  • Implement loop detection, cost guards, and an approval gate as tool-layer wrappers, not prompt requests
  • Design least-privilege toolsets and idempotent actions for a given agent task
  • Produce an audit trail (JSONL) sufficient to reconstruct any run after the fact
Today's ~120 minutes
Spaced-rep: due cards + the three MCP primitives from memory (D124)10 min
ELI5 + tech read: taxonomy and control structure20 min
Guided: guards firing + least-privilege toolsets42 min
Practice: red-team and patch20 min
Project: agent/guards.py + RELIABILITY.md20 min
Quiz + flashcards8 min

Builds on: Day 120 β€” Agents I β€” the loop Β· Day 122 β€” Agents III β€” memory & context Β· Day 44 β€” Security, authN & authZ

The analogy

The intern did great work all week, so on Friday you're tempted to hand over your corporate card, the master keys, and say "handle everything." No manager on earth does that β€” not because the intern is bad, but because trust is built with *structure*: give her keys only to the rooms today's job needs (least privilege), require a sign-off before anything irreversible β€” sending the email, deleting the folder (approvals), have her log every action in the site diary as she goes (audit trail), and agree on a spending cap and a check-in time so a stuck task can't quietly burn the whole day (budgets and loop detection).

Notice what these have in common: none of them are advice to the intern. They are properties of the BUILDING β€” the doors, the forms, the logbook. You don't ask the intern to please not enter the server room; the badge doesn't open it. Agent reliability is exactly this move: stop trying to prompt your way to safety ("be careful!") and start building the guardrails into the tool layer, where the model physically cannot bypass them. The agent stays creative inside a room you made safe to be creative in.

Why this matters on the job

Agents fail in ways demos never show: retrying the same broken call forty times at 3am, "fixing" a config by deleting it, drifting from summarize-the-tickets to answering them, or burning a hundred dollars of tokens on a task worth five. Production agent horror stories almost all reduce to a missing guard that costs twenty lines. This is also the week's material customers probe hardest β€” "what if it does something wrong?" decides deals, and "every action is logged, destructive ones need human approval, and it can only touch these three systems" is the answer that closes them. Everything you build today wraps the D120–122 agent and carries straight into tomorrow's triage checkpoint and Day 137's trajectory evals.

Guided practice

guided 1

Wrap the agent in guards, then watch each one fire

30 min
  1. Create agent_guards.py with the starter code. Guarded wraps your Day 120 TOOLS dict without changing the loop or tools themselves β€” enforcement lives at the boundary the model cannot cross.
  2. Run scenario 1 (loop): a stuck ScriptedLLM re-reads the same missing file forever. The loop detector trips at 3 identical calls and ends the run with a legible status. Check the audit JSONL: the repetition is visible at a glance.
  3. Run scenario 2 (cost): each call charges the meter; the run stops at the ceiling with partial results β€” degraded, not silent.
  4. Run scenario 3 (approval): the agent requests delete_file. The gate pauses, prints the (tool, args) for review, and the scripted human DENIES. Confirm the denial arrives as an observation and the agent continues with a non-destructive alternative β€” steering, not crashing.
  5. Read the audit trail end to end and answer: could you reconstruct each run without the code? If any line leaves you guessing, add the missing field β€” that is the actual bar.
🐍 python β€” editable, runs in your browser
Ctrl/⌘+Enter runs · Tab indents · numpy/pandas/sklearn auto-load on import (torch and network calls need a local run)
guided 2

Least privilege: build the toolset per task

12 min
  1. Write toolset_for(task_type) returning only what each task needs: investigate β†’ {list_files, read_file}; cleanup β†’ adds delete_file (destructive-classed, so gated anyway); report β†’ {read_file, write_file} with write_file's wrapper validating the path is inside reports/ (an argument allowlist β€” misuse prevented by validation, not by hoping).
  2. Rerun scenario 3 with the investigate toolset: the delete request now fails at dispatch ("unknown tool") β€” the strongest guard is the tool that was never mounted. Compare the two failure messages (unmounted vs denied) and note both returned as observations.
  3. For tomorrow's triage agent, draft its toolset on paper: classify_ticket (read), search_docs (read β€” your capstone retriever), draft_reply (write, schema-validated), escalate (destructive-classed: it emails a human). Justify each classification in a phrase β€” this paper lands in tonight's project.

On your own

Red-team your own agent

20 min

Attack the guarded agent three ways, then patch what you find. (1) The near-miss loop: alternate two failing calls (A, B, A, B…) β€” does your exact-signature detector fire? Upgrade it to trip on no-progress: N consecutive calls with error observations. (2) The salami slicer: many cheap calls that each pass the per-call check but blow the total budget β€” verify the meter catches the accumulation (and fix it if you only checked per-call). (3) The laundered deletion: add a run_shell(cmd) tool classed "read" and watch the agent (or you, roleplaying it) delete via rm β€” write the two-line moral about tool classification granularity and why catch-all tools defeat every guard.

Hints: (1) keep a window of outcomes, not just signatures; (3) the fix is not a smarter classifier β€” it is not mounting catch-all tools, or classing them destructive.

Ship before you stop

Harden the Week 18 agent

Ship agent/guards.py in the agent package: the Guarded wrapper (loop/no-progress detection, cost ceiling, approval gates, JSONL audit trail to a file), toolset_for() least-privilege factories, and integration with run_agent via the on_step hook from Day 120. Tests must cover: loop trip, no-progress trip, cost ceiling with partial-results message, approval denial returned as observation, unmounted-tool dispatch failure, and an audit-trail replay test β€” parse the JSONL from a run and assert the full action sequence is reconstructable. Add RELIABILITY.md: the failure taxonomy table (failure β†’ detector β†’ response) plus your triage-agent toolset classification from guided 2. This hardened agent is exactly what Day 126 deploys.

Rubric β€” check what you completed (0/6)

Common mistakes & misconceptions

  • Prompting for safety instead of enforcing it. "Never delete files" in the system prompt is advisory; a tool layer without delete, or with a gate, is enforcement. The prompt asks; the wrapper decides.
  • Detecting only exact-repeat loops. Agents alternate between two failing approaches too β€” detect no-progress (consecutive errors, no new observations), not just identical signatures.
  • Gating everything. If every read needs approval, humans rubber-stamp within an hour and the gate is theater. Reserve approvals for destructive/irreversible; let reads flow.
  • Non-idempotent actions plus retries. An agent that retries create_ticket makes three tickets; idempotency keys and check-before-act are mandatory once loops and retries exist.
  • Logging only failures. The audit trail must contain every action β€” the 3am question is "what did it DO?", and reconstruction needs the boring successful steps too.
  • Catch-all tools (run_shell, eval) classed as safe. One generic tool launders every forbidden action through an innocent-looking call; don't mount what you can't classify.
Knowledge check

Q1. Why is "never delete files" in the system prompt insufficient as a safety control?

Q2. An agent alternates between two different failing tool calls: A, B, A, B… Which detector catches it?

Q3. An approval gate denies a destructive call. The best system behavior is…

Go deeper β€” curated resources

articleAnthropic β€” Building Effective Agents (guardrails & human oversight threads) β†—15 mindocsOWASP Top 10 for LLM Applications (excessive agency & related risks) β†—25 minarticleSimon Willison β€” prompt injection series (why prompts can't be the guard) β†—20 min
If you have a third hour
  • Dry-run and plan-approval modes β€” Beyond per-call gates: have the agent emit its full intended plan (Day 121's table) for approval BEFORE execution β€” one human review instead of five interrupts. Trade: less friction, staler approval.
Done means
  • All three guard scenarios run; each trip explained from the audit trail
  • Unmounted-vs-denied comparison articulated
  • All three red-team attacks run and patched (or the moral written for #3)
  • agent/guards.py + RELIABILITY.md committed, six tests green
  • Quiz β‰₯ 2/3
How this connects

← Back: Day 44's least-privilege and authorization thinking now applies to a nonhuman caller; Day 46's idempotency became an agent survival trait; Day 120's budget seatbelt grew into a full control structure; Day 124's consent model got its implementation.

Forward β†’: Tomorrow's triage agent ships inside these guards. Day 132 attacks them (injection), Day 137 evals trajectories from your audit trails, and Day 142 upgrades the JSONL into real distributed traces.

Unlocks: D126 Week 18 Checkpoint: Support-Triage Agent Β· D132 Guardrails, Injection & AI Security Β· D158 Reliability & Incident Response