LangGraph e' diventato nel 2026 lo standard de facto per costruire agenti IA in Python: lo usano in produzione Klarna, LinkedIn, Uber e Replit, ed e' alla base di molti dei prodotti agentici che vediamo nelle suite enterprise di OpenAI, Anthropic e Google. Rispetto al primo LangChain, LangGraph porta un modello di esecuzione robusto: definisci uno stato tipizzato, nodi che leggono e scrivono quello stato, edge che dirigono il flusso, e ogni transizione viene salvata automaticamente su un checkpoint. Il risultato e' che l'agente sa sempre dov'e' arrivato, puoi metterlo in pausa e ripartire, mostrare i suoi passi all'utente, fare debug come su una macchina a stati.
In questo tutorial costruiamo - da zero - un agente di ricerca su prodotti tecnologici. Riceve una domanda dall'utente, decide se rispondere direttamente o se cercare informazioni sul web, esegue una ricerca con DuckDuckGo, ragiona sui risultati, eventualmente fa una seconda ricerca, e poi sintetizza la risposta. Il tutto con memoria persistente: se riavvii lo script, l'agente ricorda le conversazioni precedenti.
A chi serve, cosa otterrai, prerequisiti
Il tutorial e' pensato per sviluppatori Python che hanno familiarita' con virtualenv e pip, conoscono un LLM (GPT-5, Claude, Gemini, DeepSeek), e vogliono passare da chiamate isolate alle API alle pipeline strutturate. Al termine avrai uno script funzionante che fa girare un agente in locale, configurabile, esportabile e pronto a essere il cuore di un servizio piu' grande.
Prerequisiti reali:
- Python 3.11 o 3.12 installato. Su macOS:
brew install python@3.12. Su Linux: dal package manager. Su Windows: dall'installer ufficiale o da Microsoft Store. - Una chiave API per OpenAI o Anthropic. Useremo OpenAI come esempio, ma il codice e' identico in pratica per Anthropic - basta cambiare due righe.
- Editor di testo, anche solo VS Code.
- Un terminale: bash, zsh, PowerShell, indifferente.
Quale modello usare
LangGraph e' agnostico rispetto al modello: funziona con tutti quelli che hanno API. Per task agentici nel 2026 le tre prime scelte sono Claude Opus 4.7 (il piu' bravo nei task multi-step ma anche il piu' caro), GPT-5.5 (buon compromesso prezzo-velocita') e DeepSeek V4 (eccellente costo, buono il reasoning, ma piu' lento nei tool calls). Per imparare suggerisco GPT-5.5 mini o Claude Sonnet 4.5: pochi euro di credito permettono centinaia di esecuzioni del tutorial. Per esercizio finale, una volta che il codice funziona, prova a sostituire OpenAI con Anthropic - cambia solo l'import.
Passo 1 - Setup dell'ambiente
Crea una cartella e un virtualenv:
mkdir agente-langgraph && cd agente-langgraph
python3.12 -m venv .venv
source .venv/bin/activate # su Windows: .venv\Scripts\activate
pip install -U pip
pip install langgraph langchain langchain-openai langchain-community duckduckgo-search python-dotenv
Crea un file .env:
OPENAI_API_KEY=sk-...
Mai committarlo. Se preferisci Anthropic: pip install langchain-anthropic e usa ANTHROPIC_API_KEY.
Passo 2 - Definire lo stato
Lo stato e' il cuore di LangGraph. E' un TypedDict che descrive cosa l'agente conosce a un certo punto dell'esecuzione. Crea agent.py:
from typing import Annotated, Sequence, TypedDict
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
iterations: int
Il campo messages usa l'helper add_messages che gestisce il merge dei messaggi tra le iterazioni. iterations tiene il conto delle volte che l'agente ha ragionato: utile per evitare loop infiniti.
Passo 3 - Definire i tool
I tool sono le funzioni che l'agente puo' chiamare. Aggiungiamo una ricerca web:
from langchain_community.tools import DuckDuckGoSearchRun
from langchain_core.tools import tool
search = DuckDuckGoSearchRun()
@tool
def web_search(query: str) -> str:
"""Cerca su DuckDuckGo. Usa parole chiave brevi, non frasi lunghe."""
return search.invoke(query)
tools = [web_search]
La descrizione nei docstring conta: l'LLM la legge per capire quando chiamare il tool e come.
Passo 4 - Definire i nodi
Un nodo e' una funzione che prende lo stato e ne restituisce un aggiornamento parziale. Ne servono due: il "ragionatore" (l'LLM che decide cosa fare) e l'"esecutore tool".
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import ToolNode
from dotenv import load_dotenv
load_dotenv()
model = ChatOpenAI(model="gpt-5.5", temperature=0).bind_tools(tools)
def reasoner(state: AgentState):
response = model.invoke(state["messages"])
return {"messages": [response], "iterations": state.get("iterations", 0) + 1}
tool_node = ToolNode(tools)
Il ToolNode e' un nodo pre-costruito che esegue tool chiamati dal modello e ne restituisce gli output come ToolMessage.
Passo 5 - Costruire il grafo
Adesso il pezzo importante: collegare i nodi. Aggiungiamo un edge condizionale per decidere se chiamare un tool o terminare.
from langgraph.graph import StateGraph, END, START
def should_continue(state: AgentState):
last_msg = state["messages"][-1]
if state.get("iterations", 0) > 5:
return END # safety: dopo 5 giri, basta
if last_msg.tool_calls:
return "tools"
return END
workflow = StateGraph(AgentState)
workflow.add_node("reasoner", reasoner)
workflow.add_node("tools", tool_node)
workflow.add_edge(START, "reasoner")
workflow.add_conditional_edges("reasoner", should_continue)
workflow.add_edge("tools", "reasoner")
Passo 6 - Aggiungere memoria persistente
LangGraph offre dei "checkpoint saver". Usiamo SQLite per salvare lo stato fra esecuzioni:
from langgraph.checkpoint.sqlite import SqliteSaver
checkpointer = SqliteSaver.from_conn_string("agent_memory.db")
app = workflow.compile(checkpointer=checkpointer)
Il database agent_memory.db verra' creato al primo run. Ogni conversazione e' identificata da un thread_id: usando lo stesso thread, l'agente "ricorda" tutto.
Passo 7 - Eseguire l'agente
Aggiungiamo l'eseguibile in fondo a agent.py:
from langchain_core.messages import HumanMessage
if __name__ == "__main__":
config = {"configurable": {"thread_id": "sessione-test-1"}}
while True:
q = input("\n> ")
if q.lower() in ("exit", "quit", ""):
break
result = app.invoke(
{"messages": [HumanMessage(content=q)]},
config=config,
)
print("\nAgente:", result["messages"][-1].content)
Lancia:
python agent.py
Prova un prompt:
Qual e' la versione piu' recente di Python e quali sono le novita' chiave introdotte negli ultimi sei mesi?
L'agente capira' che la sua conoscenza non e' aggiornata, chiamera' web_search("Python latest version 2026 release notes"), leggera' i risultati, magari fara' una seconda ricerca per dettagli, e poi sintetizzera'. Tu vedrai solo l'output finale; per debuggare i passi intermedi attiva il tracing.
Passo 8 - Streaming e debugging
Per vedere i passi in tempo reale - utili per debug - sostituisci app.invoke con app.stream:
for chunk in app.stream({"messages": [HumanMessage(content=q)]}, config=config):
for node, value in chunk.items():
print(f"\n[{node}]", value.get("messages", [""])[-1].content[:300])
Per il tracing piu' avanzato, registrati gratis su LangSmith e aggiungi LANGSMITH_API_KEY al .env: ogni run sara' visualizzata in dashboard con tempi, costi e payload.
Varianti e casi avanzati
Una volta che il base agent gira, ecco alcune evoluzioni utili:
- Multi-agente: due nodi LLM con prompt diversi (es. "ricercatore" e "verificatore") che si passano lo stato.
- Strumenti reali: sostituisci DuckDuckGo con Tavily (piu' affidabile) o aggiungi una tool su un database aziendale (con SQL parametrizzato).
- Human-in-the-loop: usa
workflow.interrupt_before=["tools"]per chiedere conferma all'utente prima di eseguire un tool sensibile (es. inviare una mail, fare un acquisto). - Postgres invece di SQLite: per piu' utenti concorrenti, usa
PostgresSaverdella librerialanggraph-checkpoint-postgres. - Sostituire OpenAI con Anthropic:
from langchain_anthropic import ChatAnthropicemodel = ChatAnthropic(model="claude-opus-4-7").bind_tools(tools).
Errori comuni
- "Tool not found": il modello cita un tool che non esiste. Spesso e' perche' la docstring non e' chiara. Migliora la descrizione e l'esempio nel docstring del tool.
- Loop infinito di tool calls: l'agente continua a chiamare lo stesso tool. Il limite
iterations > 5nelloshould_continueimpedisce il disastro. Per evitarlo, dai prompt al modello con istruzioni chiare su quando smettere. - Output del tool troppo grande: se DuckDuckGo restituisce 10 KB di testo, il contesto LLM si satura. Trunc-a il risultato a 2-3 KB nel tool.
- Costi che esplodono: ogni iterazione spedisce tutta la storia al modello. Per agenti lunghi conviene fare prompt-caching (su Claude e' nativo) o riassumere i messaggi vecchi con un "reducer" node.
Alternative e quando NON usare LangGraph
LangGraph e' giusto quando il flusso e' complesso, ramificato, con stato. Se devi fare una sola chiamata a un modello, non serve. Per pipeline lineari basta langchain base. Per agenti molto verticali esistono framework piu' opinati (CrewAI per multi-agente, AutoGen di Microsoft, OpenAI Agents SDK). LangGraph rimane la scelta piu' flessibile e produzione-ready nel 2026.
Come proseguire
Adesso che il primo agente funziona, prova a renderlo utile: integralo dietro a un endpoint Flask o FastAPI per esporlo come API, collegalo a Slack o Telegram per parlarci da chat, deploya il tutto su Render o Railway. La documentazione ufficiale di LangGraph ha esempi completi per ogni pattern. Una settimana di esperimenti e' il tempo medio per arrivare a un agente "abbastanza buono" da risparmiarti due ore al giorno di lavoro ripetitivo. Inizia con un caso d'uso piccolo (es. uno script che ti riassume la posta del giorno) e cresci da li'.




