Crear un agente de IA desde cero con Python es una excelente forma de entender cómo funcionan estos sistemas por dentro.
En lugar de utilizar frameworks como LangChain o CrewAI, podemos construir una versión simple para aprender conceptos fundamentales como memoria, herramientas, razonamiento, objetivos y ambiente.
El objetivo será crear un agente que pueda conversar desde la terminal y que, además, sea capaz de leer, crear y editar archivos en la computadora.
Qué es un agente de IA
Un agente de IA es un sistema que utiliza inteligencia artificial para cumplir un objetivo.
A diferencia de un chatbot simple, un agente puede recibir una tarea, analizarla, dividirla en pasos, usar herramientas y continuar trabajando hasta completar el objetivo.
Un agente puede incluir varios elementos importantes:
- Conocimiento.
- Razonamiento.
- Memoria.
- Herramientas.
- Un ambiente donde actuar.
- Objetivos que debe cumplir.
En un ejemplo simple, el agente puede comenzar como un chatbot. Luego se le puede agregar memoria y herramientas para hacerlo más útil.
Qué vamos a crear
El proyecto consistirá en crear un agente en Python que funcione desde la terminal.
Primero se construirá un chatbot básico. Después se agregará memoria para que recuerde la conversación. Finalmente, se añadirán herramientas para que pueda listar archivos, leer archivos y editar archivos.
Con esto podremos pedirle tareas como crear un archivo de Python, modificar una función existente o generar una pequeña página web.
Crear el proyecto en Python
Para comenzar, se puede abrir Visual Studio Code en una carpeta vacía y crear un archivo llamado main.py.
Como prueba inicial, podemos ejecutar algo simple:
print("Hola desde mi agente de IA")
Con esto comprobamos que Python está funcionando correctamente.
Crear un ambiente virtual
Antes de instalar dependencias, es recomendable crear un ambiente virtual para el proyecto.
python -m venv venv
Luego se activa el ambiente virtual según el sistema operativo.
En Windows:
venv\Scripts\activate
En macOS o Linux:
source venv/bin/activate
Instalar dependencias
Para interactuar con un modelo de lenguaje se puede utilizar la biblioteca oficial del proveedor elegido.
En este ejemplo se trabaja con OpenAI y con python-dotenv para manejar variables de entorno.
pip install openai python-dotenv
Guardar la clave API en un archivo .env
La clave API no debe escribirse directamente dentro del código.
Una forma más ordenada es crear un archivo llamado .env y guardar allí la clave.
OPENAI_API_KEY=tu_clave_api
Este archivo debe mantenerse privado y no subirse a repositorios públicos.
Crear el cliente del modelo
En el archivo main.py podemos importar las dependencias necesarias y cargar las variables de entorno.
from openai import OpenAI from dotenv import load_dotenv load_dotenv() client = OpenAI()
Con esto ya podemos crear un cliente para enviar mensajes al modelo.
Hacer una primera llamada al modelo
Para comprobar que todo funciona, se puede enviar una entrada simple al modelo y mostrar la respuesta.
response = client.responses.create( model="modelo-a-utilizar", input="Dime el nombre de cinco personajes del Señor de los Anillos, solo el nombre." ) print(response.output_text)
El nombre exacto del modelo puede cambiar según el proveedor y la disponibilidad, por lo que conviene revisar la documentación oficial antes de usarlo en un proyecto real.
Convertirlo en un chatbot
Para convertir el código en un chatbot de terminal, se puede crear un ciclo infinito que reciba mensajes del usuario.
while True: user_input = input("Tú: ") response = client.responses.create( model="modelo-a-utilizar", input=user_input ) print("Asistente:", response.output_text)
Esto permite escribir mensajes en la terminal y recibir respuestas del modelo.
Agregar una forma de salir
También es útil permitir que el usuario termine la conversación escribiendo una palabra específica.
while True: user_input = input("Tú: ") if user_input.lower() in ["salir", "exit", "quit"]: print("Asistente: Hasta luego.") break response = client.responses.create( model="modelo-a-utilizar", input=user_input ) print("Asistente:", response.output_text)
El problema de la memoria
Si usamos el modelo de forma directa, cada mensaje se procesa de manera aislada.
Por ejemplo, si le dices tu nombre y luego le preguntas cómo te llamas, puede que no lo recuerde si no se le envió el historial anterior.
Esto ocurre porque el modelo no conserva memoria por sí solo entre llamadas separadas.
Agregar memoria simple al chatbot
Una forma sencilla de agregar memoria es guardar el historial de mensajes en una lista.
messages = [ { "role": "system", "content": "Eres un asistente útil que habla español y responde de forma concisa." } ]
Luego, cada mensaje del usuario se agrega al historial.
messages.append({ "role": "user", "content": user_input })
Y cada respuesta del asistente también se guarda.
messages.append({ "role": "assistant", "content": assistant_response })
Después, en cada nueva llamada, se envía el historial completo al modelo.
Ejemplo de chatbot con memoria
messages = [ { "role": "system", "content": "Eres un asistente útil que habla español y responde de forma concisa." } ] while True: user_input = input("Tú: ") if not user_input: continue if user_input.lower() in ["salir", "exit", "quit"]: print("Asistente: Hasta luego.") break messages.append({ "role": "user", "content": user_input }) response = client.responses.create( model="modelo-a-utilizar", input=messages ) assistant_response = response.output_text messages.append({ "role": "assistant", "content": assistant_response }) print("Asistente:", assistant_response)
Esta memoria es simple y funciona bien para un ejemplo pequeño.
La desventaja es que, mientras más larga sea la conversación, más tokens se enviarán en cada petición.
Qué son las herramientas en un agente de IA
Un agente se vuelve más útil cuando puede usar herramientas.
Una herramienta puede ser una función que permite hacer algo fuera del modelo, por ejemplo:
- Consultar una base de datos.
- Buscar información en internet.
- Leer archivos.
- Crear archivos.
- Editar archivos.
- Enviar correos.
- Conectarse a sistemas externos.
El modelo no ejecuta directamente esas funciones. Lo que hace es indicar qué función quiere llamar y con qué argumentos. Luego el programa en Python es quien ejecuta la herramienta y devuelve el resultado al modelo.
Crear una herramienta para listar archivos
La primera herramienta puede servir para listar archivos de un directorio.
import os def list_files_in_dir(directory="."): try: files = os.listdir(directory) return { "success": True, "files": files } except Exception as error: return { "success": False, "error": str(error) }
Esta función recibe un directorio y devuelve los archivos encontrados.
Definir la herramienta para el modelo
Para que el modelo sepa que existe una herramienta, debemos describirla.
La descripción es importante porque ayuda al modelo a decidir cuándo debe usarla.
tools = [ { "type": "function", "name": "list_files_in_dir", "description": "Lista los archivos que existen en un directorio dado. Por defecto usa el directorio actual.", "parameters": { "type": "object", "properties": { "directory": { "type": "string", "description": "Directorio del cual se quieren listar los archivos." } } } } ]
La estructura exacta puede variar según el proveedor del modelo, por lo que siempre conviene revisar la documentación correspondiente.
Qué ocurre cuando el modelo quiere usar una herramienta
Cuando el modelo considera que necesita una herramienta, no la ejecuta directamente.
En lugar de devolver un mensaje normal, puede devolver una respuesta indicando:
- El nombre de la función que quiere llamar.
- Los argumentos que quiere enviarle.
- Un identificador del llamado.
El programa debe leer esa respuesta, ejecutar la función correspondiente y devolver el resultado al modelo para que continúe.
Procesar llamados de función
Para manejar respuestas con herramientas, se debe revisar la salida del modelo.
Si la salida indica un llamado de función, se toman los argumentos, se convierten desde JSON a un objeto de Python y se ejecuta la función correspondiente.
import json for output in response.output: if output.type == "function_call": function_name = output.name arguments = json.loads(output.arguments) if function_name == "list_files_in_dir": result = list_files_in_dir(**arguments)
Después se debe enviar ese resultado nuevamente al modelo para que pueda continuar el proceso.
Crear una clase Agent
Para ordenar mejor el proyecto, podemos crear un archivo llamado agent.py y definir una clase Agent.
Esta clase puede encargarse de:
- Inicializar el historial de mensajes.
- Configurar las herramientas.
- Ejecutar herramientas.
- Procesar respuestas del modelo.
class Agent: def __init__(self): self.setup_tools() self.messages = [ { "role": "system", "content": "Eres un asistente útil que habla español y responde de forma concisa." } ] def setup_tools(self): self.tools = []
Crear una herramienta para leer archivos
Para que el agente pueda revisar código existente, necesita una herramienta que lea archivos.
def read_file(self, path): try: with open(path, "r", encoding="utf-8") as file: return file.read() except Exception as error: return f"Error leyendo el archivo: {error}"
Esta herramienta recibe la ruta de un archivo y devuelve su contenido.
Crear una herramienta para editar archivos
También podemos agregar una herramienta para crear o modificar archivos.
Esta función puede recibir la ruta, el texto anterior y el texto nuevo.
def edit_file(self, path, old_text="", new_text=""): try: if os.path.exists(path) and old_text: content = self.read_file(path) if old_text not in content: return "No se encontró el texto a reemplazar." content = content.replace(old_text, new_text) action = "editado" else: directory = os.path.dirname(path) if directory: os.makedirs(directory, exist_ok=True) content = new_text action = "creado" with open(path, "w", encoding="utf-8") as file: file.write(content) return f"El archivo {path} fue {action} correctamente." except Exception as error: return f"Error editando el archivo: {error}"
Con esta herramienta el agente puede crear archivos nuevos o reemplazar partes de archivos existentes.
Registrar las herramientas de lectura y edición
Después de crear las funciones, hay que declararlas en la lista de herramientas para que el modelo conozca su existencia.
{ "type": "function", "name": "read_file", "description": "Lee el contenido de un archivo dado.", "parameters": { "type": "object", "properties": { "path": { "type": "string", "description": "Ruta del archivo que se quiere leer." } }, "required": ["path"] } }
Para editar archivos, se puede declarar una herramienta como esta:
{ "type": "function", "name": "edit_file", "description": "Edita un archivo reemplazando old_text por new_text. Crea el archivo si no existe.", "parameters": { "type": "object", "properties": { "path": { "type": "string", "description": "Ruta del archivo que se quiere crear o modificar." }, "old_text": { "type": "string", "description": "Texto anterior que será reemplazado. Puede estar vacío si se creará un archivo nuevo." }, "new_text": { "type": "string", "description": "Nuevo texto que se escribirá en el archivo." } }, "required": ["path", "new_text"] } }
Ejecutar herramientas según el nombre
Cuando el modelo solicita una función, el agente debe revisar el nombre y ejecutar la herramienta correcta.
if function_name == "list_files_in_dir": result = self.list_files_in_dir(**arguments) elif function_name == "read_file": result = self.read_file(**arguments) elif function_name == "edit_file": result = self.edit_file(**arguments)
Luego ese resultado se agrega al historial para que el modelo pueda interpretarlo y continuar.
Proceso iterativo del agente
El funcionamiento de un agente con herramientas es iterativo.
- El usuario pide una tarea.
- El modelo analiza la solicitud.
- Si necesita una herramienta, devuelve un llamado de función.
- Python ejecuta esa herramienta.
- El resultado se devuelve al modelo.
- El modelo decide si ya puede responder o si necesita usar otra herramienta.
Por eso se puede usar un ciclo que continúe mientras el modelo siga solicitando herramientas.
while True: response = client.responses.create( model="modelo-a-utilizar", input=agent.messages, tools=agent.tools ) calls_tool = agent.process_response(response) if not calls_tool: break
Probar el agente
Una vez agregadas las herramientas, se puede probar el agente con tareas como:
- Listar los archivos del directorio actual.
- Crear un archivo llamado
ejemplo.py. - Agregar funciones para sumar, restar y multiplicar.
- Leer el archivo creado.
- Modificar una función específica.
- Crear una página HTML con Bootstrap.
El agente puede llamar una o varias herramientas según lo que necesite para completar la tarea.
Advertencia de seguridad
Permitir que un agente lea y edite archivos puede ser útil, pero también puede ser peligroso si no se aplican límites.
En un proyecto real conviene restringir el agente a una carpeta específica, validar rutas, evitar que modifique archivos sensibles y pedir confirmación antes de escribir cambios importantes.
También es recomendable registrar todo lo que el agente hace para poder auditar sus acciones.
Qué se puede mejorar
Este agente es una versión simple, pero se puede ampliar de muchas formas.
- Agregar memoria persistente en una base de datos.
- Permitir búsqueda en internet.
- Conectar con sistemas externos.
- Agregar herramientas para bases de datos.
- Separar tareas en varios agentes especializados.
- Usar modelos distintos según la dificultad de cada tarea.
- Crear validaciones antes de ejecutar herramientas peligrosas.
Agentes y sistemas multiagente
Cuando un agente empieza a tener demasiadas herramientas o responsabilidades, puede ser mejor dividir el trabajo en varios agentes.
Un sistema multiagente permite que varios agentes colaboren para completar tareas complejas.
Por ejemplo, un agente puede clasificar la tarea, otro puede escribir código, otro puede revisar errores y otro puede generar documentación.
Esta separación puede ayudar a mejorar el orden, reducir costos y usar modelos más adecuados para cada parte del proceso.
Conclusión
Crear un agente de IA desde cero con Python permite entender mejor cómo funcionan estos sistemas internamente.
El proceso puede comenzar con un chatbot simple, luego agregar memoria y finalmente incorporar herramientas para que el agente pueda interactuar con archivos y sistemas externos.
El punto más importante es entender que el modelo no ejecuta herramientas por sí solo. El modelo decide qué herramienta necesita y el programa en Python es quien la ejecuta, devuelve el resultado y permite que el agente continúe razonando.
Con esta base, es posible construir agentes más útiles, seguros y adaptados a necesidades reales.



