diff --git a/README.md b/README.md index 1f2e06d..9cb7c9d 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,11 @@ nube. Núcleo propio, escrito para caber en una tarjeta pequeña (NVIDIA T1200 d todo en 127.0.0.1 · 0 llamadas a la nube ``` - +![El panel de JARVIS](docs/panel.png) + +*El panel: telemetría del sistema, el reactor, lo que oye y hace, el catálogo de +acciones, y las métricas de rendimiento del propio asistente. Hay un +[vídeo de ejemplo](docs/demo.webm) (47 s) en `docs/`.* ## El stack @@ -117,7 +119,8 @@ Habla en castellano, natural. **150 acciones** en el catálogo, agrupadas: Si lo que pides no está en el catálogo, el modelo lo resuelve con un **comando de shell** (de solo lectura por defecto). Y si pregunta *cómo* se hace algo técnico, puede **buscar en tus apuntes** (RAG) antes de responder, para dar el comando que -ya has probado en vez de inventarlo. +ya has probado en vez de inventarlo. El método, el pipeline y los resultados +medidos están en [docs/rag.md](docs/rag.md). ## Órdenes con root diff --git a/docs/demo.webm b/docs/demo.webm new file mode 100644 index 0000000..7036ba1 Binary files /dev/null and b/docs/demo.webm differ diff --git a/docs/panel.png b/docs/panel.png new file mode 100644 index 0000000..d714159 Binary files /dev/null and b/docs/panel.png differ diff --git a/docs/rag.md b/docs/rag.md new file mode 100644 index 0000000..4ead34a --- /dev/null +++ b/docs/rag.md @@ -0,0 +1,82 @@ +# 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 en sí no se publica +—contiene los apuntes, que son privados—, pero el código que lo construye sí +(`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. diff --git a/nucleo/cara/hud/hud.js b/nucleo/cara/hud/hud.js index a0e098e..40ce5c4 100644 --- a/nucleo/cara/hud/hud.js +++ b/nucleo/cara/hud/hud.js @@ -944,5 +944,14 @@ { pid: 1201, nombre: "pipewire", cpu: 2.0, mem: 0.3 }, ], }}); + + window.jarvis.recibe({ tipo: "medidas", datos: { + n: 240, + lat_p50: 2.1, lat_p95: 4.8, lat_max: 7.2, + lat_cerebro: 2.7, lat_catalogo: 0.2, + pct_cerebro: 44, pct_catalogo: 53, pct_ruido: 3, + vol24: 87, porhora: [2, 0, 1, 4, 6, 3, 5, 8, 4, 2, 1, 3], + rag: { hit5: 95, hit1: 82 }, + }}); } })();