RAG Hub — Infraestructura¶
Visión general¶
┌─────────────────────────┐
│ FastAPI RAG Hub │
│ (puerto 8000) │
│ │
│ GET /health │
│ GET /models │
│ GET /collections │
│ POST /query/{col} │
│ POST /v1/chat/complet │
│ POST /responses │
└──────┬──────────┬───────┘
│ │
┌────────────┘ └────────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Ollama │ │ Qdrant │
│ localhost:11434│ │ localhost:6333 │
│ │ │ │
│ mxbai-embed-lrg │ │ smallcountry │ ← 1024d
│ deepseek-r1:8b │ │ (futuras...) │
└─────────────────┘ └─────────────────┘
│ │
└──────────────────┬───────────────┘
▼
┌─────────────────────┐
│ Consumidores │
│ │
│ • Hermes Agent │
│ • AnythingLLM │
│ (Docker, vía Resp.)│
│ • Bot Telegram │
└──────────────────────┘
Servicios¶
| Servicio | Puerto | Estado | Cómo se gestiona |
|---|---|---|---|
| RAG Hub API | 8000 | 🟢 systemd user | systemctl --user {start,stop,restart} rag-hub.service |
| Auto-indexer | — | 🟢 systemd user | systemctl --user {start,stop,restart} rag-hub-indexer.service |
| Check integridad | — | 🟢 timer noc. | systemctl --user start rag-hub-integrity.service |
| Ollama | 11434 | 🟢 Docker | docker compose en ~/ai-stack/ |
| Qdrant | 6333 | 🟢 Docker | Mismo compose |
| AnythingLLM | 3002 | 🟢 Docker indep. | Ver sección integración |
Ubicación del proyecto¶
| Ruta | Contenido |
|---|---|
~/ai-stack/rag-api/ |
Código fuente del Hub |
~/ai-stack/rag-api/main.py |
FastAPI app (174 líneas) |
~/ai-stack/rag-api/collection_config.py |
Config de colecciones (fuente de verdad) |
~/ai-stack/rag-api/embedding_router.py |
Routing de embeddings |
~/ai-stack/rag-api/auto_indexer.py |
Watchdog (inotify) |
~/ai-stack/rag-api/check_integrity.py |
Verificación nocturna |
~/ai-stack/rag-api/migrate_smallcountry.py |
Migración 768d → 1024d |
~/.config/systemd/user/rag-hub.service |
Unit systemd API |
~/.config/systemd/user/rag-hub-indexer.service |
Unit systemd indexer |
~/.config/systemd/user/rag-hub-integrity.{service,timer} |
Unit systemd integridad |
~/ai-stack/anythingllm_data/ |
Datos persistentes AnythingLLM (Docker volume) |
Colecciones y embeddings¶
| Colección | Modelo | Dim | Origen | Estado |
|---|---|---|---|---|
smallcountry |
mxbai-embed-large |
1024 | Ollama | 🟢 787 pts (migrada) |
smallcountry_full |
nomic-embed-text |
768 | Ollama | ⏳ Legacy (backup) |
Migración de embedding¶
Los documentos fueron indexados originalmente con nomic-embed-text (768d).
Para mejorar calidad en español se migró a mxbai-embed-large (1024d).
Resultado: 787 puntos migrados de 865 (78 omitidos por texto binario).
Systemd services¶
rag-hub.service (API server)¶
[Unit]
Description=RAG Hub API Server — FastAPI multi-embedding Qdrant
After=network-online.target
[Service]
Type=simple
Environment=PYTHONUNBUFFERED=1
WorkingDirectory=/home/tonatiuh/ai-stack/rag-api
ExecStart=/home/tonatiuh/ai-stack/rag-api/.venv/bin/python -u main.py
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
rag-hub-indexer.service (auto-indexador watchdog)¶
Vigila ~/SmallCountry/ con inotify. Al crear o modificar un .md/.txt/.pdf,
lo fragmenta, lo embediza con el modelo de la colección, y lo indexa en Qdrant.
rag-hub-integrity.timer (check nocturno)¶
Se ejecuta cada día a las 00:00. Verifica que todos los archivos en los directorios vigilados estén correctamente indexados. Si un archivo cambió (hash SHA256 diferente), lo re-indexa automáticamente.
Integración con AnythingLLM¶
La conexión se hace vía Responses API (OpenAI nuevo formato).
Configuración del contenedor Docker¶
docker run -d --name anythingllm \
-p 3002:3001 \
-v ~/ai-stack/anythingllm_data:/app/server/storage \
-e STORAGE_DIR=/app/server/storage \
-e OLLAMA_BASE_URL=http://host.docker.internal:11434 \
-e QDRANT_ENDPOINT=http://host.docker.internal:6333 \
-e OPENAI_BASE_URL=http://host.docker.internal:8000 \
--add-host host.docker.internal:host-gateway \
mintplexlabs/anythingllm:latest
Configuración en la UI¶
- Settings → LLM → OpenAI: API key dummy (
sk-not-needed-local-rag-hub) - Workspace → modelo:
gpt-4o(el Hub lo redirige asmallcountry) - El Hub expone
GET /modelspara que AnythingLLM descubra modelos disponibles - Las consultas se envían a
POST /responsescon formato Responses API
Formato Responses API¶
AnythingLLM envía las consultas en el nuevo formato OpenAI Responses API:
{
"model": "gpt-4o",
"input": [
{"role": "system", "content": [{"type": "input_text", "text": "system prompt"}]},
{"role": "user", "content": [{"type": "input_text", "text": "¿pregunta?"}]}
]
}
El RAG Hub aplanea recursivamente estos mensajes, embediza la query, busca en Qdrant y genera respuesta con deepseek-r1:8b.
Errores comunes y solución¶
| Error | Causa | Solución |
|---|---|---|
404 en /models |
Endpoint no implementado | Añadir GET /models al Hub |
400 en /responses |
Formato Responses API no soportado | Añadir POST /responses con flatten recursivo |
500 en responses |
content es lista de |
Aplanar item.content como lista, no string |
host.docker.internal no resuelve |
Falta --add-host |
Añadir --add-host host.docker.internal:host-gateway |
Modelos Ollama disponibles¶
| Modelo | Uso |
|---|---|
mxbai-embed-large |
Embeddings (español, 1024d) — principal |
nomic-embed-text |
Embeddings (fallback, 768d) |
deepseek-r1:8b |
Generación de respuestas RAG |
gemma4:e2b-it-q8_0 |
Chat general (AnythingLLM anterior) |
qwen3-vl:8b |
Modelo multimodal (vision + texto) |
Lo que NO se usa¶
- ❌ LlamaIndex — routing manual es más simple
- ❌ Cron — reemplazado por systemd timers (journald, Persistent=true)
- ❌ APIs externas de embedding — todo 100% offline
- ❌ OpenAI real — el Hub reemplaza la necesidad de API keys externas