Guía paso a paso para construir un agente de IA múltiple personalizable con Langgraph y Claude para la creación de agentes dinámicos

En este tutorial integral, guiamos a los usuarios a través de la creación de un potente agente de IA múltiples de herramientas que usa Langgraph y Claude, optimizado para diversas tareas que incluyen cálculos matemáticos, búsquedas en la web, consultas meteorológicas, análisis de texto y recuperación de información en tiempo real. Comienza simplificando las instalaciones de dependencia para garantizar una configuración sin esfuerzo, incluso para principiantes. Luego se introduce a los usuarios a implementaciones estructuradas de herramientas especializadas, como una calculadora segura, una utilidad eficiente de búsqueda en la web que aprovecha DuckDuckgo, un proveedor de información meteorológica simulada, un analizador de texto detallado y una función de recolección de tiempo. El tutorial también delinea claramente la integración de estas herramientas dentro de una arquitectura de agente sofisticada construida con Langgraph, que ilustra el uso práctico a través de ejemplos interactivos y explicaciones claras, facilitando a los principiantes y desarrolladores avanzados para implementar agentes de IA multifuncionales personalizados rápidamente.

import subprocess
import sys


def install_packages():
    packages = [
        "langgraph",
        "langchain",
        "langchain-anthropic",
        "langchain-community",
        "requests",
        "python-dotenv",
        "duckduckgo-search"
    ]
   
    for package in packages:
        try:
            subprocess.check_call([sys.executable, "-m", "pip", "install", package, "-q"])
            print(f"✓ Installed {package}")
        except subprocess.CalledProcessError:
            print(f"✗ Failed to install {package}")


print("Installing required packages...")
install_packages()
print("Installation complete!\n")

Automatizamos la instalación de paquetes esenciales de Python requeridos para construir un agente de IA múltiple basado en Langgraph. Aprovecha un subproceso para ejecutar los comandos PIP en silencio y garantiza que cada paquete, que va desde componentes de cadena larga hasta herramientas de búsqueda y manejo de entornos web, se instala correctamente. Esta configuración optimiza el proceso de preparación del entorno, que hace que el cuaderno sea portátil y amigable para principiantes.

import os
import json
import math
import requests
from typing import Dict, List, Any, Annotated, TypedDict
from datetime import datetime
import operator


from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, ToolMessage
from langchain_core.tools import tool
from langchain_anthropic import ChatAnthropic
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import ToolNode
from langgraph.checkpoint.memory import MemorySaver
from duckduckgo_search import DDGS

Importamos todas las bibliotecas y módulos necesarios para construir el agente de IA de múltiples toallas. Incluye bibliotecas estándar de Python como OS, JSON, MATH y DateTime para la funcionalidad de uso general y bibliotecas externas como solicitudes de llamadas HTTP y DuckDuckgo_Search para implementar la búsqueda web. Los ecosistemas de Langchain y Langgraph traen tipos de mensajes, decoradores de herramientas, componentes de gráficos de estado y utilidades de control de control, mientras que Chatanthrope permite la integración con el modelo Claude para la inteligencia conversacional. Estas importaciones forman los bloques de construcción fundamentales para definir herramientas, flujos de trabajo de agentes e interacciones.

os.environ["ANTHROPIC_API_KEY"] = "Use Your API Key Here"


ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY")

Establecemos y recuperamos la tecla API antrópica requerida para autenticar e interactuar con los modelos Claude. La línea OS.environ asigna su clave API (que debe reemplazar con una clave válida), mientras que OS.GetEnv la recupera de forma segura para su uso posterior en la inicialización del modelo. Este enfoque asegura que la clave sea accesible en todo el script sin codificarla varias veces.

from typing import TypedDict


class AgentState(TypedDict):
    messages: Annotated[List[BaseMessage], operator.add]


