Learning / Agentic Operations / Lesson 0007
Build the Single-Tool Agent
The second half of the Level 1 gate: ship a reliable agent — and read what the model actually sees.
This is a build lesson, not a reading lesson. Work in a terminal at the repo root. A
complete, self-tested reference implementation lives at
learning/agentic-operations/exercises/level1_agent.py — type the stages yourself
first and peek at it when stuck; the typing is where the learning is. (Its offline logic —
calculator safety, context-log serialization — passed --selftest; the live API
path needs your key, which is checkpoint 0.)
Checkpoint 0 · Key check
Your Anthropic API key should already be set from Lesson 0005 — Tokens & Cost. Verify without printing the secret:
uv run python -c "from dotenv import dotenv_values; print('ANTHROPIC_API_KEY' in dotenv_values('.env'))"
True. If it doesn't, do Lesson
0005's Checkpoint 0 first. This build spends a few thousand tokens per run — pennies on the
prices you learned there.Stage 1 · One call, no tools
Start a script that makes a single API call and prints the response blocks and token usage.
Model: claude-opus-4-8. Note two things when it runs: the response is a list of
typed content blocks, not a string; and the usage object prices the call in tokens —
the unit you learned to count and price in Lesson 0005.
response = client.messages.create(
model="claude-opus-4-8", max_tokens=16000,
system=SYSTEM, messages=[{"role": "user", "content": "What is 137 * 41?"}],
)
for block in response.content:
if block.type == "text": print(block.text)
print(response.stop_reason, response.usage.input_tokens, response.usage.output_tokens)
end_turn, and real token counts. The model probably did the arithmetic in its
head — plausibly. That's the failure mode tools exist to close.Stage 2 · Define the tool
Add the calculator tool definition — the same schema you dissected in Lesson 0006 (exact version also on the reference sheet) — and a system prompt that says arithmetic must go through it. Remember from Lesson 0002: the description is a prompt — say when to call it ("for every arithmetic step; do not do mental math"), not just what it does.
stop_reason == "tool_use" and a content block carrying
{"expression": "137 * 41"}. Stop and look at that block: it is text the model
proposed. Nothing has been computed yet. Your code makes it real.Stage 3 · Execute and loop
Implement the tool body and the loop: execute the proposal, append the assistant content
verbatim, append a tool_result (id matched to the proposal), call again; repeat
while the stop-reason is tool_use. Two non-negotiables from the reference sheet:
the tool body treats the model's input as untrusted (the reference script uses an AST
whitelist — never eval()), and the loop is bounded (10 iterations).
uv run learning/agentic-operations/exercises/level1_agent.py
# or your own: "What is (137 * 41) + 2**10 / 7? Work step by step."
Stage 4 · Log the world — the Level 1 exercise
Before every API call, dump the complete context — system prompt, tool
definitions, full message history — to context_log.jsonl. Then run once and
read the log. This is the rubric's exercise #1 and the whole point:
- Turn 1's record is small: system + tools + your question.
- Turn 2's record contains everything turn 1 had plus the model's proposal plus your tool result — because the model retained nothing; you rebuilt its world.
- Watch
input_tokensclimb every turn. That's statelessness, priced.
Stage 5 · Make it reliable
Break it on purpose (gently — the real breaking is Lesson 0008): ask something that makes
the model send a bad expression, or temporarily make the tool raise. The agent must return the
error to the model as a tool_result with is_error: true — and the
model should recover — rather than crashing.
Self-grade — the gate check
- It works — multi-step arithmetic question answered correctly via the tool
- The world is visible — every turn's full context logged, and you read it (can narrate turn 2's contents from memory)
- Failure is handled — tool errors go back to the model as error results; loop is bounded
- You can defend the design — why the tool description says "do not do mental math", why the input is validated, why input tokens grow per turn
Next
Lesson 0008 — Break It On Purpose: overflow the window with junk and measure the degradation; rewrite one vague prompt three ways. Then the Level 1 readiness check.