Add log review workflow for RAG evaluation
This commit is contained in:
parent
98faecb967
commit
8ce0d7223b
8 changed files with 255 additions and 2 deletions
|
|
@ -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/<id>" \
|
||||
-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
|
||||
|
|
|
|||
129
RAG/docs/LOGS_EVALUACION.md
Normal file
129
RAG/docs/LOGS_EVALUACION.md
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Pick<EvaluationLogEntry, "reviewStatus" | "severity" | "reviewedBy" | "resolutionNote" | "fixReference" | "supersedesLogId">>): Promise<EvaluationLogEntry | null> {
|
||||
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<string, unknown>
|
||||
}]
|
||||
});
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
private async ensureCollection(vectorSize: number): Promise<void> {
|
||||
if (this.collectionReady) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue