How to Build an AI Agent: A Practical Guide for Developers
Building an AI agent requires an LLM with tool calling and a loop that runs until completion. Five steps with working code, common failure patterns, and when to use a framework vs. build from scratch.
Building an AI agent requires two things: an LLM that supports tool calling, and a loop that runs until the goal is achieved. Everything else - frameworks, orchestration layers, memory systems - is built on top of this foundation. Start with the minimal implementation, verify it works, and add complexity only when you have a concrete reason.
This guide walks through the five steps to build a working agent from scratch using the Anthropic SDK. The same concepts apply to the OpenAI SDK or any other provider that supports tool calling.
What You Need Before You Start
An API key for a model that supports tool calling (Claude, GPT-4o, Gemini Pro)
A clear, narrow goal for the agent
Defined tools (functions the agent can call)
A stopping condition
The last two are where most first agents fail. Unclear goals produce agents that loop without making progress. Missing stopping conditions produce agents that run indefinitely or get stuck.
Step 1: Define the Agent's Goal and Scope
Narrow goals produce better agents. "Help with software development" is too broad - the agent will never know when it is done. "Fix the failing tests in the auth module and report what you changed" is narrow enough to be completable.
For your first agent, pick a goal that:
Has a clear success condition ("tests pass," "file created," "answer found")
Requires 3 to 10 steps (not 1 to 2, which does not need an agent; not 20+, which is too complex to debug)
Has a bounded action space (a small number of well-defined tools)
Team workspace
Ship faster with chat, meetings, and projects in one place — Zlyqor.
Tools are functions that the agent can call. Each tool needs a name, a description, an input schema, and an implementation.
const tools = [
{
name: "search_web",
description: "Search the web for current information. Use when you need facts, recent events, or data not in your training knowledge.",
input_schema: {
type: "object",
properties: {
query: {
type: "string",
description: "The search query. Be specific for better results."
}
},
required: ["query"]
}
},
{
name: "read_file",
description: "Read the contents of a file. Use when you need to inspect code or data.",
input_schema: {
type: "object",
properties: {
path: {
type: "string",
description: "The file path relative to the project root."
}
},
required: ["path"]
}
},
{
name: "write_file",
description: "Write content to a file, creating it if it does not exist.",
input_schema: {
type: "object",
properties: {
path: { type: "string" },
content: { type: "string" }
},
required: ["path", "content"]
}
}
];
async function executeTool(name: string, input: Record<string, string>): Promise<string> {
switch (name) {
case "search_web":
return await searchWeb(input.query);
case "read_file":
return await fs.readFile(input.path, "utf-8");
case "write_file":
await fs.writeFile(input.path, input.content, "utf-8");
return "File written successfully.";
default:
return `Unknown tool: ${name}`;
}
}
Step 3: Write the System Prompt
The system prompt defines the agent's role, available tools, and how it should behave:
You are a research assistant with access to web search and file tools.
Your goal is to complete the user's research request by:
1. Breaking the request into specific search queries
2. Searching for information
3. Synthesizing results into a structured answer
4. Writing the answer to a file if the user requests it
Use tools when you need current information or need to read/write files.
Think carefully about what to search for before calling the search tool - specific queries return better results than broad ones.
When you have enough information to answer fully, say TASK_COMPLETE before your final answer.
Step 4: Implement the Agent Loop
This is the core of any agent: call the model, check if it wants to use a tool, execute the tool, add the result to context, repeat.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
async function runAgent(goal: string): Promise<string> {
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: goal }
];
let finalAnswer = "";
let iterations = 0;
const MAX_ITERATIONS = 15;
while (iterations < MAX_ITERATIONS) {
iterations++;
const response = await client.messages.create({
model: "claude-opus-4-5",
max_tokens: 4096,
system: systemPrompt,
tools: tools,
messages: messages
});
messages.push({ role: "assistant", content: response.content });
const toolUses = response.content.filter(
(block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
);
if (toolUses.length === 0) {
const textBlocks = response.content.filter(
(block): block is Anthropic.TextBlock => block.type === "text"
);
finalAnswer = textBlocks.map(b => b.text).join("
");
break;
}
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const toolUse of toolUses) {
const result = await executeTool(
toolUse.name,
toolUse.input as Record<string, string>
);
toolResults.push({
type: "tool_result",
tool_use_id: toolUse.id,
content: result
});
}
messages.push({ role: "user", content: toolResults });
if (response.stop_reason === "end_turn") {
const lastText = response.content
.filter((b): b is Anthropic.TextBlock => b.type === "text")
.map(b => b.text)
.join("
");
if (lastText.includes("TASK_COMPLETE")) {
finalAnswer = lastText.replace("TASK_COMPLETE", "").trim();
break;
}
}
}
if (iterations >= MAX_ITERATIONS) {
finalAnswer = "Agent reached maximum iteration limit without completing the task.";
}
return finalAnswer;
}
Step 5: Add Stopping Conditions
Stopping conditions prevent infinite loops and contain runaway agents.
Hard limit: A maximum number of iterations. Always include this.
Completion signal: A specific phrase the model outputs when it believes the task is done ("TASK_COMPLETE" in the example above).
Error budget: If the same tool call fails more than N times, stop and report rather than retrying indefinitely.
Infinite loops. The agent calls the same tool repeatedly without making progress. Cause: the goal is unclear, the tool is not providing useful results, or the model is confused about what progress means. Fix: add iteration limits and log each step so you can see where the loop starts.
Tool hallucinations. The model invents tool names or parameters that do not exist. Fix: list available tools explicitly in the system prompt.
Context overflow. On long tasks, the message history grows until it exceeds the context window. Fix: summarize older context periodically for long-running agents.
Goal drift. The agent starts pursuing a sub-goal and forgets the original goal. Fix: include the goal in the system prompt, not just the first user message.
When to Use a Framework vs. Build From Scratch
Build from scratch when:
Your agent has 2 to 5 tools and a single well-defined task type
You want full visibility into what the agent is doing at each step
Debugging is more important than feature richness
Use LangChain, LangGraph, or LlamaIndex when:
You need complex multi-agent coordination (supervisor/worker patterns)
You need built-in memory backends
You need streaming, checkpointing, or human-in-the-loop patterns
The raw API approach above is roughly 80 lines of TypeScript. For simple agents, framework abstraction is overhead. For complex multi-agent pipelines, it pays for itself.
Pristren builds AI-powered software for teams. Zlyqor is our all-in-one workspace - chat, projects, time tracking, AI meeting summaries, and invoicing - in one tool. Try it free.
Practical deep-dives on LLMs, developer tools, and AI engineering. No filler. Unsubscribe any time.
// written byFIG. AUTH-01
530
Mahmudul Haque Qudrati
CEO & ML Engineer
CEO and ML Engineer at Pristren. Builds AI-powered software for teams and writes about machine learning, LLMs, developer tools, and practical AI applications.
What is Harness engineering: Leveraging Codex in an agent-first world? A Practical Overview
Harness engineering is the practice of building structured, safe environments for AI agents to execute code. This post explains how to leverage OpenAI Codex in an agent-first world, with concrete examples, cost breakdowns, and honest tradeoffs.