Volver al inicio

Legal RAG ARLC 2026: 17 iteraciones hasta 0.791

El artículo desglosa el pipeline RAG para el desafío legal ARLC 2026: desde la primera presentación con grounding 0.05 hasta 0.791. Describe la arquitectura con indexación a nivel de página, búsqueda hybrid RRF, cross-encoder reranking y fast-paths para respuestas tipadas. Análisis de la caída de rendimiento al escalar de 30 a 300 documentos.

RAG en PDFs legales: de fracaso a puntuación máxima ARLC
Advertisement 728x90

RAG legal en ARLC 2026: De 0,034 a 0,791 en 17 iteraciones con análisis de escalabilidad

En el reto legal de ARLC 2026, la pipeline RAG comenzó con una puntuación de base de 0,05 y una puntuación total de 0,034. Las respuestas deterministas (S_det) ya alcanzaban 0,857, pero el factor G estaba anulando los resultados. El problema se rastreó hasta el formato del doc_id: submission.json esperaba el nombre del archivo sin '.pdf', mientras que el código pasaba el nombre completo. Corrigiendo una sola línea, el factor G subió a 0,55 y la puntuación total a 0,438 — una mejora de 13 veces.

Lección para desarrolladores de RAG: validar el formato de envío debe anteceder a la optimización de recuperación. Incluso un reordenamiento perfecto es inútil sin un mapeo correcto a (doc_id, número_de_página).

Arquitectura de la pipeline: Ingesta a nivel de página y búsqueda híbrida

La pipeline indexa páginas completas del documento, evitando la fragmentación. Esto simplifica el posicionamiento a nivel de página, pero requiere una distilación de contexto antes del procesamiento por LLM.

Google AdInline article slot

Extracción de PDF con fallback OCR

def extract_pages(pdf_path, min_chars=50, ocr_dpi=300):
    pages = []
    doc = pdfplumber.open(pdf_path)
    for i, page in enumerate(doc.pages):
        text = page.extract_text() or ""
        if len(text.strip()) < min_chars:
            text = ocr_page(pdf_path, i + 1, dpi=ocr_dpi)
        pages.append({
            "doc_id": pdf_path.stem,      # sin .pdf!
            "page_number": i + 1,
            "text": text
        })
    return pages

El código maneja PDFs escaneados mediante OCR cuando el texto extraído es mínimo. doc_id utiliza la raíz sin extensión; page_number es 1-basado.

Recuperación híbrida con RRF

Combinando BM25 para coincidencias exactas y embeddings para significado usando Fusión de Rango Recíproco (k=60):

def hybrid_search(query, bm25_index, embedding_index, pages, top_k=20, rrf_k=60):
    bm25_scores = bm25_index.get_scores(tokenize(query))
    bm25_ranked = sorted(range(len(pages)), key=lambda i: -bm25_scores[i])

    q_emb = embed_model.encode([query[:512]], normalize_embeddings=True)
    sim_scores = (embedding_index @ q_emb.T).flatten()
    emb_ranked = sorted(range(len(pages)), key=lambda i: -sim_scores[i])

    combined = {}
    for rank, idx in enumerate(bm25_ranked[:top_k * 3]):
        combined[idx] = combined.get(idx, 0) + 1.0 / (rrf_k + rank)
    for rank, idx in enumerate(emb_ranked[:top_k * 3]):
        combined[idx] = combined.get(idx, 0) + 1.0 / (rrf_k + rank)

    return sorted(combined, key=lambda i: -combined[i])[:top_k]

Modelo de embeddings: all-MiniLM-L6-v2 (22M parámetros). RRF no requiere normalización de escala — funciona directamente sobre rangos.

Google AdInline article slot

Reordenamiento y etiquetado de prioridad

Un cross-encoder (ms-marco-MiniLM-L-6-v2) reordena las 30 páginas superiores. Un límite rígido de 30 evita la explosión de TTFT O(N²).

def rerank(pages, query, top_k=5):
    HARD_CAP = 30
    priority = [p for p in pages if p.get("_priority")]
    non_priority = pages[:HARD_CAP - len(priority)]

    all_pages = priority + non_priority
    pairs = [(query, p["text"][:512]) for p in all_pages]
    scores = cross_encoder.predict(pairs)

    for i, p in enumerate(all_pages):
        if p.get("_priority"):
            scores[i] = 1000.0

    ranked = sorted(zip(scores, all_pages), key=lambda x: -x[0])
    return [p for _, p in ranked[:top_k]]

Las páginas prioritarias (portadas, artículos) obtienen una puntuación de 1000 — garantizan su inclusión en el contexto.

Enrutamiento de documentos para consultas comparativas

Para preguntas como "¿quién fue nombrado antes en CFI 001/2020 vs CFI 002/2021", se construye un índice de portadas:

Google AdInline article slot
  • Patrones: CFI 010/2024 → doc_id
  • Consulta dual con intercalación round-robin de contextos

Caminos rápidos deterministas para respuestas tipadas

Tipos: número (±1%), booleano, nombre (exacto), fecha (YYYY-MM-DD), nombres (Jaccard), texto libre (juicio por LLM).

Ejemplos de extracción con regex:

  • Número de ley: re.search(r"(?:DIFC\s+)?Law\s+No\.\s*(\d+)")
  • Fecha de emisión: parsear primeras páginas usando Date of Issue[:\s]+(\w+ \d+,?\s+\d{4})
  • Monto: extraer reclamaciones monetarias mediante case_ref

Los caminos rápidos ahorran 700 ms en llamadas a Haiku, devolviendo respuesta + base de verificación.

Fórmula de puntuación y optimización de TTFT

Total = (0.7 × S_det + 0.3 × S_asst) × G × T × F
  • G (F-beta, β=2.5): posicionamiento a nivel de página — el multiplicador clave
  • F: <1000 ms → +5%, >3000 ms → -15%

| TTFT (ms) | Multiplicador |

|-----------|------------|

| <1000 | 1.05 |

| <2000 | 1.02 |

| <3000 | 1.00 |

| >3000 | 0.85–0.99 |

Pared de escalabilidad: Calentamiento vs Final

Con 30 documentos (calentamiento), la puntuación fue de 0,791. Con 300 (final), cayó un 42%. Razones:

  • El corpus más grande diluye la calidad de recuperación
  • El TTFT crece linealmente con el tamaño
  • El reordenamiento en 300+ páginas perjudica F

Optimizaciones finales: caché de embeddings, agrupación en lotes del cross-encoder, detención temprana en búsqueda híbrida.

Lo que realmente importa

  • Indexación a nivel de página: simplifica el posicionamiento, pero exige distilación de contexto.
  • RRF (k=60): fusión óptima de BM25 + embeddings sin normalización.
  • Etiquetado de prioridad: asegura que las páginas críticas siempre estén en el contexto.
  • Camino rápido: regex para el 80% de consultas tipadas reduce significativamente el TTFT.
  • Enfoque TTFT-primer: velocidad otorga un bono del +5% gratis al igualar la calidad.

— Editorial Team

Advertisement 728x90

Leer después