Yesterday: one tool, one call. Today: two tools, the model picks both in the right order.
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
@agent.tool_plain
def multiply(a: int, b: int) -> int:
"""Return the product of two integers."""
return a * b
result = agent.run_sync("What is (3 + 4) * 5?")
print(result.output) # contains "35"The model has to figure out: first add 3 and 4, then multiply that by 5. Two distinct tool calls in a single run_sync.
Right. Pydantic-AI runs the tool-call loop until the model says it's done. Each iteration: model decides next tool (or finalises), library executes, result fed back. Could be 2 calls, could be 5 — the model decides when the answer is complete.
What if the model gets the order wrong?
It happens. "What is 3 + 4 * 5?" without parentheses is genuinely ambiguous (the model has to decide: PEMDAS or left-to-right?). The fix: be specific in the prompt, or split the math into smaller steps. Today's prompt is unambiguous — parentheses force the order.
The pattern is the same as single tool calling. The library loops until the model emits a final answer instead of another tool call:
prompt + 2 schemas
↓
LLM #1 — "call add(3, 4)"
↓
add(3, 4) → 7
↓
LLM #2 — "call multiply(7, 5)"
↓
multiply(7, 5) → 35
↓
LLM #3 — "The answer is 35."
↓
result.output
Three LLM calls under one run_sync. Quota math: ~3-4 slots for this lesson.
It reads the prompt, plans, and emits one tool-call request at a time. When the result comes back, it plans again with the new context. For "(3 + 4) * 5":
3+4 first, then multiply by 5"add(3, 4) → gets 7 backmultiply(7, 5) → gets 35 backThe planning is implicit — it's just next-token prediction conditioned on "I've seen these tool results so far".
If you want to confirm the model used both tools, inspect result.all_messages(). Tool calls appear as their own message kind. For now, asserting the final output contains "35" is enough — if the model only added or only multiplied, the answer would be different.
Most common: the model uses the wrong tool, or only one tool when both were needed. Mitigations:
Week 3's agent loop and week 3's eval suite are the tools for catching these failures systematically.
Yesterday: one tool, one call. Today: two tools, the model picks both in the right order.
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
@agent.tool_plain
def multiply(a: int, b: int) -> int:
"""Return the product of two integers."""
return a * b
result = agent.run_sync("What is (3 + 4) * 5?")
print(result.output) # contains "35"The model has to figure out: first add 3 and 4, then multiply that by 5. Two distinct tool calls in a single run_sync.
Right. Pydantic-AI runs the tool-call loop until the model says it's done. Each iteration: model decides next tool (or finalises), library executes, result fed back. Could be 2 calls, could be 5 — the model decides when the answer is complete.
What if the model gets the order wrong?
It happens. "What is 3 + 4 * 5?" without parentheses is genuinely ambiguous (the model has to decide: PEMDAS or left-to-right?). The fix: be specific in the prompt, or split the math into smaller steps. Today's prompt is unambiguous — parentheses force the order.
The pattern is the same as single tool calling. The library loops until the model emits a final answer instead of another tool call:
prompt + 2 schemas
↓
LLM #1 — "call add(3, 4)"
↓
add(3, 4) → 7
↓
LLM #2 — "call multiply(7, 5)"
↓
multiply(7, 5) → 35
↓
LLM #3 — "The answer is 35."
↓
result.output
Three LLM calls under one run_sync. Quota math: ~3-4 slots for this lesson.
It reads the prompt, plans, and emits one tool-call request at a time. When the result comes back, it plans again with the new context. For "(3 + 4) * 5":
3+4 first, then multiply by 5"add(3, 4) → gets 7 backmultiply(7, 5) → gets 35 backThe planning is implicit — it's just next-token prediction conditioned on "I've seen these tool results so far".
If you want to confirm the model used both tools, inspect result.all_messages(). Tool calls appear as their own message kind. For now, asserting the final output contains "35" is enough — if the model only added or only multiplied, the answer would be different.
Most common: the model uses the wrong tool, or only one tool when both were needed. Mitigations:
Week 3's agent loop and week 3's eval suite are the tools for catching these failures systematically.
Create a free account to get started. Paid plans unlock all tracks.