LangGraph para Agents: Construye IA Agéntica con State Machines (Guía Práctica 2025)

¿Quieres construir AI agents que ejecuten workflows complejos en producción? LangGraph es el framework líder para crear sistemas agénticos con state machines, usado por Klarna, Uber y LinkedIn. En esta guía aprenderás a construir agents con grafos stateful, control de flujo avanzado, y arquitecturas que escalan en producción.


¿Qué es LangGraph y Por Qué Lo Necesitas?

LangGraph es un framework de orquestación low-level diseñado para construir, gestionar y deployar sistemas de AI agents sofisticados. Desarrollado por el equipo de LangChain, LangGraph lleva los agents más allá de simples cadenas lineales hacia grafos stateful con control de flujo completo.

El Problema Que Resuelve

Cuando construyes AI agents en producción, los frameworks tradicionales te limitan:

    • Workflows lineales: Las cadenas (chains) solo van en una dirección, sin loops ni branching
    • Sin persistencia de estado: Cada invocación empieza desde cero, sin memoria entre pasos
    • Control de flujo limitado: No puedes implementar lógica condicional compleja o ciclos
    • Falta de observability: Difícil debuggear qué hizo el agent en cada paso

LangGraph resuelve todo esto con arquitectura de grafos stateful:

┌─────────────────────────────────────────────────────┐
│          Problema              Solución LangGraph   │
├─────────────────────────────────────────────────────┤
│ Workflows lineales    →   Grafos cíclicos          │
│ Sin estado           →   State machines stateful   │
│ Flujo fijo           →   Conditional routing       │
│ No debuggeable       →   Checkpoints + LangSmith   │
│ Falla sin recuperar  →   Durable execution         │
└─────────────────────────────────────────────────────┘

Casos de Uso Reales

Empresas usando LangGraph en producción:

Empresa Caso de Uso Escala
Klarna AI customer service 85M usuarios
Uber Automated support workflows Millones de requests/día
LinkedIn Content moderation agents Alto throughput
Replit Code generation pipelines Real-time coding
Elastic Data analysis workflows Enterprise scale

Paper oficial: LangGraph Documentation


State Machines: El Corazón de LangGraph

LangGraph modela agents como máquinas de estado (state machines), donde cada nodo procesa y actualiza un estado compartido.

Anatomía de un State Machine

┌──────────────────────────────────────────────┐
│          State Machine Workflow              │
├──────────────────────────────────────────────┤
│                                              │
│  START                                       │
│    │                                         │
│    ▼                                         │
│  ┌─────────────┐                            │
│  │  Node A     │  ──→ update state          │
│  │  (analyze)  │                            │
│  └─────────────┘                            │
│    │                                         │
│    ▼                                         │
│  ┌─────────────┐                            │
│  │  Node B     │  ──→ conditional           │
│  │  (decide)   │                            │
│  └─────────────┘                            │
│    │                                         │
│    ├──→ condition_true ──→ Node C           │
│    └──→ condition_false ──→ Node D          │
│                              │               │
│                              ▼               │
│                            END               │
└──────────────────────────────────────────────┘

Componentes Clave

1. State (Estado)
El estado es un objeto compartido que persiste a través del grafo. Se define como TypedDict:

from typing import TypedDict, List

class AgentState(TypedDict):
    messages: List[str]      # Historial de mensajes
    current_step: str        # Paso actual
    data: dict              # Datos procesados
    iterations: int         # Contador de iteraciones

2. Nodes (Nodos)
Cada nodo es una función que recibe el estado, lo procesa, y devuelve actualizaciones:

def analyze_node(state: AgentState) -> AgentState:
    """Analiza los datos del estado"""
    messages = state["messages"]
    # Procesar datos
    result = analyze_data(messages)

    return {
        "data": result,
        "current_step": "analysis_complete"
    }

3. Edges (Aristas)
Las aristas definen el flujo entre nodos:

    • Normal edges: Transiciones directas e incondicionales
    • Conditional edges: Branching basado en el estado
def route_decision(state: AgentState) -> str:
    """Decide el siguiente nodo basándose en el estado"""
    if state["data"]["confidence"] > 0.8:
        return "high_confidence_path"
    else:
        return "low_confidence_path"

Tu Primer Agent con LangGraph: Paso a Paso

Vamos a construir un agent de investigación que analiza preguntas, busca información, y genera respuestas.

Paso 1: Instalación

# Instalar LangGraph y dependencias
pip install langgraph langchain langchain-openai

# Variables de entorno
export OPENAI_API_KEY="tu-api-key"

Paso 2: Definir el Estado

from typing import TypedDict, Annotated, List
from langgraph.graph import StateGraph, START, END
from langchain_core.messages import HumanMessage, AIMessage

class ResearchState(TypedDict):
    """Estado del agent de investigación"""
    question: str                    # Pregunta original
    search_queries: List[str]        # Queries generadas
    search_results: List[dict]       # Resultados de búsqueda
    analysis: str                    # Análisis de resultados
    final_answer: str               # Respuesta final
    iterations: int                 # Contador de iteraciones

Paso 3: Crear Nodos de Procesamiento

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4", temperature=0)

