← Blog

Claude Tool Use: Building Multi-Step Agent Workflows

2026-10-25 · 5 min read · SubToAPI Team

When people search for "Claude tool use multi step agent workflow," they're usually trying to solve one of two problems: either Claude keeps stopping after a single tool call when it should keep working toward a goal, or they're not sure how to structure the loop that lets Claude call multiple tools in sequence to complete a task. Both come down to the same thing — understanding the request/response cycle that drives agentic behavior with tool use.

This article walks through how Claude's tool use actually works across multiple steps, the loop structure you need to build, and common failure modes (infinite loops, dropped context, malformed tool inputs) along with how to fix them.

How Multi-Step Tool Use Actually Works

Claude doesn't execute tools itself. When you give it a set of tool definitions, it decides when a tool is needed, returns a tool_use content block with the tool name and input, and then stops generating. Your application code is responsible for:

  1. Running the actual tool (a function call, API request, database query, etc.)
  2. Sending the result back to Claude as a tool_result block
  3. Letting Claude continue — which might mean calling another tool, asking a follow-up, or producing a final answer

A "multi-step agent workflow" is just this loop repeated until Claude returns a final text response with no further tool calls. There's no special "agent mode" flag — it's a pattern you implement around the API.

The Basic Loop Structure

Here's the shape of a minimal agent loop in JavaScript:

async function runAgent(userMessage, tools, toolHandlers) {
  let messages = [{ role: "user", content: userMessage }];

  while (true) {
    const response = await callClaude(messages, tools);
    messages.push({ role: "assistant", content: response.content });

    const toolCalls = response.content.filter(
      (block) => block.type === "tool_use"
    );

    if (toolCalls.length === 0) {
      return response; // final answer, no more tools needed
    }

    const toolResults = await Promise.all(
      toolCalls.map(async (call) => {
        const result = await toolHandlers[call.name](call.input);
        return {
          type: "tool_result",
          tool_use_id: call.id,
          content: JSON.stringify(result),
        };
      })
    );

    messages.push({ role: "user", content: toolResults });
  }
}

The key details that trip people up:

If you're calling the API directly, the request/response contract is documented at /docs/messages and the tool schema specifics at /docs/tools.

Handling Parallel Tool Calls

Claude can request multiple tools in a single turn — for example, checking weather in three cities at once. Your loop should handle an array of tool_use blocks, not assume there's only one. The example above already does this with Promise.all, which also keeps latency down when tools are independent of each other.

If one tool depends on the output of another, Claude generally won't request them in parallel — it'll wait for the first result before deciding on the next call. You don't need to detect dependencies yourself; just execute whatever Claude asks for in that turn and feed results back.

Stopping Conditions and Guardrails

The biggest practical risk in multi-step workflows is runaway loops: Claude calls a tool, gets a result it doesn't like, calls the same tool again with slightly different input, and repeats. A few guardrails that matter in production:

try {
  const result = await toolHandlers[call.name](call.input);
  return { type: "tool_result", tool_use_id: call.id, content: JSON.stringify(result) };
} catch (err) {
  return {
    type: "tool_result",
    tool_use_id: call.id,
    content: `Error: ${err.message}`,
    is_error: true,
  };
}

Designing Tools for Reliable Multi-Step Behavior

How you define tools affects how well Claude chains them:

Running This in Production

If you're building this loop against Claude directly, you're managing API keys, retry logic on transient errors, and usage tracking yourself. If you're routing it through SubToAPI, the loop structure is identical — same tool_use/tool_result contract — but you get an sub_live_... application key, streaming support for long-running agent turns, and usage metadata per request so you can see exactly how many tool round-trips a given workflow took. That last part is useful once you're running agents in production: multi-step workflows can quietly use far more tokens than a single-turn chat, and visibility into per-step cost matters. See /docs/quickstart for setup and /pricing for plan details, or /signup to start a free trial.

For streaming agent responses — useful when a step involves a long tool result or final answer — check /docs/streaming.

Questions

Does Claude automatically keep calling tools until a task is done? No. Claude decides when a tool is needed and stops after requesting it. Your application code must run the tool, send the result back, and call Claude again — repeating this loop is what creates multi-step agent behavior.

How do I prevent an agent loop from running forever? Set a maximum iteration count, add timeouts around tool execution, and treat tool failures as tool_result errors (not exceptions) so Claude can react instead of the loop crashing or hanging indefinitely.

Can Claude call multiple tools in one step? Yes. A single response can contain several tool_use blocks when the calls are independent of each other. Your loop should process an array of tool calls per turn, not assume only one.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →