An agent that just does what it decides
Before any governance, here is the problem it solves. This lesson builds a shop agent out of plain Python and then watches it do something nobody wanted.
The shop has orders, and four things the agent can do about them. Two are harmless and two are not.
ORDERS = {
"A17": {"item": "Noise-cancelling headphones", "paid": 249.0},
"B22": {"item": "Laptop stand", "paid": 39.0},
}
def lookup_order(order_id):
return ORDERS.get(order_id, {"error": f"no order {order_id}"})
def delete_order(order_id):
ORDERS.pop(order_id, None)
return {"deleted": order_id}
print(lookup_order("A17")["item"])lookup_order reads. delete_order destroys. To the program calling them they are the same shape: a name, some arguments, a dictionary back.
A loop that trusts the agent
Now the piece that turns a message into a call. For the moment it is a dictionary of tools and a function that picks one by looking for words.
TOOLS = {"lookup_order": lookup_order, "delete_order": delete_order}
def decide(message):
if "delete" in message.lower():
return "delete_order", {"order_id": "A17"}
return "lookup_order", {"order_id": "A17"}
for message in ["Where is my order?", "Please delete order A17"]:
tool, args = decide(message)
print(tool, "->", TOOLS[tool](**args))The order is gone. A customer typed a sentence and a record was destroyed, because the only thing standing between the message and the deletion was a function that believed whatever it was told.
The three places you could put a rule
You could check inside delete_order, but then every tool needs its own copy and a new tool arrives with none. You could check inside decide, but that is the part an attacker steers with a sentence. Or you could check in the loop between them, which is the one place every call has to pass.
That last one is what the toolkit does, and lesson 4 is where the loop grows a gate.
- Add a third message that mentions deleting order B22, and watch that one go too.
- Move the
ifindecideto the bottom, so no message ever deletes anything, then ask yourself what happens the day someone edits that function. - Print
ORDERSafter the loop to see what is left.
Little by little, you're building something great.