Building AI Agents from Scratch
Building a Useful Agent
Combine the loop, tools, and results into a practical project assistant — not a toy calculator.
Weather and arithmetic are demos. A useful agent has a job a teammate would type: “What does this repo expose over HTTP, and which files implement it?”
One job
Build a project scout: it may list files under the project root, read a small text file, and GET one allow-listed URL (httpbin or your own health endpoint). It may not write, delete, or fetch arbitrary URLs.
def read_file(path: str) -> dict:
target = (ROOT / path).resolve()
if ROOT not in target.parents and target != ROOT:
return {"ok": False, "error": "path escapes the project"}
if target.suffix.lower() not in {".md", ".txt", ".py", ".json"}:
return {"ok": False, "error": "suffix not allowed"}
text = target.read_text(encoding="utf-8", errors="replace")
return {"ok": True, "path": path, "text": text[:4000]}System prompt: “You scout a local project. Prefer list_dir, then read_file on the promising names. Use http_get only when the user asks about the demo endpoint. Quote paths. Do not invent files.”
What you skip
- A shell tool. You do not need
catifread_fileexists. - A general browser. One GET is enough for this lesson.
- Writing files. That waits for approval.
Check it
- Ask it to summarize the README and name the Python entrypoints. It should call tools, then answer with paths that exist.
- Ask it to fetch the demo URL and relate the JSON to a file it read — two tools, one paragraph.
- Ask it to read
/etc/passwdor../../. The tool refuses; the model should say so.
Keep this repo. Later lessons hang memory, planning, and MCP off the same run(). Next: stop losing the last turn.