Module 2 · Building Agents · scripted
Tools: Constraining the Actions
From producing text to taking action
Remember the shape of an agent: it chooses an action, the action touches the world, and a report of what happened comes back into the conversation to drive the next choice.
The agent loop
In everything we've done so far, the actions have really just been producing text — instructions for a human to carry out. But most of the time, we want agents to take real actions that affect the real world: reach into a calendar and pull the available meeting times, send an email, start a machine. And the sveler agent showed the problem with letting the LLM dream its actions up: it assumed a fully equipped kitchen and planned with tools nobody said existed.
So we do something better: we tell the LLM, up front, exactly what tools it has — and the tools bound the space of actions it can take.
Tools bound the action space
The prompt: tools, task, rules
Here is the prompt shape we'll use for the rest of this lesson — the tools declared as a list, the task, and rules that force one clearly formatted step at a time:
The shape of the prompt
Example 1 · Two tools
You have the following tools available for use:
- microwave
- plate
Task: Reheat a frozen dinner that needs 90 seconds on high.
Rules:
- You must select one step at a time.
- You must output a step in the format
Step <N>: Use <Tool> - <Notes> - You wait for a description of what happened to be provided back to you.
- You choose the next step.
- When done, you output just END.
Step 1: Use plate - Take the frozen dinner out of its box and place it on the plate.
Done. The dinner is on the plate.
Step 2: Use microwave - Heat the dinner on high for 90 seconds.
The microwave ran for 90 seconds and beeped. The dinner is hot.
END
Same task, finer tools
Now keep the task and the rules identical — and only change the tool list. These tools are smaller: each one does one tiny thing.
You have the following tools available for use:
- set_microwave_power( power )
- set_microwave_cook_time( time in seconds )
- open_microwave_door()
- close_microwave_door()
- put_item_in_microwave( item )
- remove_item_from_microwave( item )
Task: Reheat a frozen dinner that needs 90 seconds on high.
Rules: the same five rules as before.
Step 1: Use open_microwave_door() - So the dinner can go in.
The door is open.
Step 2: Use put_item_in_microwave( dinner ) - Set it in the center.
The dinner is inside.
Step 3: Use close_microwave_door() - Sealed before heating.
The door is closed.
Step 4: Use set_microwave_power( high ) - The dinner needs full power.
Power is set to high.
Step 5: Use set_microwave_cook_time( 90 ) - Ninety seconds, per the package.
The microwave ran for 90 seconds and beeped.
Step 6: Use open_microwave_door() - To get the dinner out.
The door is open. Steam is coming out.
Step 7: Use remove_item_from_microwave( dinner ) - Careful, it's hot.
The dinner is out.
END
Granularity is a dial
Tools can also fold several actions into one word. One more tool set, same task:
You have the following tools available for use:
- reheat_in_microwave( item, time )
- put_item_in_microwave( item )
- remove_item_from_microwave( item )
Task: Reheat a frozen dinner that needs 90 seconds on high.
Rules: the same five rules.
Step 1: Use put_item_in_microwave( dinner ) - In the center.
The dinner is inside.
Step 2: Use reheat_in_microwave( dinner, 90 ) - One call covers power, timing, and running.
The microwave ran for 90 seconds and beeped.
Step 3: Use remove_item_from_microwave( dinner ) - Done heating.
The dinner is out.
END
reheat_in_microwave folded door, power, time, and start into a
single word — and the solution shrank to match. Granularity is a
design dial: you choose how much each word of the language means.Different tools, different solution
Finally, take the microwave away entirely. Same frozen dinner — but now the tools describe a completely different corner of the kitchen:
You have the following tools available for use:
- heat_water_in_tea_kettle()
- pour_water_from_tea_kettle( where to pour )
- put_item_in_bowl( item )
- remove_item_from_bowl( item )
Task: Reheat a frozen dinner that needs 90 seconds on high. The dinner is in a sealed, waterproof pouch.
Rules: the same five rules.
Step 1: Use heat_water_in_tea_kettle() - We'll use boiling water instead of a microwave.
The kettle has boiled.
Step 2: Use put_item_in_bowl( sealed dinner pouch ) - Keep it sealed; the bowl becomes our hot-water bath.
The pouch is in the bowl.
Step 3: Use pour_water_from_tea_kettle( into the bowl, over the pouch ) - Cover it completely, then let it sit about five minutes. Tell me when time is up.
Five minutes have passed. The water is still warm.
Step 4: Use remove_item_from_bowl( dinner pouch ) - It should be heated through.
The pouch is out and hot to the touch.
END
- The task never changed. List what DID change across the four runs — and trace each change back to the tool list.
- In Example 2, which steps exist only because the tools are small?
In Example 3, what decisions disappeared inside
reheat_in_microwave— and who makes them now? - What's the difference between "the LLM can't do X" and "X isn't in the tool list"?
Constraints as a design instrument
Declaring tools turns out to be one of the most important design moves in all of agent building. The tool list is how we tell the agent what kind of world it is acting in — and, just as important, what it must work around. A bowl becoming a hot-water bath and a seven-step microwave dance come from the same mechanism: the conversation states what actions exist, at what granularity, and the LLM composes a trajectory out of exactly those actions.
But so far, our tools are mostly just names. A real microwave doesn't accept "high" without being told what the choices are — it wants a power level and a time, with units and limits. That's the next lesson: tools have controls.
Pick a task from your own domain and write two tool lists for it: one coarse (two or three big tools) and one fine (six or more tiny ones). Give an LLM the same task and the same five rules with each list. Where did the fine list force decisions the coarse list hid? Where did it just force busywork?