Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ChatBotIA-Local-RAG

Chatbot de ventas y soporte con RAG 100% local: responde desde tu propia documentación, deriva a un humano cuando no sabe, y trae bandeja de conversaciones en vivo y un CRM básico.

Sin costo por mensaje y sin que los datos salgan de tu servidor.

Widget web  →  FastAPI  →  ┌─ embeddings ──→ Ollama (embeddinggemma)
                           ├─ búsqueda ────→ SQLite + sqlite-vec + FTS5
                           └─ respuesta ───→ Ollama (gemma3:4b)
                                  ↓
                    Panel: bandeja · CRM · contenido · métricas

Qué incluye

  • RAG sobre tus documentos en Markdown, con reindexado desde el panel.
  • Búsqueda híbrida: vectorial + léxica (FTS5), fusionadas con Reciprocal Rank Fusion.
  • Guardarraíles: no inventa precios ni datos; si no sabe, deriva a una persona.
  • Chat en vivo: un operador toma la conversación y el bot se calla.
  • CRM: contactos con etapas, notas e historial, editables desde el propio chat.
  • Panel web con autenticación, métricas y edición del contenido.
  • Widget autónomo sin dependencias, para pegar en cualquier sitio.

Requisitos

  • Linux con Ollama
  • Python 3.11+
  • GPU con 4 GB de VRAM basta (gemma3:4b). También corre en CPU, más lento.
ollama pull embeddinggemma
ollama pull gemma3:4b

Instalación

git clone https://github.com/leoses03/ChatBotIA-Local-RAG.git
cd ChatBotIA-Local-RAG
curl -LsSf https://astral.sh/uv/install.sh | sh     # sin sudo
uv sync

cp .env.example .env      # edita BRAND, ADMIN_PASSWORD y los tokens
python -c "import secrets; print(secrets.token_urlsafe(32))"   # para los secretos

uv run python ingest.py   # indexa corpus/
uv run uvicorn app:app --host 127.0.0.1 --port 8000

Panel en http://127.0.0.1:8000/admin.

Servicio permanente (systemd de usuario, sin root)

# ~/.config/systemd/user/chatbot-rag.service
[Unit]
Description=ChatBot IA Local RAG
After=network.target

[Service]
Type=simple
WorkingDirectory=%h/ChatBotIA-Local-RAG
ExecStart=%h/.local/bin/uv run uvicorn app:app --host 127.0.0.1 --port 8000
Restart=always
RestartSec=5

[Install]
WantedBy=default.target
loginctl enable-linger $USER          # sobrevive reinicios
systemctl --user enable --now chatbot-rag

Exponerlo a internet

Con Cloudflare Tunnel, sin abrir puertos en el router. Ajusta ALLOWED_ORIGIN al dominio de tu sitio.

El widget

<script>window.CHAT_API = "https://chat.tu-dominio.com";</script>
<script src="/ruta/chat-widget.js" defer></script>

Personalizarlo

  1. corpus/*.md — tu contenido. Es lo que más importa: el bot solo sabe lo que está ahí.
  2. .envBRAND, BRAND_DESC, BRAND_REGION y el resto de la configuración.
  3. prompt.py — tono y reglas.
  4. widget/chat-widget.js — colores y tipografías (arriba del archivo).

Cosas aprendidas construyéndolo

Estos puntos costaron horas de depuración. Si vas a tocar el código, léelos.

La distancia de sqlite-vec no es una escala 0-1

Devuelve distancia L2 sobre vectores sin normalizar. Medido con embeddinggemma:

Caso Distancia
Acierto claro 0.84 – 0.98
Acierto justo (pregunta corta) ~1.10
Fuera de tema 1.12 – 1.27

Con un umbral de 0.75 (asumiendo escala 0-1) todo se derivaba. Si cambias de modelo de embeddings, vuelve a medir: hay un script de diagnóstico en el panel.

FTS5 no hace stemming en español

Buscar "planes" no encontraba "Plan Pro". Por eso la consulta léxica usa prefijos de 4 letras con comodín (plan*). Sin esto, la pregunta "¿qué planes tienen?" no recuperaba el documento de planes y el modelo inventaba nombres de planes.

Moraleja general: en un RAG, una alucinación casi siempre es un fallo de recuperación, no del prompt.

El rank de FTS5 no sirve como señal de derivación

Se midió: una consulta válida daba -8.5 y una fuera de tema -4.2. No separa. La búsqueda léxica mejora qué se recupera; no decide si hay respuesta. Usarla para eso dejó al bot sin derivar nunca.

La derivación usa dos señales independientes: la distancia vectorial, y detectar cuándo el modelo mismo admite que no puede ayudar (NEEDS_HUMAN_RE).

Chunks autocontenidos

Describir un plan como "todo lo del Esencial más X" hacía que el modelo mezclara y le atribuyera funciones equivocadas. Al listar cada plan por completo, se corrigió. Con modelos pequeños, evita contenido que obligue a inferir.

Los filtros de estilo van después de generar

El prompt puede prohibir el voseo, pero a un modelo de 4B se le escapa. prompt.clean_reply() lo corrige tras generar: determinista y no depende de que el modelo obedezca.

Preguntas de seguimiento

"¿Cuánto sale?" no significa nada aislado y se derivaba sin motivo. Si el mensaje es corto y hay historial, la búsqueda concatena el mensaje anterior del visitante.

Un panel que se refresca borra lo que estás escribiendo

La bandeja se actualiza cada 5 s. La barra del CRM no se redibuja si el operador tiene el foco dentro, ni si nada cambió.

Seguridad

  • El panel cambia lo que el bot responde a tus clientes: nunca lo expongas sin contraseña.
  • Cookie de sesión firmada con HMAC, HttpOnly + Secure, 8 horas.
  • Los nombres de archivo del corpus se validan contra path traversal.
  • La configuración editable desde el panel excluye los secretos.
  • CORS restringido a tu dominio y límite de mensajes por IP.
  • Para una capa extra, pon Cloudflare Access delante de /admin.

Licencia

MIT

About

Chatbot de ventas con RAG 100% local: Ollama + SQLite + FastAPI. Busqueda hibrida, chat en vivo con operador y CRM basico. Sin costo por mensaje.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages