跪拜 Guibai
← All articles
Node.js · Frontend Framework · Artificial Intelligence

The Tool Loop That Turns a Chatbot Into an Agent

By 东方小月 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

A tool loop is the difference between a demo chatbot and an agent that can read files, run commands, or modify a codebase. Getting the control flow right — serial execution, parameter validation on untrusted model input, and safe cancellation — prevents the agent from executing garbage arguments or leaving the conversation in an unrecoverable state.

Summary

An LLM cannot execute tools itself; it only returns a structured intent. The agent must find the local function, validate the model's untrusted parameters, run it, and construct a tool_result message for the next model request. This creates a loop where the model proposes an action, the agent executes it, and the model observes the outcome before responding.

The implementation separates concerns cleanly: a ToolDefinition (name, description, parameters) is sent to the provider, while the AgentTool adds a local execute() function the provider never sees. Every tool call goes through a strict sequence: emit a start event, check for cancellation, look up the tool by name, validate arguments against the schema, catch execution errors, and unify everything into a ToolResultMessage.

Cancellation is handled at multiple checkpoints. An AbortSignal is checked before execution, after execution, and between serial tool calls in a batch. If cancelled mid-loop, the agent appends a locally-constructed aborted assistant message so the prompt settles cleanly rather than leaving the conversation in a broken state.

Takeaways
Models return tool_call intents, not execution results; the agent must run tools locally and feed results back.
One prompt can contain multiple turns, each a model response plus the tool executions it triggers.
AgentTool extends ToolDefinition with an execute() function that the provider never sees or serializes.
Model-generated tool names and arguments are untrusted input and must be validated before execution.
Tools execute serially, not in parallel, to guarantee deterministic event ordering and safe cancellation.
An AbortSignal is checked before tool execution, after execution, and between tools in a batch.
Unknown tools and parameter validation failures produce error ToolResultMessages rather than crashing the loop.
On cancellation, a locally-constructed aborted assistant message is appended so the prompt settles cleanly.
Conclusions

The design treats tool name errors and parameter validation failures as recoverable conversation events, not fatal exceptions, because the model can often correct itself when it sees the error result.

Serial tool execution is a deliberate trade-off: determinism and cancellation safety are prioritized over concurrency at this stage of the agent's development.

Copying the tools array at construction and again at each prompt() call prevents external mutation from changing the tool set mid-conversation, a class of bug that is hard to diagnose.

The double AbortSignal check after await is necessary because an AbortSignal is a request, not an enforcement mechanism; a tool might ignore it and still return a result.

Concepts & terms
Tool Call Loop
A control flow where the model requests a tool, the agent executes it locally, the result is appended to message history, and the model is queried again — repeating until the model produces a final text response.
ToolResultMessage
A structured message with role 'tool_result' that carries a tool's output or error back to the model, keyed by toolCallId so the model can match results to specific calls.
Type Predicate
A TypeScript return type of the form 'content is ToolCallContent' that narrows the type of filtered array elements, allowing safe access to type-specific properties after a .filter() call.
Faux Provider
A test double that returns pre-configured model responses in sequence, enabling deterministic testing of multi-turn tool loops without real API calls.
From the discussion
Featured comments
二萌吖 1 likes

An agent loop from agent_start to end refers to the end of the entire conversation; a turn loop refers to the end of a single large model streaming request.

东方小月

[Like]

See top comments, translated →
Source: juejin.cn ↗ Google Translate ↗ Backup ↗