LLM Agents & Tool Use
Reviewed & published by Brayan K
An LLM agent is a language model that can do things, not just talk. You give it tools (search, code, APIs) and run it in a loop: it reasons about what to do, emits a structured call to a tool, your code runs that tool and returns the result, and the model continues until the task is done. The formula is simple: agent = LLM + tools + a loop.
Part of the free AI & Machine Learning course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll learn function/tool calling, the ReAct (reason + act) loop, planning and multi-step execution, memory, reflection, and the guardrails that keep an agent safe — the same building blocks used by frameworks like LangChain, LlamaIndex, and the native tool APIs from OpenAI and Anthropic.
What You'll Learn in This Lesson
- Why agent = LLM + tools + a loop
- How function/tool calling works (the model emits a call, your code runs it)
- The ReAct loop: reason, act, observe, repeat
- Planning and multi-step execution with tools
- Memory, reflection, and self-correction
- Guardrails, stopping conditions, and frameworks
1 Agent = LLM + tools + a loop
A plain chatbot answers once and stops. An agent can take actions in the world and react to what it sees. The three ingredients:
prompt -> model -> one answer
(no tools, no follow-up actions)Great for a single answer, but it can't look anything up or act on the result.
loop:
reason about the goal
call a tool (search/code/API)
observe the result
stop when the task is doneThe loop is what lets it break a task into steps and adapt as it learns more.
2 Function / tool calling — who runs what
This is the most misunderstood part: the model never runs your code. You describe each tool to the model, and when it wants one, it emits a structured call. Your application executes it and returns the result. The steps:
| Step | Who does it |
|---|---|
| 🧰 Describe tools (name + JSON schema) | You, once, up front. |
| 🧠 Decide to call a tool | The model — it emits a structured call. |
| ⚙️ Run the real function | Your code (the model can't execute anything). |
| 🔁 Return the result | You feed it back into the conversation. |
| ✅ Use the result | The model, on the next step of the loop. |
Tip: a tool's schema (clear name, description, typed arguments) is part of the prompt — well-described tools get called correctly far more often.
3 The ReAct loop — reason, act, observe
ReAct stands for Reason + Act. Instead of answering in one shot, the agent interleaves thinking and doing, then observes and repeats:
- Reason — “To answer this I need today's exchange rate.”
- Act — call the get_rate tool.
- Observe — read the returned rate.
- Repeat — reason again with the new fact, or finish.
"The rate is probably about 1.1"
(no tool, possibly stale or wrong)Thought: I need the live rate.
Action: get_rate("EUR","USD")
Observation: 1.08
Answer: 1.08 (from the live tool)Run this tiny agent. The “model” is faked so you can watch the reason → act → observe loop without an API key:
# An LLM agent is just: a model + tools + a LOOP.
# Here we FAKE the model's decision so you can watch the loop run.
def search(query): # a "tool" the agent can call
return "Paris is the capital of France."
def fake_model(question, observations):
# A real LLM would reason here. We hard-code the decision:
if not observations:
return {"action": "search", "input": question} # ACT: call a tool
return {"action": "final", "input": observations[-1]} # we have enough info
def run_agent(question, max_steps=5):
observations = []
for step in range(max_steps): # the LOOP (stops at max_steps)
decision = fake_model(question, observations) # REASON
if decision["action"] == "final":
return decision["input"]
result = search(decision["input"]) # ACT: run the tool
observations.append(result) # OBSERVE: feed result back
return "Stopped: hit the step limit."
print(run_agent("What is the capital of France?"))
# Output: Paris is the capital of France.And here's what tool calling really looks like — the model emits a structured call, your code runs it:
# WHAT THE MODEL ACTUALLY EMITS for tool calling: a STRUCTURED call.
# The model does NOT run the function — your code does, then returns the result.
import json
# 1) The model outputs something like this (a structured tool call):
tool_call = json.loads('{"tool": "get_weather", "arguments": {"city": "Paris"}}')
# 2) YOUR code looks up the real function and runs it:
def get_weather(city):
return f"It is 21C and sunny in {city}."
tools = {"get_weather": get_weather}
result = tools[tool_call["tool"]](**tool_call["arguments"]) # you execute it
# 3) You hand the result BACK to the model for the next step:
print("tool result:", result)
# Output: tool result: It is 21C and sunny in Paris.# 🎯 YOUR TURN — replace each ___ using the hint beside it.
import ast
import re
def add(a, b):
return a + b
def word_count(text):
return len(text.split())
TOOLS = {"add": add, "word_count": word_count}
SCRIPTED_MODEL = [
'ACTION: add(2, 3)',
'ACTION: word_count("the quick brown fox")',
'FINAL: 5 and 4',
]
def parse(line):
# 1) Anchored at the start: a line that merely mentions ACTION is not one.
m = re.___(r'ACTION: (\w+)\((.*)\)$', line) # 👉 replace ___ with match
if not m:
return None
name = m.group(1)
raw_args = m.group(2)
# 2) literal_eval reads numbers, strings and lists — and NOTHING else.
# eval() here would let the model run any Python it liked.
args = [ast.___(a.strip()) for a in raw_args.split(",")] if raw_args else [] # 👉 replace ___ with literal_eval
return name, args
transcript = []
for step, line in enumerate(SCRIPTED_MODEL, start=1):
parsed = parse(line)
if parsed is None:
print(f"step {step}: model finished ->", line.removeprefix("FINAL: "))
break
name, args = parsed
# 3) An allow-list of tools. Anything else is refused, not attempted.
if name ___ TOOLS: # 👉 replace ___ with not in
print(f"step {step}: refused unknown tool {name}")
continue
# 4) Call the real function with the arguments the model chose.
result = TOOLS[name](___args) # 👉 replace ___ with *
shown = ", ".join(repr(a) for a in args)
print(f"step {step}: {name}({shown}) -> {result}")
# 5) The observation goes back into the transcript — that feedback is
# what makes it an agent rather than a single call.
transcript.___((name, result)) # 👉 replace ___ with append
print("Tools called:", [t[0] for t in transcript])
print("Observations fed back:", [t[1] for t in transcript])
# ✅ Expected output:
# step 1: add(2, 3) -> 5
# step 2: word_count('the quick brown fox') -> 4
# step 3: model finished -> 5 and 4
# Tools called: ['add', 'word_count']
# Observations fed back: [5, 4]4 Memory, reflection, and guardrails
A useful agent needs more than a loop. Three capabilities turn a toy into something dependable:
Memory
• short-term: the running conversation / scratchpad of steps
• long-term: a vector store of past facts and tasks to recall later
Reflection (self-correction)
• the agent critiques its own draft, spots an error, and retries
• "Check your answer against the tool result before finalising."
Guardrails & stopping conditions
• max_steps and a token/dollar budget (no infinite loops)
• an allow-list of tools and arguments (no unsafe actions)
• human confirmation before anything destructiveTogether these give an agent persistence (memory), reliability (reflection), and safety (guardrails) — the difference between a demo and something you'd let run unattended.
📋 The agent loop in pseudocode
tools = { describe each tool: name, purpose, arg schema }
memory = []
for step in range(MAX_STEPS): # stopping condition
decision = model(goal, memory, tools) # REASON (may emit a tool call)
if decision.is_final:
return decision.answer
result = run(decision.tool, decision.args) # ACT (your code runs it)
memory.append(result) # OBSERVE / remember
return "stopped: hit the step limit" # guardrailCommon Agent Mistakes (and the fix)
- Expecting the model to run your code. — It only emits a structured call; your application executes the tool and returns the result.
- No stopping condition. — Always cap steps and budget, or an agent can loop forever and burn tokens.
- Vague tool descriptions. — A clear name, purpose, and typed argument schema dramatically improves correct tool use.
- No guardrails on actions. — Allow-list tools and require confirmation before anything destructive or irreversible.
- Forgetting to feed results back. — The observation must return to the model, or it can't reason about what happened.
- No reflection. — Have the agent verify its own work against tool results before finalising the answer.
⏱ Test Yourself — Timed Quiz
10 quick questions, 12 seconds each. Instant feedback — beat the clock!
🎉 Lesson Complete
- ✅ An agent is an LLM + tools + a loop
- ✅ In tool calling, the model emits a structured call; your code runs it and returns the result
- ✅ The ReAct loop interleaves reason, act, and observe over multiple steps
- ✅ Memory persists context; reflection catches mistakes
- ✅ Guardrails and stopping conditions keep an agent safe and bounded
Practice quiz
What is the simplest way to describe an LLM agent?
- An LLM plus tools plus a loop
- A faster GPU
- A bigger training dataset
- A spreadsheet macro
Answer: An LLM plus tools plus a loop. An agent is an LLM given tools and run in a loop so it can decide, act, observe, and continue until the task is done.
In tool (function) calling, who actually runs the tool?
- Nobody — the call is only logged
- The language model executes the code itself
- Your application code runs it and returns the result to the model
- The user runs it by hand
Answer: Your application code runs it and returns the result to the model. The model only emits a structured request to call a tool; your code executes it and feeds the result back into the conversation.
What does the model emit when it decides to use a tool?
- A random number
- A structured call naming the tool and its arguments
- A compiled binary
- A new model weight
Answer: A structured call naming the tool and its arguments. Tool calling makes the model output a structured object (tool name plus JSON arguments) that your code can parse and execute.
What do the two parts of the ReAct loop stand for?
- Retry and Accept
- Read and Act
- React and Acquire
- Reason and Act
Answer: Reason and Act. ReAct interleaves Reasoning (thinking about what to do) and Acting (calling a tool), then observing the result and repeating.
Why give an agent a loop rather than a single model call?
- So it can act, observe results, and adjust over multiple steps
- Loops are required by HTTP
- To use more tokens for billing
- To slow it down deliberately
Answer: So it can act, observe results, and adjust over multiple steps. Multi-step tasks need the agent to observe each tool result and decide the next action — a loop enables planning and correction.
Which of these is a typical agent tool?
- The training loss
- A web search function
- The model's softmax layer
- The GPU driver
Answer: A web search function. Tools are external capabilities you expose — web search, code execution, database queries, or third-party APIs.
What role does memory play in an agent?
- It speeds up matrix multiplication
- It compresses the model weights
- It replaces the need for tools
- It lets the agent recall earlier steps, facts, or past tasks
Answer: It lets the agent recall earlier steps, facts, or past tasks. Memory (conversation history or a vector store) lets the agent carry context across steps and sessions instead of forgetting.
What is reflection (self-correction) in an agent?
- The agent deletes its tools
- The agent restarts the GPU
- The agent reviews its own output and fixes mistakes before continuing
- The agent copies the user's last message
Answer: The agent reviews its own output and fixes mistakes before continuing. Reflection has the agent critique or verify its own intermediate work, catching errors before they compound.
Why are stopping conditions and guardrails important?
- They make the model larger
- They prevent infinite loops, runaway costs, and unsafe actions
- They improve image quality
- They are only for training
Answer: They prevent infinite loops, runaway costs, and unsafe actions. Without a max-step limit, budget cap, or action allow-list, an agent can loop forever or take harmful actions.
Which of these is a framework commonly used to build agents?
- LangChain
- Photoshop
- PostgreSQL
- FFmpeg
Answer: LangChain. LangChain, LlamaIndex, and the native tool-calling APIs from providers like OpenAI and Anthropic are common ways to build agents.
Continue this course
- Previous: Model Interpretability (SHAP & LIME)
- Next: Handling Imbalanced Data — Precision/recall over accuracy, SMOTE resampling, class weights and threshold tuning
- Quick reference: AI & Machine Learning cheat sheet
Frequently asked questions
What exactly is an LLM agent?
An agent is a language model wired into a loop with tools. Instead of answering once, the model can decide to call a tool (search the web, run code, query an API), your code executes that tool and returns the result, and the model continues — reasoning, acting, and observing — until the task is complete. In short: agent = LLM + tools + a loop.
How does tool (function) calling actually work?
You describe each tool to the model (its name, what it does, and a JSON schema for its arguments). When the model wants to use one, it does NOT run anything itself — it emits a structured call naming the tool and the arguments. Your application code parses that, runs the real function, and passes the result back into the conversation so the model can use it on the next step.
What is the ReAct loop?
ReAct stands for Reason + Act. The agent alternates between reasoning about what to do next and acting by calling a tool, then observes the tool's result and reasons again. This reason-act-observe cycle, repeated in a loop, is what lets an agent break a hard task into steps and adapt as it learns more.
How do I keep an agent from looping forever or doing something unsafe?
Use guardrails and stopping conditions: cap the maximum number of steps, set a token or dollar budget, restrict which tools and arguments are allowed, require confirmation for destructive actions, and validate every tool result. Reflection (having the agent check its own work) and clear success criteria also help it stop at the right time.