Volver a proyectos
2026 · ML & IA · Activo

Virtual Assistant — Un Agente de IA que Corre donde Otros No Pueden

Proyecto para aprender a construir agentes de IA desde cero, optimizado para iGPU integrada (Radeon 680M). Responde en ~2s con modelos 3B-4B donde frameworks establecidos piden 24GB+ VRAM y modelos de 31B-70B.

Python llama.cpp llama-router Hammer2.1-3B Gemma-4 ONNX Vulkan Home Assistant Telegram Código

Problema

Los frameworks de agentes de IA existentes (OpenClaw CLI, Hermes Agent) están diseñados para hardware con GPU dedicada o cloud. OpenClaw recomienda genéricamente usar el modelo más potente disponible, y en la práctica modelos sin fine-tuning de tool calling fallan en bucles. Hermes Agent requiere modelos con al menos 64K tokens de contexto. En mi hardware — una iGPU Radeon 680M con 24GB de RAM compartida — estas soluciones o no caben o van demasiado lentas para ser prácticas.

Solución

Construir un agente desde cero aprendiendo cada pieza del pipeline: clasificación de intenciones, routing predictivo de modelos, tool calling eficiente, validación de respuestas, y memoria persistente. Optimizado para exprimir cada recurso: modelos 3B-4B en lugar de 31B-70B, pre-resolución de datos fuera del loop, KV-caching, y un sistema de perfiles que permite cambiar de modelo sin tocar código.

Logros clave

  • Aprendizaje real de todo el stack de agentes: percepción, routing, context building, tool dispatch, grounding, reflection
  • Responde en ~2s con Hammer2.1-3B — más rápido que competidores locales con hardware 10x más caro
  • Routing predictivo: el 80% de peticiones usan el modelo pequeño. Solo 20% necesitan el pensador (Gemma-4-E2B)
  • Sistema de perfiles intercambiables: 6 perfiles distintos, cambias de modelo sin recompilar
  • Grounding sin LLM: valida respuestas en <1ms con reglas, donde otros agentes harían otra llamada de 2-10s
  • 16 módulos de herramientas: Home Assistant, Podman, búsqueda web, Waze, Streamlink, memoria semántica, etc.
  • Corre 24/7 en un servidor casero consumiendo ~25W en idle, ~35W bajo carga

Por qué lo hice

Quería aprender cómo se construye un agente de IA desde cero. No un wrapper de APIs, no un chatbot — un agente que realmente ejecuta herramientas, toma decisiones, y se autocorrige.

Probé opciones existentes:

  • OpenClaw CLI está optimizado para APIs cloud. Su documentación recomienda “usar el modelo más potente disponible”. En la práctica, modelos pequeños sin fine-tuning de tool calling “a menudo se quedan en bucles o fallan al formatear JSON para tool calls”. Mi iGPU no carga un 7B a velocidad usable.

  • Hermes Agent (Nous Research) está diseñado para APIs cloud; requiere modelos con al menos 64K tokens de contexto. Su documentación no prescribe modelos locales específicos para tool calling. En hardware local, modelos sin fine-cutting de tool calling fallan en tareas agénticas.

  • Frameworks cloud no son una opción: dependen de internet, tienen latencia alta, y no conocen mi infraestructura local (Home Assistant, contenedores, etc.).

La solución no era comprar hardware mejor. Era aprender a hacer más con menos.


Qué aprendí

1. Un modelo 3B bien afinado hace tool calling mejor que uno 7B genérico

Hammer2.1-3B (fine-tune de Qwen2.5-Coder para function calling) puntúa mejor en el benchmark BFCL-v3 que modelos de 7B sin especializar. Corre a ~35 tok/s en mi iGPU. El truco no es el tamaño del modelo, sino que esté entrenado para la tarea correcta.

2. Decidir ANTES de ejecutar es la optimización más importante

La mayoría de agentes intentan con el modelo grande y escalan si falla. Este proyecto hace lo contrario: clasifica la intención primero, y solo usa el modelo caro si la tarea lo requiere. El 80% de las peticiones se resuelven con el modelo pequeño (~1-3s).

EscenarioSin optimizarCon routing predictivo
”Enciende la luz”~8s (escala a capable)~2s (standard directo)
“¿Qué temperatura hace?”~6s (embedding + capable)~2.5s (keyword + standard)
“Búscame horarios de cine”~45s (3 rondas capable)~12s (planner→standard, 2 rondas)

3. La separación razonamiento/ejecución funciona independientemente del modelo

Un patrón que descubrí por experimentación: el modelo capaz (Gemma-4-E2B) genera un plan, el modelo standard (Hammer2.1-3B) lo ejecuta paso a paso. El modelo pequeño es mejor siguiendo instrucciones de tool calling que el grande, que tiende a divagar. Esto contradice la intuición de “modelo más grande = mejor en todo”.

4. La validación sin IA es más importante que la IA misma

El sistema de grounding verifica cada respuesta contra los datos reales de las herramientas usando solo regex y reglas de dominio. Tarda <1ms y detecta fechas inventadas, estados incorrectos, y alucinaciones numéricas. En otros frameworks esto se hace con otra llamada LLM (2-10s adicionales).

5. Los perfiles de modelos intercambiables permiten experimentar sin miedo

Los modelos se definen externamente en archivos INI que llama-router lee. Hay 6 perfiles distintos, cada uno con 3 modelos (standard/capable/fallback). Cambiar de perfil no requiere tocar el código del agente. Esto me ha permitido probar combinaciones sin riesgo.


Resultados

Rendimiento vs alternativas

