#!/usr/bin/env bash # El pipeline de la noche: mejora el RAG hasta nivel pentesting profesional. # # ./correr_noche.sh corre las cuatro fases y decide # ./correr_noche.sh --sin-promo igual, pero NO sustituye el indice vivo # # ── Que hace, en orden ───────────────────────────────────────────────────── # # 1. COSECHA rescata la metodologia de COFRE que el indexador se dejaba # (el OSCP_Vault entero, 0 de 72 notas estaban en el indice). # 2. SINTETIZA por cada fragmento, preguntas en castellano que lo encuentran. # Es la fase larga: horas, con el modelo local. Reanudable. # 3. REINDEXA une vivo + cosecha + sintesis y calcula los vectores. Escribe # a saber.jsonl.nuevo. NO toca el indice vivo. # 4. EVALUA mide recuperacion del vivo contra el candidato, con numeros. # # ── No rompe nada ────────────────────────────────────────────────────────── # # El indice vivo solo se sustituye si evalua DICE que el candidato es mejor, y # antes se guarda una copia con fecha. Si el candidato empeora, se queda el # vivo y el candidato espera revision. Reversible siempre. # # Cada fase se salta si ya esta hecha, asi que relanzarlo continua donde iba. set -uo pipefail AQUI=$(cd -P "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd) RAIZ=$(cd -P "$AQUI/../.." && pwd) # .../nucleo DATOS="$RAIZ/datos" PY="$RAIZ/venv/bin/python" [ -x "$PY" ] || PY=python3 LOG="$DATOS/noche_rag.log" # El modelo NO se fija aqui a proposito: sintetiza.py mira que tiene ollama # cargado y usa ESE, para no forzar cambios en la tarjeta de 4 GB. Si el verde # esta abierto, generara con el verde; si no, cae al naranja. Solo se fuerza si # exportas JARVIS_MODELO tu. Aun asi, para la noche mas rapida y limpia, lo # suyo es cerrar el TUI verde: con un solo modelo ollama no recarga nada. PROMO=si [ "${1:-}" = "--sin-promo" ] && PROMO=no fecha() { date '+%Y-%m-%d %H:%M:%S'; } fase() { echo "" | tee -a "$LOG"; echo "[$(fecha)] === FASE $* ===" | tee -a "$LOG"; } echo "[$(fecha)] arranca el pipeline de la noche (modelo $JARVIS_MODELO)" | tee -a "$LOG" # ── 1. COSECHA ───────────────────────────────────────────────────────────── fase "1/4 COSECHA" if [ -s "$DATOS/cosecha.jsonl" ]; then echo " ya hecha ($(wc -l <"$DATOS/cosecha.jsonl") fragmentos), se salta" | tee -a "$LOG" else "$PY" "$AQUI/cosecha.py" 2>&1 | tee -a "$LOG" fi # ── 2. SINTETIZA (la larga) ──────────────────────────────────────────────── fase "2/4 SINTETIZA (horas; reanudable)" # hecha del todo = el .hecho llego al ultimo fragmento TOTAL=$(wc -l <"$DATOS/cosecha.jsonl") HECHO=$(cat "$DATOS/sintesis.jsonl.hecho" 2>/dev/null || echo -1) if [ "$HECHO" -ge "$((TOTAL - 1))" ] 2>/dev/null; then echo " ya completa ($(wc -l <"$DATOS/sintesis.jsonl" 2>/dev/null || echo 0) preguntas)" | tee -a "$LOG" else "$PY" "$AQUI/sintetiza.py" 2>&1 | tee -a "$LOG" fi # ── 3. REINDEXA ──────────────────────────────────────────────────────────── fase "3/4 REINDEXA" "$PY" "$AQUI/reindexa.py" 2>&1 | tee -a "$LOG" # ── 4. EVALUA ────────────────────────────────────────────────────────────── fase "4/4 EVALUA" INFORME="$DATOS/informe_rag.txt" "$PY" "$AQUI/evalua.py" 2>&1 | tee "$INFORME" | tee -a "$LOG" VEREDICTO=$(grep -oE 'VEREDICTO (PROMOCIONAR|MANTENER)' "$INFORME" | awk '{print $2}' | tail -1) # ── Decision ─────────────────────────────────────────────────────────────── fase "DECISION" if [ "$PROMO" = no ]; then echo " --sin-promo: dejo el candidato en saber.jsonl.nuevo sin tocar el vivo" | tee -a "$LOG" elif [ "$VEREDICTO" = PROMOCIONAR ]; then COPIA="$DATOS/saber.jsonl.antes-$(date +%Y%m%d-%H%M)" cp "$DATOS/saber.jsonl" "$COPIA" mv "$DATOS/saber.jsonl.nuevo" "$DATOS/saber.jsonl" echo " PROMOCIONADO. El candidato es mejor y ya es el indice vivo." | tee -a "$LOG" echo " copia del anterior: $COPIA" | tee -a "$LOG" echo " para deshacer: cp '$COPIA' '$DATOS/saber.jsonl'" | tee -a "$LOG" else echo " MANTENIDO el vivo: el candidato no mejora la evaluacion." | tee -a "$LOG" echo " candidato en saber.jsonl.nuevo e informe en informe_rag.txt para revisar." | tee -a "$LOG" fi echo "[$(fecha)] pipeline terminado" | tee -a "$LOG"