How to Build an AI Agent with the Claude API
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:
- A system prompt that defines the agent's role, constraints, and available tools at a high level.
- Tool definitions — JSON schemas describing functions Claude can call (search, database query, code execution, API calls).
- An execution loop that sends messages, detects tool calls, runs them, and appends results back into the conversation.
- 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:
- Cap the loop. Set a max number of iterations (10–20 is typical) so a confused agent doesn't run forever and burn tokens.
- Summarize long histories. Once a conversation grows past a few thousand tokens of tool results, compress older turns into a summary before continuing, or you'll hit context limits and pay for redundant tokens.
- Persist state outside the conversation. For anything that needs to survive across sessions (user preferences, task progress, prior decisions), store it in a database and inject relevant pieces into the system prompt rather than relying on conversation history alone.
- Log every tool call and result. When an agent misbehaves, the tool call log is almost always where the bug lives.
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
- Giving Claude too many tools at once. Ten overlapping tools confuse the model more than they help. Start with the three or four the agent actually needs.
- Skipping the max-iteration cap. A loop with no ceiling is a runaway cost problem waiting to happen.
- Not validating tool inputs. Claude can hallucinate arguments that look plausible but are wrong — validate before executing, especially for anything that writes data or spends money.
- Treating the system prompt as static. Update it as you learn which instructions the model actually follows versus ignores in practice.
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.