def generate_queries_node(state: ResearchState) -> dict:
    """Genera queries de búsqueda optimizadas"""
    question = state["question"]

    prompt = f"""
    Genera 3 queries de búsqueda optimizadas para responder:
    {question}

    Devuelve solo las queries, una por línea.
    """

    response = llm.invoke(prompt)
    queries = response.content.strip().split("\n")

    return {
        "search_queries": queries,
        "iterations": state.get("iterations", 0) + 1
    }

def search_node(state: ResearchState) -> dict:
    """Simula búsqueda (en producción: usar Tavily, SerpAPI, etc.)"""
    queries = state["search_queries"]

    # Aquí irían llamadas reales a APIs de búsqueda
    results = []
    for query in queries:
        results.append({
            "query": query,
            "snippet": f"Resultado simulado para: {query}",
            "url": f"https://example.com/{query.replace(' ', '-')}"
        })

    return {"search_results": results}

def analyze_node(state: ResearchState) -> dict:
    """Analiza resultados y genera respuesta"""
    question = state["question"]
    results = state["search_results"]

    results_text = "\n".join([
        f"- {r['snippet']}" for r in results
    ])

    prompt = f"""
    Pregunta: {question}

    Resultados de búsqueda:
    {results_text}

    Genera una respuesta completa y precisa basada en estos resultados.
    """

    response = llm.invoke(prompt)

    return {
        "analysis": results_text,
        "final_answer": response.content
    }

Paso 4: Construir el Grafo

# Crear el grafo
workflow = StateGraph(ResearchState)

# Añadir nodos
workflow.add_node("generate_queries", generate_queries_node)
workflow.add_node("search", search_node)
workflow.add_node("analyze", analyze_node)

# Definir flujo con aristas
workflow.add_edge(START, "generate_queries")
workflow.add_edge("generate_queries", "search")
workflow.add_edge("search", "analyze")
workflow.add_edge("analyze", END)

# Compilar el grafo
app = workflow.compile()

Paso 5: Ejecutar el Agent

# Invocar el agent
result = app.invoke({
    "question": "¿Cuáles son las mejores prácticas para deployar LLMs en producción?",
    "iterations": 0
})

print("=== RESPUESTA FINAL ===")
print(result["final_answer"])
print(f"\nIteraciones: {result['iterations']}")
print(f"Queries generadas: {len(result['search_queries'])}")

Output esperado:

=== RESPUESTA FINAL ===
Para deployar LLMs en producción se recomienda:
1. Usar frameworks de inferencia optimizados como vLLM o TensorRT-LLM
2. Implementar caching de embeddings y prompts frecuentes
3. Configurar rate limiting y monitoring de costos
4. Usar quantization (GPTQ, AWQ) para reducir VRAM
5. Implementar fallbacks y retry logic con timeouts

Iteraciones: 1
Queries generadas: 3

Conditional Routing: Workflows Dinámicos

Lo potente de LangGraph es el routing condicional: el agent decide dinámicamente qué nodo ejecutar basándose en el estado.

Ejemplo: Agent con Auto-Corrección

from typing import Literal

class CodeReviewState(TypedDict):
    code: str
    issues: List[str]
    fixed_code: str
    attempts: int
    max_attempts: int

def review_code_node(state: CodeReviewState) -> dict:
    """Revisa el código y detecta issues"""
    code = state["code"]

    # En producción: usar LLM para análisis real
    issues = []
    if "import os" not in code and "subprocess" in code:
        issues.append("Falta import os")
    if "try:" not in code:
        issues.append("Falta manejo de errores")

    return {
        "issues": issues,
        "attempts": state["attempts"] + 1
    }

def fix_code_node(state: CodeReviewState) -> dict:
    """Intenta corregir el código"""
    code = state["code"]
    issues = state["issues"]

    # Simular corrección (en producción: LLM)
    fixed = code
    for issue in issues:
        if "import" in issue:
            fixed = "import os\n" + fixed
        if "try:" in issue:
            fixed = f"try:\n    {fixed}\nexcept Exception as e:\n    print(e)"

    return {"fixed_code": fixed, "code": fixed}

def should_continue(state: CodeReviewState) -> Literal["fix_code", "end"]:
    """Decide si continuar iterando o terminar"""
    if len(state["issues"]) == 0:
        return "end"
    elif state["attempts"] >= state["max_attempts"]:
        return "end"
    else:
        return "fix_code"

# Construir grafo con routing condicional
workflow = StateGraph(CodeReviewState)

workflow.add_node("review", review_code_node)
workflow.add_node("fix_code", fix_code_node)

workflow.add_edge(START, "review")
workflow.add_conditional_edges(
    "review",
    should_continue,
    {
        "fix_code": "fix_code",
        "end": END
    }
)
workflow.add_edge("fix_code", "review")  # Loop back

app = workflow.compile()

# Ejecutar
result = app.invoke({
    "code": "subprocess.run(['ls'])",
    "issues": [],
    "attempts": 0,
    "max_attempts": 3
})

print(f"Código corregido después de {result['attempts']} intentos:")
print(result['fixed_code'])

Human-in-the-Loop: Control Manual en Workflows

LangGraph permite pausar la ejecución para que un humano revise o modifique el estado.

