hr-faq-rag
by fellgar246
README.md
# FAQ RAG Chatbot — PeopleForce HR SaaS
Sistema de chatbot inteligente de soporte para FAQs basado en **Retrieval-Augmented Generation (RAG)**. Procesa un documento de preguntas frecuentes de una empresa HR SaaS, lo indexa en una base de datos vectorial y responde preguntas de usuarios recuperando los fragmentos más relevantes del documento para generar respuestas precisas con un LLM. Esto elimina la necesidad de búsquedas manuales y reduce la carga del equipo de soporte al cliente.
---
## Arquitectura RAG
```
┌──────────────────────────────────────────────────────────────────┐
│ PIPELINE DE INDEXACIÓN │
│ │
│ faq_document.txt ──► Chunking ──► Embeddings ──► ChromaDB │
│ (300 chars, (text-embedding (persistente │
│ 50 overlap) -3-small) local) │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ PIPELINE DE CONSULTA │
│ │
│ Pregunta ──► Embedding ──► k-NN Search ──► Contexto ──► LLM │
│ del usuario de query (coseno, (top-k (gpt-4o │
│ ChromaDB) chunks) -mini) │
│ │ │
│ ▼ │
│ JSON Response │
│ { user_question, │
│ system_answer, │
│ chunks_related } │
└──────────────────────────────────────────────────────────────────┘
```
---
## Instalación
### 1. Clonar el repositorio
```bash
git clone <repo-url>
cd kunz-mcp-project
```
### 2. Crear entorno virtual e instalar dependencias
```bash
python -m venv .venv
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windows
pip install -r requirements.txt
```
### 3. Configurar API Key
```bash
cp .env.example .env
# Edita .env y agrega tu clave de OpenAI:
# OPENAI_API_KEY=sk-...
```
---
## Uso
### Ejecutar el pipeline de indexación
```bash
python src/build_index.py
```
Esto carga `data/faq_document.txt`, lo divide en chunks, genera embeddings y los almacena en ChromaDB (`data/chroma_db/`).
### Ejecutar una consulta
```bash
python src/query.py "¿Cuántos días de vacaciones me corresponden?"
```
Salida JSON de ejemplo:
```json
{
"user_question": "¿Cuántos días de vacaciones me corresponden?",
"system_answer": "Todos los colaboradores de tiempo completo tienen derecho a 15 días hábiles de vacaciones al año a partir de su primer aniversario. Con más de 3 años de antigüedad, se reciben 20 días hábiles, y con más de 7 años, 25 días hábiles.",
"chunks_related": [
{
"text": "¿Cuántos días de vacaciones me corresponden?...",
"metadata": {
"chunk_index": 1,
"total_chunks": 30,
"source": "faq_document.txt"
}
}
]
}
```
### Ejecutar el agente evaluador (Bonus)
```bash
python src/evaluator.py
```
Evalúa las respuestas en `outputs/sample_queries.json` y devuelve un puntaje 0-10 con justificación.
---
## Servidor MCP (Model Context Protocol)
El proyecto incluye `src/mcp_server.py`, que expone el pipeline RAG como un servidor **MCP** para que agentes de IA (Claude Desktop, Cursor, VS Code con Copilot, etc.) puedan invocar las herramientas directamente.
### Tools disponibles
| Tool | Descripción |
|---|---|
| `ask_hr_faq(question)` | Pipeline RAG completo: busca en ChromaDB y genera respuesta con GPT-4o-mini |
| `evaluate_rag_response(user_question, system_answer, chunks_related)` | Evalúa la calidad de una respuesta RAG (puntaje 0-10 con justificación) |
| `rebuild_index()` | Reindexar el documento FAQ en ChromaDB (útil tras actualizar el FAQ) |
### Prerequisito
Asegúrate de haber construido el índice antes de levantar el servidor:
```bash
python src/build_index.py
```
### Opción A — Ejecutar directamente (modo stdio)
```bash
python src/mcp_server.py
```
Esto lanza el servidor en modo `stdio`, compatible con cualquier cliente MCP.
### Opción B — Ejecutar con MCP CLI
```bash
mcp run src/mcp_server.py
```
### Opción C — Integrar con Claude Desktop
Edita el archivo de configuración de Claude Desktop:
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"hr-faq-rag": {
"command": "python",
"args": ["/ruta/absoluta/a/kunz-mcp-project/src/mcp_server.py"],
"env": {
"OPENAI_API_KEY": "sk-..."
}
}
}
}
```
Reinicia Claude Desktop. El servidor aparecerá como herramienta disponible en el chat.
### Opción D — Integrar con Cursor o VS Code
Agrega en la configuración MCP del editor (`.cursor/mcp.json` o `settings.json`):
```json
{
"mcpServers": {
"hr-faq-rag": {
"command": "python",
"args": ["src/mcp_server.py"]
}
}
}
```
> **Nota**: el servidor lee `OPENAI_API_KEY` desde el archivo `.env` del proyecto; si el editor no hereda el entorno, pásala explícitamente en el bloque `"env"` como se muestra en la Opción C.
---
## Estructura del proyecto
```
kunz-mcp-project/
├── README.md # Documentación del proyecto
├── requirements.txt # Dependencias con versiones
├── .env.example # Plantilla de variables de entorno
├── config.yaml # Configuración del modelo, embeddings y RAG
├── data/
│ └── faq_document.txt # Documento FAQ fuente (≥1000 palabras)
├── src/
│ ├── __init__.py
│ ├── build_index.py # Pipeline de indexación (load → chunk → embed → store)
│ ├── query.py # Pipeline de consulta (search → generate → JSON)
│ ├── evaluator.py # Agente evaluador de calidad (bonus)
│ ├── mcp_server.py # Servidor MCP (expone los tools vía FastMCP)
│ └── shared/
│ ├── __init__.py
│ ├── config_loader.py # Carga config.yaml + .env
│ └── logger.py # Logger con Rich (colores y formato)
└── outputs/
└── sample_queries.json # ≥3 ejemplos de consulta-respuesta
```
---
## Decisiones técnicas
### Estrategia de chunking
Se usa **`RecursiveCharacterTextSplitter`** con `chunk_size=300` y `chunk_overlap=50`.
- **¿Por qué recursivo?** Los separadores jerárquicos (`\n\n` → `\n` → `.` → ` `) preservan los límites semánticos naturales del texto (secciones, párrafos, oraciones), produciendo chunks más coherentes que un corte por tamaño fijo.
- **¿Por qué 300 caracteres?** Genera chunks de ~75-125 tokens, dentro del rango requerido de 50-500 tokens. Chunks más pequeños mejoran la precisión de la búsqueda vectorial al reducir el ruido semántico.
- **¿Por qué 50 de overlap?** El solapamiento asegura continuidad de contexto entre chunks adyacentes, evitando que información relevante quede cortada en un límite.
### Método de búsqueda vectorial
Se usa **k-NN (k-Nearest Neighbors) con similitud coseno** sobre el índice HNSW de ChromaDB.
- **¿Por qué k-NN?** Es el método más directo y predecible para búsqueda de vectores similares. ChromaDB optimiza internamente con HNSW (Hierarchical Navigable Small World) para búsquedas sub-lineales.
- **¿Por qué coseno?** La similitud coseno mide la dirección semántica de los vectores, no su magnitud. Es ideal para embeddings de texto normalizados como los de OpenAI (`text-embedding-3-small`), donde vectores con significado similar apuntan en la misma dirección.
- **Top-k = 3** retorna entre 2-5 chunks por consulta, suficientes para dar contexto sin introducir ruido.
### Beneficios de RAG
- **Actualización sin re-training**: Basta con actualizar el documento fuente y re-indexar, sin necesidad de fine-tuning costoso del LLM.
- **Transparencia**: Cada respuesta incluye los chunks utilizados (`chunks_related`), permitiendo verificar la fuente de información.
- **Atribución**: Los metadatos de cada chunk (`source`, `chunk_index`) habilitan la trazabilidad completa de la respuesta.
---
## Configuración
El archivo `config.yaml` centraliza todos los parámetros:
| Parámetro | Valor | Descripción |
|-----------|-------|-------------|
| `model.name` | `gpt-4o-mini` | Modelo LLM para generación |
| `model.temperature` | `0.3` | Baja temperatura para respuestas consistentes |
| `embedding.model` | `text-embedding-3-small` | Modelo de embeddings (1536 dims) |
| `rag.chunk_size` | `300` | Tamaño máximo de chunk en caracteres |
| `rag.chunk_overlap` | `50` | Solapamiento entre chunks |
| `rag.top_k` | `3` | Chunks a recuperar por consulta |
| `rag.collection` | `faq_hr_saas` | Nombre de la colección en ChromaDB |
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessSyncing