# How to Build an AI Agent

- Tool: Any LLM or framework
- Difficulty: Beginner
- Time required: 30-40 min
- Compatibility: Python 3.10+ (or Node.js 20+), LangChain 1.x, Claude or OpenAI API key, any OS
- Last updated: November 2026

## TL;DR

Building an AI agent means picking a model, giving it tools it can call, and running a loop that plans and acts until the task is done. In 2026 the fastest path is a framework like LangChain's create_agent, not a from-scratch loop. This guide builds a meeting-prep agent with two tools and a memory checkpoint, then links out to multi-agent, RAG, and security patterns. Budget 30 minutes and about $0.02 per run on Claude Sonnet 5.5.

## What you'll build

You'll build a meeting-prep agent: give it a calendar event ID, and it looks up the event, researches each attendee, and drafts a short briefing you can skim thirty seconds before the call. It's deliberately small, two tools and a system prompt, because the point of this page isn't the agent itself. It's picking the right way to build one before you invest an afternoon in the wrong approach.

Most people reach for a framework too late or too early. A framework like LangChain's create_agent, the Claude Agent SDK, or the OpenAI Agents SDK gives you a tested tool-calling loop, memory, and error handling for free. Writing the loop yourself (see the from-scratch guide) only pays off when you need to understand or control every line, or your stack has no framework support yet. A no-code builder like n8n beats both when nobody on the team wants to maintain Python or TypeScript.

This guide uses LangChain's create_agent because it's the current recommended entry point for a standard tool-calling agent in either language, and because the pattern it teaches, tools plus a checkpointer plus a system prompt, transfers directly to every other framework in this activity. Once this runs, the rest of the build-ai-agent pages go deep on one slice: raw API loops, multi-agent systems, agentic RAG, memory, security, and the no-code alternatives.

## Before you start

- Python 3.10+ and a terminal
- An Anthropic or OpenAI API key with available credits
- pip install langchain langgraph
- 15 minutes to read the overview before you touch a framework

## Step-by-step guide

### 1. Pick your approach before you pick a framework

Three paths build the same kind of agent: a framework (fastest to production, LangChain/Claude Agent SDK/OpenAI Agents SDK), a from-scratch tool-calling loop (full control, more code to maintain), or a no-code builder like n8n (no Python/TypeScript at all). Pick a framework by default. Drop to from-scratch only if you need to see or change every step of the loop. Pick no-code only if nobody on the team will maintain the code later.

**Expected result:** A one-line decision: 'I'm building with a framework' (this guide), unless you have a specific reason to go from-scratch or no-code.

### 2. Install LangChain and define your first tool