Implementación con Checkpoints

from langgraph.checkpoint.sqlite import SqliteSaver

# Configurar persistencia
memory = SqliteSaver.from_conn_string(":memory:")

class ApprovalState(TypedDict):
    content: str
    approved: bool
    feedback: str

def generate_content_node(state: ApprovalState) -> dict:
    """Genera contenido que requiere aprobación"""
    content = "Este es el contenido generado automáticamente..."
    return {"content": content, "approved": False}

def approval_node(state: ApprovalState) -> dict:
    """Nodo de aprobación humana"""
    # En producción: mostrar UI para aprobación
    print(f"Contenido generado:\n{state['content']}\n")
    print("Esperando aprobación humana...")

    # Aquí el workflow se pausaría esperando input
    return {"approved": True}  # Simulado

def publish_node(state: ApprovalState) -> dict:
    """Publica solo si está aprobado"""
    if state["approved"]:
        print("✅ Contenido publicado!")
    return state

# Grafo con checkpointing
workflow = StateGraph(ApprovalState)
workflow.add_node("generate", generate_content_node)
workflow.add_node("approval", approval_node)
workflow.add_node("publish", publish_node)

workflow.add_edge(START, "generate")
workflow.add_edge("generate", "approval")
workflow.add_edge("approval", "publish")
workflow.add_edge("publish", END)

# Compilar con checkpointer
app = workflow.compile(checkpointer=memory)

# Ejecutar con thread_id para pausar/resumir
config = {"configurable": {"thread_id": "approval_flow_1"}}
result = app.invoke({"content": "", "approved": False}, config)

Multi-Agent Systems: Coordinación de Agents

LangGraph permite orquestar múltiples agents que colaboran en tareas complejas.

Ejemplo: Sistema de Investigación Multi-Agent

class MultiAgentState(TypedDict):
    task: str
    researcher_output: str
    writer_output: str
    reviewer_output: str
    final_report: str

def researcher_agent(state: MultiAgentState) -> dict:
    """Agent especializado en investigación"""
    task = state["task"]
    # Simular investigación profunda
    research = f"Investigación completa sobre: {task}"
    return {"researcher_output": research}

def writer_agent(state: MultiAgentState) -> dict:
    """Agent especializado en escritura"""
    research = state["researcher_output"]
    # Generar draft basado en investigación
    draft = f"Draft basado en:\n{research}"
    return {"writer_output": draft}

def reviewer_agent(state: MultiAgentState) -> dict:
    """Agent especializado en revisión"""
    draft = state["writer_output"]
    # Revisar y mejorar
    review = f"Versión revisada de:\n{draft}"
    return {"reviewer_output": review, "final_report": review}

# Grafo multi-agent
workflow = StateGraph(MultiAgentState)

workflow.add_node("researcher", researcher_agent)
workflow.add_node("writer", writer_agent)
workflow.add_node("reviewer", reviewer_agent)

# Pipeline secuencial
workflow.add_edge(START, "researcher")
workflow.add_edge("researcher", "writer")
workflow.add_edge("writer", "reviewer")
workflow.add_edge("reviewer", END)

app = workflow.compile()

result = app.invoke({
    "task": "Analizar tendencias de IA en 2025"
})

print(result["final_report"])

LangGraph vs Otros Frameworks: Comparativa 2025

Tabla Comparativa Detallada

Feature LangGraph CrewAI AutoGen OpenAI Agents SDK
Arquitectura Grafos stateful Role-based teams Conversational Function calling
Control de flujo ✅ Completo (conditional, loops) ⚠️ Limitado ✅ Bueno ⚠️ Básico
State management ✅ Nativo, persistente ⚠️ Básico ✅ Bueno ❌ No nativo
Production-ready ✅ Sí (Klarna, Uber) ⚠️ Emergente ✅ Sí (Microsoft) ⚠️ Nuevo (2024)
Learning curve 🔴 Alta (low-level) 🟢 Baja 🟡 Media 🟢 Baja
Observability ✅ LangSmith integration ⚠️ Básico ✅ Logging completo ⚠️ Beta
Checkpointing ✅ Nativo ❌ No ⚠️ Limitado ❌ No
Multi-agent ✅ Flexible ✅ Excelente ✅ Conversational ⚠️ Limitado
Precio 🟢 Open source 🟢 Open source 🟢 Open source 🟡 OpenAI pricing
Velocidad 🟡 Media 🟢 Rápida (5.7x vs LG*) 🟡 Media 🟢 Rápida
Mejor para Workflows complejos Prototipado rápido Enterprise + research Apps OpenAI-first

* Según benchmarks de CrewAI

Cuándo Usar LangGraph

✅ Usa LangGraph cuando:

    • Necesitas control total sobre el flujo de ejecución
    • Workflows complejos con branches, loops, y conditional logic
    • Requieres persistencia de estado entre ejecuciones
    • Deployando en producción con alta escala (ej: Klarna con 85M usuarios)
    • Necesitas human-in-the-loop workflows
    • Debugging y observability son críticos

❌ NO uses LangGraph si:

    • Quieres prototipado ultra-rápido (usa CrewAI)
    • Workflows simples lineales (usa LangChain Chains)
    • No tienes experiencia con grafos/state machines
    • Prefieres abstracciones de alto nivel

