JJoeven

Curriculum/Tools & Function Calling

Why Tools

Weights guess. Tools fetch, compute, and change the world. Agents need both.

beginner20 min1 / 24

A language model predicts the next token. That is the whole trick. It does not know the time, your tickets, whether a refund landed, or what is in ticket 9182. It will still speak as if it does. Fluency is not a database. Confidence is not a side effect.

A tool is a function your code runs because the model asked — or because your workflow asked, without a model in the middle. The model proposes a name and arguments. The runtime validates, dispatches, and logs. The world is the only source of truth. If there is no log line, it did not happen.

This track is about those functions and the runtime around them: schema, dispatch, idempotency, sandboxes, MCP, and permissions your process actually enforces. The agent loop is a client of tools. It does not become a tool by writing a story about one.

Weights freeze at train time. Tools run now. You need both. Weights give you language, ranking, and a guess at which tool to call. Tools give you four things weights cannot:

NeedWeightsTool
Fresh factsFrozen at train timeSearch, SQL, HTTP GET
Side effectsCannot email or payMail, GitHub, refunds
Trusted mathApproximate arithmeticCalculator, interpreter
Private dataNot in the corpusYour CRM, with auth

If the user asks “what is in ticket 9182?”, the honest design is: call get_ticket. The dishonest design is: hope the model memorized Jira. The model may still summarize the ticket after the tool returns. Summarizing is language. Fetching is a tool.

Weights guess. Tools act.
AskToolWorld

Fresh facts and side effects live in functions you run now.

Weights guess. Tools act.

Without tools you have a chatbot

A chatbot continues text. An agent with tools has hands. Hands are not a personality. They are a catalog of functions plus a dispatcher that will not run unknown names.

The split is easy to blur in a demo. You print “I emailed the user” and the audience nods. No mail server ran. The next demo adds “I refunded INV-17.” Still no ledger. Then you ship, and a real refund function exists, and the model has learned that saying the action is the same as doing it. That is the failure this lesson exists to prevent.

Never let the model “execute” by writing a story about having executed. The UI must not show “Refund sent” because the assistant wrote a polite paragraph. Only the dispatcher’s log is truth. Later lessons make that log mechanical. Here you only need the rule: speech is not a side effect.

Tools are also how you stop paying a model to do work a function already knows. If the step is “count open bugs in this dict,” do not prompt. Call tool_sprint. Deterministic work belongs in code. The model should spend tokens on choosing and wording, not on pretending to have a clock.

What a tool is allowed to be

A tool is small and typed. It has a stable name, a schema for arguments, a return blob, and a place in a registry. It is not a 40-page SDK dumped into the prompt. It is not “the internet.” It is not a comment in Figma. If the runtime cannot call it, it is fan fiction. The next lessons name that test. Keep it in your head now: callable or not a tool.

A tool may be a read (observe the world) or a write (change it). Mixing them in one function named sync_customer is how traces lie. Split them. Reads are cheap to retry. Writes are product risk. You will spend a whole lesson on that split. The reason it exists is this one: weights cannot change the world, so every change must go through a named write.

Private data is the quiet reason companies add tools. The corpus does not contain Ada’s invoices. Your CRM does. The tool is the only legal path to that row, and it carries auth. If you paste Ada’s row into the system prompt “so the model knows,” you have turned private data into prompt text and given up the gate. Fetch through the tool. Pass the observation. Cap it.

Trusted math is the other quiet reason. Models are messy calculators. A calculator tool, a code interpreter in a sandbox, or a billing function that uses integer cents — those are tools. Do not ask the model to multiply refunds in its head and then wire money.

Freshness is a contract

“As of” is part of the answer. A closed-book model will tell you the sprint is all green because that sentence was likely in 2023. A tool can return bugs_open: 7 and as_of: 2026-09-21. Put the timestamp in the observation. The model may still ignore it. Your UI should still show it. Humans debug dates. Models do not feel embarrassed about being a year off.

Search, HTTP GET, and SQL are freshness tools. They can also be injection surfaces and cost centers. That does not make them optional. It makes the runtime’s job bigger: validate args, allowlist hosts, truncate results. Those are later lessons. The point now is: if the fact can change, it is not in the weights.

Side effects are the product

Mail, GitHub, refunds, ticket state, calendar invites: these are why someone funded the agent. They are also why someone will page you. A wrong get_job wastes tokens. A wrong refund wastes money. Treat writes as the product, not as a clever extra.

The model does not “have” your Stripe key. It has a string that looks like arguments. If your code does not run, nothing in the world changes. That is good. It is why a demo that prints success with no backend is a lie, and why a production agent that skips the dispatcher is a larger lie.

How the classroom box maps to a real catalog

The live box is a tiny closed world. WEIGHTS is the frozen book. WORLD is the live dict. closed_book answers from training-like memory. tool_sprint reads WORLD. agent is a fake chooser: if the question is about the sprint, it calls the tool; otherwise it stays closed-book. There is no vendor API. There is no loop library. That is the point. The loop, when you build one, is a client of this same idea: choose a name, run a function, use the blob.

Run it. Read the three prints. The closed-book sprint line is stale on purpose. The tool sprint line can be checked against WORLD. The capital of France never needed a tool — weights are allowed to know Paris. Knowing Paris does not mean knowing your bug count.

Change WORLD["bugs_open"] and run again. The tool answer moves. The closed-book answer does not. That is the whole argument for tools, in one dict.

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

What printed: closed-book sprint is the 2023 green sentence. Tool sprint names 7 bugs and today’s date. Capital of France is Paris from weights. WORLD did not change — this tool was a read. If your UI had shown “all green” from the first line, you would have lied about the sprint.

What goes wrong

Teams skip tools because the model “already knows” the handbook. Then finance changes the refund window and the bot keeps quoting the old one. Teams skip tools because HTTP is fussy. Then they paste a CSV into the prompt every morning. Teams add tools and then let the model narrate success without checking the log. Users learn to trust the paragraph. On-call learns the paragraph was fiction.

The other failure is tool as personality. “You have access to the internet” in a system prompt is not a tool. The runtime still cannot browse. You will meet that lesson by name. Do not advertise hands you did not build.

How agents use this

Skip the model when a deterministic function already answers the step. Tools are not only for the LLM — your workflow can call them too. A cron that calls get_ticket is using the same catalog the agent uses. That is a feature: one registry, many clients.

When you design a product, list the questions that must hit a tool: anything fresh, private, numeric-with-money, or world-changing. If that list is empty, you may not need an agent. You may need a FAQ. If the list is long, you need a runtime, not a longer prompt.

Name tools after jobs, not after vendors. get_ticket not jira_magic. The loop should not care which HTTP client sits behind the name. The loop is a client. The tool is the contract.

Note:Later lessons add schema, dispatch, and permissions. None of those replace this rule: if the fact can move, fetch it.

Check your understanding

What do tools add that model weights cannot?