Install langchain and langgraph (langgraph ships the checkpointer you'll use in step 4). Define get_calendar_event with the @tool decorator: a type-hinted function with a docstring, which LangChain turns into both the tool's schema and the description the model reads to decide when to call it. Keep the handler returning a plain string for now; swap in a real calendar API call later.

```
pip install langchain langgraph

from langchain.tools import tool

@tool
def get_calendar_event(event_id: str) -> str:
    """Look up a calendar event by ID. Returns its title, time, and attendee emails."""
    event = CALENDAR.get(event_id)
    if not event:
        return f"No event found for {event_id}"
    return f"{event['title']} at {event['time']} with {', '.join(event['attendees'])}"
```

**Expected result:** A decorated function you can call directly in a Python shell for a quick sanity check.

### 3. Add a second tool and wire up create_agent

Add research_attendee, which looks up a person's role and company from their email. Pass both tools into create_agent along with a model string and a system prompt that states the sequence explicitly: look up the event first, then research every attendee before drafting anything. create_agent is the current recommended entry point for a standard tool-calling agent, replacing the older create_react_agent function.

```
from langchain.agents import create_agent

@tool
def research_attendee(email: str) -> str:
    """Look up a person's role and company given their work email."""
    person = DIRECTORY.get(email)
    return f"{person['name']}, {person['role']} at {person['company']}" if person else "Unknown"

agent = create_agent(
    model="anthropic:claude-sonnet-5-5",
    tools=[get_calendar_event, research_attendee],
    system_prompt=(
        "You prepare meeting briefings. Always look up the event first, "
        "then research every attendee, then write a 3-sentence briefing."
    ),
)
```

**Expected result:** An agent object you can call with agent.invoke(), with no memory yet.

### 4. Give the agent memory with a checkpointer

Without a checkpointer, every call to the agent starts from zero, it won't remember the event it just looked up if you ask a follow-up. Pass an InMemorySaver into create_agent and a thread_id in the config on every call. In production swap InMemorySaver for a persistent checkpointer (Postgres, SQLite) so memory survives a restart.

```
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent(
    model="anthropic:claude-sonnet-5-5",
    tools=[get_calendar_event, research_attendee],
    checkpointer=InMemorySaver(),
)
config = {"configurable": {"thread_id": "meeting-prep-001"}}
```

**Expected result:** The same agent, now able to answer 'who's in that meeting again?' without you repeating the event ID.

### 5. Run it and read the trace

Call agent.invoke() with the thread_id config and a user message naming the event. Print every message in the result, not just the final one, so you can see which tools were called and in what order. This is the step most tutorials skip and most production bugs come from, the agent calling tools in the wrong order or not calling one at all.

```
result = agent.invoke(
    {"messages": [{"role": "user", "content": "Prep me for event EVT-204"}]},
    config=config,
)
for m in result["messages"]:
    print(type(m).__name__, getattr(m, "content", ""))
```

**Expected result:** A printed trace showing get_calendar_event, then two research_attendee calls (one per attendee), then a final briefing message.

### 6. Harden it, then pick your next page

Before anyone else touches this: cap the number of steps so a confused agent fails fast instead of looping, catch exceptions inside tool handlers and return an error string instead of crashing, and move the system prompt's sequencing rule into an eval you run on every change. From here, go deep on exactly one thing: raw API control (from-scratch), many cooperating agents (multi-agent), retrieval over your own documents (agentic RAG), or locking down what tools can do (security).

```
agent = create_agent(
    model="anthropic:claude-sonnet-5-5",
    tools=[get_calendar_event, research_attendee],
    checkpointer=InMemorySaver(),
)
# Step cap and error handling live inside the tool handlers and the
# framework's own recursion limit (pass config={"recursion_limit": 15}).
```

**Expected result:** An agent that fails with a clear error instead of looping silently, and a decision about which pattern page to read next.

## Complete code example

File: `meeting_prep_agent.py`

```python
"""Meeting-prep agent: looks up an event, researches attendees, drafts a briefing.
Run: python meeting_prep_agent.py (pip install langchain langgraph; set ANTHROPIC_API_KEY)
"""
from langchain.agents import create_agent
from langchain.tools import tool
from langgraph.checkpoint.memory import InMemorySaver

CALENDAR = {
    "EVT-204": {
        "title": "Q4 renewal call",
        "time": "2026-11-10 14:00",
        "attendees": ["jordan@acme.com", "priya@acme.com"],
    }
}
DIRECTORY = {
    "jordan@acme.com": {"name": "Jordan Lee", "role": "VP Operations", "company": "Acme Co"},
    "priya@acme.com": {"name": "Priya Nair", "role": "Finance Lead", "company": "Acme Co"},
}


@tool
def get_calendar_event(event_id: str) -> str:
    """Look up a calendar event by ID. Returns its title, time, and attendee emails."""
    event = CALENDAR.get(event_id)
    if not event:
        return f"No event found for {event_id}"
    return f"{event['title']} at {event['time']} with {', '.join(event['attendees'])}"


@tool
def research_attendee(email: str) -> str:
    """Look up a person's role and company given their work email."""
    person = DIRECTORY.get(email)
    if not person:
        return f"No directory entry for {email}"
    return f"{person['name']}, {person['role']} at {person['company']}"


SYSTEM_PROMPT = (
    "You prepare meeting briefings. Always look up the event first, "
    "then research every attendee before writing anything, then write "
    "a 3-sentence briefing covering who's in the room and why it matters."
)

agent = create_agent(
    model="anthropic:claude-sonnet-5-5",
    tools=[get_calendar_event, research_attendee],
    system_prompt=SYSTEM_PROMPT,
    checkpointer=InMemorySaver(),
)

if __name__ == "__main__":
    config = {"configurable": {"thread_id": "meeting-prep-001"}}
    result = agent.invoke(
        {"messages": [{"role": "user", "content": "Prep me for event EVT-204"}]},
        config=config,
    )
    for m in result["messages"]:
        print(type(m).__name__, "->", getattr(m, "content", ""))
```

## Common mistakes

- **Writing a from-scratch tool-calling loop before trying a framework's high-level entry point** — undefined Fix: Start with create_agent, the Claude Agent SDK, or the OpenAI Agents SDK. Drop to a raw loop only once you know specifically what the framework can't do for your case.
- **Skipping the checkpointer, then being surprised the agent forgets the event it just looked up** — undefined Fix: Add a checkpointer from the first version, even InMemorySaver for local testing. Retrofitting memory later means rewriting whatever ad-hoc state you built by hand.
- **Writing a one-line tool docstring like 'gets event info'** — undefined Fix: The docstring is the only thing the model reads to decide when to call the tool. Describe inputs, outputs, and when to use it, as if onboarding a new hire.
- **Never setting a recursion or step limit** — undefined Fix: A confused agent that keeps calling tools in a loop burns real money. Pass a recursion_limit and treat hitting it as a bug to fix, not a fluke to ignore.
- **Shipping the first version without ever printing the full message trace** — undefined Fix: Print every message, not just the final answer, at least once. It's the fastest way to catch a tool being called in the wrong order or not at all.

## Best practices

- Default to a framework's high-level entry point (create_agent, Claude Agent SDK's query(), Agents SDK's Runner) over a hand-rolled loop.
- Write every tool docstring for the model: what it does, what it returns, when to call it.
- Add a checkpointer and a thread_id from day one, even for a prototype.
- Set a step or recursion cap so a confused agent fails fast instead of looping.
- Log every tool call during development; you'll need that trace the first time the agent does something unexpected.
- Treat this page as a map. Once the minimal agent runs, go read the specific pattern page for what you're actually building.

## Use cases

### undefined



### undefined



### undefined



## Frequently asked questions

### What's the fastest way to build an AI agent in 2026?

Use a framework's high-level entry point, LangChain's create_agent, the Claude Agent SDK, or the OpenAI Agents SDK, rather than writing the tool-calling loop yourself. All three give you tool registration, memory, and error handling out of the box, which is most of the work in a first agent.

### Do I need a framework, or can I just call the API directly?

You can call the API directly (see the from-scratch guide), and it's a good way to understand what a framework is doing for you. For anything you plan to maintain past a prototype, a framework saves real time on memory, retries, and tool-schema generation.

### How much does it cost to run an agent like this?

On Claude Sonnet 5.5 ($2/M input tokens, $10/M output), a short exchange with two tool calls and a few thousand tokens of history runs about $0.01-0.03 per turn uncached. Prompt caching cuts the repeated system-prompt-and-tools cost once it stabilizes.

### Which framework should I pick for my first agent?

LangChain's create_agent if you want the most examples and middleware available; the Claude Agent SDK if you specifically want Claude Code's permission model and built-in tools; the OpenAI Agents SDK if you're already OpenAI-first and want handoffs and guardrails built in.

### How do I make the agent remember earlier messages in the same conversation?

Pass a checkpointer (InMemorySaver for local testing, a persistent one for production) into create_agent, and reuse the same thread_id across calls in a conversation. Without both, every call starts from a blank slate.

### My agent calls the wrong tool or calls nothing at all. What's wrong?

Almost always the tool docstring or the system prompt's sequencing instructions. Print the full message trace, not just the final answer, and check whether the model even considered the right tool before tightening the description.

### Can someone build this for me instead of doing it myself?

Yes. RapidDev builds production agents across LangChain, the Claude Agent SDK, and n8n, including the memory, guardrail, and observability pieces most tutorials skip. A free 30-minute consultation is the fastest way to scope your version.

---

Source: https://www.rapidevelopers.com/build-ai-agent/how-to-build-an-ai-agent
© RapidDev — https://www.rapidevelopers.com/build-ai-agent/how-to-build-an-ai-agent
