Voice-to-SQL: hablarle a tu base de datos con un LLM (y por qué la seguridad es lo difícil)
Construí una demo que traduce voz y texto a SQL con Llama 3.3 70B. La voz va por la Web Speech API (coste cero) y el SQL del LLM pasa por un sanitizador SELECT-only: el modelo propone, la ingeniería dispone.
Las preguntas sobre datos casi nunca las hace quien sabe SQL. Las hace alguien de negocio, marketing o dirección, que tiene que pedírselas a un analista y esperar. Voice-to-SQL ataca justo esa fricción: que cualquiera pueda preguntarle a la base de datos hablando, y obtener la respuesta al instante.
El problema
Quería una demo que tradujera lenguaje natural —por voz o texto— a SQL, lo ejecutara sobre una base de datos real y devolviera la tabla, mostrando el SQL generado. Tres requisitos no negociables: que la voz no costara dinero, que fuera seguro dejar que un LLM tocara la base de datos, y que la respuesta llegara en menos de un segundo.
La voz: en el navegador, no en el backend
La tentación es mandar el audio al servidor y transcribirlo con Whisper o un servicio de pago. Lo descarté: añade latencia, coste y complejidad. En su lugar uso la Web Speech API, que viene integrada en Chrome, Edge y Safari. La transcripción ocurre en el dispositivo del usuario; el backend solo recibe texto. Coste de transcripción: cero. El precio a pagar es la dependencia del navegador, un compromiso razonable para una demo web.
De texto a SQL: el esquema es el prompt
El corazón del sistema es la conversión texto→SQL con un LLM (Llama 3.3 70B vía Groq, por su latencia muy baja). La clave no es el modelo, sino lo que se le da: junto a la pregunta, le paso el esquema exacto de la base de datos —tablas, columnas, tipos, valores posibles de los enums y un par de reglas del dialecto SQLite—. Sin ese contexto, el modelo inventa columnas. Con él, genera JOINs y GROUP BY correctos a la primera.
La parte difícil: que sea seguro
Aquí está el verdadero reto de ingeniería. Dar a un LLM una conexión a tu base de datos es una receta para el desastre: una pregunta mal interpretada (o malintencionada) podría acabar en un DROP TABLE. La regla de oro es no confiar nunca en el SQL generado.
Por eso, antes de ejecutar nada, el SQL pasa por un sanitizador que:
- Solo acepta sentencias que empiecen por
SELECToWITH. - Rechaza por lista negra
INSERT,UPDATE,DELETE,DROP,ALTER,CREATE,PRAGMA,ATTACHyREPLACE. - Bloquea el encadenamiento de varias sentencias con punto y coma (un clásico vector de inyección).
- Impone un tope absoluto de 100 filas por respuesta.
Es una defensa en capas, deliberadamente conservadora: prefiero rechazar una consulta legítima rara antes que permitir una destructiva. El LLM propone; el sanitizador dispone.
La base de datos demo
Para que las preguntas tengan sentido, generé con un script una base SQLite que imita el back-office de una empresa SaaS: 200 clientes (país, sector, plan, churn), 8 productos (planes y add-ons) y 5.000 ventas del último año con su aporte al MRR. Así se pueden hacer preguntas analíticas de verdad —ingresos por país, MRR por plan, churn— y no juguetes.
Resultado
De la pregunta a la tabla, en torno a medio segundo (la mayor parte es la generación del LLM; SQLite ejecuta en local en milisegundos). Y cada respuesta enseña el SQL que se generó, lo que convierte la demo en algo didáctico además de útil.
Qué aprendí
Que en un sistema "LLM + base de datos", el modelo es la parte fácil. Lo que de verdad decide si esto se puede poner delante de un usuario es la capa de seguridad y la calidad del contexto (el esquema) que le das al modelo. La inteligencia genera el SQL; la ingeniería hace que sea seguro ejecutarlo.
Sobre este proyecto
Voice-to-SQL Dashboard
Pregunta a tus datos por voz o texto y obtén la respuesta al instante: un LLM (Llama 3.3 70B) traduce tu pregunta a SQL, la ejecuta sobre una base de datos SaaS de ejemplo y te mue...