@tool
def calculator(expression: str) -> str:
    """
    Perform mathematical calculations. Supports basic arithmetic, trigonometry, and more.
   
    Args:
        expression: Mathematical expression as a string (e.g., "2 + 3 * 4", "sin(3.14159/2)")
   
    Returns:
        Result of the calculation as a string
    """
    try:
        allowed_names = {
            'abs': abs, 'round': round, 'min': min, 'max': max,
            'sum': sum, 'pow': pow, 'sqrt': math.sqrt,
            'sin': math.sin, 'cos': math.cos, 'tan': math.tan,
            'log': math.log, 'log10': math.log10, 'exp': math.exp,
            'pi': math.pi, 'e': math.e
        }
       
        expression = expression.replace('^', '**')  
       
        result = eval(expression, {"__builtins__": {}}, allowed_names)
        return f"Result: {result}"
    except Exception as e:
        return f"Error in calculation: {str(e)}"

Definimos el estado interno del agente e implementamos una herramienta de calculadora robusta. La clase AgentState usa Typeddict para estructurar la memoria del agente, rastreando específicamente los mensajes intercambiados durante la conversación. La función de la calculadora, decorada con @Tool para registrarla como una utilidad utilizable en AI, evalúa de forma segura expresiones matemáticas. Permite el cálculo seguro al limitar las funciones disponibles a un conjunto predefinido del módulo de matemáticas y reemplazar la sintaxis común como ^ con el operador de exponenciación de Python. Esto asegura que la herramienta pueda manejar funciones aritméticas y avanzadas simples como trigonometría o logaritmos al tiempo que evita la ejecución de código inseguro.

@tool
def web_search(query: str, num_results: int = 3) -> str:
    """
    Search the web for information using DuckDuckGo.
   
    Args:
        query: Search query string
        num_results: Number of results to return (default: 3, max: 10)
   
    Returns:
        Search results as formatted string
    """
    try:
        num_results = min(max(num_results, 1), 10)  
       
        with DDGS() as ddgs:
            results = list(ddgs.text(query, max_results=num_results))
       
        if not results:
            return f"No search results found for: {query}"
       
        formatted_results = f"Search results for '{query}':\n\n"
        for i, result in enumerate(results, 1):
            formatted_results += f"{i}. **{result['title']}**\n"
            formatted_results += f"   {result['body']}\n"
            formatted_results += f"   Source: {result['href']}\n\n"
       
        return formatted_results
    except Exception as e:
        return f"Error performing web search: {str(e)}"

Definimos una herramienta Web_Search que permite al agente obtener información en tiempo real de Internet utilizando la API de búsqueda de DuckDuckgo a través del paquete PuckDuckGo_Search Python. La herramienta acepta una consulta de búsqueda y un parámetro opcional num_results, asegurando que el número de resultados devueltos sea entre 1 y 10. Abre una sesión de búsqueda de Duckduckgo, recupera los resultados y los formatea perfectamente para una pantalla amigable para el usuario. Si no se encuentran resultados o se produce un error, la función la maneja con gracia devolviendo un mensaje informativo. Esta herramienta equipa al agente con capacidades de búsqueda en tiempo real, mejorando la capacidad de respuesta y la utilidad.

@tool
def weather_info(city: str) -> str:
    """
    Get current weather information for a city using OpenWeatherMap API.
    Note: This is a mock implementation for demo purposes.
   
    Args:
        city: Name of the city
   
    Returns:
        Weather information as a string
    """
    mock_weather = {
        "new york": {"temp": 22, "condition": "Partly Cloudy", "humidity": 65},
        "london": {"temp": 15, "condition": "Rainy", "humidity": 80},
        "tokyo": {"temp": 28, "condition": "Sunny", "humidity": 70},
        "paris": {"temp": 18, "condition": "Overcast", "humidity": 75}
    }
   
    city_lower = city.lower()
    if city_lower in mock_weather:
        weather = mock_weather[city_lower]
        return f"Weather in {city}:\n" \
               f"Temperature: {weather['temp']}°C\n" \
               f"Condition: {weather['condition']}\n" \
               f"Humidity: {weather['humidity']}%"
    else:
        return f"Weather data not available for {city}. (This is a demo with limited cities: New York, London, Tokyo, Paris)"

Definimos una herramienta Weather_Info que simula la recuperación de datos meteorológicos actuales para una ciudad determinada. Si bien no se conecta a una API meteorológica en vivo, utiliza un diccionario predefinido de datos simulados para las principales ciudades como Nueva York, Londres, Tokio y París. Al recibir un nombre de la ciudad, la función lo normaliza a minúsculas y verifica su presencia en el conjunto de datos simulados. Devuelve la temperatura, la condición climática y la humedad en un formato legible si se encuentra. De lo contrario, notifica al usuario que los datos meteorológicos no están disponibles. Esta herramienta sirve como marcador de posición y luego se puede actualizar para obtener datos en vivo de una API meteorológica real.

@tool
def text_analyzer(text: str) -> str:
    """
    Analyze text and provide statistics like word count, character count, etc.
   
    Args:
        text: Text to analyze
   
    Returns:
        Text analysis results
    """
    if not text.strip():
        return "Please provide text to analyze."
   
    words = text.split()
    sentences = text.split('.') + text.split('!') + text.split('?')
    sentences = [s.strip() for s in sentences if s.strip()]
   
    analysis = f"Text Analysis Results:\n"
    analysis += f"• Characters (with spaces): {len(text)}\n"
    analysis += f"• Characters (without spaces): {len(text.replace(' ', ''))}\n"
    analysis += f"• Words: {len(words)}\n"
    analysis += f"• Sentences: {len(sentences)}\n"
    analysis += f"• Average words per sentence: {len(words) / max(len(sentences), 1):.1f}\n"
    analysis += f"• Most common word: {max(set(words), key=words.count) if words else 'N/A'}"
   
    return analysis

La herramienta Text_Analyzer proporciona un análisis estadístico detallado de una entrada de texto dada. Calcula métricas como el recuento de caracteres (con y sin espacios), el recuento de palabras, el recuento de oraciones y las palabras promedio por oración, e identifica la palabra más frecuente. La herramienta maneja la entrada vacía con gracia al solicitar al usuario que proporcione un texto válido. Utiliza operaciones de cadena simples y el conjunto de Python y las funciones Max para extraer ideas significativas. Es una utilidad valiosa para el análisis del idioma o las verificaciones de calidad de contenido en el kit de herramientas del agente de inteligencia artificial.

@tool
def current_time() -> str:
    """
    Get the current date and time.
   
    Returns:
        Current date and time as a formatted string
    """
    now = datetime.now()
    return f"Current date and time: {now.strftime('%Y-%m-%d %H:%M:%S')}"

La herramienta Current_Time proporciona una forma directa de recuperar la fecha y hora del sistema actual en un formato legible por humanos. Usando el módulo de fecha y hora de Python, captura el momento presente y lo formatea como aaaa yyyy-mm-dd hh: mm: ss. Esta utilidad es particularmente útil para respuestas de estampado de tiempo o responder consultas de los usuarios sobre la fecha y hora actuales dentro del flujo de interacción del agente de IA.

tools = [calculator, web_search, weather_info, text_analyzer, current_time]


def create_llm():
    if ANTHROPIC_API_KEY:
        return ChatAnthropic(
            model="claude-3-haiku-20240307",  
            temperature=0.1,
            max_tokens=1024
        )
    else:
        class MockLLM:
            def invoke(self, messages):
                last_message = messages[-1].content if messages else ""
               
                if any(word in last_message.lower() for word in ['calculate', 'math', '+', '-', '*', '/', 'sqrt', 'sin', 'cos']):
                    import re
                    numbers = re.findall(r'[\d\+\-\*/\.\(\)\s\w]+', last_message)
                    expr = numbers[0] if numbers else "2+2"
                    return AIMessage(content="I'll help you with that calculation.",
                                   tool_calls=[{"name": "calculator", "args": {"expression": expr.strip()}, "id": "calc1"}])
                elif any(word in last_message.lower() for word in ['search', 'find', 'look up', 'information about']):
                    query = last_message.replace('search for', '').replace('find', '').replace('look up', '').strip()
                    if not query or len(query) < 3:
                        query = "python programming"
                    return AIMessage(content="I'll search for that information.",
                                   tool_calls=[{"name": "web_search", "args": {"query": query}, "id": "search1"}])
                elif any(word in last_message.lower() for word in ['weather', 'temperature']):
                    city = "New York"
                    words = last_message.lower().split()
                    for i, word in enumerate(words):
                        if word == 'in' and i + 1 < len(words):
                            city = words[i + 1].title()
                            break
                    return AIMessage(content="I'll get the weather information.",
                                   tool_calls=[{"name": "weather_info", "args": {"city": city}, "id": "weather1"}])
                elif any(word in last_message.lower() for word in ['time', 'date']):
                    return AIMessage(content="I'll get the current time.",
                                   tool_calls=[{"name": "current_time", "args": {}, "id": "time1"}])
                elif any(word in last_message.lower() for word in ['analyze', 'analysis']):
                    text = last_message.replace('analyze this text:', '').replace('analyze', '').strip()
                    if not text:
                        text = "Sample text for analysis"
                    return AIMessage(content="I'll analyze that text for you.",
                                   tool_calls=[{"name": "text_analyzer", "args": {"text": text}, "id": "analyze1"}])
                else:
                    return AIMessage(content="Hello! I'm a multi-tool agent powered by Claude. I can help with:\n• Mathematical calculations\n• Web searches\n• Weather information\n• Text analysis\n• Current time/date\n\nWhat would you like me to help you with?")
           
            def bind_tools(self, tools):
                return self
       
        print("⚠️  Note: Using mock LLM for demo. Add your ANTHROPIC_API_KEY for full functionality.")
        return MockLLM()


llm = create_llm()
llm_with_tools = llm.bind_tools(tools)

Inicializamos el modelo de idioma que alimenta al agente de IA. Si hay disponible una clave API antrópica válida, utiliza el modelo Claude 3 Haiku para respuestas de alta calidad. Sin una clave API, se define un MockllM para simular el comportamiento básico de la redacción de herramientas basado en la coincidencia de palabras clave, lo que permite al agente funcionar fuera de línea con capacidades limitadas. El método bind_tools vincula las herramientas definidas con el modelo, lo que permite invocarlas según sea necesario.

def agent_node(state: AgentState) -> Dict[str, Any]:
    """Main agent node that processes messages and decides on tool usage."""
    messages = state["messages"]
    response = llm_with_tools.invoke(messages)
    return {"messages": [response]}


def should_continue(state: AgentState) -> str:
    """Determine whether to continue with tool calls or end."""
    last_message = state["messages"][-1]
    if hasattr(last_message, 'tool_calls') and last_message.tool_calls:
        return "tools"
    return END

Definimos la lógica de toma de decisiones básicas del agente. La función Agent_Node maneja los mensajes entrantes, invoca el modelo de idioma (con herramientas) y devuelve la respuesta del modelo. La función debería ser_continue evalúa si la respuesta del modelo incluye llamadas de herramientas. Si es así, enruta el control al nodo de ejecución de la herramienta; De lo contrario, dirige el flujo para finalizar la interacción. Estas funciones permiten transiciones dinámicas y condicionales dentro del flujo de trabajo del agente.

def create_agent_graph():
    tool_node = ToolNode(tools)
   
    workflow = StateGraph(AgentState)
   
    workflow.add_node("agent", agent_node)
    workflow.add_node("tools", tool_node)
   
    workflow.add_edge(START, "agent")
    workflow.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
    workflow.add_edge("tools", "agent")
   
    memory = MemorySaver()
   
    app = workflow.compile(checkpointer=memory)
   
    return app


print("Creating LangGraph Multi-Tool Agent...")
agent = create_agent_graph()
print("✓ Agent created successfully!\n")

Construimos el flujo de trabajo alimentado por Langgraph que define la estructura operativa del agente de IA. Inicializa un nodo de herramientas para manejar las ejecuciones de herramientas y utiliza un StateGraph para organizar el flujo entre las decisiones del agente y el uso de la herramienta. Los nodos y los bordes se agregan para administrar las transiciones: comenzando con el agente, enriquecer condicionalmente a las herramientas y retroceder según sea necesario. Un MemorySaver está integrado para el seguimiento estatal persistente en las curvas. El gráfico se compila en una aplicación ejecutable (APP), que permite un agente múltiple estructurado y consciente de la memoria listo para la implementación.

def test_agent():
    """Test the agent with various queries."""
    config = {"configurable": {"thread_id": "test-thread"}}
   
    test_queries = [
        "What's 15 * 7 + 23?",
        "Search for information about Python programming",
        "What's the weather like in Tokyo?",
        "What time is it?",
        "Analyze this text: 'LangGraph is an amazing framework for building AI agents.'"
    ]
   
    print("🧪 Testing the agent with sample queries...\n")
   
    for i, query in enumerate(test_queries, 1):
        print(f"Query {i}: {query}")
        print("-" * 50)
       
        try:
            response = agent.invoke(
                {"messages": [HumanMessage(content=query)]},
                config=config
            )
           
            last_message = response["messages"][-1]
            print(f"Response: {last_message.content}\n")
           
        except Exception as e:
            print(f"Error: {str(e)}\n")

La función test_agent es una utilidad de validación que garantiza que el agente Langgraph responda correctamente en diferentes casos de uso. Ejecuta consultas predefinidas, aritmética, búsqueda web, clima, tiempo y análisis de texto, e imprime las respuestas del agente. Usando un thread_id consistente para la configuración, invoca al agente con cada consulta. Muestra cuidadosamente los resultados, ayudando a los desarrolladores a verificar la integración de herramientas y la lógica de conversación antes de pasar al uso interactivo o de producción.

def chat_with_agent():
    """Interactive chat function."""
    config = {"configurable": {"thread_id": "interactive-thread"}}
   
    print("🤖 Multi-Tool Agent Chat")
    print("Available tools: Calculator, Web Search, Weather Info, Text Analyzer, Current Time")
    print("Type 'quit' to exit, 'help' for available commands\n")
   
    while True:
        try:
            user_input = input("You: ").strip()
           
            if user_input.lower() in ['quit', 'exit', 'q']:
                print("Goodbye!")
                break
            elif user_input.lower() == 'help':
                print("\nAvailable commands:")
                print("• Calculator: 'Calculate 15 * 7 + 23' or 'What's sin(pi/2)?'")
                print("• Web Search: 'Search for Python tutorials' or 'Find information about AI'")
                print("• Weather: 'Weather in Tokyo' or 'What's the temperature in London?'")
                print("• Text Analysis: 'Analyze this text: [your text]'")
                print("• Current Time: 'What time is it?' or 'Current date'")
                print("• quit: Exit the chat\n")
                continue
            elif not user_input:
                continue
           
            response = agent.invoke(
                {"messages": [HumanMessage(content=user_input)]},
                config=config
            )
           
            last_message = response["messages"][-1]
            print(f"Agent: {last_message.content}\n")
           
        except KeyboardInterrupt:
            print("\nGoodbye!")
            break
        except Exception as e:
            print(f"Error: {str(e)}\n")

La función chat_with_agent proporciona una interfaz de línea de comandos interactiva para conversaciones en tiempo real con el agente múltiple de langgraph. Apoya las consultas del lenguaje natural y reconoce comandos como “ayuda” para la guía de uso y “dejar de salir” para salir. Cada entrada del usuario se procesa a través del agente, que selecciona e invoca dinámicamente las herramientas de respuesta apropiadas. La función mejora la participación del usuario al simular una experiencia de conversación y mostrar las capacidades del agente en el manejo de varias consultas, desde la búsqueda en matemáticas y web hasta el clima, el análisis de texto y la recuperación de tiempo.

if __name__ == "__main__":
    test_agent()
   
    print("=" * 60)
    print("🎉 LangGraph Multi-Tool Agent is ready!")
    print("=" * 60)
   
    chat_with_agent()


def quick_demo():
    """Quick demonstration of agent capabilities."""
    config = {"configurable": {"thread_id": "demo"}}
   
    demos = [
        ("Math", "Calculate the square root of 144 plus 5 times 3"),
        ("Search", "Find recent news about artificial intelligence"),
        ("Time", "What's the current date and time?")
    ]
   
    print("🚀 Quick Demo of Agent Capabilities\n")
   
    for category, query in demos:
        print(f"[{category}] Query: {query}")
        try:
            response = agent.invoke(
                {"messages": [HumanMessage(content=query)]},
                config=config
            )
            print(f"Response: {response['messages'][-1].content}\n")
        except Exception as e:
            print(f"Error: {str(e)}\n")


print("\n" + "="*60)
print("🔧 Usage Instructions:")
print("1. Add your ANTHROPIC_API_KEY to use Claude model")
print("   os.environ['ANTHROPIC_API_KEY'] = 'your-anthropic-api-key'")
print("2. Run quick_demo() for a quick demonstration")
print("3. Run chat_with_agent() for interactive chat")
print("4. The agent supports: calculations, web search, weather, text analysis, and time")
print("5. Example: 'Calculate 15*7+23' or 'Search for Python tutorials'")
print("="*60)

Finalmente, orquestamos la ejecución del agente múltiple de Langgraph. Si el script se ejecuta directamente, inicia test_agent () para validar la funcionalidad con consultas de muestra, seguido por el lanzamiento del modo interactivo chat_with_agent () para la interacción en tiempo real. La función Quick_Demo () también muestra brevemente las capacidades del agente en matemáticas, búsqueda y consultas de tiempo. Las instrucciones de uso claras se imprimen al final, guiando a los usuarios a configurar la clave API, ejecutar demostraciones e interactuar con el agente. Esto proporciona una experiencia de incorporación suave para que los usuarios exploren y extiendan la funcionalidad del agente.

En conclusión, este tutorial paso a paso brinda información valiosa para construir un agente de IA multifacética que aproveche las capacidades generativas de Langgraph y Claude. Con explicaciones directas y demostraciones prácticas, la guía permite a los usuarios integrar diversas utilidades en un sistema cohesivo e interactivo. La flexibilidad del agente en la realización de tareas, desde cálculos complejos hasta recuperación de información dinámica, muestra la versatilidad de los marcos modernos de desarrollo de IA. Además, la inclusión de funciones fáciles de usar tanto para las pruebas como para el chat interactivo mejora la comprensión práctica, lo que permite la aplicación inmediata en varios contextos. Los desarrolladores pueden extender y personalizar con confianza a sus agentes de IA con este conocimiento fundamental.


Mira el Cuaderno en Github. Todo el crédito por esta investigación va a los investigadores de este proyecto. Además, siéntete libre de seguirnos Gorjeo Y no olvides unirte a nuestro 95k+ ml de subreddit y suscribirse a Nuestro boletín.


Asif Razzaq es el CEO de MarktechPost Media Inc .. Como empresario e ingeniero visionario, ASIF se compromete a aprovechar el potencial de la inteligencia artificial para el bien social. Su esfuerzo más reciente es el lanzamiento de una plataforma de medios de inteligencia artificial, MarktechPost, que se destaca por su cobertura profunda de noticias de aprendizaje automático y de aprendizaje profundo que es técnicamente sólido y fácilmente comprensible por una audiencia amplia. La plataforma cuenta con más de 2 millones de vistas mensuales, ilustrando su popularidad entre el público.