SistemaHardware mínimoModelo recomendadoLatencia típica
OpenClaw CLIGPU 8GB+ VRAMModelo más potente disponible (cloud/local)Depende del hardware
Hermes Agent8GB RAM + 6GB VRAM64K+ contexto (cloud/local)~30-120s en CPU
Este proyectoiGPU integrada + 24GB RAMHammer2.1-3B + Gemma-4-E2B~2s (80%), ~12s (20%)

Datos reales de inferencia en mi hardware

Benchmarks medidos en AMD Ryzen 7 7840HS + Radeon 680M iGPU (Vulkan):

ModeloTamañoVelocidadVRAMPrimera respuesta
Hammer2.1-3B (Q4_K_M)3B params~35 tok/s~4GB~200ms
Gemma-4-E2B (Q4_K_M)2B params efectivos~15 tok/s~5GB~400ms
Qwen2.5-Coder-7B (Q6_K, CPU offload)7B params~8 tok/s~2GB GPU+4GB RAM~800ms

Para contexto: Gemma-4-E2B en un DGX Spark (NVIDIA GB10, 128 GB memoria unificada, 273 GB/s ancho de banda) hace ~53 tok/s. En mi iGPU (Radeon 680M, ~100 GB/s ancho de banda compartido) hace ~15 tok/s. La diferencia es ~3.5x, explicable por la combinación de mayor ancho de banda de memoria (~2.7-3x) más la ventaja computacional sustancial del DGX Spark.

Eficiencia energética

El sistema corre 24/7 en un servidor que consume ~25W en reposo, ~35W bajo carga. Para comparar, una RTX 4090 consume 450W solo la GPU. Esto significa que puedo tener el asistente funcionando todo el día por el coste de una bombilla.


Cómo funciona (el mínimo necesario para entenderlo)

Tú: "enciende la luz del salón"


┌─────────────────────────┐
│ 1. Clasificar           │  → es una orden de domótica
│    (qué quiere)         │     (11 tipos posibles)
└─────────┬───────────────┘


┌─────────────────────────┐
│ 2. Decidir               │  → es simple → modelo rápido
│    (quién lo hace)       │     (árbol de 11 reglas)
└─────────┬───────────────┘


┌─────────────────────────┐
│ 3. Preparar contexto     │  → "salón" = "light.salon", está apagado
│    (datos antes del LLM) │
└─────────┬───────────────┘


┌─────────────────────────┐
│ 4. Ejecutar             │  → LLM decide: ha_turn_on
│    (modelo + tools)     │  → Home Assistant: luz ON
└─────────┬───────────────┘


┌─────────────────────────┐
│ 5. Validar              │  → "encendida" coincide con ok:true ✓
│    (no alucine)         │     (<1ms, regex, sin LLM)
└─────────┬───────────────┘


"Encendida la luz del salón"   ← ~2 segundos

El asistente tiene 3 niveles de “cerebro” que se activan según la dificultad de la tarea:

NivelModeloVelocidadSe usa para
StandardHammer2.1-3B~35 tok/sLuces, clima, saludos, consultas simples
CapableGemma-4-E2B~15 tok/sBúsquedas web, multi-paso, planificación
FallbackQwen2.5-Coder-7B~8 tok/sCuando standard y capable fallan

Lo que el asistente sabe hacer

Actualmente entiende 11 tipos de intenciones y ejecuta herramientas en 16 dominios:

  • Casa inteligente: encender luces, cambiar termostato, pasar aspiradora, consultar sensores
  • Búsqueda web: preguntas factuales, horarios, noticias, navegación de URLs si los snippets no bastan
  • Contenedores: estado, logs, reinicio de servicios Podman
  • Rutas: tiempo de viaje con tráfico real vía Waze
  • Memoria: recordar y recuperar información entre sesiones
  • Archivos: leer, escribir y listar archivos del servidor
  • Streaming: gestionar streams de Twitch/YouTube
  • Metro y autobuses: consultar tiempos de transporte público de Málaga

Tecnologías usadas

ComponenteTecnologíaPor qué
Clasificación de intentsONNX + all-MiniLM-L6-v2 + cross-encoderSin GPU, corre en CPU en <50ms
Servidor LLMllama.cpp con backend VulkanÚnica opción que acelera modelos pequeños en iGPU AMD
Router de modelosllama-router (wrapper propio)Lee perfiles INI, mapea tiers lógicos a GGUFs
Comunicaciónpython-telegram-botAsync, long-polling, sin servidor web
HTTPhttpx (pool singleton)Keepalive 120s, sin TCP handshake por request
InfraestructuraPodman + Docker Compose4 redes externas, containers separados por servicio

Una lección importante: llama.cpp con backend Vulkan fue la única opción real para acelerar modelos en una iGPU AMD. Todas las alternativas (CUDA, ROCm, DirectML) o requieren hardware NVIDIA o tienen soporte experimental. El stack de inferencia local para AMD sigue siendo un punto débil del ecosistema.


Estado actual y próximos pasos

El sistema funciona 24/7 en un servidor casero. Se autoevalúa continuamente con phase scores (0-100 por fase del pipeline) y un runtime analyzer genera sugerencias de mejora automáticamente. Los phase scores actuales: Percepción 91, Routing 63, Contexto 88, Agent Loop 74, Tools 74, Memory 72, Validation 71, Reflection 69. Objetivo: 100/100 en cada fase.

El proyecto sigue activo. Las próximas áreas de mejora incluyen compresión adaptativa de contexto, detección más robusta de escalación como degradación, y TTL adaptativo en memoria semántica.