JJoeven

Curriculum/Getting Started

Your First Tiny Agent

A complete think-act-observe loop: fake model, two tools, a transcript, a step budget, and a final answer for job 17.

beginner22 min8 / 8

This lesson puts the whole Getting Started track into one small program. You will run a file-answering agent with no paid API. A fake model chooses tools from simple rules. The surrounding code is production-shaped: named tools, a transcript, a budget.

A transcript is the ordered list of messages the policy is allowed to see: the user goal, then tool results, then the next decision. The fake model is the policy. Later it becomes an LLM that must return JSON matching a tool name and arguments. The loop does not change.

People confuse this exercise with “a toy, so it does not count.” The toy is the model. The loop, the tools, the budget, and the finish action are the real thing. If you skip them and jump to a vendor SDK, you will still need them, only hidden.

The pieces in this program

PieceIn this boxLater
Goal“What is the status of job 17?”Any checkable question
EnvironmentJOBS dictionaryA real job API
Actionsget_job, finishSearch, SQL, shell, tickets
Policyfake_modelAn LLM call that returns JSON
Memorytranscript listTraces in a database
Budgetmax_stepsMax steps plus max tokens plus spend
A tiny agent with two tools
Thinkget_jobSee resultfinish

A fake model picks the next tool. The loop, the transcript, and the budget are the real product.

A tiny agent with two tools

Goal. Ops wants the status of job 17. Done means a final sentence that used the job record, not a guess.

Environment. Two jobs exist: 17 failed with a vendor timeout, 42 is ok. Unknown ids return an error object.

Actions. get_job reads. finish stops with an answer. There is no third tool yet. That is a feature.

Policy. If the transcript has no tool result yet, call get_job for 17. If it has a result, call finish with a sentence built from status and error.

Memory. Each tool result is appended. The fake model looks at the last tool message. A real model would look at all of them.

Budget. Four steps. If finish never comes, return budget exceeded.

An ops person at 4 p.m.

Priya on-call sees “job 17 failed” in a dashboard with no error string. She should not paste a production key into a chat box. She should run an agent (or a workflow) that is allowed to call get_job and nothing else expensive.

Step 1: policy chooses get_job with job_id 17. Observation: status failed, error timeout talking to vendor. Step 2: policy chooses finish with a sentence that includes both. Stop. Two steps, under budget. If JOBS had no 17, the observation would be an error, and a better policy would finish with “not found” instead of inventing a status. Our fake model is naive: it still formats the error dict. That honesty is useful. You can see the weakness and fix the policy. A giant framework would hide the same weakness in three classes.

Write the stop rule in your head before you run: success is finish; failure is max_steps; there is no human handoff in this tiny version, but you can imagine ask_human as a third tool.

Live PythonOpen full playgroundpython
Output
Run to execute this in your browser. Nothing is sent to a server.

The first printed step is get_job with job_id 17, and the result dict with status failed and the timeout error. The second step is finish with an answer string, and a result dict that has final. Then ANSWER: repeats that sentence: job 17 is failed, timeout talking to vendor. Then a probe of job 99 prints not found — the tool is honest when the environment has no record. The fake model always asks for 17, even if you change the goal string. That is the next weakness to fix (the exercise below).

What you just learned (the whole course in miniature)

  • Goal — a question with a checkable answer
  • Toolsget_job, finish
  • Policyfake_model (later: a real LLM)
  • Transcript — the memory of the loop
  • Budgetmax_steps

When you swap fake_model for an API call that must return JSON matching tool plus args, you have a real agent. The rest of Joeven is how to make that swap reliable: schemas, evals, RAG, planning, multi-agent, and production.

Exercise

Change the fake model so it can answer job 42 as well, by reading the goal string for a number. Then add a third tool list_failed_jobs. Keep max_steps. Do not add a paid API. If you parse no number, finish with a short “missing job id” instead of guessing 17.

Next track: Python, because the quality of your agents will never exceed the quality of your functions.

What goes wrong

  • No finish tool. The loop cannot stop except by blowing the budget. Always give the policy a legal way to end.
  • Guessing job 17 forever. The policy ignores the user’s number. That is our fake model’s bug. Fix it in the exercise.
  • Swallowing not found. The agent writes “all good” after an error dict. Append the error. Then finish with failure text.
  • Budget too high, no goal check. Four steps is small. Four thousand with a paid search tool is a bill.
  • Printing secrets in the answer. Job error strings might contain tokens. Redact in real tools.
  • Calling tools that are not in TOOLS. A real model will try. Your execute line should catch KeyError and return an error result, not crash without a trace.
  • Replacing the loop with a chat SDK and no transcript. You cannot test. You cannot eval. You cannot bill per step.
  • Skipping Python next. This box used functions, dicts, and a for loop. The next track makes those boring and solid.

Where this goes next

Python is next on purpose. Then math, ML, transformers, LLMs. Then prompt, tools, RAG, agents. Then multi-agent, eval, production, projects. This tiny agent is the costume rack empty: no RAG, no swarm, no vendor. Keep it in your head when a framework diagram has twelve boxes. Twelve boxes still need a goal, tools, a transcript, and a budget.

How agents use this

Ship the shape you just ran. Swap the fake model last.

  • Code: TOOLS as a dict of callables. run_agent(goal, max_steps). fake_model isolated so tests can inject a script. Parse job_id with int(...) and handle bad values. Build answer strings with concatenation or str joins, not with silent guesswork.
  • Logs: one print per step with name, args, and result — the classroom already does this. In production, write the same fields to a trace store, plus a run id.
  • Tests: job 17 returns a sentence that contains failed and timeout. Job 99’s tool returns not found. max_steps=1 returns budget exceeded because finish never runs. A decision with a fake tool name does not kill logging.
  • Stop conditions: finish returns the final string; max_steps returns budget exceeded; later, ask_human returns control. Do not stop because the model wrote “done” inside get_job.

You now have the whole Joeven argument in one function: the model is replaceable; the loop is the product.

Check your understanding

In the tiny agent, what is the policy?