Skip to content

Step 2 · A tool is just a function

What this step adds: the tool — written and called with no AI anywhere in sight.

A tool is a function the model is allowed to ask you to run. That’s the entire definition. Not a framework object, not a special class — a normal function. The “agentic” part comes later, and it isn’t the function; it’s who decides to call it.

Create step2.py:

def get_transaction(txn_id):
records = {
"T-1002": {"amount": 4200, "country": "Nigeria", "card_present": False},
"T-1003": {"amount": 35, "country": "Australia", "card_present": True},
}
return records[txn_id]
result = get_transaction("T-1002")
print("Tool returned:")
print(result)
print()
print("Amount was:", result["amount"])
print("Country was:", result["country"])
Terminal window
uv run step2.py

Expect:

Tool returned:
{'amount': 4200, 'country': 'Nigeria', 'card_present': False}
Amount was: 4200
Country was: Nigeria

Nothing AI happened. You wrote a function and called it — and that’s the point. There is the answer the model invented in step 1, now sitting in a dictionary: T-1002 is $4,200, in Nigeria, card not present. Real data (well, realistic fake data — this is what card-network records look like), unreachable by the model.

Notice who made the decisions: you chose to call get_transaction, and you chose the argument "T-1002". Hold onto that, because in the next step you hand both of those decisions to the model — and that handover is the single most important idea in agent engineering.

card_present is worth a word: it records whether the physical card was used (tapped or inserted) versus a remote transaction (online, phone). Card-not-present transactions carry most of the fraud risk, which is why our fake record bothers to track it.

The model can’t reach this function, and doesn’t know it exists. The bridge between them — describing your function to the model so it can ask for it — is step 3.

Step 3 — the model decides →