Cortex Lead Hunter
Motor autónomo de generación de leads B2B, corriendo en una Raspberry Pi con CI/CD propio — un producto construido para vender otro producto.
- Python / FastAPI
- SQLAlchemy 2 (async)
- PostgreSQL + pgvector
- Groq (con fallback a Ollama local)
- Next.js 16
- Raspberry Pi 5 + Tailscale
- Tests
- 61
- Pipeline
- búsqueda → dedup semántica → análisis LLM → aprobación → email
- Infraestructura
- self-hosted, CI/CD propio
Qué es
Un motor autónomo de prospección B2B construido para encontrar clientes potenciales de Cortex. El pipeline busca empresas por API (Serper/Google), descarta duplicados primero por URL exacta y después por similitud semántica sobre embeddings (distancia coseno en pgvector), analiza cada lead con un LLM para generar un fit score de 0 a 100 con puntos de dolor y una propuesta de contacto sugerida, y deja el resultado en una cola de aprobación manual antes de enviar el email de contacto — con tracking de apertura vía webhook firmado.
Es, de los proyectos de este portfolio, el que tiene la autoría más limpia: código, infraestructura y decisiones son enteramente míos.
Arquitectura y decisiones técnicas
Embeddings locales para no pagar por descartar duplicados. La deduplicación semántica usa nomic-embed-text vía Ollama corriendo en la propia Raspberry Pi — así el filtrado de leads repetidos ocurre antes de gastar un solo token del LLM de pago.
Proveedores intercambiables por factory pattern. Tanto el proveedor de LLM (Groq con fallback a Ollama local) como el de búsqueda están detrás de una factory configurable por variable de entorno, pensada para operar con margen cuando una API externa falla o se agota la cuota.
Parseo de JSON a dos pasadas. Cuando el LLM devuelve el análisis envuelto en prosa en lugar de JSON puro, un rescate por regex más un reintento con un prompt más estricto evitan que un lead se pierda por un formato inesperado.
Bloqueo con pg_try_advisory_lock en el scheduler, para que varios workers no dupliquen la misma ejecución programada — el tipo de detalle que solo aparece cuando un sistema realmente corre desatendido, no en una demo.
Estado actual
Desplegado con systemd y expuesto vía Tailscale Funnel, con CI/CD sobre un runner self-hosted en la propia Raspberry Pi. Actualmente pausado a la espera de remontar la infraestructura tras una incidencia de seguridad en el homelab (ver Homelab).