CreaRack-SL

Tool MCP bib_eval_retrieval: harness A/B del retrieval

Resumen

Tool MCP reproducible para validar y calibrar el retrieval sin redeploy. Compara variantes (baseline = chunks enteros vs trim = recortado a frases relevantes) sobre un set de preguntas reales o custom, produciendo métricas cuantificables: tokens en contexto, reducción %, scores y solapamiento de chunks.

Rol: Harness A/B del ArcRift cherry-pick #1 (sentence-trimming).

Invocación

bib_eval_retrieval(
  questions?: string[],             // preguntas a evaluar (opt)
  variants?: ('baseline' | 'trim')[],  // variantes (default ['baseline', 'trim'])
  top_k?: number,                   // chunks (default 5, max 20)
  trim_threshold?: number,          // coseno mínimo (default 0.38)
  trim_window?: number,             // contexto ±N frases (default 1)
  synthesize?: boolean,             // sintetizar respuestas (default false, lento/caro)
  source_type?: string,             // filtro: tipo de fuente
  app?: string                      // filtro: app Django
)

Parámetros detallados

questions (opcional)

Array de preguntas a evaluar.

Comportamiento:

  • Si se pasan: evaluar exactamente esas preguntas.
  • Si vacío o se omite: cargar las últimas 15 preguntas reales de oraculo_queries (consulta SELECT question FROM oraculo_queries WHERE ... GROUP BY question ORDER BY MAX(id) DESC LIMIT 15).

Recomendación: usar preguntas golden (casos típicos, edge cases) para reproducibilidad. Ej:

{
  "questions": [
    "¿Qué es multi-tenancy?",
    "¿Cómo se configura RLS?",
    "¿Cuál es el flow de autenticación?"
  ]
}

variants (opcional, default ['baseline', 'trim'])

Variantes del retrieval a comparar.

  • baseline: chunks enteros, sin trimming.
  • trim: recortado a frases relevantes por trim_threshold + ventana.

Ejemplo: variants: ['baseline', 'trim'] → correr ambas, comparar.

top_k (opcional, default 5)

Número de chunks a recuperar por pregunta. Max 20 (para evitar overload).

trim_threshold (opcional, default 0.38)

Coseno mínimo (0.0–1.0) para conservar una frase en la variante trim.

  • 0.38 = umbral default (calibrado en ArcRift).
  • 0.40–0.45 = más estricto, menos frases, menos tokens.
  • 0.30–0.35 = más permisivo, más ruido, más tokens.

Uso para calibración:

bib_eval_retrieval(
  questions: ["¿Multi-tenancy?"],
  trim_threshold: 0.42
)
// Ejecutar múltiples runs con thresholds distintos
// para hallar el óptimo (máx reducción, mín overlap loss)

trim_window (opcional, default 1)

Frases de contexto ±N alrededor de las frases relevantes.

  • 0 = solo frases seleccionadas, sin contexto.
  • 1 = ±1 frase (default: equilibrio ruido/contexto).
  • 2+ = más contexto, menos reducción de tokens.

synthesize (opcional, default false)

Si true: sintetizar la respuesta con Gemma/Oraculo por variante. Mucho más lento y caro (llama al LLM).

  • false: aislar retrieval puro (rápido, barato, recomendado para calibración).
  • true: incluir answer en cada variante (útil para validar calidad end-to-end).

source_type, app (opcionales)

Filtros de búsqueda:

  • source_type: tipo de fuente (ej "doc", "wiki", "code").
  • app: app Django (ej "core", "monitoring", "signage").

Ejemplo: evaluar solo chunks de la app core:

bib_eval_retrieval(
  questions: [...],
  app: "core"
)

Salida

JSON con estructura:

{
  "summary": {
    "questions": 3,
    "top_k": 5,
    "trim_threshold": 0.38,
    "trim_window": 1,
    "avg_tokens_baseline": 156,
    "avg_tokens_trim": 89,
    "token_reduction_pct": 43,
    "avg_overlap_vs_baseline": 0.92
  },
  "results": [
    {
      "question": "¿Qué es multi-tenancy? (primer 100 chars)",
      "variants": {
        "baseline": {
          "chunk_ids": [123, 456, 789],
          "top_score": 0.845,
          "tokens": 180,
          "tokens_before": 200
        },
        "trim": {
          "chunk_ids": [123, 456],
          "top_score": 0.845,
          "tokens": 95,
          "tokens_before": 200,
          "overlap_vs_baseline": 0.67,
          "answer": "Multi-tenancy es ... [truncado a 600 chars si synthesize=true]"
        }
      }
    },
    // ... más resultados
  ]
}

summary

Agregación sobre todas las preguntas evaluadas:

  • questions: número de preguntas.
  • top_k, trim_threshold, trim_window: parámetros usados.
  • avg_tokens_baseline: promedio de tokens por pregunta (retrieval completo).
  • avg_tokens_trim: promedio de tokens con trimming.
  • token_reduction_pct: % reducción (100 * (1 - trim/baseline)).
  • avg_overlap_vs_baseline: fracción promedio de chunks que baseline y trim comparten (ej 0.92 = 8% de chunks perdidos con trim).

results

Array de resultados por pregunta:

  • question: primeros 100 caracteres de la pregunta.
  • variants.baseline:
    • chunk_ids: IDs de chunks recuperados.
    • top_score: score de similitud del chunk #1 (coseno).
    • tokens: estimación pre-trimming.
    • tokens_before: duplica tokens (legacy).
  • variants.trim:
    • chunk_ids: IDs tras recorte (subset de baseline en general).
    • top_score: idem (no cambia por trimming, es score del chunk original).
    • tokens: estimación post-trimming (< baseline).
    • tokens_before: estimación pre-trimming (= baseline.tokens).
    • overlap_vs_baseline: fracción de chunks trim que están en baseline (ej 0.67 = 67% overlap).
    • answer: respuesta sintetizada (solo si synthesize=true).

Workflow de calibración

1. Línea base

bib_eval_retrieval(
  top_k: 5,
  trim_threshold: 0.38,  // default
  trim_window: 1
)
// Salida: avg_tokens_baseline=156, avg_tokens_trim=89, token_reduction_pct=43, overlap=0.92
// Interpretación: 43% menos tokens, perdemos <10% de chunks

2. Ajustar threshold

bib_eval_retrieval(
  top_k: 5,
  trim_threshold: 0.40,  // más estricto
  trim_window: 1
)
// Salida: avg_tokens_trim=75, token_reduction_pct=52, overlap=0.88
// Interpretación: más reducción, pero 12% chunks perdidos
bib_eval_retrieval(
  top_k: 5,
  trim_threshold: 0.35,  // más permisivo
  trim_window: 1
)
// Salida: avg_tokens_trim=110, token_reduction_pct=30, overlap=0.95
// Interpretación: menos reducción, pero casi sin perder chunks

Decisión: elegir threshold que balancee reducción y overlap. Ej, 0.40 con overlap 0.88 es aceptable si el beneficio de tokens es importante.

3. Validar con synthesis

Una vez calibrado threshold, opcionalmente sintetizar para validar que las respuestas siguen siendo correctas:

bib_eval_retrieval(
  questions: ["¿Multi-tenancy?", "¿RLS?"],
  trim_threshold: 0.40,
  synthesize: true
)
// Verifica que `answer` en `variants.trim` sigue siendo precisa

4. Desplegar

Una vez validado, actualizar en el entorno:

RETRIEVAL_TRIM=1
RETRIEVAL_TRIM_THRESHOLD=0.40
# redeploy

Implementación

Handler: functions/api/mcp/handlers/archivo.ts:467–574.

Lógica:

  1. Validar env AI + DB.
  2. Si no hay questions, cargar desde oraculo_queries.
  3. Para cada pregunta:
    • Embeddings de la query.
    • Por cada variante: retrieve() con parámetros correspondientes.
    • Registrar métricas (chunk_ids, tokens, scores).
    • Opcionalmente sintetizar.
  4. Agregar en summary.
  5. Retornar JSON.

Tool registration: functions/api/mcp/tools.ts:999–1015.

Véase también

  • [[feature—biblioteca—arcrift-cherry-pick-1]]
  • [[entity—functions—service—sentence-trimming]]
  • [[entity—functions—handler—archivo-ask]]
  • [[concept—observability—metrics]]
  • [[concept—testing—a-b-harness]]