
Durante mucho tiempo usé ChatGPT y Gemini como los usa casi todo el mundo, como un chat. Les preguntaba cosas, me explicaban una función que no terminaba de entender, me ayudaban a redactar un texto y ahí se acababa todo. Y funcionaba, no te voy a decir que no. Pero conforme los usaba más, más claro veía lo limitado que era aquello, porque tenía delante algo que parecía entenderlo todo y era incapaz de hacer absolutamente nada. No me leía el correo, no me gestionaba el calendario, no me apuntaba una idea, no me resumía las noticias del día. Sabía hablar de todo y no podía tocar nada. En el episodio 843 te conté cómo le había dado memoria a mi asistente. Hoy te cuento la otra mitad del problema, la que lo convierte en algo útil de verdad: cómo se le dan manos a una IA, y qué cuesta hacerlo.
Un asistente que solo habla es un loro
El otro día, dándole vueltas al guion de este episodio, me salió una frase que me parece la más justa para describir el punto de partida: un asistente que solo habla no vale para absolutamente nada, es un loro. Muy listo, muy bien hablado, con unas formas impecables, pero un loro al fin y al cabo. Repite, resume, razona sobre lo que le cuentas, y cuando llega el momento de hacer algo se queda mirándote. Le faltan manos. Y ese es exactamente el hueco que quiero tapar hoy.
Porque fíjate en lo que le pedirías tú a un asistente de verdad. Que mirara tu correo y te dijera que ahí hay uno importante. Que te ayudara a redactarlo. Que te organizara el calendario. Que cuando aparece un capítulo nuevo o una noticia nueva no se limite a avisarte de que existe, sino que la resuma. Que si tienes cien noticias pendientes sea capaz de sacar de entre todas ellas las cuatro que merecen la pena. Nada de eso es «hablar». Todo eso es «hacer».
Y aquí conviene parar un momento y explicar qué es, por debajo, una de esas manos. Lo que los proveedores llaman function calling o tool use. La idea es engañosamente sencilla. Al modelo, además de la conversación, le envías una lista de funciones que tiene a su disposición, cada una con un nombre, una descripción de para qué sirve y un esquema de los parámetros que acepta. Cuando el modelo decide que necesita una de esas funciones, no la ejecuta. Emite una llamada, es decir, te dice «quiero llamar a esta herramienta con estos argumentos». Y el que la ejecuta de verdad eres tú, tu código, que luego le devuelve el resultado. Insisto en esto porque es donde más gente se lía: la IA no hace cosas por arte de magia, propone una llamada y algo de tu lado la lleva a cabo. Es la diferencia entre el que pide y el que paga.
Es un mecanismo estándar y está documentado por todos los grandes. OpenAI lo describe en su guía de function calling, y Gemini ofrece exactamente lo mismo en su documentación de function calling. Anthropic, que ha pensado mucho sobre esto, lo formula de una manera que me gusta especialmente: dice que las herramientas son un contrato entre un sistema determinista, tu código, y un agente no determinista, el modelo. Y añade un aviso que conviene tener siempre presente, que un agente puede equivocarse, alucinar incluso, y no saber cómo usar una herramienta que le has dado. Es decir, dar manos añade capacidades, sí, pero también la posibilidad de que quien las use no haga lo que esperas.
Así que, resumiendo el diagnóstico: el modelo no era el problema, no era tonto. El problema era que estaba manco. Y como con un manco no se va a ningún sitio, me puse a darle manos a mi asistente, a Valet.
Anuncios parroquiales: err-serve, podtrack y el MCP del blog
Antes de entrar en materia quiero hacer un hueco para contarte un par de cosas en las que he estado trabajando estos días, al más puro estilo de los anuncios parroquiales de otros podcast de la red. Y te aviso de que casi todo esto lo he montado ayudándome de modelos de lenguaje, que es de lo que va el episodio.
Lo primero, err-serve. Es una herramienta que está directamente ligada con Traefik, el proxy inverso que uso delante de mis sitios. Lo que hace es muy concreto: cuando alguien pide una página que no existe y el servidor no la encuentra, en lugar de devolver el error genérico, sirve una página que tú hayas configurado. Esto me soluciona un problema que arrastraba desde hace tiempo con la herramienta que usaba antes, y que me di cuenta de que tenía precisamente estos días. Aquella, en vez de devolver el 404 de «no encontrado», lo que te devolvía siempre era un 200, un «todo bien». O sea, que las páginas que servían de verdad no parecían caídas aunque lo estuvieran, y llevaba un tiempo creyendo que todo iba bien cuando no era así. Lo tienes en github.com/atareao/errserve.
Lo segundo, que probablemente dé para otro episodio, es el trabajo sobre Valet, mi asistente. Estos días he estado liado con el vault de notas y con las tareas dentro del asistente, que es justo la parte de la que te hablo hoy, así que en cierto modo este episodio es un avance de aquello. Y lo tercero es podtrack, una herramienta pequeña, casi de andar por casa, que me he montado para poder gestionar todos los episodios del podcast. Más que gestionar podría decir ordenar, porque lo que hago es que cada vez que se me ocurre una idea la apunto ahí, reorganizo la lista, muevo episodios de un sitio a otro y voy dejando preparado el calendario. Lo tienes en github.com/atareao/podtrack.
Y el cuarto es el blog. He dado una segunda vuelta al servidor MCP de atareao.es, del que ya te he hablado en otras ocasiones, de forma que ahora te puedes conectar a mi blog a través de tu propio modelo de lenguaje usando ese protocolo. Pero no solo eso, porque además vas a poder hacer bastantes más cosas con él. De hecho, una de las que estoy haciendo ahora es subir todas las transcripciones de cada uno de los episodios al servidor, para que sean consultables. Cualquiera de estas herramientas la puedes usar, que para eso están.
Las manos: 33 herramientas repartidas en fichas
Vamos al grano. Cuando me puse a ello, lo que hice fue darle a mi asistente treinta y tres herramientas distintas. Treinta y tres manos, cada una para una cosa. Hay herramientas para trabajar con el correo, para el calendario, para las tareas, para el diario, para las notas, para los RSS, es decir, para las noticias. Hay herramientas para que me diga la previsión meteorológica, para que busque lugares, para recordatorios, para el deporte. Prácticamente todo lo que se te ocurra.
Y alguna de ellas tiene una historia detrás. La de buscar lugares, por ejemplo, viene heredada directamente del viaje que hicimos por el sur de Italia, por Puglia, del que te hablé en el episodio del asistente de viaje. Aquel asistente era precisamente eso, un guía que te decía dónde comer cerca, qué museo merecía la pena, qué playa no te podías perder. De ahí nacieron las manos de entorno, las de lugares y geolocalización. No salieron de un diseño en una pizarra, salieron de una necesidad real, de estar perdido en un pueblo de Puglia con hambre y con el móvil en la mano.
Ahora, treinta y tres herramientas sueltas serían un cajón desastre, tanto para mí como para el propio modelo. Así que lo primero que hice fue organizarlas en bloques, que yo llamo fichas, y que en la jerga de esto vendrían a ser las skills, las habilidades. Cada ficha agrupa las herramientas de un mismo dominio y lleva su propio criterio. Fichas como la agenda, los pendientes, los recuerdos, el entorno, la web, los widgets, el running, la línea del tiempo, el correo, los RSS y el blog. Cada una con lo suyo, y dentro de cada una, sus herramientas.
Y fíjate en la diferencia entre una ficha y una herramienta, porque es importante. La ficha es la categoría, el cajón. La herramienta es la mano concreta que hay dentro. La ficha «entorno», por ejemplo, agrupa las herramientas de lugar y meteo, y todas ellas comparten un criterio común de enrutado, que ya te contaré. En total, doce fichas para treinta y tres herramientas, y cada bloque con su ficha correspondiente.
¿Y qué lleva dentro una herramienta, qué es lo que ve el modelo exactamente? Una definición, que en el fondo es un trozo de JSON con tres partes. Un nombre, una descripción de para qué sirve y un esquema con los parámetros que acepta. Para que te hagas una idea, así se ve un esquema abreviado de una de las mías, la de la previsión del tiempo:
{
"name": "weather",
"description": "Get the weather forecast for a location by coordinates.",
"parameters": {
"type": "object",
"properties": {
"latitude": { "type": "number" },
"longitude": { "type": "number" }
},
"required": ["latitude", "longitude"]
}
}
Eso es un encargo de trabajo para el modelo: «si necesitas el tiempo, llámame así y dame estas dos cosas». Y aquí viene el primer detalle que me sorprendió cuando empecé a mirar las cifras. Dentro de una definición, lo que suele pesar más no es la descripción, son los parámetros. Te pongo el caso más exagerado de los míos, la herramienta de notas, que dedica dos mil doscientos cincuenta y tres caracteres solo a su esquema de parámetros y apenas quinientos cincuenta a la descripción. Casi todo el peso está en explicar qué datos acepta, no en decir para qué sirve. Y cada uno de esos caracteres, como vas a ver, se paga.
El peaje: 11.000 tokens para un «hola»
Y aquí llega la parte incómoda de dar manos, la que nadie te cuenta en los artículos bonitos. Para que todo esto funcione, cada vez que le hago una pregunta a mi asistente yo le envío tres cosas: las últimas conversaciones que hemos tenido, los recuerdos que su memoria ha considerado relevantes y, además, todas las herramientas de las que dispone para trabajar. Todo eso viaja junto en cada turno. El modelo no sabe que tiene treinta y tres herramientas porque las lleve dentro; lo sabe porque yo se lo estoy diciendo cada vez, con todo lujo de detalles.
Y ahora echa la cuenta. Si tengo treinta y tres fichas o treinta y tres herramientas, esa lista de definiciones que le envío cada vez son, estimando, unos once mil tokens. Para que te hagas una idea, equivale a mandarle cada vez un documento de la extensión de un capítulo de un libro, y no precisamente corto. Con un matiz de honestidad que me gusta dejar claro: ese número sale de un estimador propio, no de un contador de tokens real, así que hablo de «unos once mil», no de «once mil exactos». En la medición que hice sobre mi propio catálogo salieron algo más de veintisiete mil caracteres y unos once mil doscientos sesenta y cinco tokens estimados.
¿Y ves el absurdo? Si yo le digo «buenos días» y él, para contestarme, arrastra todo ese manual detrás, estamos tirando tokens a mansalva. Le estoy enviando once mil tokens únicamente para que me conteste «hola, buenos días». Es como si cada vez que quieres preguntarle la hora a alguien tuvieras que leerle antes el manual de instrucciones de toda la casa entero. Funciona, sí, pero es un desperdicio enorme, y encima se paga en cada turno, para siempre.
Y ojo, que esto no es un problema casero de un tipo con un asistente en un contenedor. Anthropic lo ha medido y cuenta que con cincuenta y ocho herramientas, tan solo las definiciones, ya se te van unos cincuenta y cinco mil tokens antes de haber empezado a conversar, con GitHub, Slack y Jira repartiéndose la mayor parte de la factura. Y cuentan que han llegado a ver definiciones de herramientas consumiendo ciento treinta y cuatro mil tokens. Con su solución de búsqueda de herramientas han conseguido recortar hasta un ochenta y cinco por ciento, y en algunos casos subir la precisión de acertar la herramienta correcta del cuarenta y nueve al setenta y cuatro por ciento. Hasta tienen una frase que debería ir enmarcada: más herramientas no siempre significan mejores resultados. Demasiadas herramientas, o herramientas que se solapan entre sí, distraen al modelo. Es el contrapunto perfecto a mi lista de treinta y tres. Por mi parte, un trabajo sobre selección de herramientas, el que llaman RAG-MCP, cifra el problema igual de claro: recortando lo que le mandas puedes bajar más de la mitad de los tokens y más que triplicar el acierto al elegir herramienta, de un trece por ciento a un cuarenta y tres.
Así que tenía dos problemas en uno. El primero, el gasto, que es evidente. El segundo, más sutil, que cuantas más manos le doy, peor elige cuál usar. Y los dos se arreglan con la misma pieza.
El enrutador: un segundo modelo que decide qué enseñar
La solución que encontré es tan sencilla de decir como difícil de montar, y me parece la pieza más interesante de todo el episodio. La idea es no enviarle al modelo todas las herramientas siempre, sino decidir en cada momento qué herramientas le tengo que enviar. Así, de golpe, el manual entero se convierte en un folleto de las páginas que hacen falta para esa pregunta concreta.
¿Y cómo decides eso? Pues usando otro modelo de lenguaje. Fíjate en la jugada: tengo un primer modelo, el que habla conmigo, el que me contesta y utiliza las herramientas; y tengo un segundo modelo que hace de enrutador, de portero, que decide qué manos se merece cada mensaje. Es el modelo de decisiones del enrutador, y no es un modelo generativo como el otro. No escribe texto ni razona en voz alta; yo le paso una pregunta tipada y él me devuelve una respuesta tipada, sí o no. Nada más.
Ese segundo modelo es Jev, de TypeSafe, y funciona con un criterio binario por cada ficha. Te pongo el ejemplo de la ficha de la web, que es la que mejor se entiende. Al clasificador le pregunto algo como: «¿la respuesta requiere información externa de internet?». Y le doy los dos criterios. El sí es que el mensaje pide información que no está en los datos del usuario, noticias, precios, documentación, cosas que cambian. El no es que el mensaje se responde con los datos del propio usuario, con lo que ya sé de ti. Con eso, el modelo devuelve un sí o un no y yo sé si tengo que anunciar la herramienta de búsqueda web o no.
Y lo mismo con cada ficha. La de la agenda responde a «¿la respuesta requiere mirar o cambiar la agenda?», con su ámbito bien definido: eventos, citas, reuniones, cumpleaños, disponibilidad. La de los pendientes, la de los recuerdos, la del entorno, todas tienen su criterio de sí o no. El clasificador decide, y las herramientas de las fichas seleccionadas se unen al núcleo, que son un par de herramientas que van siempre expuestas. El modelo final, el que me contesta, solo ve lo que se anuncia en el mensaje. Nunca ve el catálogo entero. Eso es lo que le permite al asistente tener un montón de capacidades sin ahogarse.
Este enfoque tiene un nombre en la literatura. Anthropic lo llama simplemente el patrón de enrutado, o routing, y lo describe como clasificar la entrada y dirigirla a la tarea especializada, en lugar de darle todo a un solo proceso que lo haga todo. Es exactamente lo que hago, solo que en lugar de dirigir a un trabajador especializado, dirijo a un conjunto de herramientas.
Ahora, la parte honesta, porque el enrutador no es magia y tiene peligro. Yo estoy decidiendo a priori si el modelo va a necesitar una herramienta o no, y puedo equivocarme. Si decido que no la va a necesitar y resulta que sí, esa herramienta no le llega al modelo, y el modelo, simplemente, no la puede usar. Hace lo que puede con lo que tiene. Es un poco arriesgado, y es la manera más sencilla que he encontrado de hacer este enrutamiento. A cambio, tengo un detalle de diseño que me parece muy sano y que quiero contarte tal cual: si el enrutador se apaga, si el clasificador falla o si tarda demasiado, el sistema no le quita capacidades al asistente, se las da todas. Ante un fallo del clasificador, mi asistente prefiere dar de más antes que quedarse mudo. Eso se llama fallarse hacia lo abierto, y es una decisión deliberada, no un descuido. El precio de esa decisión es que ese turno viaja con el manual completo, con sus once mil tokens, pero el asistente sigue funcionando.
Un par de números del clasificador, que son sus límites de trabajo. Le doy ochocientos milisegundos para decidir, y le paso las últimas seis conversaciones como contexto para la clasificación, nunca más de diez. Y hay una anécdota de su puesta en marcha que me hace gracia: nació apagado y se encendió por defecto al día siguiente. Con el enrutador apagado, cada turno anuncia las treinta y tres herramientas. Con él encendido, solo las que hacen falta.
El ejemplo del café: seis herramientas y 1.060 tokens
Para que veas cuánto cambia esto, nada mejor que un ejemplo real y tonto. Yo le digo a mi asistente: «busca una cafetería cerca». Y ahí se dispara el enrutador. ¿Qué fichas hacen falta? La de dónde estoy, la de buscar sitios y la de geocodificar. Y esas tres fichas agrupan entre todas seis herramientas, ni una más. Porque dónde estás tiene un par de herramientas, buscar sitio tiene otro par y geocodificar tiene otras dos. En total, seis manos para resolver la cafetería, y esas seis definiciones son, estimando, unos mil sesenta tokens. Compáralo con los once mil del catálogo entero. Ahí está la diferencia.
Y hay más ejemplos de lo mismo. Cuando por la mañana le digo «buenos días», el enrutador enciende la agenda, los pendientes, el entorno y los widgets, y eso son once herramientas, unos dos mil diez tokens. Le digo buenos días y él ya sabe que tiene que mirar el correo, los RSS, las notificaciones, y me lo cuenta. Y si le digo un simple «hola», sin más intención, solo se anuncian las dos del núcleo, unos doscientos once tokens. Nada de once mil.
De hecho, tengo dos herramientas que van siempre expuestas, sin pasar por el enrutador. Son la hora y la ubicación, porque están íntimamente ligadas con la persona y con el asistente, y me parecen las dos manos imprescindibles. Y las dos son facilísimas de implementar, que ese es el otro motivo. Una herramienta de hora es trivial. La de ubicación también, y en mi caso la saco directamente del navegador, porque la interfaz la puedo abrir desde el móvil y ahí ya me sale exactamente dónde estoy.
El caso es que, con todo esto, hice un muestreo de lo que había ido usando y me di cuenta de que había ahorrado alrededor de un veinticinco por ciento. Todavía tengo margen para afinar más, pero el veinticinco por ciento ya es un pellizco importante, y lo he conseguido sin quitarle ni una sola capacidad al asistente. Y hay algo que me gusta de este diseño, y es que al final lo que me ha quedado es la posibilidad de definir o modificar, según mi criterio, tanto el prompt que envío como los criterios del enrutador y el umbral de cada ficha. O sea, que el que manda sigo siendo yo: yo decido qué manos se enseñan y cuándo. No es el modelo el que decide lo que puede hacer; lo decide el humano que lo configura, que en este caso soy yo.
Y cada vez que añado una ficha nueva, lo hago sin miedo a que el contexto se me dispare, porque el enrutador es el que se encarga de que solo lleguen las que tocan. Antes esto era distinto, porque al principio lo publicaba todo, utilizaba siempre todas las herramientas, y me di cuenta enseguida de que era una barbaridad. Con el enrutador, ese problema desaparece.
Dar manos es dar responsabilidad
Y aquí llega el segundo gran tema del episodio, el que para mí es tan importante como el de los tokens. Dar manos es tener responsabilidad. Tú lo que estás haciendo es darle todas las posibilidades a tu asistente, y eso da un poco de vértigo, porque imagínate que tu asistente decide hacer cualquier cosa por su cuenta, como enviar un correo electrónico sin tu consentimiento. Ahí es donde entra la responsabilidad.
Y esto es más fácil de entender con un ejemplo. No es lo mismo leer tu agenda que borrar tu agenda. Las dos cosas son «usar el calendario», pero una es inofensiva y la otra te puede arruinar el día. Así que no todas las manos se comportan igual, y ahí es donde yo le pongo los guardarraíles.
En concreto, le he dado tres niveles de permiso. Uno, el primero, es que el asistente puede usar la herramienta sin preguntarte nada, directa y silenciosamente. El segundo es que te avisa, es decir, te dice «voy a hacer esto» y lo hace. Y el tercero es que te pide el sí explícitamente, que te obliga a decir que sí antes de hacer nada. Borrar algo o escribir un correo electrónico caen en este tercer nivel, porque son operaciones que no quiero que se le escapen de las manos.
El reparto, en mi caso, es este. El nivel más estricto, el que exige que le des permiso, lo tienen las herramientas que borran eventos del calendario, borran tareas, borran entradas del diario, borran hechos de la línea de tiempo, envían correos, o escriben y borran en el almacén de notas. El nivel intermedio, el que simplemente avisa, lo tienen los recordatorios siempre, y las creaciones y actualizaciones del calendario, de las tareas y de las notas. Y el nivel más permisivo, el que no pregunta nada, lo tienen todas las lecturas y las escrituras de bajo riesgo: mirar el correo, leer los RSS, el tiempo, buscar lugares, buscar en la web, apuntar una nota.
Y hay un detalle fino que me gusta, y es que el permiso no se decide solo por herramienta, se decide por los argumentos con los que se llama. No es lo mismo usar la herramienta de notas para leer que para borrar, aunque sea la misma herramienta. El permiso mira qué le estás pidiendo hacer, no solo a quién. Eso te da un control mucho más fino del que parece. A ti te corresponde crear todas tus herramientas y poner los guardarraíles que consideres, para evitar que tu modelo haga exactamente lo que quiera con toda la información que está guardando. Y no hay una respuesta única, porque no es igual de grave en todos los sitios. En mi caso concreto, borrar una nota no le he dicho que pida permiso, pero borrar una tarea sí. Y ese tipo de decisiones solo las puedes tomar tú, porque sabe cada cosa lo que te importa.
El silencio no es un permiso
Y ahora te cuento la regla que da título a este bloque y que, de todo lo que he aprendido montando esto, es la que más me llevo. El silencio no es un permiso.
Te pongo la escena. Yo le digo «borra la reunión del martes». Esa es una operación del nivel más estricto, así que el sistema no la ejecuta, se queda esperando tu sí. Ahora imagina que tú, por lo que sea, no le contestas. Te has ido a hacer otra cosa, se te ha ido el santo al cielo, lo que sea. Y ahí hay dos caminos posibles. Uno, malísimo, es que el sistema asuma el sí, que interprete tu silencio como un «adelante» y borre la reunión por su cuenta. El otro, el correcto, es que el permiso expire. Y expirado no significa «pues adelante ahora que nadie mira», significa que si nadie contesta en cinco minutos, el silencio se toma como un no. Se acabó. No se borra nada. Tienes que volver a pedirlo.
En mi sistema hay cuatro resultados posibles, no dos, cuando el asistente te pide permiso. Que apruebes, que digas que no, que se agote el tiempo, o que la petición se cancele porque el turno que la esperaba desapareció o no había canal para preguntarte. Y de esos cuatro, solo uno autoriza la acción: que apruebes. Los otros tres son, todos, un no. El temporizador está puesto en cinco minutos, y en el código está escrito con esa intención, tratando el tiempo agotado como una negativa. Cinco minutos y el silencio es un no.
Y esto no es una ocurrencia mía de fin de semana, que conste. El propio estándar del que te hablo más abajo, el protocolo de contexto de modelos, dice que por confianza y seguridad siempre debería haber un humano en el circuito, con capacidad de denegar la invocación de una herramienta. Y su mecanismo de elicitación, que es como llama a preguntarle algo al usuario, distingue tres respuestas, no dos: que aceptes y mandes los datos, que rechaces explícitamente, o que canceles cerrando el diálogo sin elegir. En las dos últimas no hay permiso, igual que pasa con el silencio. El SDK de agentes de OpenAI va más allá y falla hacia lo cerrado cuando no puede inspeccionar con seguridad los argumentos de una aprobación, es decir, ante la duda, no ejecuta. Toda la industria seria ha llegado a la misma conclusión por caminos distintos: cuando no hay un sí claro, no hay permiso.
Y este es un tema que me importa mucho, porque estas manos no son juguetes. Tienen acceso a tu correo, a tu calendario, a tus notas, a tu diario. Un sistema que interpreta el silencio como un sí te puede borrar el martes entero mientras estás comiendo. Por eso lo digo sin rodeos y lo pongo en negrita aunque quede feo: el silencio no es un permiso.
Las manos que ya tengo, una a una
Vale, ya tienes la teoría, el coste y los permisos. Ahora déjame que te enseñe el catálogo, porque al final de eso va el episodio, de las manos que se le pueden dar a un asistente personal. Estas son las mías, y te las cuento por bloques.
El correo electrónico es probablemente la mano que más uso. Tengo herramientas para listar los no leídos, para leer el cuerpo de un mensaje y para marcarlo como leído, y esas tres no preguntan nada, son de lectura. Y luego está la de enviar correo, que es la que sí te pide permiso siempre, porque escribir en tu nombre es de las cosas que no quieres que se le escapen. Es un ejemplo perfecto de lo que te decía: leer tu correo y enviarlo en tu nombre son dos cosas con riesgos completamente distintos. Si quieres montarte algo así, Gmail tiene su propia API documentada en las guías de la API de Gmail, que es por donde empezar.
El calendario es la ficha de la agenda, de la que ya te he hablado. Ahí tengo anotados distintos eventos a lo largo de todo el año, y el asistente puede crearlos, actualizarlos y borrarlos. Crear y actualizar avisan; borrar exige tu sí. Y luego, en el cuerpo del asistente, tengo un montón de pequeñas herramientas con las que puede crear un evento, borrar un evento y hacer todo tipo de operaciones, según lo que yo le pida en cada momento.
Las tareas merecen un comentario aparte, porque al principio las tenía montadas dentro de mi propia herramienta y al final opté por buscar una pieza externa. Uso OpenTodo como backend de tareas, y lo que hice fue implementar dentro del asistente las herramientas necesarias para conectarse con él. Es una decisión que me parece interesante: en lugar de reinventar el gestor de tareas, le doy manos al asistente para hablar con el que ya uso. Las creaciones y actualizaciones avisan; borrar una tarea exige el sí explícito, porque un borrado no tiene vuelta atrás.
Las notas y el diario son otra cosa. Aquí tengo herramientas para apuntar cosas sueltas, para llevar el diario, del que ya te hablé en el episodio de la memoria, y para trabajar con mi almacén real de notas, que es una pieza que uso mucho y que tiene bastante dentro. Apuntar avisa; borrar una entrada del diario exige permiso. Y con las notas hay una excepción que quiero confesar en voz alta, porque es de esas cosas que se dicen o no se dicen: borrar una nota, en mi caso, no pide permiso. Es la única de las operaciones destructivas que se salta la regla, y es deuda técnica, no diseño. La regla se cumple en cuatro de cada cinco sitios, y justo el que se salta es el que más uso. Lo digo porque me parece que la credibilidad de todo lo demás depende de contar también lo que no está fino.
Los RSS, es decir, las noticias, son una ficha que me gusta mucho, porque son las que dan sentido a la frase del principio, esa de que el asistente no se quede en avisarte de que tienes una noticia nueva, que sea capaz de resumirla y de sacar de cien las cuatro que importan. Tengo herramientas para listar los no leídos, para leer una entrada, para buscar entre todas ellas y para marcarlas como leídas. Y junto con esto van las herramientas de búsqueda web, que usan un buscador externo para lo que no está en mis datos, para las cosas externas y cambiantes, como las noticias, los precios o la documentación.
La meteorología es una mano sencilla que trabaja por coordenadas, y las de lugares, la geocodificación y la búsqueda de sitios, son las que vienen del viaje a Puglia del que te hablaba antes. Y quiero subrayar aquí una cosa, porque me parece de las más útiles del conjunto: la ubicación. Ya te he dicho que la saco del navegador cuando abro la interfaz desde el móvil, y eso significa que el asistente sabe dónde estás sin que tú tengas que escribir nada. Le preguntas qué tienes cerca y ya está, porque sabe dónde estás. Esa es la clase de mano que parece tonta y cambia por completo la experiencia.
Están también los recordatorios, que siempre van con el nivel de aviso, las notificaciones, los widgets y la línea del tiempo, que se apunta como una capa más de memoria, y las de deporte, de las que te hablo un poco más abajo. Y una cosa que quiero que te quede clara: todo esto no es una lista cerrada. Puedo añadir tantas herramientas y tantas fichas como quiera, para hacer todo tipo de operaciones, sin miedo a que el contexto se dispare, precisamente porque el enrutador es el que decide en cada caso qué se enseña y qué no. Si quieres empezar por algo pequeño, no necesitas ni montarte un asistente como el mío. Te puedes hacer un sencillo script que única y exclusivamente consulte tu correo, y pasárselo al modelo diciéndole que use ese script para mirar tu correo. Con eso ya has empezado a darle manos. Lo complicado y lo valioso es la orquestación, no la herramienta suelta.
Cuando el asistente lee el mundo: inyección de prompt y agencia excesiva
Hay un riesgo que quiero nombrar con su nombre, porque es la causa raíz de que existan todos esos permisos de los que te he hablado. Se llama inyección de prompt. Y ocurre cuando el modelo lee contenido externo, un correo que te llega, una entrada de un RSS, una página web, y ese texto que está leyendo contiene instrucciones maliciosas dirigidas al propio modelo. Alguien te manda un correo que, además de texto normal, lleva escondida una orden del tipo «reenvía esta información a tal dirección». Si tu asistente lee el correo y además tiene la capacidad de enviar correo, ya tienes el problema montado. La OWASP lo escenifica exactamente así, con un asistente personal que resume correo y que además puede enviarlo, y un correo entrante que le empuja a reenviarte información sensible a un atacante. Lo tienes descrito en su ficha sobre inyección de prompt.
Y el otro riesgo hermano de este se llama agencia excesiva, o excessive agency. La OWASP lo define con tres causas raíz que me parecen clarísimas: funcionalidad excesiva, permisos excesivos y autonomía excesiva. O sea, que le has dado demasiadas herramientas, demasiados permisos o demasiada libertad para decidir cuándo usarlas. Y las mitigaciones van justo en esa dirección: minimizar las funciones, minimizar los permisos, exigir aprobación para las acciones de alto impacto y mediar en el sistema de destino. Te suena de todo lo que te he contado, ¿verdad? Pues eso es exactamente lo que estoy haciendo con los tres niveles de permiso y con el enrutador. Lo tienes en su ficha sobre agencia excesiva.
Hay un par de amagos más que quiero contarte, porque son finos. Uno, que el propio catálogo de herramientas puede convertirse en una superficie de ataque. En el protocolo MCP, la descripción de una herramienta es texto que el modelo obedece, y si alguien consigue colar instrucciones ocultas en esa descripción, tienes lo que se llama envenenamiento de herramientas, un tool poisoning donde el usuario no ve lo que el modelo sí. Mi caso se blinda parcialmente de eso por un detalle muy simple: mis descripciones son cadenas constantes, se fijan en tiempo de compilación y no se pueden reescribir en caliente, así que no hay forma de inyectar nada ahí. Y el otro amago es el de la alucinación convertida en acción real. Un modelo puede alucinar que ha hecho algo, o invocar mal una herramienta, y con herramientas de lectura eso solo produce una respuesta mala, pero con herramientas de escritura una alucinación se puede convertir en un borrado de verdad. Por eso existen el aviso y la confirmación explícita, no para el caso bonito, sino para el caso en el que el modelo se equivoca.
Y te dejo una tarea pendiente de la mía, que no quiero disimular. El estándar de MCP define unas anotaciones para decir si una herramienta es de solo lectura o destructiva, y mi sistema no tiene un equivalente a eso. No declara por sí mismo qué acciones son destructivas; eso lo tienes que saber tú y configurarlo a mano con los permisos. Además, no me avisa si una descripción se me ha vuelto kilométrica, que es una fuente de gasto silenciosa. Son deudas, no catástrofes, pero las digo porque son parte del mismo problema.
El estándar de la industria: MCP como el enchufe común
De todo lo que he leído sobre esto, hay una pieza que es el marco de referencia de la industria y que conviene conocer aunque tu asistente no la use por dentro. Es el Model Context Protocol, o MCP. La idea es sencilla: un protocolo abierto para que cualquier modelo se conecte a herramientas y datos externos de una manera estandarizada. En lugar de que cada uno invente su propio enchufe, el modelo y la herramienta hablan el mismo idioma. La introducción oficial está en la página de inicio de MCP, y merece la pena leerla.
¿Y cómo funciona por dentro? El cliente descubre las herramientas disponibles pidiendo una lista, y luego las ejecuta llamándolas por su nombre. Cada herramienta que se anuncia lleva su nombre, un título, una descripción y un esquema de entrada, igual que las mías, solo que con nombres y formato fijos para que todo el mundo coincida. La especificación detallada está en la sección de herramientas de la spec 2025-06-18, y ahí se ven un par de cosas que enlazan con todo lo que hemos hablado. La primera es que el estándar recomienda que siempre haya un humano en el circuito con capacidad de denegar la invocación de una herramienta, que es exactamente el «el silencio no es un permiso» pero escrito en una especificación. Y la segunda son las anotaciones de las herramientas, esas pistas que dicen si una herramienta solo lee, si es destructiva, si es idempotente o si trabaja con datos que pueden cambiar. Con un aviso muy sensato: son solo pistas, y si vienen de un servidor en el que no confías, no te debes fiar de ellas.
Y fíjate en lo que te decía antes: mi asistente no está montado sobre MCP por dentro, usa herramientas propias en Rust, pero MCP es el marco en el que todos nos estamos entendiendo. Y lo tienes en mi propio blog, en ese servidor MCP de atareao.es del que te hablaba en los anuncios: te puedes conectar a mi blog desde tu modelo de lenguaje y consultar las transcripciones de los episodios. Es la misma idea, aplicada a otro sitio.
Las otras manos: Strava, notificaciones y Watchbit
Y ya que tengo el catálogo montado, te cuento las integraciones, que es por donde va a ir el episodio que cierra esta serie. He integrado Strava directamente dentro del asistente, de forma que tengo herramientas para consultar mis actividades recientes, el detalle de una actividad concreta, sus datos en bruto y mis estadísticas de deportista. Strava tiene su API documentada en la referencia de la API v3, y con eso el asistente sabe cuánto he corrido, a qué ritmo y con qué desnivel, sin que yo tenga que contárselo. Es una mano que me gusta porque conecta el asistente con algo que ya hacía antes de tenerlo.
Pero lo que más he usado estos días no ha sido que el asistente consulte cosas, sino lo contrario, que le envíe a él las notificaciones. Antes, ese tipo de avisos los mandaba a otro sitio, por ejemplo a Matrix; ahora me he dado cuenta de que es mucho más cómodo enviármelos al propio asistente. ¿Y qué tipo de notificaciones? Pues por ejemplo, cuando se ha caído una página web. O cuando se ha actualizado de forma completamente automática la imagen de algún contenedor. Todo eso lo empujo hacia el asistente, y él lo tiene en cuenta.
¿Y para qué sirve mandarle todo eso? Aquí está lo bonito. Porque yo simplemente le pregunto por el correo y él, que ya tiene todo el contexto, me dice: oye, todos estos correos no valen la pena, pero este y este sí. O me dice: te han llegado setenta notificaciones de Watchbit, que es la herramienta que implementé para saber si alguna de mis páginas se cae, y de esas setenta se han caído treinta y se han levantado treinta, con lo que ni te preocupes. Fíjate en la diferencia entre recibir setenta notificaciones sueltas y que alguien te resuma que el susto ya ha pasado. Lo mismo con las noticias: en lugar de que me avise de que hay cien cosas nuevas, me dice cuáles merecen la pena. Recibir el aviso es fácil; lo valioso es que alguien lo lea, lo entienda y te dé la conclusión. Eso es tener manos y tener criterio.
Y hay algo que enlaza con el episodio 843, el de la memoria. Todas esas notificaciones que le mando van alimentando lo que el asistente sabe de mí. Él va guardando información sobre mis gustos, mis preferencias, y poco a poco va aprendiendo cómo quiero que me dé la información, de qué manera, con qué nivel de detalle. La memoria y las manos, juntas, son las que convierten una herramienta en algo que trabaja de verdad a tu lado.
Lo que me llevo
Así que poco más que decirte. Dar manos a una IA no es apretar un botón ni instalar un plugin. Es sentarte a decidir qué quieres que pueda hacer tu asistente, con qué herramientas, con qué criterios para enseñárselas en cada momento y con qué permisos para cada una de esas operaciones. Y descubrir, por el camino, que el peaje de los tokens y el peaje de la responsabilidad crecen a la vez que las capacidades. Cuantas más manos, más útil, pero también más caro y más arriesgado.
Si me llevo una sola idea de todo este recorrido, es la de los permisos, y dentro de ella, la del silencio. Porque está muy bien eso de darle treinta y tres herramientas y montar un enrutador para que solo use las que tocan, pero el día que te descuides y el asistente te borre algo sin preguntarte, ninguno de esos logros te va a consolar. Leer tu agenda no es lo mismo que borrarla, y tratarlas igual es el error que más caro sale.
Y te dejo con un aviso. Este es el segundo episodio de una serie de tres sobre el asistente: en el 843 te hablé de la memoria, en este de las manos, y en el siguiente, que es el último, te hablaré de las integraciones. De cómo conecto todo esto con Strava, con las notificaciones, con las noticias, y de qué más piezas se le pueden enganchar. Si te interesa el asistente, ese cierre no te lo pierdas.
Mientras tanto, si quieres trastear, el asistente está en GitHub, en github.com/atareao/valet-ai, con licencia MIT, y se monta en un contenedor Docker. Te lo descargas, lo levantas y puedes ver cómo está montado todo esto por dentro, con sus fichas, sus herramientas y sus criterios de enrutado. Y si tienes cualquier idea o sugerencia, o quieres contarme qué manos le has dado tú a tu asistente, me lo dices, que de ahí salen los mejores episodios.
Más información
- MCP — Tools (spec 2025-06-18) — cómo se descubre y ejecuta una herramienta, con su esquema y sus anotaciones de seguridad.
- MCP — Introducción — qué es el protocolo de contexto de modelos y por qué estandariza el enchufe entre modelo y herramienta.
- MCP — Elicitation (spec 2025-06-18) — las tres respuestas posibles a una petición de permiso: aceptar, rechazar o cancelar.
- OpenAI — Function calling — la guía oficial del mecanismo por el que el modelo emite la llamada que ejecuta tu código.
- Gemini — Function calling — el mismo mecanismo documentado por Google.
- Anthropic — Introducing advanced tool use — las cifras del coste de las definiciones de herramientas y la búsqueda de herramientas que lo recorta.
- Anthropic — Writing effective tools for agents — las herramientas como contrato con un agente no determinista y por qué más herramientas no son siempre mejor.
- Anthropic — Building effective agents — el patrón de enrutado, clasificar la entrada y dirigirla a la tarea especializada.
- Anthropic — Code execution with MCP — cómo ejecutar código dentro del propio flujo del protocolo para no arrastrar todo el catálogo.
- OpenAI Agents SDK — Human-in-the-loop — por qué el SDK falla hacia lo cerrado cuando no puede inspeccionar los argumentos de una aprobación.
- RAG-MCP (arXiv:2505.03275) — recortar el prompt con recuperación reduce los tokens y multiplica el acierto al elegir herramienta.
- OWASP — LLM06:2025 Excessive Agency — las tres causas de la agencia excesiva y sus mitigaciones en permisos y funcionalidad.
- OWASP — LLM01:2025 Prompt Injection — la inyección de prompt en el escenario del asistente que resume y envía correo.
- Gmail API — Guías — por dónde empezar si quieres que tu asistente pueda leer tu correo.
- Strava — API v3 reference — las actividades, el detalle y las estadísticas del deportista.
- Valet en GitHub — el asistente completo, público y con licencia MIT, con sus fichas, sus herramientas y su enrutador.
- err-serve en GitHub — la herramienta que sirve una página propia cuando el servidor no encuentra la que pides, con el 404 de verdad.
- podtrack en GitHub — la mini herramienta con la que ordeno las ideas y los episodios del podcast.