Skip to main content
RapidDev - Software Development Agency
build-ai-agent

How to Build an AI Agent

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 learn

  • Decide whether to use a framework, raw API calls, or a no-code builder before writing anything
  • Define tools with LangChain's @tool decorator and register them with create_agent
  • Add a checkpointer so the agent remembers earlier turns in the same thread
  • Know which deeper pattern page to read next for your specific agent
Book a free consultation
4.9Clutch rating ⭐
1,000+Happy partners
20+Countries served
200+Team members
Beginner9 min read30-40 minPython 3.10+ (or Node.js 20+), LangChain 1.x, Claude or OpenAI API key, any OSLast updated November 2026RapidDev Engineering Team
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.

Quick facts about this guide
FactValue
ToolAny LLM or framework
DifficultyBeginner
Time required30-40 min
CompatibilityPython 3.10+ (or Node.js 20+), LangChain 1.x, Claude or OpenAI API key, any OS
Last updatedNovember 2026

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.

Prerequisites

  • 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.

typescript
1pip install langchain langgraph
2
3from langchain.tools import tool
4
5@tool
6def get_calendar_event(event_id: str) -> str:
7 """Look up a calendar event by ID. Returns its title, time, and attendee emails."""
8 event = CALENDAR.get(event_id)
9 if not event:
10 return f"No event found for {event_id}"
11 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.

typescript
1from langchain.agents import create_agent
2
3@tool
4def research_attendee(email: str) -> str:
5 """Look up a person's role and company given their work email."""
6 person = DIRECTORY.get(email)
7 return f"{person['name']}, {person['role']} at {person['company']}" if person else "Unknown"
8
9agent = create_agent(
10 model="anthropic:claude-sonnet-5-5",
11 tools=[get_calendar_event, research_attendee],
12 system_prompt=(
13 "You prepare meeting briefings. Always look up the event first, "
14 "then research every attendee, then write a 3-sentence briefing."
15 ),
16)

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.

typescript
1from langgraph.checkpoint.memory import InMemorySaver
2
3agent = create_agent(
4 model="anthropic:claude-sonnet-5-5",
5 tools=[get_calendar_event, research_attendee],
6 checkpointer=InMemorySaver(),
7)
8config = {"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.

typescript
1result = agent.invoke(
2 {"messages": [{"role": "user", "content": "Prep me for event EVT-204"}]},
3 config=config,
4)
5for m in result["messages"]:
6 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).

typescript
1agent = create_agent(
2 model="anthropic:claude-sonnet-5-5",
3 tools=[get_calendar_event, research_attendee],
4 checkpointer=InMemorySaver(),
5)
6# Step cap and error handling live inside the tool handlers and the
7# 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 working example

meeting_prep_agent.py
1"""Meeting-prep agent: looks up an event, researches attendees, drafts a briefing.
2Run: python meeting_prep_agent.py (pip install langchain langgraph; set ANTHROPIC_API_KEY)
3"""
4from langchain.agents import create_agent
5from langchain.tools import tool
6from langgraph.checkpoint.memory import InMemorySaver
7
8CALENDAR = {
9 "EVT-204": {
10 "title": "Q4 renewal call",
11 "time": "2026-11-10 14:00",
12 "attendees": ["jordan@acme.com", "priya@acme.com"],
13 }
14}
15DIRECTORY = {
16 "jordan@acme.com": {"name": "Jordan Lee", "role": "VP Operations", "company": "Acme Co"},
17 "priya@acme.com": {"name": "Priya Nair", "role": "Finance Lead", "company": "Acme Co"},
18}
19
20
21@tool
22def get_calendar_event(event_id: str) -> str:
23 """Look up a calendar event by ID. Returns its title, time, and attendee emails."""
24 event = CALENDAR.get(event_id)
25 if not event:
26 return f"No event found for {event_id}"
27 return f"{event['title']} at {event['time']} with {', '.join(event['attendees'])}"
28
29
30@tool
31def research_attendee(email: str) -> str:
32 """Look up a person's role and company given their work email."""
33 person = DIRECTORY.get(email)
34 if not person:
35 return f"No directory entry for {email}"
36 return f"{person['name']}, {person['role']} at {person['company']}"
37
38
39SYSTEM_PROMPT = (
40 "You prepare meeting briefings. Always look up the event first, "
41 "then research every attendee before writing anything, then write "
42 "a 3-sentence briefing covering who's in the room and why it matters."
43)
44
45agent = create_agent(
46 model="anthropic:claude-sonnet-5-5",
47 tools=[get_calendar_event, research_attendee],
48 system_prompt=SYSTEM_PROMPT,
49 checkpointer=InMemorySaver(),
50)
51
52if __name__ == "__main__":
53 config = {"configurable": {"thread_id": "meeting-prep-001"}}
54 result = agent.invoke(
55 {"messages": [{"role": "user", "content": "Prep me for event EVT-204"}]},
56 config=config,
57 )
58 for m in result["messages"]:
59 print(type(m).__name__, "->", getattr(m, "content", ""))
60

Common mistakes

Why it's a problem: Writing a from-scratch tool-calling loop before trying a framework's high-level entry point

How to avoid: 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.

Why it's a problem: Skipping the checkpointer, then being surprised the agent forgets the event it just looked up

How to avoid: 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.

Why it's a problem: Writing a one-line tool docstring like 'gets event info'

How to avoid: 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.

Why it's a problem: Never setting a recursion or step limit

How to avoid: 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.

Why it's a problem: Shipping the first version without ever printing the full message trace

How to avoid: 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.

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I have a LangChain create_agent agent with get_calendar_event and research_attendee tools and an InMemorySaver checkpointer (code below). Add a third tool, draft_briefing_email, that formats the briefing as a sendable email, and update the system prompt to call it last. [paste complete_code]

Build AI Agents Prompt

In Claude Code, open meeting_prep_agent.py and ask: 'Add a recursion_limit to the invoke config and a try/except around each tool handler that returns an error string instead of raising.'

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.

RapidDev

Talk to an Expert

Our team has built 1,000+ apps. Get personalized help with your project.

Book a free consultation
Matt Graham

Written by

Matt Graham · CEO & Founder, RapidDev

1,000+ client projects delivered. Columbia University & Harvard Business School alumnus, U.S. Navy veteran. About the author →

Learning is great. Shipping is faster with help.

Our engineers have built 1,000+ apps on your platform and the tools around it. If your project needs to be live sooner than your learning curve allows — book a free consultation.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.