Patrones de Arquitectura Avanzados

1. Reflexión y Auto-Mejora

Agent que itera sobre su propia salida hasta alcanzar calidad:

class ReflectionState(TypedDict):
    task: str
    draft: str
    critique: str
    iterations: int
    max_iterations: int
    quality_score: float

def generate_draft(state: ReflectionState) -> dict:
    """Genera draft inicial"""
    return {
        "draft": f"Draft para: {state['task']}",
        "iterations": state["iterations"] + 1
    }

def critique_draft(state: ReflectionState) -> dict:
    """Critica el draft"""
    # En producción: LLM evalúa calidad
    score = 0.7 + (state["iterations"] * 0.1)  # Simular mejora
    critique = f"Score: {score}, necesita mejorar X, Y, Z"
    return {"critique": critique, "quality_score": score}

def should_continue(state: ReflectionState) -> Literal["generate", "end"]:
    if state["quality_score"] >= 0.9:
        return "end"
    elif state["iterations"] >= state["max_iterations"]:
        return "end"
    else:
        return "generate"

workflow = StateGraph(ReflectionState)
workflow.add_node("generate", generate_draft)
workflow.add_node("critique", critique_draft)

workflow.add_edge(START, "generate")
workflow.add_edge("generate", "critique")
workflow.add_conditional_edges(
    "critique",
    should_continue,
    {"generate": "generate", "end": END}
)

app = workflow.compile()

2. Subgrafos y Composición

Puedes componer grafos dentro de otros grafos:

def create_analysis_subgraph():
    """Subgrafo para análisis de datos"""
    subgraph = StateGraph(AnalysisState)
    subgraph.add_node("load_data", load_data_node)
    subgraph.add_node("clean_data", clean_data_node)
    subgraph.add_node("analyze", analyze_node)
    # ... configurar edges
    return subgraph.compile()

# Grafo principal que usa el subgrafo
main_workflow = StateGraph(MainState)
analysis_graph = create_analysis_subgraph()

main_workflow.add_node("preprocessing", preprocessing_node)
main_workflow.add_node("analysis", analysis_graph)  # ← Subgrafo como nodo
main_workflow.add_node("reporting", reporting_node)

3. Parallel Execution

Ejecutar múltiples nodos en paralelo:

from langgraph.graph import MessageGraph

def parallel_tasks_pattern(state: State) -> dict:
    """Pattern para ejecutar tareas en paralelo"""
    # LangGraph ejecuta nodos sin dependencias en paralelo
    return state

# Configurar nodos paralelos
workflow = StateGraph(State)
workflow.add_node("task_a", task_a_node)
workflow.add_node("task_b", task_b_node)
workflow.add_node("task_c", task_c_node)
workflow.add_node("merge", merge_results_node)

# Todos desde START en paralelo
workflow.add_edge(START, "task_a")
workflow.add_edge(START, "task_b")
workflow.add_edge(START, "task_c")

# Merge results
workflow.add_edge("task_a", "merge")
workflow.add_edge("task_b", "merge")
workflow.add_edge("task_c", "merge")
workflow.add_edge("merge", END)

Deployment en Producción

Opción 1: LangGraph Cloud

# Configurar para LangGraph Cloud
from langgraph.graph import StateGraph
from langgraph.checkpoint.postgres import PostgresSaver

# Usar PostgreSQL para checkpoints en producción
checkpointer = PostgresSaver.from_conn_string(
    "postgresql://user:pass@host:5432/db"
)

app = workflow.compile(checkpointer=checkpointer)

# Deploy a LangGraph Cloud
# Ver: https://langchain-ai.github.io/langgraph/cloud/

Opción 2: Docker Self-Hosted

# Dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"]
# api.py - FastAPI wrapper
from fastapi import FastAPI, BackgroundTasks
from langgraph.graph import StateGraph

app = FastAPI()
workflow = ...  # Tu grafo compilado

@app.post("/invoke")
async def invoke_agent(request: dict):
    result = workflow.invoke(request)
    return result

@app.post("/stream")
async def stream_agent(request: dict):
    for chunk in workflow.stream(request):
        yield chunk

Opción 3: Kubernetes

# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: langgraph-agent
spec:
  replicas: 3
  selector:
    matchLabels:
      app: langgraph-agent
  template:
    metadata:
      labels:
        app: langgraph-agent
    spec:
      containers:
      - name: agent
        image: your-registry/langgraph-agent:latest
        ports:
        - containerPort: 8000
        env:
        - name: OPENAI_API_KEY
          valueFrom:
            secretKeyRef:
              name: openai-secret
              key: api-key
        resources:
          requests:
            memory: "2Gi"
            cpu: "1"
          limits:
            memory: "4Gi"
            cpu: "2"

Monitoring y Observability con LangSmith

LangGraph se integra nativamente con LangSmith para debugging y observability.

Configuración Básica

import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "tu-langsmith-key"
os.environ["LANGCHAIN_PROJECT"] = "mi-agent-produccion"

# Ejecutar agent - todas las trazas van a LangSmith
result = app.invoke({"question": "..."})

Métricas Clave a Monitorear

