En el capítulo anterior vimos que un agente de IA se compone de 4 elementos: cerebro (LLM), herramientas, memoria y bucle (control). En este capítulo, por fin, nos ponemos manos a la obra. La meta es sencilla: construir «un agente que funciona» combinando los 4 elementos en su forma mínima, ponerlo en marcha de verdad y observar su comportamiento. Todavía no añadimos funciones llamativas. Primero, se trata de que puedas girar con tus propias manos el corazón del agente: «hacer pensar al LLM, invocar una herramienta, devolver el resultado, volver a hacerle pensar y detenerse al completar».
«Montar y poner en marcha, por ti mismo, un agente mínimo»
Qué es el agente mínimo
El «agente mínimo» es combinar los 4 elementos del capítulo anterior, cada uno en su forma más pequeña. No hace falta una memoria lujosa, ni muchas herramientas, ni varios agentes. Como en la tabla siguiente, empezamos por una configuración recortada al máximo. Si entiendes esto, lo demás es solo ir engordando cada elemento.
Basta con invocar un solo modelo Claude. En el prompt, escribe el rol en una línea: «Eres un asistente que puede usar herramientas».
Solo una herramienta. Puede ser de búsqueda o de cálculo. Al principio, una función simple cuyo funcionamiento sea seguro.
Basta con un único array del historial de la conversación. Solo apilas los intercambios en orden. Aún no piensas en persistirlo.
Un solo while. Gira con «si hay petición de herramienta, ejecútala; si no, ha terminado». Solo fija un número máximo de vueltas.
💡 Lo único que lo diferencia de «una sola llamada a la API» es el bucle. Si solo preguntas una vez al LLM y recibes su respuesta, eso es simple uso de una API. En el momento en que le añades esa repetición —«ejecutar la herramienta, devolver el resultado y hacerle pensar otra vez»—, se convierte en un agente. En esencia, lo único que crece es ese bucle. Por eso, entenderlo por completo primero es el camino más corto.
Qué hay dentro del bucle del agente
El corazón del agente es un único bucle. En un programa gira lo mismo que hace una persona: «investiga, piensa, actúa, mira el resultado y, si aún falta, repite». Primero, captemos con un diagrama el flujo de una vuelta.
Pasas al LLM el historial de conversación y la lista de herramientas. El LLM decide si «responde» o «usa una herramienta».
Cuando el LLM responde «quiero usar esta herramienta con estos argumentos», nosotros ejecutamos de verdad esa función.
Añades el resultado (el valor de retorno de la herramienta) al historial y lo vuelves a pasar al LLM. Aquí regresas al PASO 1.
Cuando el LLM devuelve la respuesta final sin usar herramientas, se da por logrado el objetivo y se sale del bucle.
La clave es que giras los PASOS 1 a 3 una y otra vez, y solo sales en el PASO 4. El LLM quizá no termine en una sola vuelta. Como en «primero busco, veo el resultado y vuelvo a buscar», da varias vueltas para acercarse al objetivo. Escrito en pseudocódigo, debería resultar asombrosamente corto.
# Bucle mínimo del agente (pseudocódigo) messages = [ user("Investiga la temperatura media del mes pasado y resúmela") ] while True: reply = llm.think(messages, tools=[search_tool]) # PASO1 pensar if reply.wants_tool: # ¿pide herramienta? result = run_tool(reply.tool_name, reply.args) # PASO2 invocar messages.append(assistant(reply)) messages.append(tool_result(result)) # PASO3 devolver else: return reply.text # PASO4 detenerse al completar
⚠️ Pon siempre un número máximo de vueltas. El pseudocódigo de arriba usa while True solo para explicar, pero en un caso real siempre metemos un freno de «hasta un máximo de N vueltas». El bucle infinito en el que el LLM sigue invocando herramientas sin parar es un accidente que, de hecho, ocurre a menudo. Lo tratamos en detalle en Puntos donde se atasca.
Darle una herramienta
A continuación, le damos al LLM un instrumento. Lo importante aquí es que el LLM no puede ejecutar código por sí mismo. Lo que el LLM puede hacer llega hasta pedir con palabras «quiero usar esta herramienta con estos argumentos». Ejecutar de verdad la función y devolver el resultado es siempre nuestro trabajo (el de tu programa).
Para eso, primero le pasamos al LLM la definición de la herramienta. La definición de la herramienta es el manual de «qué puede hacer esta herramienta y qué argumentos toma». El LLM lo lee y decide cuándo y cómo usarla.
Ej.: search_weather «devuelve la temperatura media si le pasas una ciudad y un mes». La descripción es lo que usa el LLM para decidir, así que escríbela con cuidado.
Especificas qué argumentos recibe y de qué tipo mediante un esquema (definición en formato JSON). Ej.: city (cadena) y month (número).
El cuerpo de código que funciona de verdad. Recibe los argumentos que devolvió el LLM y devuelve el resultado. Aquí basta con una función normal y corriente.
De este trío, el truco está en pasar ①② al LLM y quedarte ③ en tu lado. Cuando el LLM pide «quiero usar search_weather(city=\"París\", month=6)», recibes ese nombre y esos argumentos, invocas la función ③ y devuelves su valor a la conversación como resultado de la herramienta. Veámoslo en pseudocódigo.
# ① y ② … definición de herramienta que pasas al LLM search_tool = { "name": "search_weather", "description": "devuelve la temperatura media (°C) si le pasas una ciudad y un mes", "input_schema": { "city": "string", "month": "number", }, } # ③ … la función real que te quedas. Solo una función def run_tool(name, args): if name == "search_weather": return weather_db.lookup(args["city"], args["month"]) return "unknown tool"
📊 La descripción es parte del prompt. La description de la herramienta es la única pista que tiene el LLM para decidir «cuándo usarla». Si es ambigua, no la usará o la usará en momentos raros. El truco es escribirla como si le explicaras a una persona «qué devuelve y cuándo debe usarse». El diseño de herramientas lo profundizamos aún más en el siguiente capítulo, con MCP.
Cómo implementarlo: bucle a mano y SDK
Al montar las piezas vistas hasta aquí, tu primer agente funciona. Hay, a grandes rasgos, dos formas de implementarlo. Para aprender el mecanismo, a mano; para ahorrar trabajo en la práctica, con un SDK: por dentro, ambos son el mismo bucle. Ordenemos primero las diferencias.
whileGiras la llamada a la API y la ejecución de la herramienta con tu propio while. Como ves todo lo que ocurre dentro, es ideal para aprender. Y el control es total.
Cuándo conviene: quieres entender el mecanismo / controlar al detalle.
Registras la definición de la herramienta y la función en el bucle de ejecución de herramientas que ofrecen SDKs como los de Claude, y lo delegas. Te ahorras la parte repetitiva y es robusto.
Cuándo conviene: quieres construir rápido / delegar la parte rutinaria en producción.
El panorama de A. el bucle a mano es solo enlazar de forma directa las piezas vistas hasta ahora. Tienes un historial de conversación, invocas al LLM, si hay petición de herramienta la ejecutas y devuelves el resultado, y si no, sales. Eso es todo.
# A. Bucle a mano (pseudocódigo / estilo de mensajes de Claude) messages = [ user(goal) ] for step in range(MAX_STEPS): # ← freno con el límite reply = client.messages.create( model="claude-…", messages=messages, tools=[search_tool], ) log(step, reply) # ← registra siempre, para observar if reply.stop_reason == "tool_use": out = run_tool(reply.tool_name, reply.tool_args) messages += [ assistant(reply), tool_result(out) ] else: break # salió la respuesta final → fin
Si usas B. el tool runner del SDK, la propia biblioteca se encarga de ese bucle for. Lo único que escribes es «la definición de la herramienta», «la función real» y «el objetivo inicial». El bucle, la gestión del historial y la devolución del resultado de la herramienta se procesan por dentro.
# B. Delegar en el tool runner del SDK (pseudocódigo) runner = ToolRunner( model="claude-…", tools=[search_tool], # definición handlers={"search_weather": run_tool}, # función real ) answer = runner.run(goal) # el bucle gira por dentro
💡 Los nombres exactos de los métodos, en la documentación oficial. Aquí, client.messages.create y ToolRunner son pseudocódigo para transmitir la idea. Los nombres reales de los argumentos, la forma de los valores de retorno y los ID de modelo difieren en cada SDK y se actualizan con frecuencia, así que consulta siempre la versión más reciente en la documentación oficial. Primero captar el concepto y luego rellenar los detalles con la documentación: esa es la forma de no dar rodeos. Como introducción paso a paso, consulta también Cómo crear un agente de IA (introducción).
La recomendación es «primero escríbelo a mano una sola vez con A, y a partir de ahí ahórrate trabajo con B». Una vez que giras tú mismo el bucle, el SDK deja de ser una caja negra y, cuando te atascas, puedes imaginar qué está pasando dentro.
Ponerlo en marcha y observar
Una vez montado, ponlo en marcha. Lo importante aquí no es solo hacerlo funcionar, sino observar «dónde pensó qué y dónde falló». En el desarrollo de agentes, la calidad de esta observación separa los resultados. Por eso metemos registros (logs) desde el principio.
Como mínimo, registra lo siguiente en cada vuelta. Con un bucle a mano, basta con la línea log(step, reply).
Si en esa vuelta el LLM decidió «usar una herramienta» o dar la respuesta final. El punto de bifurcación de la decisión.
El nombre de la herramienta y los argumentos. Si esto es raro, el resultado también se tuerce. Es el punto donde más se nota un desajuste en la comprensión del LLM.
El valor de retorno de la herramienta. Aquí se esconde lo que tuerce la siguiente decisión: demasiado grande, vacío, error…
Al ponerlo en marcha de verdad, se ven comportamientos curiosos (y engorrosos). Por ejemplo: el LLM invoca una herramienta sin necesitarla. O, al revés, no la invoca cuando debía y responde solo con la memoria. Se equivoca ligeramente en el nombre de la ciudad del argumento. Repite la misma búsqueda varias veces cuando una habría bastado. De estos «tics de decisión» solo te das cuenta al mirar los registros.
✅ Los registros no son una «función de lujo», sino imprescindibles desde el principio. Como el interior de un agente es difícil de ver, sin registros no entiendes en absoluto «por qué actuó así». De momento basta con una línea de print. La evaluación y la observabilidad, que sistematizan esta observación, las tratamos en serio en el capítulo 5. Por ahora, adquiere aquí el «hábito de mirar».
Puntos donde se atasca
Incluso con la configuración mínima, al ponerlo en marcha siempre chocas con varios muros. Todos son atascos clásicos del desarrollo de agentes que iremos resolviendo capítulo a capítulo. Aquí captamos su «naturaleza» y el «apaño que puedes hacer ahora», y dejamos el tratamiento serio para los capítulos posteriores.
Sigue invocando la misma herramienta sin parar y no termina nunca. Gira en vacío porque no logra juzgar que ya alcanzó el objetivo.
Apaño: pon siempre un límite máximo de vueltas. Detecta y detén las llamadas consecutivas con los mismos argumentos.
La herramienta devuelve un JSON enorme o el texto completo de una página, y devolverlo entero a la conversación dispara coste y latencia.
Apaño: en la propia herramienta, limita a los campos necesarios / resume antes de devolver. No pases el texto completo sin procesar.
Cuantas más vueltas, más se acumula el historial, se acerca al límite y se vuelve lento, caro e inestable.
Apaño: resume y comprime los intercambios antiguos / descarta los resultados de herramientas que ya no hacen falta. Tratamiento serio a partir del siguiente capítulo.
📊 Los tres son problemas de «diseño del contexto». El bucle infinito, el inflado del valor de retorno y el inflado del contexto: la raíz de todos llega al diseño del contexto, es decir, «qué y cuánto le pasas al LLM». Este enfoque está sistematizado como ingeniería de contexto y es la columna vertebral del desarrollo de agentes. Para empezar, ten como lema «no pasar de más ni acumular de más».
- El agente mínimo = los 4 elementos montados en su forma más pequeña. Lo único que lo diferencia de un uso único de la API es el bucle.
- El bucle repite una vuelta de «pensar → invocar la herramienta → devolver el resultado → volver a pensar → detenerse al completar». El freno del número máximo de vueltas es imprescindible.
- De la herramienta, pasas la definición (nombre, descripción, argumentos) al LLM, y la función real la ejecutas en tu lado. El LLM solo la pide.
- La implementación tiene 2 formas: bucle a mano (para aprender) y tool runner del SDK (para la práctica). Por dentro son lo mismo.
- Desde el principio, observa con registros y detecta los atascos clásicos: bucle infinito, inflado del valor de retorno e inflado del contexto.
Una vez que tengas un agente en marcha, el siguiente paso es aumentar sus herramientas en serio. En el siguiente capítulo 3, «MCP y conexión de herramientas», conectaremos las herramientas a servicios y datos externos por la vía estándar (MCP) y ampliaremos de golpe las manos del agente. Cuando quieras repasar el panorama del capítulo anterior, vuelve al capítulo 1.