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.
| Fact | Value |
|---|---|
| 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 |
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
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.
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.
1pip install langchain langgraph23from langchain.tools import tool45@tool6def 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.
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.
1from langchain.agents import create_agent23@tool4def 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"89agent = 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.
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.
1from langgraph.checkpoint.memory import InMemorySaver23agent = 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.
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.
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.
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).
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 the7# 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
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_agent5from langchain.tools import tool6from langgraph.checkpoint.memory import InMemorySaver78CALENDAR = {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}192021@tool22def 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'])}"282930@tool31def 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']}"373839SYSTEM_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)4445agent = 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)5152if __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", ""))60Common 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.
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]
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.
Talk to an Expert
Our team has built 1,000+ apps. Get personalized help with your project.
Book a free consultation