Que es un RAG
RAG (Retrieval-Augmented Generation) es un patron de arquitectura que combina dos cosas:
- Retrieval (Recuperacion): Buscar informacion relevante en tus documentos usando busqueda semantica (vectores).
- Generation (Generacion): Enviar esa informacion como contexto a un LLM para que genere una respuesta fundamentada en datos reales.
¿Por que importa? Porque un LLM por si solo "alucina" (inventa datos). Con RAG, el modelo solo responde con informacion que realmente existe en tus documentos. Es la diferencia entre preguntarle a alguien que no sabe nada de tu infra vs. darle tus runbooks y que responda basandose en ellos.
Caso de uso: equipos de Ops
Imagina poder cargar toda tu documentacion interna (runbooks, configuraciones, playbooks, postmortems) y preguntar en lenguaje natural:
- "¿Como reinicio el cluster de Kafka en produccion?"
- "¿Que reglas de firewall tenemos para el segmento DMZ?"
- "¿Cual fue el workaround del incidente INC-4523?"
Eso es exactamente lo que vamos a construir.
Que vamos a montar
- ChromaDB como base de datos vectorial (ligero, persistente, en Docker)
- Cualquier LLM compatible con formato OpenAI como motor de generacion
- Ingesta de ficheros
.md,.yaml,.conf,.shde tus servidores - CLI simple:
python rag.py -q "tu pregunta"
Para esta prueba de concepto usaremos las APIs gratuitas de Grok (xAI) y NVIDIA NIM, que no requieren pago ni desplegar infraestructura propia. El codigo esta preparado para que lo conectes a cualquier LLM (Azure OpenAI, AWS Bedrock, un modelo self-hosted, etc.) simplemente cambiando una variable de entorno.
Para entornos enterprise: Al final del post incluyo recomendaciones sobre que opciones existen para desplegar un LLM privado con las garantias de seguridad y compliance que necesitas.
Requisitos previos
| Componente | Minimo | Recomendado |
|---|---|---|
| RAM | 4 GB | 8 GB+ |
| Disco | 5 GB libres | 10 GB+ |
| Docker | 24.x+ | 27.x+ |
| Docker Compose | v2.x | v2.x |
| Python | 3.11+ | 3.13+ |
Ademas necesitaras una API key de al menos uno de estos proveedores:
- Grok (xAI): Obtener en console.x.ai
- NVIDIA NIM: Obtener en build.nvidia.com
Ambos ofrecen tier gratuito suficiente para seguir este tutorial.
Arquitectura
┌─────────────────────────────────────────────────────┐
│ Usuario │
│ python rag.py --provider nvidia │
└──────────────────────┬──────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ RAG Engine (Python) │
│ │
│ 1. Recibe pregunta │
│ 2. Genera embedding → consulta ChromaDB │
│ 3. Recupera documentos relevantes (top 5) │
│ 4. Construye prompt con contexto │
│ 5. Envia al LLM via API │
│ 6. Devuelve respuesta │
└───────┬──────────────────┬───────────────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────────────┐
│ ChromaDB │ │ LLM Provider │
│ (Vectores) │ │ │
│ Docker │ │ Grok API (xAI) │
│ │ │ NVIDIA NIM │
│ │ │ Azure OpenAI / Bedrock │
└──────────────┘ └──────────────────────────┘La clave de esta arquitectura es la separacion entre la logica de recuperacion (vectores) y la logica de generacion (LLM). Cambiar de proveedor LLM es solo cambiar una variable de entorno.
Paso 1: Estructura del proyecto
mkdir -p rag-ops/{data,chroma_data}
cd rag-opsEstructura final:
rag-ops/
├── docker-compose.yaml
├── requirements.txt
├── rag.py
├── ingest.py
├── config.py
├── .env
├── .gitignore
└── data/
└── (tus ficheros .md, .yaml, .conf, .sh)Crea el .gitignore desde el principio:
echo -e ".env\n.venv/\n__pycache__/\nchroma_data/" > .gitignorePaso 2: Docker Compose - ChromaDB
Solo necesitamos ChromaDB en Docker. El LLM se consume via API externa.
Crea docker-compose.yaml:
services:
chromadb:
image: chromadb/chroma:latest
container_name: rag-chromadb
ports:
- "8000:8000"
volumes:
- ./chroma_data:/chroma/chroma
environment:
- ANONYMIZED_TELEMETRY=FALSE
restart: unless-stoppedNota: Si tienes el puerto 8000 ocupado (por ejemplo con otro servicio), cambia el mapeo a
"8001:8000"y ajustaCHROMA_PORTen el.enva8001. El puerto interno del contenedor siempre es 8000.
Levanta el servicio:
docker compose up -dVerifica que esta corriendo:
curl http://localhost:8000/api/v2/heartbeat
# Respuesta esperada: {"nanosecond heartbeat":...}Paso 3: Obtener API Keys (para nuestra PoC)
Para esta prueba de concepto usaremos dos proveedores gratuitos. En un entorno real, sustituirias estas APIs por la de tu LLM corporativo (ver seccion final).
Grok (xAI)
- Ve a console.x.ai
- Crea una cuenta o inicia sesion
- En el dashboard, genera una API key (empieza por
xai-) - El tier gratuito incluye suficientes tokens para pruebas
La API de Grok es compatible con el formato OpenAI, por lo que usaremos el mismo SDK con diferente base_url.
NVIDIA NIM
- Ve a build.nvidia.com
- Crea una cuenta NVIDIA
- Selecciona un modelo con "Free Endpoint" (recomendado:
z-ai/glm4.7omistralai/mistral-nemotron) - Haz clic en "Get API Key" (empieza por
nvapi-)
Importante: Algunos modelos de NVIDIA NIM tienen restriccion geografica. Si ves "This NIM is unavailable in your location", prueba otro modelo que tenga "Free Endpoint".
NVIDIA NIM tambien usa formato OpenAI-compatible.
Paso 4: Dependencias Python
Crea requirements.txt:
langchain>=0.3.25
langchain-huggingface>=1.0.0
langchain-openai>=0.3.12
langchain-text-splitters>=0.3.0
chromadb>=1.0.0
sentence-transformers>=4.0.0
python-dotenv>=1.0.0
rich>=14.0.0Instala en un virtualenv:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtImportante: Siempre activa el virtualenv (
source .venv/bin/activate) antes de ejecutar los scripts. Si vesModuleNotFoundError, es que no tienes el venv activo.
Paso 5: Configuracion
Crea el fichero .env:
# Proveedor LLM: "grok" o "nvidia"
LLM_PROVIDER=nvidia
# Grok (xAI) - Compatible con formato OpenAI
GROK_API_KEY=xai-tu-clave-aqui
GROK_BASE_URL=https://api.x.ai/v1
GROK_MODEL=grok-3-mini
# NVIDIA NIM - Compatible con formato OpenAI
NVIDIA_API_KEY=nvapi-tu-clave-aqui
NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
NVIDIA_MODEL=z-ai/glm4.7
# ChromaDB
CHROMA_HOST=localhost
CHROMA_PORT=8000
CHROMA_COLLECTION=ops-docs
# Embeddings (se ejecutan localmente, no requieren API)
EMBEDDING_MODEL=all-MiniLM-L6-v2Seguridad: Nunca subas
.enva git. Ya lo tenemos en.gitignore.
Crea config.py:
import os
from dotenv import load_dotenv
load_dotenv()
class Config:
# LLM Provider
LLM_PROVIDER = os.getenv("LLM_PROVIDER", "grok")
# Grok (xAI)
GROK_API_KEY = os.getenv("GROK_API_KEY", "")
GROK_BASE_URL = os.getenv("GROK_BASE_URL", "https://api.x.ai/v1")
GROK_MODEL = os.getenv("GROK_MODEL", "grok-3-mini")
# NVIDIA NIM
NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY", "")
NVIDIA_BASE_URL = os.getenv("NVIDIA_BASE_URL", "https://integrate.api.nvidia.com/v1")
NVIDIA_MODEL = os.getenv("NVIDIA_MODEL", "z-ai/glm4.7")
# ChromaDB
CHROMA_HOST = os.getenv("CHROMA_HOST", "localhost")
CHROMA_PORT = int(os.getenv("CHROMA_PORT", "8000"))
CHROMA_COLLECTION = os.getenv("CHROMA_COLLECTION", "ops-docs")
# Embeddings
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "all-MiniLM-L6-v2")Paso 6: Script de ingesta
Este script lee tus documentos, los divide en chunks, genera embeddings y los almacena en ChromaDB.
Crea ingest.py:
#!/usr/bin/env python3
"""Ingesta de documentos en ChromaDB para el RAG."""
import sys
from pathlib import Path
import chromadb
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from rich.console import Console
from rich.progress import track
from config import Config
console = Console()
def load_documents(data_dir: str) -> list[dict]:
"""Carga todos los ficheros soportados del directorio."""
extensions = {".md", ".yaml", ".yml", ".conf", ".sh", ".txt", ".json", ".toml"}
documents = []
data_path = Path(data_dir)
if not data_path.exists():
console.print(f"[red]Error: directorio '{data_dir}' no existe[/red]")
sys.exit(1)
for filepath in data_path.rglob("*"):
if filepath.suffix.lower() in extensions and filepath.is_file():
try:
content = filepath.read_text(encoding="utf-8")
documents.append({
"content": content,
"metadata": {
"source": str(filepath.relative_to(data_path)),
"extension": filepath.suffix,
"filename": filepath.name,
}
})
except Exception as e:
console.print(f"[yellow]Aviso: no se pudo leer {filepath}: {e}[/yellow]")
return documents
def chunk_documents(documents: list[dict]) -> list[dict]:
"""Divide documentos en chunks manejables."""
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
separators=["\n## ", "\n### ", "\n\n", "\n", " "],
)
chunks = []
for doc in documents:
splits = splitter.split_text(doc["content"])
for i, split in enumerate(splits):
chunks.append({
"content": split,
"metadata": {
**doc["metadata"],
"chunk_index": i,
}
})
return chunks
def ingest(data_dir: str = "data"):
"""Pipeline principal de ingesta."""
console.print("[bold blue]RAG Ops - Ingesta de documentos[/bold blue]\n")
# 1. Cargar documentos
console.print(f"Cargando documentos de [green]{data_dir}/[/green]...")
documents = load_documents(data_dir)
console.print(f" Encontrados: [bold]{len(documents)}[/bold] ficheros\n")
if not documents:
console.print("[red]No se encontraron documentos para ingestar.[/red]")
sys.exit(1)
# 2. Dividir en chunks
console.print("Dividiendo en chunks...")
chunks = chunk_documents(documents)
console.print(f" Total chunks: [bold]{len(chunks)}[/bold]\n")
# 3. Generar embeddings
console.print(f"Generando embeddings con [green]{Config.EMBEDDING_MODEL}[/green]...")
console.print(" (primera vez descarga el modelo ~80MB, luego es instantaneo)\n")
embeddings = HuggingFaceEmbeddings(model_name=Config.EMBEDDING_MODEL)
# 4. Almacenar en ChromaDB
console.print(f"Conectando a ChromaDB en {Config.CHROMA_HOST}:{Config.CHROMA_PORT}...")
client = chromadb.HttpClient(host=Config.CHROMA_HOST, port=Config.CHROMA_PORT)
# Borrar coleccion existente si hay (re-ingesta limpia)
try:
client.delete_collection(Config.CHROMA_COLLECTION)
console.print(" Coleccion anterior eliminada.")
except Exception:
pass
collection = client.create_collection(
name=Config.CHROMA_COLLECTION,
metadata={"hnsw:space": "cosine"},
)
# 5. Insertar chunks
console.print("\nInsertando chunks en ChromaDB...")
batch_size = 100
for i in track(range(0, len(chunks), batch_size), description="Ingesta"):
batch = chunks[i:i + batch_size]
texts = [c["content"] for c in batch]
metadatas = [c["metadata"] for c in batch]
ids = [f"chunk_{i + j}" for j in range(len(batch))]
embs = embeddings.embed_documents(texts)
collection.add(
documents=texts,
embeddings=embs,
metadatas=metadatas,
ids=ids,
)
console.print(f"\n[bold green]Ingesta completada![/bold green]")
console.print(f" Documentos: {len(documents)}")
console.print(f" Chunks almacenados: {len(chunks)}")
console.print(f" Coleccion: {Config.CHROMA_COLLECTION}")
if __name__ == "__main__":
data_dir = sys.argv[1] if len(sys.argv) > 1 else "data"
ingest(data_dir)Paso 7: El motor RAG
Crea rag.py:
#!/usr/bin/env python3
"""RAG Ops - Asistente de infraestructura con soporte multi-proveedor LLM."""
import argparse
import sys
import chromadb
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from rich.console import Console
from rich.markdown import Markdown
from rich.panel import Panel
from config import Config
console = Console()
SYSTEM_PROMPT = """Eres un asistente tecnico de infraestructura y operaciones.
Responde usando la informacion del contexto proporcionado.
Si no encuentras la respuesta en el contexto, di "No tengo informacion sobre eso en los documentos cargados."
Da respuestas detalladas y completas. Incluye ejemplos de configuracion, comandos y nombres de ficheros cuando sea relevante.
Estructura la respuesta con secciones si es necesario.
Responde en el mismo idioma en que te preguntan.
CONTEXTO:
{context}
"""
def get_llm(provider: str):
"""Factory que devuelve el LLM segun el proveedor.
Tanto Grok como NVIDIA NIM son compatibles con el formato OpenAI,
por lo que usamos ChatOpenAI con diferente base_url y api_key.
Para anadir cualquier otro proveedor OpenAI-compatible, solo necesitas
una nueva entrada con su base_url, api_key y model.
"""
if provider == "grok":
if not Config.GROK_API_KEY:
console.print("[red]Error: GROK_API_KEY no configurada en .env[/red]")
sys.exit(1)
console.print(f" LLM: Grok ({Config.GROK_MODEL})")
return ChatOpenAI(
api_key=Config.GROK_API_KEY,
base_url=Config.GROK_BASE_URL,
model=Config.GROK_MODEL,
temperature=0.1,
max_tokens=4096,
)
elif provider == "nvidia":
if not Config.NVIDIA_API_KEY:
console.print("[red]Error: NVIDIA_API_KEY no configurada en .env[/red]")
sys.exit(1)
console.print(f" LLM: NVIDIA NIM ({Config.NVIDIA_MODEL})")
return ChatOpenAI(
api_key=Config.NVIDIA_API_KEY,
base_url=Config.NVIDIA_BASE_URL,
model=Config.NVIDIA_MODEL,
temperature=0.1,
max_tokens=4096,
extra_body={
"chat_template_kwargs": {
"enable_thinking": False,
}
},
)
else:
console.print(f"[red]Proveedor '{provider}' no soportado. Usa 'grok' o 'nvidia'.[/red]")
sys.exit(1)
def search_context(query: str, n_results: int = 5) -> str:
"""Busca documentos relevantes en ChromaDB."""
embeddings = HuggingFaceEmbeddings(model_name=Config.EMBEDDING_MODEL)
client = chromadb.HttpClient(host=Config.CHROMA_HOST, port=Config.CHROMA_PORT)
collection = client.get_collection(Config.CHROMA_COLLECTION)
query_embedding = embeddings.embed_query(query)
results = collection.query(
query_embeddings=[query_embedding],
n_results=n_results,
)
# Construir contexto con fuentes
context_parts = []
for doc, metadata in zip(results["documents"][0], results["metadatas"][0]):
source = metadata.get("source", "desconocido")
context_parts.append(f"[Fuente: {source}]\n{doc}")
return "\n\n---\n\n".join(context_parts)
def ask(question: str, provider: str):
"""Pipeline principal: buscar contexto -> generar respuesta."""
# 1. Buscar contexto relevante
console.print("Buscando en documentos...")
context = search_context(question)
if not context:
console.print("[yellow]No se encontraron documentos relevantes.[/yellow]")
return
# 2. Construir prompt
prompt = ChatPromptTemplate.from_messages([
("system", SYSTEM_PROMPT),
("human", "{question}"),
])
# 3. Obtener LLM
llm = get_llm(provider)
# 4. Ejecutar chain
chain = prompt | llm | StrOutputParser()
console.print("Generando respuesta...\n")
response = chain.invoke({
"context": context,
"question": question,
})
# 5. Mostrar resultado
console.print(Panel(Markdown(response), title="Respuesta", border_style="green"))
def interactive_mode(provider: str):
"""Modo interactivo: pregunta tras pregunta."""
console.print(Panel(
f"[bold]RAG Ops - Modo interactivo[/bold]\n"
f"Proveedor: [green]{provider}[/green]\n"
f"Escribe 'salir' o 'exit' para terminar.",
border_style="blue",
))
while True:
try:
question = console.input("\n[bold blue]Pregunta>[/bold blue] ").strip()
if question.lower() in ("salir", "exit", "quit", "q"):
console.print("[dim]Hasta luego.[/dim]")
break
if not question:
continue
ask(question, provider)
except KeyboardInterrupt:
console.print("\n[dim]Interrumpido.[/dim]")
break
def main():
parser = argparse.ArgumentParser(description="RAG Ops - Asistente de infraestructura")
parser.add_argument(
"--provider", "-p",
choices=["grok", "nvidia"],
default=Config.LLM_PROVIDER,
help="Proveedor LLM (default: valor de .env)",
)
parser.add_argument(
"--question", "-q",
type=str,
help="Pregunta directa (sin modo interactivo)",
)
args = parser.parse_args()
if args.question:
ask(args.question, args.provider)
else:
interactive_mode(args.provider)
if __name__ == "__main__":
main()Paso 8: Probar el sistema
8.1 Anadir documentos
Copia ficheros de configuracion o documentacion a data/. Cuanta mas documentacion metas, mejores seran las respuestas:
# Ejemplos: configs, scripts, manuales, runbooks
cp /etc/nginx/nginx.conf data/
cp /etc/nginx/sites-available/* data/
cp /path/to/runbooks/*.md data/
cp /path/to/ansible/playbooks/*.yaml data/Importante: El RAG solo es tan bueno como la documentacion que le metas. Con un solo fichero de configuracion por defecto, las respuestas seran pobres. Mete documentacion real y detallada para obtener respuestas utiles.
8.2 Ejecutar ingesta
source .venv/bin/activate
python ingest.py data/Salida esperada:
RAG Ops - Ingesta de documentos
Cargando documentos de data/...
Encontrados: 45 ficheros
Dividiendo en chunks...
Total chunks: 892
Generando embeddings con all-MiniLM-L6-v2...
(primera vez descarga el modelo ~80MB, luego es instantaneo)
Conectando a ChromaDB en localhost:8000...
Insertando chunks en ChromaDB...
Ingesta ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
Ingesta completada!
Documentos: 45
Chunks almacenados: 892
Coleccion: ops-docsLa primera ejecucion descarga el modelo de embeddings (~80MB). Las siguientes son instantaneas porque se cachea en
~/.cache/huggingface/.
8.3 Consultar
# Pregunta directa
python rag.py --provider nvidia -q "Que reglas protegen contra SQL injection"
# Modo interactivo
python rag.py --provider nvidia8.4 Cambiar de proveedor
# Con Grok
python rag.py --provider grok -q "Como configuro SSL en nginx"
# Con NVIDIA NIM
python rag.py --provider nvidia -q "Como configuro SSL en nginx"Paso 9: Anadir un nuevo proveedor LLM
La arquitectura esta preparada para anadir cualquier proveedor compatible con el formato OpenAI. El patron es siempre el mismo: ChatOpenAI + base_url + api_key + model.
Ejemplo: Azure OpenAI
- Anade las variables al
.env:
AZURE_OPENAI_API_KEY=tu-clave
AZURE_OPENAI_ENDPOINT=https://tu-recurso.openai.azure.com
AZURE_OPENAI_MODEL=gpt-4o
AZURE_API_VERSION=2024-10-21- Anade la configuracion en
config.py:
# Azure OpenAI
AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI_API_KEY", "")
AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT", "")
AZURE_OPENAI_MODEL = os.getenv("AZURE_OPENAI_MODEL", "gpt-4o")
AZURE_API_VERSION = os.getenv("AZURE_API_VERSION", "2024-10-21")- Anade el caso en
get_llm()derag.py:
elif provider == "azure":
from langchain_openai import AzureChatOpenAI
return AzureChatOpenAI(
api_key=Config.AZURE_OPENAI_API_KEY,
azure_endpoint=Config.AZURE_OPENAI_ENDPOINT,
azure_deployment=Config.AZURE_OPENAI_MODEL,
api_version=Config.AZURE_API_VERSION,
temperature=0.1,
max_tokens=4096,
)- Anade
"azure"achoicesen el argparser.
El mismo patron aplica para AWS Bedrock, GCP Vertex AI, o cualquier LLM self-hosted que exponga una API OpenAI-compatible (vLLM, Ollama, LiteLLM, etc.).
Paso 10: Recomendaciones para entornos enterprise
En un entorno empresarial, no deberias usar APIs publicas con datos internos sensibles. Las opciones recomendadas:
Opcion A: LLM gestionado en cloud privado
| Proveedor | Servicio | Ventaja |
|---|---|---|
| Azure | Azure OpenAI Service | Datos no salen de tu tenant, SLA 99.9%, compliance SOC2/ISO |
| Azure | Azure AI Foundry | Catalogo multi-modelo (OpenAI, Llama, Mistral), MLOps integrado |
| AWS | Amazon Bedrock | Multi-modelo (Claude, Llama, Mistral), VPC endpoints |
| GCP | Vertex AI | Gemini, modelos open-source, integracion con GKE |
Estos servicios garantizan que tus datos no se usan para entrenar modelos y ofrecen aislamiento de red (Private Endpoints / VPC).
Opcion B: LLM self-hosted en tu infraestructura
Para maxima privacidad, despliega el modelo en tu propio cluster:
- vLLM en Kubernetes con GPUs (A100/H100) — expone API OpenAI-compatible
- NVIDIA NIM containers en tu infraestructura on-premise
- Ollama en un servidor dedicado con GPU para equipos pequenos
Opcion C: Hibrido
- Embeddings: Siempre locales (no envian datos a ningun sitio)
- LLM para datos sensibles: Azure OpenAI / Bedrock con Private Endpoint
- LLM para datos publicos: API directa (Grok, NVIDIA NIM) por coste/velocidad
Seguridad minima recomendada
- Nunca envies credenciales, tokens o secrets al LLM — filtra antes de la ingesta
- Usa variables de entorno o un secret manager (Vault, AWS Secrets Manager)
- Audita los logs de que se envia a la API
- Implementa RBAC si multiples equipos usan el RAG
- Cifra los datos en reposo en ChromaDB (volume encryption)
Troubleshooting
ChromaDB no conecta
# Verificar que esta corriendo
docker logs rag-chromadb
# Probar conexion (ChromaDB v2+)
curl http://localhost:8000/api/v2/heartbeatSi ves Connection reset by peer, verifica que el mapeo de puertos es correcto en docker-compose.yaml. El contenedor siempre escucha en 8000 internamente. Si mapeas a otro puerto externo (ej. 8001:8000), ajusta CHROMA_PORT en .env.
Error de autenticacion en Grok
openai.AuthenticationError: Incorrect API key providedVerifica que la key en .env empieza por xai- y esta activa en console.x.ai.
Error de autenticacion o geolocalizacion en NVIDIA NIM
openai.AuthenticationError: ...
# o
This NIM is unavailable in your location- Verifica que la key empieza por
nvapi- - Si hay bloqueo geografico, cambia a otro modelo con "Free Endpoint" en build.nvidia.com
- Modelos recomendados sin restriccion:
z-ai/glm4.7,mistralai/mistral-nemotron
Respuestas vacias o muy cortas
Si el LLM devuelve respuestas vacias, puede ser que el modelo use "thinking mode" que pone el contenido en un campo separado. La solucion es desactivar el thinking en extra_body:
extra_body={
"chat_template_kwargs": {
"enable_thinking": False,
}
}Si las respuestas son demasiado cortas, aumenta max_tokens en la configuracion del LLM (recomendado: 4096).
Respuestas pobres o genericas
El RAG solo es tan bueno como la documentacion que le metas. Si las respuestas son pobres:
- Mete mas documentacion relevante en
data/— no solo configs, tambien manuales, runbooks, postmortems - Re-ejecuta la ingesta (
python ingest.py data) despues de anadir documentos - Verifica cuantos chunks tienes: pocos chunks = poco contexto = respuestas pobres
ModuleNotFoundError
ModuleNotFoundError: No module named 'langchain_huggingface'Asegurate de tener el virtualenv activo:
source .venv/bin/activate
python rag.py ...Proximos pasos
- Interfaz web: Anadir Streamlit o Gradio como frontend visual
- Ingesta automatica: Watcher que re-ingeste cuando cambian ficheros
- Multi-coleccion: Separar documentos por proyecto o entorno
- Evaluacion: Medir calidad de respuestas con RAGAS
- Historial: Implementar memoria conversacional para preguntas encadenadas
Recursos
:wq!
Comentarios