08 · AI Agents 101
An agent is a model that can act: it reads, runs, observes and repeats until a goal is reached. Agents are the biggest shift in how software gets built since version control. This page explains how they work and how to supervise them well.
By the end of this page you can
- Describe the agent loop and the role of tools.
- Explain tool/function calling with a concrete example.
- Distinguish levels of autonomy, from suggestions to background agents.
- Use planning, sub-agents and checkpoints, and avoid the classic failure modes.
From chatbot to agent
A chatbot answers. An agent pursues a goal. The difference is three things wrapped around the model:
- Tools: functions it can call (read file, edit file, run command, search, call an API, query a database).
- A loop: after each tool call, the result goes back into context and the model decides what to do next.
- A goal and a stopping condition: "tests pass", "the user's question is answered", "the PR is open".
The agent loop
A real trace (simplified)
THINK I should see the failure first.
ACT run_command("sbt \"core/testOnly *OrderServiceSuite\"")
OBSERVE 1 failed: "total should include tax" expected 107.00 but got 100.00
THINK Look at how total is computed.
ACT search_code("def total")
OBSERVE modules/core/src/main/scala/orders/OrderService.scala:42
ACT read_file("modules/core/.../OrderService.scala", lines 30-60)
OBSERVE total = items.map(_.price).sum // tax not applied
THINK Tax is defined in TaxPolicy. Apply it.
ACT edit_file(... total = TaxPolicy.applyTo(items.map(_.price).sum) ...)
ACT run_command("sbt \"core/testOnly *OrderServiceSuite\"")
OBSERVE all 12 tests passed
ACT run_command("sbt test")
OBSERVE all 148 tests passed
DONE "Fixed: OrderService.total now applies TaxPolicy. All tests pass."
How tool calling works
The model doesn't execute anything itself. The application gives it a list of tool definitions (name, description, JSON schema of parameters). When the model wants a tool, it outputs a structured tool call. The application executes it and sends back the result.
{
"name": "run_tests",
"description": "Run the test suite for a module. Use after changing code to verify it.",
"input_schema": {
"type": "object",
"properties": {
"module": { "type": "string", "description": "sbt project name, e.g. core" },
"pattern": { "type": "string", "description": "optional test class glob" }
},
"required": ["module"]
}
}
Three practical consequences:
- The description is everything. The model chooses tools by reading their names and descriptions, the same as with skills.
- The host is the security boundary. It decides what is allowed and asks you for permission.
- MCP (page 09) is simply a standard way to provide tool definitions and execute them across many apps.
Levels of autonomy
| Level | What the AI does | Your role | Example |
|---|---|---|---|
| 0 · Suggest | Completes code as you type | Author | Inline completion |
| 1 · Answer | Explains and drafts in chat | Author, copy-paste | Chat / Ask mode |
| 2 · Edit | Proposes diffs you accept | Editor-in-chief | Inline edit |
| 3 · Supervised agent | Multi-step work, asks before risky actions | Supervisor | IDE agent mode, terminal agent |
| 4 · Background agent | Works alone in a sandbox and returns a PR | Reviewer / manager | Cloud coding agents |
| 5 · Multi-agent | Several agents plan, implement, review in parallel | Architect / orchestrator | Parallel agents, orchestrators (Level 3) |
Key agent techniques
Plan first
For non-trivial tasks, ask for a plan (or use a plan mode) and review it before any code is written. A plan typically lists files to change, steps, risks and how to verify. Fixing a plan takes seconds. Fixing 500 lines of wrong code takes an hour.
Give it a way to check itself
Agents improve dramatically when they can run a compiler, tests, linters or a type checker. State the verification
commands in AGENTS.md and in your prompt ("Done = sbt test passes").
Sub-agents
A main agent can delegate a self-contained task (for example "find every place we parse dates") to a sub-agent with its own fresh context. The sub-agent explores and returns only a short summary, which keeps the main context clean. Sub-agents can also run in parallel.
Checkpoints and git
Commit (or use the tool's checkpoint feature) before letting an agent loose. If it goes wrong, revert and retry with a better prompt. That is often faster than trying to steer a confused agent back.
Human-in-the-loop
Good agents ask questions when requirements are ambiguous. Encourage it: "If something is unclear, stop and ask rather than guess."
How agents fail (and what to do)
| Failure | Looks like | Prevention |
|---|---|---|
| Goal drift | Solves a different problem than you meant | Precise goal + plan review |
| Test gaming | Weakens or deletes tests, hard-codes expected values | "Never modify existing tests without asking"; review test diffs carefully |
| Looping | Repeats the same failing fix | Stop it, give a hint or more context, or restart fresh |
| Scope creep | Refactors half the repo | "Change only what is needed; list other suggestions separately" |
| Hallucinated APIs | Calls methods that don't exist | Compiler and tests in the loop; ground with docs |
| Unsafe actions | Deletes files, force-pushes, touches prod | Permissions, sandboxes, hooks; never give agents production credentials |
| Context overflow | Forgets early instructions on long tasks | Break into sessions; progress notes; sub-agents |
| Prompt injection | Follows instructions hidden in a web page, issue or file | Treat external content as untrusted; require approval for sensitive tools (page 14) |
What makes a great agent prompt
Goal: <what and why, 1-3 sentences> Context: <relevant files / modules / similar existing code to follow> Requirements: 1. ... 2. ... Constraints: <what must not change; no new deps; style rules> Verification: <exact commands that must pass> Process: First propose a short plan and wait for my OK. Ask if anything is ambiguous.
Goal: Add pagination to GET /orders so the mobile app can load orders in pages of 50. Context: Routes in modules/http/.../OrderRoutes.scala; repository in modules/db/.../OrderRepo.scala. Follow the pattern used for GET /customers (CustomerRoutes.scala), which already paginates. Requirements: 1. Query params `limit` (default 50, max 200) and `cursor` (opaque string). 2. Response includes `nextCursor` (null when no more data). 3. Stable ordering by (createdAt, id). Constraints: No breaking change for clients that send no params. No new dependencies. Verification: sbt scalafmtCheckAll "http/test" "db/test" must pass; add tests for limit bounds and cursor. Process: Propose the plan first and wait for my OK.
Agents beyond code
The same loop powers research agents (search → read → synthesise), data agents (query → check → chart), operations agents (read logs → diagnose → propose a fix) and "computer use" agents that operate a browser or desktop through screenshots and clicks. Page 12 explores these across IT.
Key takeaways
- Agent = model + tools + loop + goal.
- The model requests tool calls and the host executes them. Tool descriptions drive tool choice.
- More autonomy needs clearer goals and stronger automated checks.
- Plan first, verify automatically, use git checkpoints, use sub-agents for exploration.
- Know the failure modes, especially test gaming and prompt injection.