JARVIS/nucleo/saber/enriquece
sito 7c5381eea7 saber: lo instalado en la maquina y los docs de repos clonados entran al indice
instalado.py lee los .desktop y los paquetes para saber que hay en el equipo y
para que sirve cada cosa. indexa.py lo engancha, y con el los docs markdown de
las herramientas clonadas en CODERS. Las dos fuentes son personales: se quedan
en el indice de la maquina y no entran en el publico.

busca_cli.py expone el mismo motor que usa el cerebro (saber.busca) para
consultar el indice desde la terminal, con --n y --json.

reentrena_noche.sh encadena las fases del reentrenamiento largo y las deja
corriendo horas; cada fase es reanudable por su cuenta.

eval del indice vivo: hit@1 43/57 (75%), hit@5 55/57 (96%), sim 0.909.
2026-08-18 12:14:57 +02:00
..
correr_noche.sh JARVIS: asistente de voz local para Linux 2026-08-16 15:34:37 +02:00
cosecha.py JARVIS: asistente de voz local para Linux 2026-08-16 15:34:37 +02:00
eval_set.jsonl saber: lo instalado en la maquina y los docs de repos clonados entran al indice 2026-08-18 12:14:57 +02:00
evalua.py JARVIS: asistente de voz local para Linux 2026-08-16 15:34:37 +02:00
experimento_embedder.py JARVIS: asistente de voz local para Linux 2026-08-16 15:34:37 +02:00
README.md JARVIS: asistente de voz local para Linux 2026-08-16 15:34:37 +02:00
reentrena_noche.sh saber: lo instalado en la maquina y los docs de repos clonados entran al indice 2026-08-18 12:14:57 +02:00
reindexa.py JARVIS: asistente de voz local para Linux 2026-08-16 15:34:37 +02:00
sintetiza.py JARVIS: asistente de voz local para Linux 2026-08-16 15:34:37 +02:00
sintetiza_catalogo.py saber: lo instalado en la maquina y los docs de repos clonados entran al indice 2026-08-18 12:14:57 +02:00

Enriquecer el RAG a nivel de pentesting profesional

El RAG del naranja ya funcionaba, pero se dejaba fuera lo mejor que hay en el disco. Medido antes de empezar: de las 72 notas del OSCP_Vault —la metodologia OSCP escrita a mano, con comandos reales— había 0 en el índice. indexa.py las descartaba por dos motivos a la vez: el nombre (SQL injection.md no lleva "notas" ni "guia") y la profundidad (viven a 5 niveles).

Este pipeline las rescata, multiplica su recuperabilidad con preguntas generadas, y mide que el resultado es mejor antes de tocar nada.

Correrlo

./correr_noche.sh              # las cuatro fases, y decide si promociona
./correr_noche.sh --sin-promo  # igual, pero deja el vivo intacto

Es reanudable: cada fase se salta si ya está hecha, así que si se corta, relanzarlo continúa. La fase larga (síntesis) es reanudable fragmento a fragmento.

Las cuatro fases

Script Qué hace Coste
1 cosecha.py rescata la metodología de COFRE que faltaba segundos, CPU
2 sintetiza.py preguntas en castellano por cada fragmento horas, modelo local
3 reindexa.py une todo y calcula vectores → saber.jsonl.nuevo minutos, CPU
4 evalua.py mide recuperación vivo vs candidato segundos

1 · Cosecha

Donde indexa.py es prudente (solo ficheros que parecen documentación, 3 niveles), esto es agresivo con el oro: las carpetas de metodología (OSCP vaults, apuntes, cheatsheets) enteras, sin límite de profundidad. Fuera de ahí pone un tope por herramienta: si un repo tiene más de 25 documentos, es una base de datos (exploitdb son 29.925 ficheros), no unos apuntes, y solo se coge su README. Así el oro no se ahoga en ruido.

2 · Síntesis — indexación multi-representación

El punto flaco de los embeddings estáticos: "cómo saco una shell reversa" no se parece vectorialmente a bash -i >& /dev/tcp/.... La solución es embeber la pregunta y devolver el fragmento. Por cada fragmento, el modelo local escribe las preguntas que responde; se indexa la pregunta, pero lo que se le muestra al cerebro es el fragmento literal.

Clave: el modelo solo escribe preguntas, nunca reescribe comandos. Si inventa una pregunta rara, esa entrada recupera peor y ya está; no corrompe una respuesta. Y el fragmento crudo sigue en el índice por su lado.

3 · Reindexado

Une el índice vivo (comandos Linux, glosario, fichas), la cosecha y la síntesis; deduplica por prefijo; calcula los vectores con el mismo model2vec de siempre. Escribe a saber.jsonl.nuevo. No toca el vivo. busca.py no cambia.

4 · Evaluación

eval_set.jsonl son ~45 preguntas de pentesting con las palabras que un fragmento correcto debe contener. Mide hit@1, hit@5 y similitud media, del índice vivo contra el candidato. Determinista y reproducible, sin juez-LLM.

La decisión, y por qué es segura

El índice vivo solo se sustituye si la evaluación dice que el candidato es mejor, y antes se guarda saber.jsonl.antes-<fecha>. Si empeora, se queda el vivo y el candidato espera revisión. Siempre reversible con un cp.

Ficheros que genera (en ../../datos/)

cosecha.jsonl        la metodología rescatada, sin vectores
sintesis.jsonl       las preguntas generadas (+ .hecho, el marcador)
saber.jsonl.nuevo    el índice candidato, con vectores
informe_rag.txt      los números de la evaluación
noche_rag.log        el registro de la noche
saber.jsonl.antes-*  copia del índice anterior, si se promocionó

Iteraciones posteriores a la primera noche

  • Troceado que no tira comandos cortos (cosecha.py). El troceado por encabezado descartaba toda sección de menos de 60 caracteres, y eso perdía el oro: ## Detección time-based + ' AND SLEEP(5)-- - son 50. Ahora una sección corta se pega a la siguiente y cada fragmento lleva delante el título de la nota. SLEEP pasó de 0 a 13 apariciones en el índice; hit@1 80→82 %. El salto en la métrica es pequeño porque las preguntas que quedan son cross-lingual, y de eso no salva el troceado.

  • experimento_embedder.py — mide, sin tocar nada, si un transformer (e5, bge) supera al model2vec estático. Resultado (16 ago): NO compensa. intfloat/multilingual-e5-base empató con el estático (hit@1 86 %, hit@5 95 % los dos): arregla las 2 preguntas que el estático fallaba, pero rompe otras 2 distintas. A cambio pediría ~50-150 ms por consulta en CPU y una dependencia de torch en cada búsqueda. Medido antes de cambiar → el estático se queda. El trabajo de recuperación lo hace la búsqueda híbrida (coseno + bono por palabras), no el embedder, y por eso subir el embedder no mueve la aguja. Reproducible: ./experimento_embedder.py.

  • Re-síntesis limpia sobre el troceado nuevo (SABER_BASE en reindexa.py reconstruye desde el índice original en vez de apilar, para no inflar). Da a los comandos rescatados (SLEEP y demás) su gancho-pregunta en castellano, que es lo que de verdad ataca las consultas cross-lingual —no el embedder—.

Nota sobre la tarjeta

La síntesis usa el modelo local por 127.0.0.1:11434. Fija qwen3.5:4b-jarvis (el naranja, que no inventa comandos). Si dejas el TUI verde abierto, ollama tiene que cambiar de modelo en cada petición y la noche va más lenta: para la síntesis más rápida, cierra el verde.