VITON13School

Generative AI for BeginnersLesson 18 of 21

AI agents: loops, tools and guardrails

A chatbot answers one message; an agent works towards a goal over several steps, choosing tools as it goes. That freedom is useful and risky in equal measure. In this lesson you write a small agent loop by hand, so Study Buddy can look things up and build a study plan on its own, within limits you set.

Course by , Founder of VITON13 SCHOOL
  • Part 4: Go further
  • 50 min

You will be able to

  • Name the four parts of an agent: goal, loop, tools and memory
  • Write a minimal agent loop with the chat completions API and a step limit
  • Keep state between steps and across sessions
  • Add guardrails that limit steps, spending and side effects
  • Decide when a plain workflow is better than an agent

What makes an agent

Definitions vary, but a practical one has four parts. A goal says what done looks like. A loop lets the model act more than once. Tools let it read or change things outside its own text. Memory keeps what happened in earlier steps so the next decision builds on them.

The key difference from the function calling in lesson 12 is who decides the sequence. In a workflow, your code fixes the steps: retrieve, then generate, then format. In an agent, the model chooses the next step each turn, including which tool to call and when to stop.

That choice is the source of both the power and the trouble. An agent can handle a request you never planned for, and it can also wander, repeat itself or call a tool you did not expect.

The agent loop

Under every agent framework sits the same small loop. You can write it in about twenty lines, and doing so once makes every framework easier to understand.

The model never runs anything itself. It only asks, and your code decides whether and how to carry out the request. That is where every guardrail lives.

A single reply can contain several tool calls at once, for example two note searches with different keywords. Run each one, answer every call with a tool message carrying its matching tool_call_id, and only then call the model again; most APIs reject a conversation where a call was left unanswered.

When a tool fails, do not crash the loop. Send the error back as the tool result in plain words, such as a missing file or an empty search, and let the model try another route or explain the problem to the learner.

  • Send the goal, the conversation so far and the tool definitions to the model.
  • If the reply contains tool calls, validate the arguments, run each tool and append the results as tool messages.
  • Send the longer conversation back and let the model decide the next move.
  • Stop when the model replies with plain text and no tool calls, or when a limit is reached.

Memory and state

Short-term memory is simply the message list. Every tool call and result is appended, so the model can see what it already tried. On long tasks this list grows fast, so summarise older steps or drop raw tool output once it has been used.

Long-term memory lives outside the model, in files or a database. For Study Buddy that means the learner's notes, found through the retrieval from lesson 16, and a study plan saved as JSON that the agent reads at the start and updates through a tool.

Keep important state in structured data your code controls, not only in the conversation. A plan stored as a list of days with topics can be validated, shown in the interface and edited by the learner; a plan hidden inside a long chat cannot.

At the start of each session, load the saved plan and put a short summary of it into the system prompt. The agent then knows what the learner covered yesterday without replaying a whole conversation.

Guardrails

Agents fail in predictable ways: endless loops, the same tool called with the same arguments, costs that climb quietly and actions nobody approved. Each guardrail below answers one of these.

Tool results deserve the same suspicion as user input. A web page or a shared note can contain instructions aimed at the model, and an agent that obeys them can misuse every tool you gave it, as lesson 14 showed.

Keep a person in the loop wherever a mistake would be costly. The agent can draft the study plan freely, but saving over an existing plan should wait for the learner to accept the change.

  • Cap the number of steps, the total tokens and the wall-clock time for each task.
  • Expose only the tools the task needs, and make them read-only unless writing is the point.
  • Validate every argument against its schema and an allow-list before running anything.
  • Ask the user to confirm actions that send, delete, buy or publish.
  • Log each step with the tool name, arguments and result so you can replay what happened.
  • Return clear error messages from tools, so the model can recover instead of guessing.

When not to use an agent

If you can write the steps down in advance, write them in code. A fixed workflow is faster, cheaper, easier to test and fails in ways you can predict. Study Buddy's quiz feature, for instance, needs one retrieval and one model call, not an agent.

Agents earn their place when the path depends on what the model finds along the way: researching a topic across several notes, or planning a study week around the gaps a quiz revealed. Even then, start with one agent and two or three tools before trying several agents that talk to each other.

Speed matters too. Every loop turn is another model call, so an agent that needs four steps makes the learner wait four times as long as a single answer would. Where waiting is acceptable, show the steps as they happen so the delay feels like progress.

