R_REDDYX.XYZ
Agents2026-06-29

How to build an AI agent from scratch in 2026: full guide with code

How to build an AI agent from scratch in 2026: full guide with code
TL;DR: AI-agent is not magic, but a cycle 'model → tool → result → model', wrapped in state management. In 2026, a basic working agent in Python with tool calling can be built in 40 lines, and a reliable production agent — on LangGraph with an explicit state graph. Below is the full path: from bare API to a graph with memory, plus a comparison of frameworks and runnable code.

WHAT IS AN AI-AGENT REALLY

Let's discard marketing. An AI-agent is a language model given the right to call functions and act in a loop until the task is solved. That's it. A chatbot answers once. An agent answers, calls a tool, looks at the result, decides what to do next — and repeats.

Three mandatory components of any agent:

  • Model (LLM) — the 'brain', makes decisions. GPT-class, Claude, local Qwen/Llama — doesn't matter, important is support for function calling.
  • Tools — functions the agent can call: search, calculator, HTTP request, DB write, code execution.
  • Control loop (loop) — code that drives the model and tools in a loop, stores history, and decides when to stop.

The keyword of 2026 is tool calling (aka function calling). The model does not execute code itself. It returns JSON like «I want to call function get_weather with argument city=Berlin», and your code executes it and returns the result back. Understand this mechanism — you'll grasp 80% of all agent frameworks.

MINIMAL AGENT WITHOUT FRAMEWORKS

Before reaching for LangGraph, build the agent with your bare hands. This disciplines you: you'll see that a framework is just a convenient wrapper over this loop. Here's a working example in Python with one tool.

import json
from openai import OpenAI

client = OpenAI()

def get_weather(city: str) -> str:
    # заглушка вместо реального API
    return f"В городе {city} сейчас +7 и облачно"

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Вернуть текущую погоду в городе",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

def run_agent(user_msg: str) -> str:
    messages = [{"role": "user", "content": user_msg}]
    while True:
        resp = client.chat.completions.create(
            model="gpt-4.1-mini",
            messages=messages,
            tools=tools,
        )
        msg = resp.choices[0].message
        messages.append(msg)
        if not msg.tool_calls:
            return msg.content  # модель закончила — выходим
        for call in msg.tool_calls:
            args = json.loads(call.function.arguments)
            result = get_weather(**args)
            messages.append({
                "role": "tool",
                "tool_call_id": call.id,
                "content": result,
            })

print(run_agent("Что надеть в Берлине сегодня?"))

That's the whole agent. The while True loop — that's what 'agency' is. The model either calls a tool (and we return the result to it), or it gives a final answer (and we exit). Everything else is just extensions on this pattern.

WHY FRAMEWORKS AT ALL

A raw loop breaks on real tasks. As soon as you need branching, retries, human-in-the-loop, parallel tools, persistent memory between sessions, and observability — you start rewriting half the framework yourself. It's easier to take a ready-made one.

What frameworks provide on top of the manual loop:

  1. State management — history, intermediate results, context stays intact.
  2. Flow control — conditional branches, loops with limits, rollbacks.
  3. Persistence — saving state to a DB so the agent survives a restart.
  4. Observability — tracing each step, which is critical for debugging.

FRAMEWORK COMPARISON 2026

The market has settled. There are three dominant approaches: graph-based (LangGraph), declaratively simple (multi-agent SDKs), and 'magic under the hood'. Below is an honest comparison based on practice, without vendor slogans.

FrameworkControl ModelLearning CurveWhen to Use
LangGraphExplicit state graph (nodes + edges)MediumProduction, complex logic, control needed
OpenAI Agents SDKHandoffs between agentsLowQuick start, multi-agent scenarios
CrewAIRoles + tasks (agent team)LowPrototypes, 'team of specialists'
Raw Python + APIManual loopHigh (you write everything yourself)Learning, maximum control, minimum dependencies

My practical conclusion for 2026: LangGraph won the serious production niche because it makes state and transitions explicit — you see the graph, not guess what's happening inside a 'smart' abstraction. For a quick prototype, grab a simpler SDK. Fresh releases of agent tools and wrappers are conveniently tracked in the REDDYX catalog — there you can see what actually takes off and what's hype for a week.

BUILDING AN AGENT WITH LANGGRAPH

LangGraph models an agent as a graph: nodes are steps (model call, tool call), edges are transitions between them. The same loop we wrote by hand, but declaratively and with persistence out of the box.

Basic graph with one tool

from langgraph.graph import StateGraph, END, MessagesState
from langgraph.prebuilt import ToolNode
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool

@tool
def search_docs(query: str) -> str:
    """Найти информацию в базе знаний по запросу."""
    return f"Найдено 3 документа по теме '{query}'"

llm = ChatOpenAI(model="gpt-4.1-mini").bind_tools([search_docs])

