5 min de lectura

Construyendo un Agente de IA desde Cero

El patrón del Pasante Digital: aprende a implementar un agente ReAct en Python que puede pensar, usar herramientas y resolver problemas multi-paso sin ningún framework.

Construyendo un Agente de IA desde Cero

El Patrón del “Pasante Digital”

Imagina que acabas de contratar a un nuevo pasante, Kevin. Kevin es entusiasta, razonablemente inteligente, pero no tiene acceso a tu software interno. Si le preguntas a Kevin, “¿Cuánto stock del Turbo-Encabulator tenemos y podemos enviarlo a Detroit para el viernes?”, Kevin no puede simplemente saber la respuesta.

En lugar de eso, Kevin ejecuta un ciclo específico de comportamientos:

  • Pensamiento: “Necesito consultar el sistema de inventario para ‘Turbo-Encabulators’.”
  • Acción: Camina hasta la computadora del almacén y escribe la consulta.
  • PAUSA: Espera frente al monitor antiguo mientras gira la ruedita de carga.
  • Observación: La pantalla muestra: 50 unidades en stock.
  • Pensamiento: “Bien, tenemos stock. Ahora necesito verificar los tiempos de envío a Detroit.”

Este “Ciclo de Kevin” es exactamente cómo funciona un agente ReAct (Razonamiento + Acción).

En EDVM, construimos sistemas ERP complejos para automatizar procesos y que los humanos no tengan que correr de un lado a otro como Kevin. Hoy vamos a construir un “Kevin Digital” en Python, un agente de IA hecho desde cero que puede pensar, usar herramientas y resolver problemas multi-paso.

Lo Que Aprenderás

  • Cómo implementar el patrón ReAct (Pensamiento, Acción, PAUSA, Observación).
  • Cómo separar el razonamiento del LLM del runtime de Python.
  • Cómo interpretar las respuestas del LLM para ejecutar funciones reales de Python.

Requisitos Previos

  • Python 3.10+
  • Una API Key de OpenAI (o cualquier endpoint de LLM)
  • pip install openai python-dotenv

El Ciclo “Pensamiento-Acción”

Un LLM por sí solo es como un cerebro en un frasco. Puede escribir poesía, pero no puede consultar tu base de datos SQL ni hacer cálculos complejos de forma fiable. Para solucionarlo, le damos un prompt específico que lo obliga a detenerse y pedir ayuda.

Le decimos al LLM: “No adivines. Si necesitas datos, indica la Acción que quieres ejecutar y luego haz una PAUSA. Nosotros (nuestro script de Python) ejecutaremos esa acción y te daremos la Observación.”

Funciona así:

  • Usuario: “¿Cuál es el costo total de 5 Laptops para el Cliente X?”
  • Agente (Pensamiento): Necesito el precio de una Laptop.
  • Agente (Acción): get_price("Laptop") -> PAUSA
  • Runtime de Python: Ejecuta la función get_price, devuelve $1000.
  • Agente (Observación): “El precio es $1000.”
  • Agente (Pensamiento): Ahora necesito el descuento del Cliente X…

Implementación Paso a Paso en Python

Construyamos un mini-agente ERP. Vamos a despojarnos de los frameworks sofisticados (LangChain, AutoGen) para ver los engranajes reales funcionando.

1. Definir las “Herramientas” (El Entorno)

Primero, necesitamos los sistemas con los que Kevin interactúa. En un escenario real de EDVM, estas serían llamadas a la API de Odoo. Aquí las simularemos.

from typing import Union, Dict, Callable

def get_product_price(item_name: str) -> str:
    """Simula la consulta de un producto en la base de datos."""
    catalog: Dict[str, float] = {
        "Turbo-Encabulator": 5000.0,
        "Flux Capacitor": 2500.0,
        "Self-Sealing Stem Bolt": 10.0
    }
    price = catalog.get(item_name)
    if price:
        return str(price)
    return "Error: Producto no encontrado."

def calculate_tax(amount: Union[str, float]) -> str:
    """Calculadora específica ya que los LLMs fallan con matemática precisa."""
    try:
        val = float(amount)
        return str(val * 1.21)  # 21% de impuesto
    except ValueError:
        return "Error: Número inválido."

# El Diccionario de Conocimiento (El Cinturón de Herramientas del Agente)
known_actions: Dict[str, Callable[[str], str]] = {
    "get_product_price": get_product_price,
    "calculate_tax": calculate_tax
}

2. El System Prompt

Aquí es donde “programamos” el comportamiento del LLM usando lenguaje natural. Le indicamos explícitamente que use el ciclo Pensamiento -> Acción -> PAUSA -> Observación.

system_prompt: str = """
Eres un Asistente ERP eficiente. Operas en un ciclo de Pensamiento, Acción, PAUSA, Observación.
Al final del ciclo, produces una Respuesta.

1. Pensamiento: Describe lo que necesitas hacer a continuación.
2. Acción: Ejecuta una de las acciones disponibles. Formato: nombre_funcion: argumento
3. PAUSA: Detente y espera el resultado.
4. Observación: El resultado de tu acción se proporcionará aquí.

Tus acciones disponibles son:
- get_product_price: nombre_producto (consulta el precio base)
- calculate_tax: monto (agrega 21% de impuesto a un monto base)

Sesión de ejemplo:
Pregunta: ¿Cuánto cuesta un Flux Capacitor con impuesto?
Pensamiento: Necesito encontrar el precio base primero.
Acción: get_product_price: Flux Capacitor
PAUSA

Observación: 2500

Pensamiento: Ahora necesito agregar impuesto a 2500.
Acción: calculate_tax: 2500
PAUSA

Observación: 3025.0

Respuesta: Un Flux Capacitor cuesta $3025.0 incluyendo impuesto.
""".strip()