Frameworks such as LangGraph, AutoGen, Microsoft Agent Framework and the OpenAI Agents SDK add state handling, tracing and multi-agent patterns. They are worth a look once your hand-written loop works and you know exactly what you need from them. For connecting tools, the Model Context Protocol from lesson 12 lets one tool server work with many agents and apps.

Example

A minimal agent loop with one tool and a step limit

import json, osfrom openai import OpenAI client = OpenAI(base_url=os.environ["LLM_BASE_URL"], api_key=os.environ["LLM_API_KEY"])NOTES = {"photosynthesis": "Plants use light, water and carbon dioxide to make glucose and release oxygen."} def search_notes(query: str) -> str:    hits = [text for key, text in NOTES.items() if key in query.lower()]    return "\n".join(hits) or "No matching notes." TOOLS = [{"type": "function", "function": {"name": "search_notes",    "description": "Search the learner's notes by topic keyword.",    "parameters": {"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]}}}]messages = [{"role": "system", "content": "You are Study Buddy. Check the notes with tools before you answer."},            {"role": "user", "content": "Ask me two quiz questions about photosynthesis from my notes."}] for step in range(5):  # hard limit on loop turns    msg = client.chat.completions.create(model=os.environ["LLM_MODEL"], messages=messages, tools=TOOLS).choices[0].message    messages.append(msg.model_dump(exclude_none=True))    if not msg.tool_calls:        print(msg.content)        break    for call in msg.tool_calls:        args = json.loads(call.function.arguments or "{}")        result = search_notes(str(args.get("query", ""))) if call.function.name == "search_notes" else "Unknown tool."        print(f"step {step}: {call.function.name}({args})")        messages.append({"role": "tool", "tool_call_id": call.id, "content": result})else:    print("Stopped: step limit reached without a final answer.")

Your model must support tool calling, which most current hosted models and many local ones do. The for ... else branch runs only when the loop ends without a final answer, which is exactly when the step limit kicked in.

Practice

Let Study Buddy build a study plan

  1. Save the example as agent.py, run it and read the printed steps to see the tool call before the final answer.
  2. Add a second tool, save_plan, that takes a list of objects with day and topic and writes them to study_plan.json after checking there are at most seven entries.
  3. Change the user message to ask for a five-day plan for a topic in your notes and run the agent again.
  4. Give the agent an impossible goal, such as a plan built from notes that do not exist, and confirm it stops at the step limit or says it cannot do it.
  5. Add a running token total from each response's usage field and stop the loop when it passes a budget you choose.

Done when: A study_plan.json file with five days appears, the printed log shows every tool call, and the impossible task ends with a clear message instead of an endless loop.

Common mistakes

  • Running an agent without a step or budget limit, so one confused task keeps calling the model.
  • Giving the agent write or send tools it does not need for the job at hand.
  • Using an agent for a task with fixed steps, which adds cost and unpredictability for no gain.
  • Trusting text returned by a tool as if it were an instruction from the user or the developer.

Check yourself

Pick an answer to see whether it is right and why.

What separates an agent from a fixed workflow that also calls a model?

Right.In a workflow your code fixes the order of steps, while an agent lets the model decide the sequence as the task unfolds.

Not quite.The right answer is “The model chooses the next step and the tools to use at each turn”. In a workflow your code fixes the order of steps, while an agent lets the model decide the sequence as the task unfolds.

Why does the example limit the loop to five turns?

Right.A step limit is the simplest guardrail against loops and runaway costs, and it guarantees the program ends.

Not quite.The right answer is “Without a cap, a confused agent could keep calling the model and spending tokens”. A step limit is the simplest guardrail against loops and runaway costs, and it guarantees the program ends.

Study Buddy needs to retrieve notes and then write a quiz, always in that order. What should you build?

Right.When the steps are known in advance, fixed code is cheaper, faster and easier to test than letting a model decide.

Not quite.The right answer is “A plain two-step workflow in code”. When the steps are known in advance, fixed code is cheaper, faster and easier to test than letting a model decide.

From the founder

Write the loop by hand before you try any agent framework, and keep the step limit in place while you experiment. Read the printed steps after every run until you can predict what the agent will do next.
Vitalii Tarasov, Founder of VITON13 SCHOOL

Course by Vitalii Tarasov, VITON13 SCHOOL. Draws in part on Microsoft's Generative AI for Beginners, MIT licence, Copyright (c) Microsoft Corporation. microsoft/generative-ai-for-beginners