FRIDAY: un asistente por voz que no puede decir «listo» sin haberlo hecho
Mi asistente personal por Telegram: agenda, correo, tareas y CRM por voz. Lo interesante no es el modelo, es el código que lo rodea: confirmaciones firmadas, privacidad por nivel y un guardián contra el «ya lo hice» sin hacerlo.
La idea
Trabajo en muchos frentes a la vez y pierdo tiempo en lo mismo: cambiar de contexto, el trabajo administrativo disperso, enterarme tarde de que algo falló. FRIDAY es un asistente personal —para un solo usuario, yo— al que le hablo por notas de voz en Telegram y que actúa sobre mi agenda, mi correo, mis tareas, una memoria propia y un CRM con espejo en HubSpot.
La regla que ordena todo: nada sale hacia afuera sin que yo lo confirme con un botón.
Cómo está montado
- Arquitectura hexagonal. El dominio no hace I/O y la aplicación depende de puertos (
Protocol), nunca de los adaptadores. - Un loop de agente propio sobre LiteLLM, sin LangGraph ni otro framework. Las confirmaciones con argumentos congelados, el ruteo por sensibilidad y el recorte de resultados son reglas mías, y no quería esconderlas dentro de una librería.
- Privacidad en tres niveles. Cada turno hereda el nivel más alto de lo que toca —historial y resultados de herramientas incluidos—, y el proveedor gratuito que entrena con los datos queda vetado en código para todo lo que no sea información general.
- Confirmaciones que no se pueden falsificar. Los argumentos de una acción se congelan en la base de datos; el botón lleva una firma HMAC con versión, vence a los 15 minutos y se consume una sola vez con un
UPDATEcondicionado, así que un doble clic ejecuta una vez. La voz nunca confirma una acción de este nivel. - Herramientas elegidas por turno. Un clasificador pequeño decide qué herramientas ve el agente en cada mensaje: un turno de agenda viaja con unos 4,000 tokens, no con el catálogo entero.
- Cuando el código puede armar la respuesta, no se llama al modelo. La agenda, el estado de un proyecto o la ficha de un cliente se componen desde la base: cero tokens y nada inventado.
- Un solo Postgres, con pgvector y embeddings locales en ONNX, de unos 11 ms por consulta.
El registro de herramientas también rechaza, al arrancar, capacidades que no quiero darle nunca:
if _FORBIDDEN_SEGMENTS.intersection(tool.name.split("_")):
problems.append("capacidad prohibida por diseño (regla 4)")
if tool.level not in ("L0", "L1", "L2"):
problems.append(f"level inválido: {tool.level}")
if tool.level == "L2" and "summarize_for_confirmation" not in type(tool).__dict__:
problems.append("L2 exige summarize_for_confirmation propio")
if problems:
raise ToolContractError(f"{tool.name}: " + "; ".join(problems))
Lo que ya funciona
Lo uso todos los días. Voz y texto por Telegram; calendario con varias cuentas e invitaciones reales; correo en lectura y borradores (nunca envía solo); tareas y recordatorios con feriados de Perú; memoria; un CRM con su pipeline y un reporte de horas; el espejo en HubSpot cada 15 minutos; y /costos y /audit para ver qué hizo y cuánto costó.
Al cerrar la segunda fase: 570 pruebas en verde, 233 llamadas al modelo sin un error por US$ 0.16 en total, y una mediana de 1.26 s por llamada.
Lo que todavía no
El briefing de la mañana y los monitores de mis servidores (la fase en curso), propuestas y finanzas, el cliente de escritorio con palabra de activación y el modo reunión.
Lo aprendido
Una regla en el prompt no es una garantía. El modelo respondió «creé la tarea» y en la tabla había cero filas. El fragmento de arriba existe por eso: si el agente dice que hizo algo sin haber llamado a la herramienta, el turno no termina; recibe un aviso y vuelve a intentarlo. Lo que importa va en código, no en instrucciones.
Los fakes no ven los bugs del proveedor real. Las pruebas con dobles pasaban; el proveedor real validaba en su servidor un formato de fecha y rechazaba todas las llamadas.
Si el código puede responder, el modelo sobra. Una consulta de agenda por voz tardaba 20.5 s; armando la respuesta por código bajó a unos 5 s. Y medir con honestidad también cuenta: la mediana de voz incluía notas sin audio, y al corregirla subió.
Siguiente paso
El resumen de cada mañana —agenda, pendientes y clima— y monitores de mis servidores que me avisen por severidad antes de que me entere por un cliente.