3. La Clase del Agente

El Agente maneja el historial. Agrega la pregunta del usuario, la envía al LLM y espera una respuesta.

from openai import OpenAI
from typing import List, Dict

client = OpenAI()  # Asume que OPENAI_API_KEY está en el entorno

class ReActAgent:
    def __init__(self, system_prompt: str) -> None:
        self.system_prompt: str = system_prompt
        self.messages: List[Dict[str, str]] = [
            {"role": "system", "content": system_prompt}
        ]

    def __call__(self, message: str) -> str:
        self.messages.append({"role": "user", "content": message})
        return self.execute()

    def execute(self) -> str:
        response = client.chat.completions.create(
            model="gpt-4o",
            temperature=0,  # Mantenemos a Kevin determinista
            messages=self.messages
        )
        content = response.choices[0].message.content
        return content if content else ""

4. El Ciclo de Ejecución (El Runtime)

Este es el “Cerebro” de la operación. Observa lo que dijo el LLM. Si el LLM dijo “PAUSA”, el script de Python se despierta, analiza la acción, ejecuta la función y devuelve el resultado.

import re

def run_agent_loop(agent: ReActAgent, question: str, max_turns: int = 5) -> None:
    next_prompt: str = question
    action_re = re.compile(r'^Action: (\w+): (.*)$')

    for step in range(max_turns):
        # 1. Preguntar al Agente
        result: str = agent(next_prompt)
        print(f"\n[Paso {step}] El Agente dice:\n{result}\n")

        # 2. Verificar si el Agente está solicitando una acción
        actions = [
            action_re.match(a)
            for a in result.split('\n')
            if action_re.match(a)
        ]

        if actions:
            match = actions[0]
            if match:
                action_name, action_input = match.groups()

                if action_name not in known_actions:
                    raise Exception(f"Herramienta desconocida: {action_name}")

                print(f"--- Python Ejecutando: {action_name}('{action_input}') ---")

                # 3. Ejecutar función Python
                observation: str = known_actions[action_name](action_input)

                # 4. Devolver el resultado al Agente
                next_prompt = f"Observation: {observation}"
                agent.messages.append({"role": "user", "content": next_prompt})
        else:
            print("--- Tarea Completada ---")
            return

Entendiendo el Flujo

Esto es lo que sucede cuando ejecutas el script. Es una conversación entre dos entidades:

  • El LLM (Kevin): “Necesito el precio del Turbo-Encabulator.” -> Escribe Acción -> Se detiene.
  • El Runtime (Tú/Python): Detecta la solicitud de acción. Buscas el precio (5000). Pegas “Observation: 5000” en el historial del chat.
  • El LLM (Kevin): Ve el 5000. “Genial. Ahora necesito calcular el impuesto sobre 5000.” -> Escribe Acción -> Se detiene.
  • El Runtime: Ejecuta el cálculo. Pega “Observation: 6050.0”.
  • El LLM (Kevin): “Respuesta: Cuesta $6050.0.”

Esta arquitectura permite que el cerebro (LLM) controle el cuerpo (funciones Python) sin que estén acoplados directamente.

Errores Comunes

  • Fragilidad del Regex: Usar regex para interpretar Action: tool: input es excelente para aprender, pero en producción es frágil. Si el LLM agrega un espacio o un error tipográfico, el regex falla. Los frameworks modernos usan modo JSON o Tool Calling API para reforzar la estructura.
  • Bucles Infinitos: Si el agente se confunde, podría preguntar el mismo precio 50 veces. Siempre implementa un límite max_turns para evitar sorpresas en la factura de la API.
  • Límite de Contexto: Cada “Observación” se agrega al historial de mensajes. Si devuelves el resultado completo de una consulta SQL masiva, desbordarás la ventana de contexto del LLM. Mantén las observaciones concisas.

Puntos Clave

  • Los Agentes son Bucles: No son magia; son simplemente bucles while que agregan cadenas de texto a una lista.
  • Las Herramientas son Funciones: Darle “herramientas” a una IA simplemente significa mapear un comando de texto (como get_price) a una función de Python.
  • Pensamiento Estructurado: El patrón “Pensamiento, Acción, Pausa” obliga al modelo a planificar, reduciendo significativamente las alucinaciones.

¿Necesitas un sistema más robusto que un pasante digital?

En EDVM, construimos sistemas ERP y CRM a medida usando Odoo y Python. Gestionamos los datos, automatizamos los flujos de trabajo y escalamos según tus necesidades para que puedas dejar de revisar stock manualmente y empezar a crecer.

Visitá edvm.network para más información.

Queres construir algo parecido?

Si estas validando un producto, ordenando operaciones o armando un MVP tecnico, podemos ayudarte.

Iniciar conversacion