AI Agents Complete Guide 2026: Build Autonomous Systems with LangGraph and AutoGen

Sanjeev SharmaSanjeev Sharma
4 min read

Advertisement

AI Agents in Production 2026

An AI agent is an LLM that can take actions — browse the web, write code, query databases, send emails — in a loop until a goal is achieved. This guide covers everything you need to build reliable production agents.

What Makes a Good Agent?

A production-ready agent needs:

  1. Tools — functions the LLM can call
  2. Memory — short-term (conversation) + long-term (vector store)
  3. Planning — ability to decompose complex tasks
  4. Error recovery — retry logic, fallbacks
  5. Observability — logging, tracing, evaluation

Simple ReAct Agent from Scratch

from openai import OpenAI
import json

client = OpenAI()

# Tool definitions
def calculator(expression: str) -> str:
    """Safely evaluate a math expression."""
    try:
        return str(eval(expression, {"__builtins__": {}}, {}))
    except Exception as e:
        return f"Error: {e}"

def search_web(query: str) -> str:
    """Simulate web search (replace with real search API)."""
    return f"Search results for '{query}': [relevant content here]"

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, and search for the current Python version?"))

LangGraph: Stateful Multi-Step Agents

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

from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage
from typing import TypedDict, Annotated
import operator

class AgentState(TypedDict):
    messages: Annotated[list, operator.add]
    step_count: int
    final_answer: str | None

llm = ChatOpenAI(model="gpt-4o")

def agent_node(state: AgentState) -> AgentState:
    """Call the LLM with current messages."""
    response = llm.invoke(state["messages"])
    return {
        "messages": [response],
        "step_count": state["step_count"] + 1,
        "final_answer": None,
    }

def should_continue(state: AgentState) -> str:
    """Decide whether to continue or end."""
    last_message = state["messages"][-1]
    if state["step_count"] >= 5:
        return "end"
    if "FINAL ANSWER:" in last_message.content:
        return "end"
    return "continue"

# Build the graph
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 process to analyze a CSV file with sales data")],
    "step_count": 0,
    "final_answer": None,
})
print(result["messages"][-1].content)

Multi-Agent Systems with AutoGen

AutoGen enables multiple AI agents to collaborate and debate:

import autogen

config_list = [{"model": "gpt-4o", "api_key": "your-key"}]
llm_config = {"config_list": config_list, "timeout": 60}

# Define specialized agents
engineer = autogen.AssistantAgent(
    name="Engineer",
    llm_config=llm_config,
    system_message="""You are a senior software engineer.
    Write clean, production-ready Python code with proper error handling.
    Always include type hints and docstrings.""",
)

critic = autogen.AssistantAgent(
    name="Critic",
    llm_config=llm_config,
    system_message="""You are a code reviewer who finds bugs, security issues, and performance problems.
    Be specific about line numbers and provide concrete improvements.""",
)

user_proxy = autogen.UserProxyAgent(
    name="User",
    human_input_mode="NEVER",
    max_consecutive_auto_reply=10,
    code_execution_config={"work_dir": "coding", "use_docker": False},
)

# Start the conversation
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.memory import ConversationBufferWindowMemory
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

# Short-term memory: last N messages
short_term = ConversationBufferWindowMemory(k=10, return_messages=True)

# Long-term memory: vector store of important facts
embeddings = OpenAIEmbeddings()
long_term_db = Chroma(persist_directory="./agent_memory", embedding_function=embeddings)

def remember(fact: str):
    """Store important information for later."""
    long_term_db.add_texts([fact])

def recall(query: str, k: int = 3) -> list[str]:
    """Retrieve relevant memories."""
    docs = long_term_db.similarity_search(query, k=k)
    return [d.page_content for d in docs]

# Agent with memory
def memory_agent(user_input: str) -> str:
    # Recall relevant past context
    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

    # Store key facts from this interaction
    remember(f"User asked: {user_input}\nAnswer: {answer[:200]}")
    return answer

Production Agent Checklist

  • Timeouts: Set max execution time per tool call
  • Retry logic: Exponential backoff on API failures
  • Logging: Log every tool call and LLM response
  • Human-in-the-loop: Flag high-risk actions for approval
  • Rate limiting: Prevent runaway agents from blowing your API budget
  • Evaluation: Test with a suite of known tasks and expected outcomes
  • Sandboxing: Run code execution in Docker containers

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro