In 2026, building an AI that can actually do things — query databases, send emails, browse the web, and make decisions — is the new baseline. This tutorial walks through constructing a fully autonomous agent using LangChain and Python, with LangGraph for stateful orchestration.
1. Setting Up Your Agent Foundation
Start by installing LangChain, LangGraph, and your preferred LLM provider. The core idea is to equip an LLM with tools it can invoke dynamically, then wrap it in a reasoning loop that decides when to act and when to respond.
pip install langchain langchain-openai langgraph # or for local models: pip install langchain-ollama
2. Defining Tools and Binding Them
Tools are Python functions with descriptive docstrings that the LLM reads to determine when to call them.
from langchain.tools import tool
import httpx
@tool
def search_web(query: str) -> str:
"""Search the web for current information."""
return httpx.get(f"https://api.duckduckgo.com/?q={query}").text
@tool
def calculate(expression: str) -> str:
"""Evaluate a mathematical expression."""
return str(eval(expression))
tools = [search_web, calculate]
3. Building the Agent Loop with LangGraph
LangGraph models the agent as a state graph. Each node is an action the agent can take, and edges represent transitions.
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated, Sequence
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
def agent_node(state: AgentState):
response = model.bind_tools(tools).invoke(state["messages"])
return {"messages": [response]}
def should_continue(state: AgentState):
last = state["messages"][-1]
if hasattr(last, "tool_calls") and last.tool_calls:
return "tools"
return END
workflow = StateGraph(AgentState)
workflow.add_node("agent", agent_node)
workflow.add_conditional_edges("agent", should_continue)
app = workflow.compile()
4. Adding Memory and Persistence
For production, agents need memory beyond a single session. Use BaseChatMemory or external stores like Redis or Postgres to persist conversation state across restarts.
“An agent without memory is just a fancy Q&A bot. Real autonomy comes from remembering context, user preferences, and past actions across sessions.”
5. Multi-Agent Orchestration
For complex tasks, split responsibilities across specialized agents — a research agent, a code-writing agent, a QA agent — and route messages between them using a supervisor graph. This pattern scales to enterprise-grade automation.
6. Deployment Considerations
Deploy your agent behind a FastAPI server with rate limiting, observability via LangSmith, and human-in-the-loop approval for sensitive tool calls like database writes or email sending.
from fastapi import FastAPI
app = FastAPI()
@app.post("/agent")
async def run_agent(message: str):
result = await app.ainvoke({"messages": [("user", message)]})
return {"response": result["messages"][-1].content}