# Custom metrics con callbacks
from langchain.callbacks import LangChainTracer

class ProductionMetrics(LangChainTracer):
    def on_chain_start(self, serialized, inputs, **kwargs):
        # Log inicio de chain
        print(f"Chain started: {serialized['name']}")

    def on_chain_end(self, outputs, **kwargs):
        # Log duración, tokens, costos
        duration = kwargs.get("duration_ms", 0)
        print(f"Chain completed in {duration}ms")

app = workflow.compile()
result = app.invoke(
    {"question": "..."},
    config={"callbacks": [ProductionMetrics()]}
)

Troubleshooting y Best Practices

Errores Comunes

1. Infinite Loops

# ❌ MAL: Sin límite de iteraciones
def should_continue(state):
    if state["done"]:
        return "end"
    return "continue"  # Puede loop infinito

# ✅ BIEN: Límite de seguridad
def should_continue(state):
    if state["done"] or state["iterations"] > 10:
        return "end"
    return "continue"

2. State No Actualizado

# ❌ MAL: Mutar estado directamente
def bad_node(state):
    state["value"] = 123  # No funciona
    return state

# ✅ BIEN: Retornar dict con updates
def good_node(state):
    return {"value": 123}  # LangGraph mergea

3. Memory Leaks con Checkpoints

# ✅ Limpiar checkpoints antiguos
from langgraph.checkpoint import CheckpointManager

manager = CheckpointManager(checkpointer)
manager.cleanup_old_checkpoints(days=7)

Best Practices

1. Diseño de Estado Mínimo

# ✅ Solo lo esencial
class GoodState(TypedDict):
    query: str
    result: str

# ❌ Demasiado complejo
class BadState(TypedDict):
    query: str
    intermediate_1: dict
    intermediate_2: list
    temp_var_a: str
    # ... 10 campos más

2. Timeouts en Nodos

import asyncio
from functools import wraps

def with_timeout(seconds):
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            return await asyncio.wait_for(
                func(*args, **kwargs),
                timeout=seconds
            )
        return wrapper
    return decorator

@with_timeout(30)
async def llm_node(state):
    # Este nodo tiene timeout de 30s
    result = await llm.ainvoke(prompt)
    return {"result": result}

3. Testing de Grafos

import pytest

def test_research_agent():
    app = create_research_agent()

    result = app.invoke({
        "question": "Test question",
        "iterations": 0
    })

    assert "final_answer" in result
    assert len(result["search_queries"]) > 0
    assert result["iterations"] == 1

def test_conditional_routing():
    app = create_conditional_agent()

    # Test path A
    result_a = app.invoke({"confidence": 0.9})
    assert result_a["path_taken"] == "high_confidence"

    # Test path B
    result_b = app.invoke({"confidence": 0.3})
    assert result_b["path_taken"] == "low_confidence"

Performance y Optimización

Benchmarks Reales (2025)

Según datos de producción de LangChain:

Métrica LangGraph v0.2 Mejora vs v0.1
Latencia media <200ms 40% faster
Throughput 1000+ req/s 3x mejora
Memory overhead ~50MB/grafo -60%
Checkpoint write 5-10ms 2x faster
Uptime (Klarna) 99.9% Production-proven

Optimizaciones Clave

1. Batch Processing

# Procesar múltiples requests en batch
results = []
for request in batch_requests:
    results.append(app.invoke(request))

# Mejor: Async batch
import asyncio

async def process_batch(requests):
    tasks = [app.ainvoke(req) for req in requests]
    return await asyncio.gather(*tasks)

results = asyncio.run(process_batch(batch_requests))

2. Caching de Resultados

from functools import lru_cache

@lru_cache(maxsize=1000)
def cached_llm_call(prompt: str) -> str:
    """Cache LLM calls con mismo prompt"""
    return llm.invoke(prompt).content

def smart_node(state):
    prompt = state["query"]
    result = cached_llm_call(prompt)  # Usa cache
    return {"result": result}

3. Streaming para UX

# Streaming de outputs intermedios
for chunk in app.stream({"question": "..."}):
    node_name = chunk.get("__node__")
    data = chunk.get("data", {})
    print(f"[{node_name}] {data}")
    # Enviar a frontend en real-time

Casos de Uso Avanzados

1. Code Generation Pipeline

class CodeGenState(TypedDict):
    requirements: str
    pseudocode: str
    code: str
    tests: str
    review: str
    final_code: str

workflow = StateGraph(CodeGenState)

workflow.add_node("plan", generate_pseudocode_node)
workflow.add_node("implement", generate_code_node)
workflow.add_node("test", generate_tests_node)
workflow.add_node("review", review_code_node)

# Pipeline con auto-corrección
workflow.add_edge(START, "plan")
workflow.add_edge("plan", "implement")
workflow.add_edge("implement", "test")
workflow.add_conditional_edges(
    "test",
    lambda s: "review" if s["tests_pass"] else "implement",
    {"review": "review", "implement": "implement"}
)
workflow.add_edge("review", END)

2. Data Analysis Agent

class AnalysisState(TypedDict):
    dataset_path: str
    data: pd.DataFrame
    insights: List[str]
    visualizations: List[str]
    report: str

