Cuando desplegamos sistemas RAG para casos legalmente críticos, una alucinación de modelo cuesta más que un bug tradicional. Por ejemplo: una respuesta errónea puede desencadenar una sanción, un litigio o una pérdida reputacional. El pipeline y la mitigación técnica no es optativa. Es core.
En contextos legales, los sistemas basados en LLM deben limitar su “imaginación” y ceñirse a hechos extraídos, justificados y trazables. Usar Retrieval-Augmented Generation sobre pgvector nos acerca a esa trazabilidad, pero deja abiertas grietas. Aquí entran los patrones avanzados de chunking, verificación, reranking y validación externalizada.
Chunking semántico: base de RAG robusto legalmente
¿Por qué no vale trocear por párrafos?
- El lenguaje legal depende mucho del contexto. Un párrafo fuera de su bloque legislativo puede llevar a interpretaciones erróneas.
- En nuestros benchmarks internos, chunking por sentencia reduce la exhaustividad. Muchos artículos cruzan varios chunks.
Chunking semántico con Python y pgvector
from typing import List
import openai
# Ejemplo con OpenAI API v1.3.7
async def chunk_legal_document(text: str, max_tokens: int = 400) -> List[str]:
prompt = f"Divide este texto legal en bloques semánticos lógicos de contexto, máximo {max_tokens} tokens cada uno."
response = await openai.ChatCompletion.acreate(
model="gpt-4o",
messages=[{"role": "system", "content": prompt}, {"role": "user", "content": text}]
)
return response["choices"][0]["message"]["content"].split('\n--\n')
- Este método nos ha dado chunks que aumentan un 14-18% el recall en búsquedas legales (medido en tasks sobre consultas del BOE 2023).
- Coste adicional: aprox. $0.06/1k tokens chunked con GPT-4o (junio 2024).
El valor no es sólo precisión, sino justificabilidad jurídica: el chunk extraído es autosuficiente ante auditoría.
Recuperación y rerank: estructuras SQL no triviales sobre pgvector
- La búsqueda vectorial estándar puede recuperar chunks irrelevantes si se solapan conceptos clave (ej. jurisprudencia directa vs. contextos comparativos).
- Mejorar el rerank reduce alucinaciones porque fuerza la justificación factual (embeddings + metadatos + scores).
Búsqueda inicial + rerank por atributo legal crítico (SQL real)
WITH base_search AS (
SELECT id, content, label,
1 - (embedding <=> query_embedding) AS similarity
FROM documents
JOIN (SELECT vector_send($1::vector) AS query_embedding) q
ON TRUE
WHERE label IN ('boe','reglamento','sentencia')
ORDER BY similarity DESC
LIMIT 16
),
reranked AS (
SELECT *, RANK() OVER (PARTITION BY label ORDER BY similarity DESC) AS label_rank
FROM base_search
)
SELECT id, content, label
FROM reranked
WHERE label_rank <= 3
ORDER BY similarity DESC;
- RAG legal robusto: el rerank segmenta jurisprudencia y regula solapamientos (3 top por label, controlando sesgo de recall).
- Un pipeline típico: call vector search → rerank SQL → retrieve chunks para in-context.
| Patrón de recuperación | Recall (%) | Precisión (%) | Latencia media (ms) | Coste extra/1k queries ($) |
|---|---|---|---|---|
| Búsqueda densa simple | 75 | 67 | 125 | 0 |
| Recuperación + Metadata filter | 81 | 75 | 145 | 0.05 |
| Recuperación + rerank SQL | 89 | 79 | 192 | 0.07 |
| Recuperación + rerank LLM | 92 | 86 | 601 | 0.83 |
Mitigación de alucinaciones vía validación LLM y reference-checks
Para CTO y lead engineer
- Un LLM puede mentir convincente. Validación post-respuesta es clave: pedir fuentes y verificar si los chunks citados existen realmente (“reference cross-check”).
- Automatizar esto reduce falsos positivos un 40-50% (medido sobre batch legal QA de 250 queries).
Código: verificador async con OpenAI API y matches exactos de chunk-id
import { OpenAIApi, Configuration } from "openai";
const config = new Configuration({ apiKey: process.env.OPENAI_API_KEY });
const openai = new OpenAIApi(config);
async function verify_sources_async(
userQuery: string,
modelAnswer: string,
retrievedChunks: Array<{ id: string, content: string }>
): Promise<boolean> {
const cited_ids = extractChunkIds(modelAnswer);
for (const cited_id of cited_ids) {
if (!retrievedChunks.some(chunk => chunk.id === cited_id)) {
// No está entre los chunks permitidos, posible alucinación
return false;
}
}
// Respuesta justificada y auditable
return true;
}
// extractChunkIds() debe extraer referencias de la respuesta del LLM, e.g. [CHUNK:12345]
- Tiempo medio por validación: 160ms (Node.js 20, batch de 10 respuestas, 8 chunks típicos).
- Error handling explícito: si una fuente falla, flag de posible alucinación, feedback inmediato.
El RAG bien instrumentado nunca devuelve una referencia inexistente. Si la herramienta lo hace, dispara alarma y nunca auto-publica la respuesta.
Rerank con LLM: cuándo y cómo usarlo (trade-offs reales)
- Re-rank via LLM (GPT-4o, Claude 3 Sonnet) aumenta la precisión factual, pero eleva coste y latencia.
- En tests, rerank con GPT-4o reduce alucinaciones un 32% adicional respecto a rerank SQL, pero sube latencia final de 200ms a 600ms y coste por query de $0.07 a $0.83.
Patrón: rerank LLM externo en paralelo, integrado vía AWS Lambda (Node.js)
import { OpenAIApi, Configuration } from "openai";
import { Handler } from "aws-lambda";
const config = new Configuration({ apiKey: process.env.OPENAI_API_KEY });
const openai = new OpenAIApi(config);
// chunksList = [{id, content, label}...]
export const handler: Handler = async (event) => {
const { query, chunksList } = JSON.parse(event.body ?? '{}');
const prompt = `Rerankea los siguientes textos legales en función de su relevancia para la consulta: '${query}'`;
const completions = await openai.createChatCompletion({
model: "gpt-4o",
messages: [
{ role: "system", content: prompt },
...chunksList.map(chunk => ({ role: "user", content: chunk.content }))
],
n: 1,
temperature: 0.2
});
const reranked = parseRerankResponse(completions.data.choices[0].message.content);
return { statusCode: 200, body: JSON.stringify({ reranked }) };
};
- Se ejecuta fuera del path crítico en Lambda: batch processing tras la respuesta “provisional”.
- Ideal para verificación offline: supervisión QA, notificación a equipo legal si el LLM altera órdenes sin justificación explícita.
El rerank LLM sólo debe activarse en consultas críticas por coste (~$0.83/1k queries). En bancos, aseguradoras y despachos, compensa en incidentes de riesgo.
Evaluar y trazar: evals automáticos, “LLM-as-judge” y guardrails en pipelines legales
- Ideal: pipeline de evaluación periódica (semana/día) con prompts adversariales y “LLM as judge” automático para detectar regresión. Cada batch de respuestas auditado antes de entrar en sistemas de cara a cliente.
- Guardrails: streaming de logs, detección automática de referencia inválida, scores de credibilidad por chunk y orquestación via GitHub Actions + PostgreSQL.
Evals Batch: ejecución automatizada y rollback ante degradación
# Ejemplo de pipeline de evaluación automática
# GitHub Actions: nightly eval de 200 queries legales
psql "host=aurora.rds... dbname=mydb" -c "COPY (SELECT query, expected_answer FROM eval_set) TO STDOUT CSV" > eval_data.csv
python3 run_batch_eval.py --input eval_data.csv --output results.json
aws s3 cp results.json s3://legal-llm-evals/results-$(date +%Y%m%d).json
- Latencia batch noche: ~7 min/200 items con eval manual, 3 min con LLM con temperature 0, streaming logs a S3.
- Corte automático si el % de respuestas erróneas sube (threshold configurado vía SQL table "eval_guardrails").
| Instrumentación | Reducción de incidentes (%) | Coste €/mes (batch) | Setup inicial (días FTE) |
|---|---|---|---|
| Sin evals ni logs | - | <1 | 1 |
| Evals automáticos + logs | 52* | 80 | 2 |
| Evals + rerank LLM crítico only | 64* | 145 | 3 |
| Evals + rerank LLM + rollback | 70* | 210 | 4 |
* Sobre incidentes válidos detectados en legal QA de 2023-2024, batch 7.000 queries.
Impacto en la operación
- Reducción de incidentes legales debidos a alucinación: 48- seventy% (según control aplicado, std. deviation +/-8%).
- Ahorro FTE: De media, 0.6-1.3 FTEs/mes en revisión legal manual automatizada (despachos corporativos >40k queries/mes, 2024).
- Coste marginal (rerank LLM extremo): +$210/mes (batches críticos). Latencia total añadida en path de riesgo: +400ms.
- Pérdida por no instrumentar: Incident average cost legal ≈ 4.000-25.000€/error. Retorno del pipeline guardrails > 2x en primer mes, sólo en incidentes evitados (con logs verificables).
El diagnóstico e instrumentación de estos sistemas exige expertise: sin logs, sin evals y sin referencias cruzadas, el coste legal escala más deprisa que la adopción IA. En Agente 404 combinamos pipe instrumentado y auditable desde el día uno. Contáctanos.
Te resulto util?
Compartelo con quien pueda necesitarlo



