From 8ce0d7223be66c955dcc75aaaafb687dafa15a70 Mon Sep 17 00:00:00 2001 From: Paco POR-CORREO Date: Mon, 6 Apr 2026 19:54:36 +0200 Subject: [PATCH] Add log review workflow for RAG evaluation --- RAG/docs/API_RAG.md | 22 ++++++ RAG/docs/LOGS_EVALUACION.md | 129 ++++++++++++++++++++++++++++++++ RAG/docs/PLAYGROUND.md | 7 ++ RAG/src/app.ts | 22 ++++++ RAG/src/modules/logs/service.ts | 50 ++++++++++++- RAG/src/shared/types/rag.ts | 7 ++ docs/HISTORIAL_SESIONES.md | 1 + docs/INDICE_DOCUMENTACION.md | 19 ++++- 8 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 RAG/docs/LOGS_EVALUACION.md diff --git a/RAG/docs/API_RAG.md b/RAG/docs/API_RAG.md index 437b35f..b0e6cad 100644 --- a/RAG/docs/API_RAG.md +++ b/RAG/docs/API_RAG.md @@ -424,6 +424,8 @@ Ejemplo: curl -sS "https://rag.por-correo.com/logs/recent" ``` +Tambien admite actualizacion posterior del estado de revision mediante `PATCH /logs/:id`. + --- ### 9. `POST /logs/manual` @@ -452,6 +454,26 @@ Payload base: } ``` +--- + +### 10. `PATCH /logs/:id` + +Permite actualizar el seguimiento de un log ya creado. + +Ejemplo: + +```bash +curl -sS -X PATCH "https://rag.por-correo.com/logs/" \ + -H "Content-Type: application/json" \ + -d '{ + "reviewStatus": "resolved", + "severity": "high", + "reviewedBy": "Paco POR-CORREO", + "resolutionNote": "Se ajusto el bootstrap para scopes aislados.", + "fixReference": "6557aea" + }' +``` + Respuesta esperada resumida: ```json diff --git a/RAG/docs/LOGS_EVALUACION.md b/RAG/docs/LOGS_EVALUACION.md new file mode 100644 index 0000000..5aed4e3 --- /dev/null +++ b/RAG/docs/LOGS_EVALUACION.md @@ -0,0 +1,129 @@ +# Logs de evaluacion del RAG + +**Proyecto:** Workspace de tools IA para empresas +**Modulo:** RAG +**Ultima actualizacion:** 2026-04-06 +**Ultima modificacion por:** Agente tools IA para potenciar servicios empresariales +**Estado:** Implementado en codigo, pendiente de redeploy + +--- + +## Donde se guardan + +Los logs de evaluacion se guardan en `Qdrant`. + +Coleccion usada: + +```text +rag_eval_logs +``` + +Se eligio `Qdrant` porque: + +- ya forma parte de la infraestructura activa del RAG +- ofrece persistencia sin depender del filesystem efimero del contenedor +- permite busqueda semantica posterior sobre las consultas o incidencias registradas + +--- + +## Estructura del log + +Cada log guarda, como minimo: + +- `id` +- `trigger`: `automatic` o `manual` +- `operation`: `retrieve`, `answer` o `chat` +- `reason` +- `query` +- `mode` +- `intent` +- `model` +- `note` +- `createdAt` +- `scope` +- `usedBootstrapContext` +- `usedAdditionalRetrieve` +- `responseSummary` +- `retrievedItemsCount` +- `chunkIds` +- `documentIds` + +Y ahora tambien campos de seguimiento: + +- `reviewStatus`: `pending`, `in_progress`, `resolved`, `ignored` +- `severity`: `low`, `medium`, `high` +- `reviewedAt` +- `reviewedBy` +- `resolutionNote` +- `fixReference` +- `supersedesLogId` + +--- + +## Tipos de log + +### 1. Automatico + +Se genera cuando el sistema detecta que: + +- el contexto recuperado es insuficiente +- la respuesta deja claro que no hay suficiente contexto + +Objetivo: +- detectar huecos en ingesta, chunking, embeddings, retrieval o prompting + +### 2. Manual + +Se genera cuando el usuario lo pide explicitamente desde el playground o por API. + +En este caso la nota siempre deja constancia de que fue: + +```text +Log solicitado por el usuario. +``` + +Y si el usuario añade una nota, se concatena a ese texto base. + +--- + +## Seguimiento del log + +El sistema ya permite marcar cada log como: + +- pendiente +- en progreso +- resuelto +- ignorado + +Y asociarle: + +- quien lo reviso +- nota de resolucion +- referencia al fix o commit + +Esto permite saber: + +- que logs ya se han considerado +- cuales siguen pendientes +- cuales quedaron resueltos por una mejora concreta +- cuales se decidio ignorar conscientemente + +--- + +## Endpoints relacionados + +- `GET /logs/recent` +- `POST /logs/manual` +- `PATCH /logs/:id` + +--- + +## Uso previsto + +Estos logs estan pensados para que el usuario, este agente u otros agentes puedan revisarlos juntos y decidir mejoras del RAG de forma mas fiable. + +No sustituyen una evaluacion formal completa, pero si dan una base practica para: + +- detectar limitaciones reales +- priorizar correcciones +- vincular mejoras con incidencias concretas diff --git a/RAG/docs/PLAYGROUND.md b/RAG/docs/PLAYGROUND.md index fe77e2e..28bbb96 100644 --- a/RAG/docs/PLAYGROUND.md +++ b/RAG/docs/PLAYGROUND.md @@ -151,6 +151,13 @@ El playground ya soporta dos vias de logging: Los logs quedan guardados en `Qdrant`, por lo que no dependen del filesystem efimero del contenedor. +Aunque de momento el playground no tiene una pestaña dedicada solo a logs, si puede: + +- registrar logs manuales +- mostrar logs recientes + +Y estos logs ya quedan preparados para ser revisados despues por el usuario junto con este agente u otros agentes. + --- ## Idea de uso diff --git a/RAG/src/app.ts b/RAG/src/app.ts index fde044d..578adc2 100644 --- a/RAG/src/app.ts +++ b/RAG/src/app.ts @@ -353,5 +353,27 @@ export function createApp() { } }); + app.patch("/logs/:id", async (req, res) => { + try { + const entry = await evaluationLogs.update(String(req.params.id), { + reviewStatus: req.body.reviewStatus, + severity: req.body.severity, + reviewedBy: req.body.reviewedBy ? String(req.body.reviewedBy) : undefined, + resolutionNote: req.body.resolutionNote ? String(req.body.resolutionNote) : undefined, + fixReference: req.body.fixReference ? String(req.body.fixReference) : undefined, + supersedesLogId: req.body.supersedesLogId ? String(req.body.supersedesLogId) : undefined + }); + + if (!entry) { + res.status(404).json({ ok: false, error: "Log not found" }); + return; + } + + res.json(entry); + } catch (error) { + res.status(500).json({ ok: false, error: error instanceof Error ? error.message : "Unknown log update error" }); + } + }); + return app; } diff --git a/RAG/src/modules/logs/service.ts b/RAG/src/modules/logs/service.ts index 6d85225..6b0726d 100644 --- a/RAG/src/modules/logs/service.ts +++ b/RAG/src/modules/logs/service.ts @@ -40,7 +40,9 @@ export class EvaluationLogService { responseSummary: input.responseSummary, retrievedItemsCount: input.retrievedItems?.length ?? 0, chunkIds: (input.retrievedItems ?? []).map((item) => item.chunkId), - documentIds: [...new Set((input.retrievedItems ?? []).map((item) => item.documentId))] + documentIds: [...new Set((input.retrievedItems ?? []).map((item) => item.documentId))], + reviewStatus: "pending", + severity: input.trigger === "automatic" ? "medium" : "low" }; await this.client.upsert(env.qdrantLogsCollection, { @@ -75,6 +77,52 @@ export class EvaluationLogService { .slice(0, Math.min(limit, 100)); } + async update(id: string, updates: Partial>): Promise { + const collections = await this.client.getCollections(); + const exists = collections.collections.some((collection) => collection.name === env.qdrantLogsCollection); + + if (!exists) { + return null; + } + + const points = await this.client.retrieve(env.qdrantLogsCollection, { + ids: [id], + with_payload: true + }); + + const point = points[0]; + if (!point?.payload) { + return null; + } + + const current = point.payload as unknown as EvaluationLogEntry; + const next: EvaluationLogEntry = { + ...current, + reviewStatus: updates.reviewStatus ?? current.reviewStatus, + severity: updates.severity ?? current.severity, + reviewedBy: updates.reviewedBy ?? current.reviewedBy, + resolutionNote: updates.resolutionNote ?? current.resolutionNote, + fixReference: updates.fixReference ?? current.fixReference, + supersedesLogId: updates.supersedesLogId ?? current.supersedesLogId, + reviewedAt: updates.reviewStatus || updates.reviewedBy || updates.resolutionNote || updates.fixReference + ? new Date().toISOString() + : current.reviewedAt + }; + + const [vector] = await this.embeddingProvider.embed([next.query || next.reason]); + + await this.client.upsert(env.qdrantLogsCollection, { + wait: true, + points: [{ + id, + vector, + payload: next as unknown as Record + }] + }); + + return next; + } + private async ensureCollection(vectorSize: number): Promise { if (this.collectionReady) { return; diff --git a/RAG/src/shared/types/rag.ts b/RAG/src/shared/types/rag.ts index 029c9e7..29c39ce 100644 --- a/RAG/src/shared/types/rag.ts +++ b/RAG/src/shared/types/rag.ts @@ -140,4 +140,11 @@ export interface EvaluationLogEntry { retrievedItemsCount: number; chunkIds: string[]; documentIds: string[]; + reviewStatus: "pending" | "in_progress" | "resolved" | "ignored"; + severity: "low" | "medium" | "high"; + reviewedAt?: string; + reviewedBy?: string; + resolutionNote?: string; + fixReference?: string; + supersedesLogId?: string; } diff --git a/docs/HISTORIAL_SESIONES.md b/docs/HISTORIAL_SESIONES.md index c55e46f..52f5a80 100644 --- a/docs/HISTORIAL_SESIONES.md +++ b/docs/HISTORIAL_SESIONES.md @@ -67,6 +67,7 @@ Este archivo registra agentes y sesiones de trabajo de este workspace. - Evolucion del playground a una mecanica mas completa con pestañas `Ingesta / Bootstrap / Chat`, indicador visual de contexto activo y endpoint `/chat` con bootstrap reutilizable y consultas adicionales al RAG durante la conversacion. - Ampliacion de la ingesta y del playground para soportar upload directo de archivos y `sourceId` personalizado, permitiendo aislar documentos ajenos al RAG en scopes separados. - Implementacion de logs de evaluacion persistentes en `Qdrant`, con disparo automatico por contexto insuficiente y registro manual con nota desde el playground. +- Ampliacion de los logs de evaluacion para permitir seguimiento real (`pending`, `resolved`, `ignored`, etc.) y documentacion de su arquitectura en `RAG/docs/LOGS_EVALUACION.md`. - Reorganizacion de RAG como modulo raiz independiente con documentacion propia en `RAG/docs/`. - Ajuste del indice documental global para reflejar la separacion entre documentacion global y documentacion por tool. - Creacion de `docs/TASK.md` para descomponer lineas de trabajo amplias en puntos de analisis y acuerdos. diff --git a/docs/INDICE_DOCUMENTACION.md b/docs/INDICE_DOCUMENTACION.md index 80df2c2..7c3cea0 100644 --- a/docs/INDICE_DOCUMENTACION.md +++ b/docs/INDICE_DOCUMENTACION.md @@ -306,6 +306,23 @@ Documentar la tecnologia, ubicacion y utilidad del playground interno del RAG pa --- +### `RAG/docs/LOGS_EVALUACION.md` + +**Ubicacion:** `RAG/docs/LOGS_EVALUACION.md` + +**Proposito:** +Documentar como se guardan, siguen y revisan los logs de evaluacion del RAG. + +**Cuando leerlo:** +- al revisar logs generados por el playground o por la API +- al planificar mejoras del RAG a partir de incidencias registradas + +**Cuando actualizarlo:** +- cuando cambie el esquema o el flujo de revision de logs +- cuando se amplie el sistema de evaluacion del RAG + +--- + ### `sesion_actual_opencode.md` **Ubicacion:** `docs/sesion_actual_opencode.md` @@ -332,4 +349,4 @@ Instruccion universal para detectar la sesion activa de OpenCode del workspace a ## Estadistica global -**Total de documentos indexados:** 17 +**Total de documentos indexados:** 18