- manuales.py cosecha el --help de las herramientas que no traen man page (ffuf, sqlmap, suite impacket, netexec, hydra...) y lo escribe como markdown en conocimiento/09 - Manuales/. Es la referencia de opciones que la man page no da; complementa el cheatsheet de invocaciones comunes. - indexa.py --publico construye saber-publico.jsonl: glosario + pack de conocimiento con los vectores ya calculados, 100% publico y portable. - busca.py usa ese indice publico como fallback cuando no hay indice personal, asi un clon recien hecho consulta al instante sin reindexar nada. - .gitignore deja pasar saber-publico.jsonl; el personal (saber.jsonl) sigue fuera. - docs/rag.md y el README del pack documentan ambas cosas.
107 lines
5.5 KiB
Markdown
107 lines
5.5 KiB
Markdown
# El RAG
|
|
|
|
JARVIS responde desde los apuntes del usuario, no desde lo que el modelo
|
|
recuerde. Para 668 herramientas de pentesting, recordar sería inventar. Este
|
|
documento explica el método y los resultados. El índice **personal** (los
|
|
apuntes de cada quien) no se publica; sí se publica un índice **público
|
|
pre-construido** —glosario de Linux más el pack de metodología y manuales, con
|
|
los vectores ya calculados (`nucleo/datos/saber-publico.jsonl`)— para que un clon
|
|
recién hecho consulte al instante, sin repetir el trabajo de indexar. El código
|
|
que lo construye está entero en `nucleo/saber/`.
|
|
|
|
## Cómo funciona
|
|
|
|
Embeddings **estáticos** (`model2vec`, `potion-multilingual-128M`) sobre los
|
|
fragmentos de los apuntes, con una **búsqueda híbrida**: similitud coseno más un
|
|
bono por palabras exactas y por nombrar la herramienta. Los estáticos son
|
|
rápidos —un vector por token, precalculado, sin red neuronal en la consulta— a
|
|
cambio de ser más flojos en lo semántico; el bono por palabras compensa esa
|
|
debilidad. No hace falta una base de datos vectorial: con unos miles de
|
|
vectores, un producto escalar en `numpy` arranca antes y no añade dependencias.
|
|
|
|
El RAG entra de **dos formas**:
|
|
|
|
- **Pasivo**: en cada pregunta se le ponen delante al modelo los fragmentos más
|
|
parecidos. Siempre dispara.
|
|
- **Agéntico**: `buscar_en_apuntes` es una herramienta que el modelo invoca
|
|
cuando lo decide, reformulando la consulta con sus palabras y buscando varias
|
|
veces. Salva los casos donde el usuario dice una cosa y el apunte está escrito
|
|
de otra.
|
|
|
|
## El pipeline de enriquecimiento
|
|
|
|
En `nucleo/saber/enriquece/`, cuatro fases, reanudable y no destructivo:
|
|
|
|
```
|
|
apuntes ──cosecha──> fragmentos ──sintetiza──> preguntas
|
|
│ │
|
|
└───── reindexa ──────────┘
|
|
│
|
|
índice + vectores
|
|
│
|
|
evalúa (hit@k) ──promociona SOLO si mejora
|
|
```
|
|
|
|
1. **Cosecha**: rescata la metodología que un indexado ingenuo se deja. En el
|
|
caso real, de 72 notas de metodología escritas a mano, **0 estaban en el
|
|
índice**: el filtro por nombre y por profundidad las descartaba. Un tope por
|
|
herramienta evita que un repo a granel (una base de exploits con decenas de
|
|
miles de ficheros) ahogue lo bueno.
|
|
2. **Síntesis** — *indexación multi-representación*: por cada fragmento se
|
|
generan las preguntas que responde, y **se embebe la pregunta, se devuelve el
|
|
fragmento**. Así una consulta coloquial ("cómo saco una shell reversa") se
|
|
compara pregunta-contra-pregunta, no contra un comando técnico en otro
|
|
idioma. El modelo solo escribe preguntas, nunca reescribe comandos: si
|
|
inventa una pregunta rara, esa entrada recupera peor y ya está.
|
|
3. **Reindexa**: une todo, deduplica y calcula los vectores.
|
|
4. **Evalúa**: mide la recuperación con un conjunto de preguntas de prueba
|
|
(`enriquece/eval_set.jsonl`). Determinista, sin juez-LLM.
|
|
|
|
## Resultados, medidos
|
|
|
|
Rescatar la metodología y añadir los ganchos-pregunta, sobre el mismo conjunto
|
|
de evaluación:
|
|
|
|
| | antes | después |
|
|
|---|---|---|
|
|
| hit@1 | 48 % | **82 %** |
|
|
| hit@5 | 77 % | **95 %** |
|
|
| similitud media | 0.689 | **0.802** |
|
|
|
|
## Un resultado negativo, útil
|
|
|
|
¿Y si se cambia el embedder estático por un transformer de verdad (e5, bge)?
|
|
Medido: **no compensa**. `intfloat/multilingual-e5-base` empató con el estático
|
|
(hit@1 86 %, hit@5 95 %), arreglando dos consultas y rompiendo otras dos, a
|
|
cambio de 50-150 ms por consulta y una dependencia de `torch` en cada búsqueda.
|
|
El trabajo de recuperación lo hace la búsqueda híbrida, no el embedder. Se
|
|
reproduce con `enriquece/experimento_embedder.py`.
|
|
|
|
## Por qué el índice no está en el repositorio
|
|
|
|
`saber.jsonl` contiene el TEXTO de los apuntes indexados, con rutas y
|
|
conocimiento personal; `diario.jsonl` es lo que se le dice al asistente. Son del
|
|
usuario. El `.gitignore` los bloquea. Lo reproducible —el método, el código y la
|
|
forma de medirlo— sí está; el corpus lo pone cada quien con sus notas.
|
|
|
|
## Qué se publica y qué no, en concreto
|
|
|
|
| | En el repo |
|
|
|---|---|
|
|
| El código: `indexa`, `busca`, `glosario`, `sistema`, `manuales`, `enriquece/` | **sí** |
|
|
| El eval (`enriquece/eval_set.jsonl`) | **sí** |
|
|
| El glosario de tareas de Linux en castellano (`glosario.py`) | **sí** (genérico) |
|
|
| **El pack de metodología y manuales** (`saber/conocimiento/`) | **sí** — limpio y genérico |
|
|
| **El índice público pre-construido** (`datos/saber-publico.jsonl`) | **sí** — glosario + pack, con vectores |
|
|
| El índice personal (`saber.jsonl`) y sus copias | **no** — los apuntes indexados |
|
|
| El diario (`diario.jsonl`) | **no** — las conversaciones |
|
|
| Lo derivado (`cosecha.jsonl`, `sintesis.jsonl`) | **no** — salen de los apuntes |
|
|
|
|
Así que un equipo recién clonado consulta **al instante**, sin dato privado y sin
|
|
reindexar: el `saber-publico.jsonl` ya trae el glosario y el pack de metodología
|
|
—enumeración, explotación web, shells, privesc, Active Directory, cheatsheets— más
|
|
los **manuales** de las herramientas que no traen man page (`saber/conocimiento/09
|
|
- Manuales/`, cosechados con `manuales.py` de su `--help`). Cuando quiera sumar sus
|
|
propias notas y las *man pages* de su máquina, corre `indexa.py` y pasa a usar su
|
|
índice personal. Los apuntes privados del usuario (su `saber.jsonl`, su diario)
|
|
siguen fuera; el pack los complementa.
|