def call_model(state: MessagesState):
    return {"messages": [llm.invoke(state["messages"])]}

def should_continue(state: MessagesState):
    last = state["messages"][-1]
    return "tools" if last.tool_calls else END

graph = StateGraph(MessagesState)
graph.add_node("agent", call_model)
graph.add_node("tools", ToolNode([search_docs]))
graph.set_entry_point("agent")
graph.add_conditional_edges("agent", should_continue)
graph.add_edge("tools", "agent")   # после инструмента — снова к модели

app = graph.compile()
out = app.invoke({"messages": [("user", "Как настроить вебхуки?")]})
print(out["messages"][-1].content)

Note the should_continue — this is the loop exit condition, extracted into a separate node. The tools → agent edge closes the loop. You literally see the architecture with your eyes, not in your head.

Adding memory between sessions

To make the agent remember the conversation after a restart, connect a checkpointer. One line turns a stateless agent into a stateful one:

from langgraph.checkpoint.memory import MemorySaver
# для продакшена: from langgraph.checkpoint.postgres import PostgresSaver

app = graph.compile(checkpointer=MemorySaver())
config = {"configurable": {"thread_id": "user-42"}}

app.invoke({"messages": [("user", "Меня зовут Влад")]}, config)
r = app.invoke({"messages": [("user", "Как меня зовут?")]}, config)
print(r["messages"][-1].content)  # агент помнит: "Влад"

In prod, replace MemorySaver with PostgresSaver — state goes to the database, and the agent survives deployment. thread_id isolates dialogs of different users.

WHAT BREAKS AGENTS IN PRODUCTION

A demo on a laptop and an agent in prod are two different universes. Based on community experience and my own hard-earned lessons, here are the main pitfalls:

  • Infinite loops. The model gets stuck in a tool call loop. Always set a hard iteration limit (e.g., recursion_limit in LangGraph). Without it, the agent will burn through the budget in minutes.
  • Context bloat. History grows, tokens grow, cost grows quadratically. Trim old messages or summarize them.
  • Hallucinated arguments. The model invents non-existent tool parameters. Validate input via Pydantic before execution.
  • Silent tool failures. API went down — return error text to the agent, not an exception. It often knows how to try another path.
  • No tracing. Without a step-by-step log, you won't understand why the agent made a dumb decision. Set up observability from day one.

By rough community estimates, a naive agent without loop control and context trimming easily spends 3–5 times more tokens than needed. Discipline in state management is direct money savings.

TOOL DESIGN — WHERE SUCCESS IS DECIDED

Secret, which tutorials keep silent about: the quality of an agent depends 70% not on the model, but on design of tools. The model is as smart as its function descriptions are understandable to it.

  • Write descriptions for the model, not for people. Clear «Return account balance in USD by user ID» beats dry «get_balance».
  • One tool — one action. Don’t make a «Swiss army knife» with ten modes. The model gets confused.
  • Return structured result. JSON or clear text, not a raw dump of 5000 tokens.
  • Make tools idempotent, where possible. The agent may call the function twice — this should not break data.

Practice: start with 2–3 tools. An agent with five well-described functions is more reliable than with thirty vague ones. Expand only when the bottleneck is genuinely a lack of capability, not poorly written descriptions.

Frequently asked questions

Do you need to know LangChain to work with LangGraph?

No, deep knowledge is not required. LangGraph — a standalone library for state graphs. It's enough to understand basic message objects and how tools are connected. You can start directly from the graph example above without studying the whole LangChain.

Which language is better for an AI agent — Python or JavaScript?

Python — the de facto standard in 2026: maximum libraries, examples, and framework support. JavaScript/TypeScript is justified if the agent lives inside a web application or if a unified codebase for front-end and back-end is critical. For learning and ML tasks, choose Python.

How much does it cost to run an AI agent?

Depends on the model and number of steps. Small mini-level models cost pennies per request, but the agent makes many calls in a loop, so the total cost adds up. The main levers for savings — iteration limit, context trimming, and choosing a cheap model where maximum accuracy is not needed.

Can an agent be built on a local model without the cloud?

Yes. Local models with tool calling support (Qwen, Llama-class) via Ollama or vLLM work with the same patterns. Function calling in local models is weaker than in cloud models, so simplify tools and validate their arguments more thoroughly.

If you want to see which agent frameworks, MCP servers, and AI tools really take off, rather than drowning in hype — I post fresh finds from GitHub without fluff. Telegram channel REDDYX AI — new repositories every 30-60 minutes.

New repositories every 30 minutes

REDDYX AI scans GitHub 24/7 and ships the best AI/ML/Web3 projects to Telegram.

Join on Telegram

← All articles

How to build an AI agent from scratch in 2026: full guide with code | REDDYX AI