def load_data(state):
    df = pd.read_csv(state["dataset_path"])
    return {"data": df}

def analyze_patterns(state):
    df = state["data"]
    insights = []
    # Análisis estadístico
    insights.append(f"Mean: {df.mean()}")
    insights.append(f"Std: {df.std()}")
    return {"insights": insights}

def generate_viz(state):
    # Generar visualizaciones
    return {"visualizations": ["chart1.png", "chart2.png"]}

def create_report(state):
    insights = state["insights"]
    viz = state["visualizations"]
    report = f"Report with {len(insights)} insights and {len(viz)} charts"
    return {"report": report}

3. Customer Support Agent

class SupportState(TypedDict):
    customer_message: str
    intent: str
    user_data: dict
    solution: str
    escalate: bool

def classify_intent(state):
    message = state["customer_message"]
    # Clasificar: technical, billing, general
    intent = "technical"  # Simulated
    return {"intent": intent}

def fetch_user_data(state):
    # Buscar datos del usuario en DB
    data = {"tier": "premium", "history": [...]}
    return {"user_data": data}

def route_to_solution(state):
    intent = state["intent"]
    if intent == "technical":
        return "technical_support"
    elif intent == "billing":
        return "billing_support"
    else:
        return "general_support"

workflow = StateGraph(SupportState)
workflow.add_node("classify", classify_intent)
workflow.add_node("fetch_data", fetch_user_data)
workflow.add_node("technical_support", technical_node)
workflow.add_node("billing_support", billing_node)
workflow.add_node("general_support", general_node)

workflow.add_edge(START, "classify")
workflow.add_edge("classify", "fetch_data")
workflow.add_conditional_edges(
    "fetch_data",
    route_to_solution,
    {
        "technical_support": "technical_support",
        "billing_support": "billing_support",
        "general_support": "general_support"
    }
)

Migración desde Otros Frameworks

Desde LangChain Chains

# Antes: LangChain Chain
from langchain.chains import LLMChain

chain = LLMChain(llm=llm, prompt=prompt)
result = chain.run(input="question")

# Después: LangGraph
def chain_as_node(state):
    result = llm.invoke(state["input"])
    return {"output": result.content}

workflow = StateGraph(State)
workflow.add_node("llm_step", chain_as_node)
workflow.add_edge(START, "llm_step")
workflow.add_edge("llm_step", END)

app = workflow.compile()
result = app.invoke({"input": "question"})

Desde CrewAI

# Antes: CrewAI
from crewai import Agent, Task, Crew

researcher = Agent(role="researcher", goal="research")
task = Task(description="research X", agent=researcher)
crew = Crew(agents=[researcher], tasks=[task])
result = crew.kickoff()

# Después: LangGraph (más control)
def researcher_node(state):
    # Mismo concepto pero más control de flujo
    research = do_research(state["task"])
    return {"research": research}

workflow = StateGraph(State)
workflow.add_node("researcher", researcher_node)
# ... más nodos y control fino

Recursos y Comunidad

Documentación Oficial

    • LangGraph Docs: https://langchain-ai.github.io/langgraph/
    • LangChain Docs: https://python.langchain.com/
    • LangSmith: https://docs.smith.langchain.com/

Repositorios de Ejemplo

    • LangGraph Examples: https://github.com/langchain-ai/langgraph-examples
    • Templates: https://github.com/langchain-ai/langgraph-template

Comunidad

    • Discord LangChain: https://discord.gg/langchain
    • GitHub Discussions: https://github.com/langchain-ai/langgraph/discussions
    • Twitter/X: @LangChainAI

Cursos y Tutoriales

    • DeepLearning.AI: AI Agents in LangGraph (curso gratuito)
    • LangChain Academy: Cursos oficiales
    • YouTube: Canal oficial de LangChain

Blogs Recomendados

    • Blog oficial de LangChain
    • Real Python tutorials
    • Towards Data Science (Medium)

Comparativa con Artículos Relacionados

Si te interesó LangGraph, estos artículos complementan tu conocimiento:


Preguntas Frecuentes (FAQs)

1. ¿LangGraph funciona solo con OpenAI o puedo usar otros LLMs?

LangGraph es agnóstico al modelo. Puedes usar:

    • Modelos OpenAI (GPT-4, GPT-3.5)
    • Anthropic Claude
    • Google Gemini
    • Modelos open-source (Llama, Mistral, etc.) vía Ollama o vLLM
    • Cualquier LLM compatible con LangChain
# Ejemplo con diferentes LLMs
from langchain_anthropic import ChatAnthropic
from langchain_community.llms import Ollama

# Claude
llm = ChatAnthropic(model="claude-3-sonnet")

# Ollama local
llm = Ollama(model="llama2")

# Usar en tus nodos
def node_with_claude(state):
    result = llm.invoke(state["prompt"])
    return {"output": result.content}

2. ¿Cuánto cuesta ejecutar agents con LangGraph en producción?

El costo depende principalmente de las llamadas a LLM, no de LangGraph (que es open-source):

Ejemplo de cálculo (GPT-4):

    • Input: $0.03 / 1K tokens
    • Output: $0.06 / 1K tokens
    • Agent típico: 3-5 llamadas LLM por request
    • Promedio: 2K tokens input + 500 tokens output por llamada
    • Costo por request: ~$0.20-$0.35

