← Blog

How to Build an AI Agent with the Claude API

2026-09-22 · 5 min read · SubToAPI Team

How to Build an AI Agent with the Claude API

Building an AI agent with the Claude API means writing code that lets Claude decide what to do next — not just answer a single prompt, but call tools, read the results, and keep working until a task is done. The core pattern is a loop: send a message, check if Claude wants to use a tool, run that tool, feed the result back, and repeat until Claude returns a final answer.

This article walks through that loop in practice: the pieces you need, how they fit together, and the decisions that actually affect whether your agent works reliably in production.

The Core Components of a Claude-Based Agent

An agent built on the Claude API has four moving parts:

  1. A system prompt that defines the agent's role, constraints, and available tools at a high level.
  2. Tool definitions — JSON schemas describing functions Claude can call (search, database query, code execution, API calls).
  3. An execution loop that sends messages, detects tool calls, runs them, and appends results back into the conversation.
  4. State/memory — the running conversation history, plus any external memory (a database, vector store, or file) the agent needs across turns or sessions.

None of this requires a framework. A well-written loop in plain JavaScript or Python is often more debuggable than a heavy abstraction layer, especially while you're still figuring out how your agent should behave.

The Agent Loop, Step by Step

Here's the minimal loop, using the Messages API pattern:

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

  while (true) {
    const response = await client.messages.create({
      model: "claude-sonnet-4-5",
      max_tokens: 1024,
      system: "You are a research assistant. Use tools when needed.",
      tools,
      messages,
    });

    messages.push({ role: "assistant", content: response.content });

    const toolUses = response.content.filter(b => b.type === "tool_use");
    if (toolUses.length === 0) {
      return response.content.find(b => b.type === "text")?.text;
    }

    const toolResults = [];
    for (const use of toolUses) {
      const result = await executeTool(use.name, use.input);
      toolResults.push({
        type: "tool_result",
        tool_use_id: use.id,
        content: JSON.stringify(result),
      });
    }
    messages.push({ role: "user", content: toolResults });
  }
}

This is the entire skeleton. Everything else — retries, guardrails, logging, multi-step planning — is built around this loop, not instead of it.

Defining Tools Claude Can Actually Use

Tool quality matters more than tool quantity. Each tool needs a clear name, a description that explains when to use it (not just what it does), and a tight input schema:

{
  "name": "search_docs",
  "description": "Search internal documentation. Use this before answering any question about internal APIs or policies.",
  "input_schema": {
    "type": "object",
    "properties": {
      "query": { "type": "string" },
      "max_results": { "type": "integer", "default": 5 }
    },
    "required": ["query"]
  }
}

Vague descriptions are the most common cause of agents calling the wrong tool or not calling one at all. Write descriptions the way you'd explain the tool to a new engineer, not the way you'd document a function signature.

Handling State and Multi-Step Tasks

Agents that do real work — fixing a bug, researching a topic, processing a batch of records — need to run for more than one tool call. A few practical rules:

Streaming for Responsive Agents

If your agent has a UI, stream the response so users see progress instead of waiting on a full tool-calling cycle. Claude's streaming API sends events for text deltas and tool use as they're generated, which lets you show "thinking" or partial output while the loop continues in the background. This matters more for agents than for simple chat, since a multi-step task can take several seconds per turn.

Where SubToAPI Fits

If you're building an agent for a team or shipping it as a product, you'll eventually need to manage API access separately from your personal Claude login — usage tracking per feature, per-user keys, and a way to rotate credentials without breaking production.

SubToAPI turns your existing Claude access into a standard HTTPS API with its own application keys (sub_live_...), so your agent code talks to a stable endpoint instead of juggling raw credentials. It supports streaming, tool use, and the same Messages format shown above, plus usage metadata per key so you can see which part of your agent is consuming the most tokens. Setup takes about the time it takes to read the quickstart.

Common Mistakes When Building Claude Agents

FAQ

Do I need a framework like LangChain to build a Claude agent? No. The agent loop is short enough to write and debug directly. Frameworks can help once you have many agents sharing infrastructure, but for a first build they often hide bugs you need to see.

How many tools should an agent have? Start with the minimum set required for the task — usually three to six. Adding tools increases the chance Claude picks the wrong one or calls tools unnecessarily.

Can I run a Claude agent without managing raw API keys myself? Yes — services like SubToAPI sit between your app and Claude, giving you application-scoped keys, usage tracking, and team access without changing how your Messages API calls are structured.

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 →