Foundations stopped at generating text. Today we cross the line into acting. The bridge is tool calling — the model decides a function should be called, you execute it, and the result goes back to the model.
Why not just ask the model directly? It already knows that 7 plus 8 is 15.
It often gets simple math right by pattern-matching. It also confidently says 7 + 8 = 17 and moves on. The defense isn't a better prompt — it's giving the model a real adder it can delegate to. The LLM picks the operation; Python computes it.
# Without tools — model writes the answer from training pattern
result = Agent(model).run_sync("What is 7 plus 8?")
print(result.output)
# → "15" (probably, but the model could be wrong)# With tools — model picks the tool; Python guarantees the math
from pydantic_ai import Agent
agent = Agent(model)
@agent.tool_plain
def add(a: int, b: int) -> int:
"""Return the sum of two integers."""
return a + b
result = agent.run_sync("What is 7 plus 8?")
print(result.output)
# → "15" — guaranteed by Python, not generated by the modelSo add is plain Python. The model just decides when to call it.
Right. The model reads the prompt, sees a registered tool whose docstring matches the request, and produces a structured tool-call request instead of free text. Pydantic-AI executes the function, hands the result back, and the model finishes its answer using the tool's output. Today's exercise: print one number from each version so you can compare.
The LLM is a great language model. It's a mediocre calculator, a worse calendar, a non-existent database. Tools let it delegate the things it's bad at to code that's good at them.
User: "What is 7 plus 8?"
↓
LLM: "I should call add(7, 8)"
↓
Python: add(7, 8) → 15
↓
LLM: "The answer is 15."
↓
User sees: "The answer is 15."
The LLM never generates the digit "15". Python does. The LLM just picks the right tool with the right arguments.
| Without tools | With tools |
|---|---|
| Model produces every token | Model produces text or a tool-call signal |
| Math/lookups depend on training | Math/lookups handled by deterministic code |
| Hard to verify correctness | Tool's output IS the truth |
| One round trip | Possibly multiple round trips per answer |
@agent.tool_plain (or pass tools=[...] at construction).agent.run_sync(prompt). Pydantic-AI handles the dispatch.The rest of week 1 unpacks each of those. Today you just see the difference.
The practice is pure Python. No LLM call. Print two strings — what the world looks like with and without tools — to internalise the shift before we wire up real calls tomorrow.
Foundations stopped at generating text. Today we cross the line into acting. The bridge is tool calling — the model decides a function should be called, you execute it, and the result goes back to the model.
Why not just ask the model directly? It already knows that 7 plus 8 is 15.
It often gets simple math right by pattern-matching. It also confidently says 7 + 8 = 17 and moves on. The defense isn't a better prompt — it's giving the model a real adder it can delegate to. The LLM picks the operation; Python computes it.
# Without tools — model writes the answer from training pattern
result = Agent(model).run_sync("What is 7 plus 8?")
print(result.output)
# → "15" (probably, but the model could be wrong)# With tools — model picks the tool; Python guarantees the math
from pydantic_ai import Agent
agent = Agent(model)
@agent.tool_plain
def add(a: int, b: int) -> int:
"""Return the sum of two integers."""
return a + b
result = agent.run_sync("What is 7 plus 8?")
print(result.output)
# → "15" — guaranteed by Python, not generated by the modelSo add is plain Python. The model just decides when to call it.
Right. The model reads the prompt, sees a registered tool whose docstring matches the request, and produces a structured tool-call request instead of free text. Pydantic-AI executes the function, hands the result back, and the model finishes its answer using the tool's output. Today's exercise: print one number from each version so you can compare.
The LLM is a great language model. It's a mediocre calculator, a worse calendar, a non-existent database. Tools let it delegate the things it's bad at to code that's good at them.
User: "What is 7 plus 8?"
↓
LLM: "I should call add(7, 8)"
↓
Python: add(7, 8) → 15
↓
LLM: "The answer is 15."
↓
User sees: "The answer is 15."
The LLM never generates the digit "15". Python does. The LLM just picks the right tool with the right arguments.
| Without tools | With tools |
|---|---|
| Model produces every token | Model produces text or a tool-call signal |
| Math/lookups depend on training | Math/lookups handled by deterministic code |
| Hard to verify correctness | Tool's output IS the truth |
| One round trip | Possibly multiple round trips per answer |
@agent.tool_plain (or pass tools=[...] at construction).agent.run_sync(prompt). Pydantic-AI handles the dispatch.The rest of week 1 unpacks each of those. Today you just see the difference.
The practice is pure Python. No LLM call. Print two strings — what the world looks like with and without tools — to internalise the shift before we wire up real calls tomorrow.
Create a free account to get started. Paid plans unlock all tracks.