Optimizaciones para reducir costos:

    • Usar GPT-3.5-turbo para tareas simples ($0.001/1K tokens)
    • Implementar caching de prompts frecuentes
    • Usar modelos open-source locales para desarrollo
    • Batch processing cuando sea posible

3. ¿Puedo ejecutar LangGraph completamente offline/local?

, configurando todo el stack localmente:

# LLM local con Ollama
from langchain_community.llms import Ollama

llm = Ollama(model="llama2")

# Embeddings locales
from langchain_community.embeddings import OllamaEmbeddings

embeddings = OllamaEmbeddings(model="llama2")

# Vector store local
from langchain_community.vectorstores import Chroma

vectorstore = Chroma(
    persist_directory="./chroma_db",
    embedding_function=embeddings
)

# Checkpoints locales (SQLite)
from langgraph.checkpoint.sqlite import SqliteSaver

checkpointer = SqliteSaver.from_conn_string("./checkpoints.db")

# Todo local!
app = workflow.compile(checkpointer=checkpointer)

4. ¿Cómo debuggeo un agent que no funciona correctamente?

Estrategias de debugging:

    • Logging detallado en cada nodo:
def debug_node(state):
    print(f"Estado actual: {state}")
    result = process(state)
    print(f"Estado después: {result}")
    return result
    • LangSmith tracing:
os.environ["LANGCHAIN_TRACING_V2"] = "true"
# Ver trazas en https://smith.langchain.com/
    • Streaming de estados intermedios:
for step in app.stream({"input": "..."}):
    print(f"Paso: {step}")
    • Tests unitarios por nodo:
def test_specific_node():
    result = my_node({"input": "test"})
    assert result["output"] == "expected"

5. ¿LangGraph escala para millones de usuarios como Klarna?

, con arquitectura adecuada:

Klarna case study (85M usuarios):

    • Horizontal scaling con instancias stateless
    • PostgreSQL para checkpoints (no SQLite en prod)
    • Load balancing con NGINX/AWS ALB
    • Caching agresivo de prompts comunes
    • Rate limiting por usuario
    • Monitoring con Datadog/Grafana

Arquitectura tipo:

┌─────────────┐
│ Load        │
│ Balancer    │
└──────┬──────┘
       │
   ┌───┴───┬───────┬───────┐
   │       │       │       │
┌──▼──┐ ┌──▼──┐ ┌──▼──┐ ┌──▼──┐
│ Pod │ │ Pod │ │ Pod │ │ Pod │ (LangGraph instances)
└──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘
   │       │       │       │
   └───┬───┴───────┴───────┘
       │
┌──────▼──────────┐
│ PostgreSQL      │ (Shared checkpoints)
│ (Checkpoints)   │
└─────────────────┘

6. ¿Cuál es la diferencia entre LangGraph y LangChain?

Aspecto LangChain LangGraph
Propósito Chains lineales Grafos cíclicos
Control de flujo Secuencial Condicional + loops
Estado No persistente Stateful
Uso Apps simples Agents complejos
Nivel Alto nivel Bajo nivel

Cuándo usar cada uno:

    • LangChain: RAG simple, Q&A básico, pipelines lineales
    • LangGraph: Multi-step agents, workflows con decisiones, human-in-loop

7. ¿Necesito experiencia con grafos o state machines para usar LangGraph?

No es requisito, pero ayuda entender conceptos básicos:

Conceptos clave (fáciles de aprender):

    • Nodo: Una función que procesa datos
    • Arista: Conexión entre funciones
    • Estado: Datos que pasan entre funciones
    • Grafo: Conjunto de nodos + aristas

Aprende haciendo:

# Esto ya es un grafo válido:
workflow = StateGraph(State)
workflow.add_node("step1", my_function)
workflow.add_node("step2", another_function)
workflow.add_edge("step1", "step2")  # step1 → step2

# Si entiendes esto, puedes usar LangGraph!

8. ¿Puedo combinar LangGraph con LangChain components?

Absolutamente. LangGraph es compatible con todo el ecosistema LangChain:

from langchain.chains import RetrievalQA
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings

# Chain de LangChain como nodo de LangGraph
def retrieval_node(state):
    vectorstore = Chroma(...)
    qa_chain = RetrievalQA.from_chain_type(
        llm=llm,
        retriever=vectorstore.as_retriever()
    )
    result = qa_chain.run(state["question"])
    return {"answer": result}

# Usar en grafo
workflow.add_node("rag", retrieval_node)

9. ¿Qué pasa si un nodo falla en medio de la ejecución?

Con checkpointing, el agent puede resumir desde el último checkpoint:

from langgraph.checkpoint.sqlite import SqliteSaver

checkpointer = SqliteSaver.from_conn_string("./checkpoints.db")
app = workflow.compile(checkpointer=checkpointer)

try:
    result = app.invoke(
        {"input": "..."},
        config={"configurable": {"thread_id": "session_1"}}
    )
except Exception as e:
    print(f"Error: {e}")
    # Reintentar desde último checkpoint
    result = app.invoke(
        {"input": "..."},
        config={"configurable": {"thread_id": "session_1"}}
    )
    # Automáticamente resume desde donde falló

