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.
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: inputes 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_turnspara 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.
Queres construir algo parecido?
Si estas validando un producto, ordenando operaciones o armando un MVP tecnico, podemos ayudarte.