Tokens, Tools, and Goals
Every agent spends three scarce things: context tokens, tool permissions, and a goal you can check with a function.
If you remember one lesson from Getting Started, remember this triad: tokens, tools, and goals.
A token is a chunk of text the model reads or writes. A tool is a function the model is allowed to call. A goal is a checkable “done.” Agents fail when any of the three is vague. They get expensive when tokens grow. They get dangerous when tools are too wide. They get fake when goals cannot be tested.
This triad exists because product language hides it. “Make it smart” does not name a token budget, a permission, or a predicate. A predicate is a function that returns true or false. Your job is to translate “smart” into those three.
People confuse tokens with words, tools with “the model can do anything,” and goals with mission statements. English words are not tokens (code and JSON often use more tokens than you think). A tool is not a superpower; it is an API with a blast radius. “Be helpful” is not a goal.
The triad
| Resource | Scarce because | You design |
|---|---|---|
| Tokens | You pay per input and output; loops resend history | Short tool results, summaries, retrieval, model size |
| Tools | Each call can change the world or leak data | Narrow args, schemas, timeouts, approval |
| Goals | You cannot hit a target you cannot check | A function that returns true on success |
Tokens cost money as the loop grows. Tools can change the world. A goal is a check that returns true or false.
Three scarce thingsTokens
LLMs read and write tokens, not words. English is often about four characters per token, but code and JSON are worse. You pay for input plus output. Agent loops re-send the growing transcript, so a 20-step run can cost many times a single chat.
Implications you will implement later:
- Keep tool results short
- Summarize old steps
- Retrieve only the chunks you need
- Prefer small models for routing and big models for hard reasoning
A 20-step research agent that pastes a full HTML page on every turn is not “thorough.” It is a token hose. The fix is not a larger context window as a first move. The fix is to store a short observation: title, url, 500 characters of text, then retrieve more if the goal still fails.
Tools
A tool is a function the model is allowed to call: search, SQL, shell, browser, ticket API.
Each tool is a loaded gun. A run_sql tool with DROP permission is not clever. It is an incident.
Design tools like public APIs:
- Narrow arguments
- JSON schema
- Timeouts
- Idempotency where you can. Idempotent means doing the action twice has the same effect as doing it once (charging a card twice is not).
- Human approval for irreversible actions
Eight tools with sharp edges beat eighty tools with poetic names. A refund tool that requires ticket_id and amount_cents plus an approval flag is safer than do_whatever(payload).
Goals
A goal that cannot be checked cannot be achieved. “Be helpful” is not a goal. “Return a GitHub issue URL whose body contains a reproducible test” is a goal.
Write goal_satisfied before you write the agent. That is test-driven agent development: the check exists first, the loop tries to make it true, the budget stops the loop if it cannot.
An ops ticket for job docs
Ops asks: “Open or find a GitHub issue that describes how to reproduce the login bug, with a real test function in the body.” That sentence is already almost a predicate.
Check 1: there is a URL that starts with https://. Check 2: the body contains def test_, the usual start of a pytest function. If either fails, the agent is not done, no matter how confident the final sentence sounds.
Walk a good ticket: url https://github.com/x/y/issues/3, body with def test_login. Both checks pass. Walk a bad ticket: empty url, body “please fix.” Both checks fail. The agent should keep working or hand off — not invent a URL in prose.
Product managers will still say “make it smart.” You translate: tokens (do not paste the whole repo), tools (search issues, not rm), goals (goal_satisfied).
Run to execute this in your browser. Nothing is sent to a server.
Four lines of output. The good ticket is True. The empty ticket is False. A https URL without a test is False. A test with http:// (not https://) is also False. The last two prints are the edges: both parts of the and must pass. If you weaken the function to only check the url, the empty-body https case will go green and you will ship a goal that forgot the test. That is how “smart” eats checks.
Note:Product managers will still say “make it smart.” Your job is to translate that into predicates, budgets, and tools.
What goes wrong
- Unbounded tokens. Every tool returns a novel. The window fills. The model attends to noise.
- Counting words as tokens. JSON keys and punctuation cost money too.
- Wide tools. Shell as the only tool. Now the policy includes
rm. - Tools without timeouts. A hung HTTP call is a loop that cannot observe.
- Goals as slogans. “Increase delight.” No function can return true.
- Checking only the model’s last sentence. Cheerful text is not
goal_satisfied. - No budget next to the goal. The check is never true, and the loop never stops.
- Idempotency ignored. The agent retries a refund and doubles it.
Where this goes next
The last Getting Started lesson puts the triad into a tiny agent: a job lookup tool, a finish tool, a fake model, a step budget. LLM and prompt tracks go deeper on tokens and JSON. Tools is the home of schemas, timeouts, and approval. RAG is how you stop pasting the whole wiki into the transcript. Evals turn goal_satisfied into a suite. Production turns token counts into bills and alerts. You do not need those tracks to write a predicate today.
How agents use this
Design in this order: goal function, tool list, token budget. Then the loop.
- Code:
goal_satisfied(state)returns a boolean. Each tool is a small function with typed args. Amax_stepsand, later, amax_tokensinteger live next to the loop, not in a wiki. - Logs: per step, log tokens in, tokens out if the vendor sends them, tool name, and
goal_satisfiedafter the step. When a run is expensive, the log should show which step bloated the context. - Tests: the four cases from the Try it box: good, empty, url-only, test-only. Add a case where a tool result is huge and a trimmer cuts it — when you write that trimmer. Assert forbidden tools are not in the allow-list.
- Stop conditions: success when
goal_satisfiedis true; failure when steps or tokens exceed the cap; handoff when a tool would be irreversible and approval is missing.
The triad is the whole course in three words. The next page is a program that uses all three.
Check your understanding