Sin checkpointing: El agent falla completamente y debe reiniciar.

10. ¿Cuánto tiempo toma aprender LangGraph?

Timeline realista:

    • 1-2 días: Conceptos básicos, primer agent simple funcionando
    • 1 semana: Dominar conditional routing, multi-node workflows
    • 2-3 semanas: Checkpointing, human-in-loop, patterns avanzados
    • 1-2 meses: Deployment en producción, optimización, scaling

Ruta de aprendizaje recomendada:

    • Tutorial oficial de LangChain (2h)
    • Documentación LangGraph (4h)
    • Construir 3-5 agents de ejemplo (1 semana)
    • Proyecto real pequeño (1 semana)
    • Deployment y producción (2 semanas)

11. ¿LangGraph es mejor que construir agents desde cero?

Depende del caso:

✅ Usa LangGraph si:

    • Necesitas checkpointing/persistencia nativo
    • Quieres integración con ecosistema LangChain
    • Valoras debugging con LangSmith
    • Deployando en producción rápido

❌ Construye desde cero si:

    • Tienes requisitos muy específicos que LangGraph no cubre
    • Quieres zero dependencies
    • Performance crítico (nanosegundos importan)
    • Ya tienes sistema custom funcionando

En general: LangGraph ahorra semanas de desarrollo vs. custom.

12. ¿Hay límites en el número de nodos o complejidad del grafo?

No hay límites técnicos duros, pero considera:

Best practices:

    • Nodos: < 20 nodos por grafo (más allá: usar subgrafos)
    • Profundidad: < 10 niveles de anidamiento
    • Estado: < 10 MB por state object
    • Iteraciones: Siempre poner límite máximo (ej: max_iterations=100)

Si necesitas más:

    • Dividir en subgrafos
    • Usar colas para procesamiento asíncrono
    • Implementar patterns de microservicios

13. ¿Puedo monetizar aplicaciones construidas con LangGraph?

, LangGraph tiene licencia MIT (completamente libre para uso comercial).

Modelos de monetización comunes:

    • SaaS con agents como servicio
    • APIs de agents especializados
    • Consultoría de implementación
    • Plugins/extensiones para plataformas

No hay royalties ni restricciones de uso comercial.

14. ¿Cómo manejo secrets y API keys de forma segura?

Best practices de seguridad:

# ✅ Variables de entorno
import os
api_key = os.getenv("OPENAI_API_KEY")

# ✅ Vaults (producción)
from azure.keyvault.secrets import SecretClient

client = SecretClient(vault_url, credential)
api_key = client.get_secret("openai-key").value

# ❌ NUNCA hardcodear
api_key = "sk-xxx..."  # MAL!

# ❌ NUNCA commitear a Git
# Usar .gitignore para .env files

Docker secrets:

# docker-compose.yml
services:
  app:
    image: langgraph-agent
    secrets:
      - openai_key
    environment:
      OPENAI_API_KEY_FILE: /run/secrets/openai_key

secrets:
  openai_key:
    file: ./secrets/openai.txt

15. ¿Dónde encuentro más ejemplos de código y templates?

Recursos oficiales:

    • GitHub LangGraph Examples: https://github.com/langchain-ai/langgraph-examples

      • 50+ ejemplos completos
      • Casos de uso reales
      • Templates production-ready
    • LangChain Templates: https://github.com/langchain-ai/langchain/tree/master/templates

      • Templates específicos por caso de uso
      • docker-compose incluido
    • LangSmith Hub: https://smith.langchain.com/hub

      • Prompts compartidos por la comunidad
      • Workflows testeados
    • Este blog:


Conclusión: El Futuro de los AI Agents

LangGraph representa el estado del arte en frameworks de IA agéntica para 2025. Su arquitectura basada en grafos stateful, combinada con checkpointing robusto y control de flujo completo, lo convierte en la elección ideal para construir agents que van a producción.

Puntos Clave

Flexibilidad: Control total sobre workflows complejos con conditional routing y loops
Production-Ready: Usado por Klarna (85M usuarios), Uber, LinkedIn en producción real
State Management: Persistencia nativa de estado entre ejecuciones
Observability: Integración con LangSmith para debugging profundo
Escalabilidad: Arquitectura probada para alto throughput y baja latencia

Próximos Pasos

    • Instala LangGraph y construye tu primer agent simple
    • Experimenta con conditional routing y human-in-the-loop
    • Deploy a producción con checkpointing y monitoring
    • Únete a la comunidad LangChain en Discord
    • Itera y mejora basándote en métricas reales

Recursos Finales

¿Listo para construir tu primer AI agent con LangGraph? Empieza con los ejemplos de código de este artículo y escala desde ahí. El futuro de la IA es agéntico, y LangGraph es tu mejor herramienta para construirlo.


¿Te gustó esta guía? Comparte con otros desarrolladores que estén construyendo AI agents. ¿Tienes dudas? Déjalas en los comentarios.

Tags: #LangGraph #AIAgents #LangChain #MachineLearning #Python #StateMachines #IA #AgenticAI #LLMs #Producción

Por ziru

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x
El Diario IA
Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.