A tool call is a proposal, not an action
The model returns a structured request such as “call read_file with path src/main.py.” That request is still data. The harness checks it, decides whether the tool is available, validates its arguments, executes the function, and packages the result. A well-designed harness never treats model output as permission by itself.
- User asks
- Model calls tool
- Harness checks
- Tool observes
- Model continues
Walk through an example
Task: “Count the words in this sentence and report the number.” The model requests count_words(text=...). The harness validates the tool name and text argument, runs the deterministic function, then appends a tool result such as {"count": 8} to the conversation. On the next turn the model sees the count and can answer.
# Model output: a request, not yet executed
call = {"name": "count_words", "arguments": {"text": "Count these words"}}
# Harness executes a registered tool and creates an observation
observation = {"ok": True, "count": count_words(**call["arguments"])}
history.append({"role": "tool", "name": call["name"], "content": observation})
Provider APIs may require a call ID and a specific message shape for tool results. Preserve that correlation identifier in your adapter so each result answers the correct request. Keep provider-specific message formats at the edge of your harness; the internal loop can use one small, tested contract.
Errors are observations too
If a file is missing or a service is unavailable, the harness can return a structured error rather than pretending the operation succeeded. The model may recover—for example, by checking a different path—or the harness may stop and report the failure. Do not silently turn a failed tool call into an empty successful result; that teaches the model the wrong state of the world.
{"ok": false,
"error": {"code": "NOT_FOUND", "message": "Requested file does not exist."}}Return enough information to choose a next step, without leaking stack traces, credentials, or unrelated records.
Connect it to reliability
Without observations, the model cannot verify whether its action worked. With observations, a harness can support an iterative process: propose, act, inspect, and revise. This is the key idea behind ReAct’s interleaving of reasoning, actions, and environment observations. The engineering lesson is simple: make the environment’s response accurate, relevant, and visible to the next turn.
Ask your teacher to trace a real tool call with you if the message handoffs still feel abstract.