AI Agents Complete Guide 2026 — Build Autonomous Systems with LangGraph

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Introduction

Why This Matters

AI agents are the fastest-growing category of LLM applications in 2026. Unlike chatbots that respond once, agents take sequences of actions — browsing the web, running code, querying databases, sending emails — in a loop until a goal is complete.

The gap between a toy agent that sometimes works and a production agent that handles real users reliably is large. Production agents need robust tool definitions, error recovery, iteration limits, logging, and human-in-the-loop for high-risk actions. Building without these causes runaway agents that consume unbounded API credits and take unintended actions.

This guide covers the full stack: a minimal agent from scratch, stateful multi-step agents with LangGraph, multi-agent collaboration with AutoGen, and the production checklist that separates demos from deployments.

Simple ReAct Agent from Scratch

from openai import OpenAI
import json
 
client = OpenAI()
 
def calculator(expression: str) -> str:
    try:
        return str(eval(expression, {"__builtins__": {}}, {}))
    except Exception as e:
        return f"Error: {e}"
 
def search_web(query: str) -> str:
    return f"Search results for '{query}': [replace with real search API]"
 
TOOLS = {"calculator": calculator, "search_web": search_web}
 
TOOL_SCHEMAS = [
    {
        "type": "function",
        "function": {
            "name": "calculator",
            "description": "Evaluate mathematical expressions",
            "parameters": {"type": "object", "properties": {"expression": {"type": "string"}}, "required": ["expression"]},
        },
    },
    {
        "type": "function",
        "function": {
            "name": "search_web",
            "description": "Search the internet for current information",
            "parameters": {"type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"]},
        },
    },
]
 
def run_agent(task: str, max_iterations: int = 10) -> str:
    messages = [
        {"role": "system", "content": "You are a helpful AI agent. Use tools to accomplish tasks."},
        {"role": "user", "content": task},
    ]
 
    for i in range(max_iterations):
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=TOOL_SCHEMAS,
            tool_choice="auto",
        )
        msg = response.choices[0].message
        messages.append(msg)
 
        if response.choices[0].finish_reason == "stop":
            return msg.content
 
        if msg.tool_calls:
            for call in msg.tool_calls:
                result = TOOLS[call.function.name](**json.loads(call.function.arguments))
                messages.append({
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": str(result),
                })
 
    return "Max iterations reached"
 
print(run_agent("What is 15% of 847?"))

LangGraph: Stateful Multi-Step Agents

LangGraph is the production standard for complex agent workflows with cycles, branching, and persistent state:

from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from typing import TypedDict, Annotated
import operator
 
class AgentState(TypedDict):
    messages: Annotated[list, operator.add]
    step_count: int
 
llm = ChatOpenAI(model="gpt-4o")
 
def agent_node(state: AgentState) -> AgentState:
    response = llm.invoke(state["messages"])
    return {"messages": [response], "step_count": state["step_count"] + 1}
 
def should_continue(state: AgentState) -> str:
    last_message = state["messages"][-1]
    if state["step_count"] >= 5:
        return "end"
    if "FINAL ANSWER:" in last_message.content:
        return "end"
    return "continue"
 
workflow = StateGraph(AgentState)
workflow.add_node("agent", agent_node)
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue, {"continue": "agent", "end": END})
 
app = workflow.compile()
result = app.invoke({
    "messages": [HumanMessage(content="Plan a 3-step approach to analyze a CSV sales file")],
    "step_count": 0,
})
print(result["messages"][-1].content)

Multi-Agent Systems with AutoGen

AutoGen enables multiple specialized agents to collaborate — engineer writes code, critic reviews it:

import autogen
 
config_list = [{"model": "gpt-4o", "api_key": "your-key"}]
llm_config = {"config_list": config_list, "timeout": 60}
 
engineer = autogen.AssistantAgent(
    name="Engineer",
    llm_config=llm_config,
    system_message="You are a senior software engineer. Write clean, production-ready Python with type hints and docstrings.",
)
 
critic = autogen.AssistantAgent(
    name="Critic",
    llm_config=llm_config,
    system_message="You are a code reviewer. Find bugs, security issues, and performance problems. Be specific about line numbers.",
)
 
user_proxy = autogen.UserProxyAgent(
    name="User",
    human_input_mode="NEVER",
    max_consecutive_auto_reply=10,
    code_execution_config={"work_dir": "coding", "use_docker": False},
)
 
user_proxy.initiate_chat(
    engineer,
    message="Write a Python function that reads a large CSV file efficiently and returns summary statistics",
)

Agent Memory Patterns

from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
 
embeddings = OpenAIEmbeddings()
long_term_db = Chroma(persist_directory="./agent_memory", embedding_function=embeddings)
 
def remember(fact: str):
    long_term_db.add_texts([fact])
 
def recall(query: str, k: int = 3) -> list[str]:
    docs = long_term_db.similarity_search(query, k=k)
    return [d.page_content for d in docs]
 
def memory_agent(user_input: str) -> str:
    memories = recall(user_input)
    context = "\n".join(memories) if memories else "No relevant memories."
 
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": f"Relevant past context:\n{context}"},
            {"role": "user", "content": user_input},
        ],
    )
    answer = response.choices[0].message.content
    remember(f"User asked: {user_input[:100]}\nAnswer: {answer[:200]}")
    return answer

Common Mistakes / Pitfalls

  • No iteration limit — agents can loop indefinitely; always set max_iterations and enforce it
  • Tools without error handling — any tool can fail; return descriptive error strings instead of raising exceptions
  • No logging — you cannot debug a production agent that has no trace of what tools it called
  • Executing untrusted code without sandboxing — always run code tools in Docker containers
  • No budget guardrails — set a max API spend limit and halt agents that exceed it

Best Practices

  • Log every tool call, argument, and result to a structured audit trail
  • Implement a human-in-the-loop gate for high-risk actions (sending emails, making purchases, deleting data)
  • Use LangSmith or similar tracing for debugging multi-step agent behavior in development
  • Return structured errors from tools, not exceptions — agents handle strings, not Python exceptions
  • Set per-agent timeouts and global budget limits before deploying to production

Key Takeaways

  • A production AI agent requires tools, memory, planning, error recovery, and observability — not just LLM calls
  • The ReAct pattern (Reason + Act interleaved) is the standard architecture for single-agent loops
  • LangGraph supports stateful graphs with cycles, branching, and checkpointing for complex workflows
  • AutoGen enables multi-agent debate and collaboration where specialized agents check each other
  • Max iteration limits are non-negotiable — without them, buggy agents run forever and drain API budgets
  • Human-in-the-loop gates are required for any action with real-world side effects (emails, payments, deletions)
  • Vector store memory lets agents recall relevant past interactions without overloading the context window
  • LangSmith provides distributed tracing for every node in a multi-agent workflow

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading