#
Usando Agentes en LlamaIndex

¿Recuerdas a Alfred, nuestro agente mayordomo útil de antes? ¡Bueno, está a punto de recibir una mejora! Ahora que entendemos las herramientas disponibles en LlamaIndex, podemos darle a Alfred nuevas capacidades para servirnos mejor.

Pero antes de continuar, recordemos qué hace funcionar a un agente como Alfred. En la Unidad 1, aprendimos que:

> Un Agente es un sistema que aprovecha un modelo de IA para interactuar con su entorno y lograr un objetivo definido por el usuario. Combina razonamiento, planificación y ejecución de acciones (a menudo a través de herramientas externas) para cumplir tareas.

LlamaIndex soporta tres tipos principales de agentes de razonamiento:

1. `Agentes de Llamada de Funciones` - Estos trabajan con modelos de IA que pueden llamar funciones específicas.
2. `Agentes ReAct` - Estos pueden trabajar con cualquier IA que tenga un endpoint de chat o texto y manejar tareas de razonamiento complejas.
3. `Agentes Personalizados Avanzados` - Estos usan métodos más complejos para manejar tareas y flujos de trabajo.

> FEncuentra más información sobre agentes avanzados en BaseWorkflowAgent

##
Inicializando Agentes

> Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab.

Para crear un agente, comenzamos proporcionándole un conjunto de funciones/herramientas que definen sus capacidades. Veamos cómo crear un agente con algunas herramientas básicas. Al momento de escribir esto, el agente usará automáticamente la API de llamada de funciones (si está disponible), o un bucle de agente ReAct estándar.

Los LLMs que soportan una API de herramientas/funciones son relativamente nuevos, pero proporcionan una forma poderosa de llamar herramientas al evitar indicaciones específicas y permitir que el LLM cree llamadas a herramientas basadas en esquemas proporcionados.

Los agentes ReAct también son buenos en tareas de razonamiento complejas y pueden trabajar con cualquier LLM que tenga capacidades de chat o completación de texto. Son más verbosos y muestran el razonamiento detrás de ciertas acciones que toman.

    from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI
    from llama_index.core.agent.workflow import AgentWorkflow
    from llama_index.core.tools import FunctionTool

    # define una herramienta de muestra -- ¡las anotaciones de tipo, nombres de funciones y docstrings están incluidos en los esquemas analizados!
    def multiply(a: int, b: int) -> int:
        """Multiplica dos enteros y devuelve el entero resultante"""
        return a * b

    # inicializa el llm
    llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct")

    # inicializa el agente
    agent = AgentWorkflow.from_tools_or_functions(
        [FunctionTool.from_defaults(multiply)],
        llm=llm
    )

Los agentes son sin estado por defecto, recordar interacciones pasadas es opcional usando un objeto `Context`. Esto puede ser útil si quieres usar un agente que necesita recordar interacciones previas, como un chatbot que mantiene el contexto a través de múltiples mensajes o un administrador de tareas que necesita rastrear el progreso a lo largo del tiempo.

    # sin estado
    response = await agent.run("¿Cuánto es 2 por 2?")

    # recordando estado
    from llama_index.core.workflow import Context

    ctx = Context(agent)

    response = await agent.run("Mi nombre es Bob.", ctx=ctx)
    response = await agent.run("¿Cuál era mi nombre de nuevo?", ctx=ctx)

Notarás que los agentes en `LlamaIndex` son asíncronos porque usan el operador await de Python. Si eres nuevo en el código asíncrono en Python, o necesitas un repaso, tienen una excelente guía de async.

Ahora que tenemos los conceptos básicos, echemos un vistazo a como podemos usar herramientas más complejas en nuestros agentes.

##
Creando Agentes RAG con QueryEngineTools

Agentic RAG es una forma poderosa de usar agentes para responder preguntas sobre tus datos. Podemos pasar varias herramientas a Alfred para ayudarlo a responder preguntas. Sin embargo, en lugar de responder la pregunta sobre los documentos automáticamente, Alfred puede decidir usar cualquier otra herramienta o flujo para responder la pregunta.

Es fácil envolver `QueryEngine` como una herramienta para un agente. Al hacerlo, necesitamos definir un nombre y una descripción. El LLM usará esta información para usar la herramienta correctamente. Veamos cómo cargar un `QueryEngineTool` usando el QueryEngine que creamos en la sección de componentes.

It is easy to wrap `QueryEngine` as a tool for an agent. When doing so, we need to define a name and description. The LLM will use this information to correctly use the tool. Let’s see how to load in a `QueryEngineTool` using the `QueryEngine` we created in the component section.

    from llama_index.core.tools import QueryEngineTool

    query_engine = index.as_query_engine(llm=llm, similarity_top_k=3) # como se mostró en la sección anterior

    query_engine_tool = QueryEngineTool.from_defaults(
        query_engine=query_engine,
        name="nombre",
        description="una descripción específica",
        return_direct=False,
    )
    query_engine_agent = AgentWorkflow.from_tools_or_functions(
        [query_engine_tool],
        llm=llm,
        system_prompt="Eres un asistente útil que tiene acceso a una base de datos que contiene descripciones de personas. "
    )

##
Creando Sistemas Multi-agente

La clase `AgentWorkflow` también soporta directamente sistemas multi-agente. Al darle a cada agente un nombre y una descripción, el sistema mantiene un único hablante activo, con cada agente teniendo la capacidad de pasar el control a otro agente.

Al reducir el alcance de cada agente, podemos ayudar a aumentar su precisión general al responder a los mensajes del usuario.

Los agentes en LlamaIndex también pueden usarse directamente como herramientas para otros agentes, para escenarios más complejos y personalizados.

    from llama_index.core.agent.workflow import (
        AgentWorkflow,
        FunctionAgent,
        ReActAgent,
    )

    # Define algunas herramientas
    def add(a: int, b: int) -> int:
        """Suma dos números."""
        return a + b

    def subtract(a: int, b: int) -> int:
        """Resta dos números."""
        return a - b

    # Crea configuraciones de agentes
    # NOTA: podemos usar FunctionAgent o ReActAgent aquí.
    # FunctionAgent funciona para LLMs con una API de llamada de funciones.
    # ReActAgent funciona para cualquier LLM.
    calculator_agent = ReActAgent(
        name="calculadora",
        description="Realiza operaciones aritméticas básicas",
        system_prompt="Eres un asistente de calculadora. Usa tus herramientas para cualquier operación matemática.",
        tools=[add, subtract],
        llm=llm,
    )

    query_agent = ReActAgent(
        name="búsqueda_de_información",
        description="Busca información sobre XYZ",
        system_prompt="Usa tu herramienta para consultar un sistema RAG y responder información sobre XYZ",
        tools=[query_engine_tool],
        llm=llm
    )

    # Crea y ejecuta el flujo de trabajo
    agent = AgentWorkflow(
        agents=[calculator_agent, query_agent], root_agent="calculadora"
    )

    # Ejecuta el sistema
    response = await agent.run(user_msg="¿Puedes sumar 5 y 3?")

> ¿No has aprendido lo suficiente todavía? Hay mucho más por descubrir sobre agentes y herramientas en LlamaIndex dentro de la Introducción Básica a AgentWorkflow o la Guía de Aprendizaje de Agentes, ¡donde puedes leer más sobre streaming, serialización de contexto y humano-en-el-bucle!

Ahora que entendemos los conceptos básicos de agentes y herramientas en LlamaIndex, ¡veamos cómo podemos usar LlamaIndex para crear flujos de trabajo configurables y manejables!

< > Update on GitHub