Marco de decisión
Árbol de decisión: ¿Regex o LLM?
Framework
La regla de oro: regex resuelve el 95–98 % de los casos a coste casi cero. El LLM solo interviene en los casos límite de baja confianza.
¿El texto sigue un formato consistente y repetible?
├── Sí (>90% sigue un patrón) → Empezar con Regex
│ ├── Regex cubre ≥95% → ✓ Salida directa, sin LLM
│ └── Regex cubre <95% → Añadir LLM solo para casos límite
└── No (texto libre, muy variable) → Usar LLM directamente
├── Sí (>90% sigue un patrón) → Empezar con Regex
│ ├── Regex cubre ≥95% → ✓ Salida directa, sin LLM
│ └── Regex cubre <95% → Añadir LLM solo para casos límite
└── No (texto libre, muy variable) → Usar LLM directamente
Arquitectura del pipeline
Texto fuente
Factura / Ticket / Pedido
→
Regex Parser
Extrae estructura (95–98%)
→
Limpiador
Elimina ruido OCR
→
Confidence
Scorer
Scorer
Puntúa 0.0–1.0
→
≥ 0.95 — Alta confianza
Salida directa ✓ Sin LLM
< 0.95 — Baja confianza
→ LLM Validator (solo edge cases)
→
Output
JSON estructurado
Análisis de documentos — FacturAI
Documento A
Factura estándar — Papelería Hernández S.L.
Factura Nº: 2024-001847
Fecha: 15/03/2024
Proveedor: PAPELERÍA HERNÁNDEZ S.L.
NIF: B12345678
Papel A4 500h x20 und. - 45,00 €
Bolígrafos BIC x50 und. - 12,50 €
Base imponible: 57,50 €
IVA 21%: 12,08 € TOTAL: 69,58 €
Campos extraídos por Regex
Nº Factura
2024-001847
Fecha
15/03/2024
NIF Proveedor
B12345678
Base Imponible
57,50 €
IVA
12,08 € (21%)
Total
69,58 €
Ruta: Salida directa — sin llamada LLM
Documento B
Ticket OCR ruidoso — Suministros García
Factur@ N: 2O24-OO1848
Fech@: 15-O3-2O24
Prove3dor: SUMIN!STROS GARCIA
N|F: B9876543
Concept0: Tóner HP - 89,00
Base: 89,OO € IVA: ??%
TOT@L: ???
Campos extraídos por Regex
Nº Factura
2O24-OO1848 ⚠
Fecha
15-O3-2O24 ⚠
NIF Proveedor
B9876543 (~)
Base Imponible
89,00 € (~)
IVA
null ✗
Total
null ✗
Ruta: → LLM Validator (Claude Haiku)
Documento C
Orden de compra — Depto IT
ORDEN DE COMPRA #PC-2024-0392
Solicitante: Departamento IT
Artículo 1: Monitor LG 27" — Qty: 2
Precio: 299,00 € Sub: 598,00 €
Artículo 2: Teclado mecánico — Qty: 5
Precio: 89,95 € Sub: 449,75 €
SUBTOTAL: 1.047,75 €
IVA (21%): 219,83 €
TOTAL PEDIDO: 1.267,58 €
Campos extraídos por Regex
Nº Documento
PC-2024-0392
Fecha
null ✗
NIF Proveedor
null ✗
Subtotal
1.047,75 €
IVA
219,83 € (21%)
Total
1.267,58 €
Ruta: → LLM Validator (Claude Haiku)
Resultado del pipeline — lote diario FacturAI
Tipo de documento
Regex OK
Confianza
Ruta
Acción LLM
Facturas estándar (1.920 docs)
96%
≥ 0.95
Directo
Sin llamada LLM — 0 tokens
Tickets OCR ruidoso (48 docs)
34–60%
< 0.60
LLM
Claude Haiku · ~200 tokens/doc
Órdenes de compra (32 docs)
70–85%
0.70–0.95
LLM
Claude Haiku · ~300 tokens/doc
TOTAL (2.000 docs/día)
96% sin LLM
Solo 80 llamadas LLM (~4%)
Métricas de producción — pipeline FacturAI
98%
Éxito Regex
en facturas estándar
4%
LLM necesario
~80 docs/día
95%
Ahorro coste
vs. 100% LLM
1.200 €
Coste anterior/mes
100% GPT-4
58 €
Coste nuevo/mes
pipeline híbrido
Implementación — código del pipeline
Regex Parser + Confidence Scorer
Capa 1 — 95%+ casos
import re
from dataclasses import dataclass
# Patrón para facturas españolas estándar
PATTERN = re.compile(
r"Factura\s+N[ºo°]?:?\s*(?P<num>\S+)"
r".*?Fecha:?\s*(?P<fecha>\d{1,2}[/-]\d{1,2}[/-]\d{2,4})"
r".*?NIF:?\s*(?P<nif>[A-Z]\d{7,8}[A-Z]?)"
r".*?TOTAL:?\s*(?P<total>[\d.,]+\s*€)",
re.DOTALL | re.IGNORECASE
)
def score_confidence(match) -> float:
score = 1.0
if not match['nif']: score -= 0.3
if not match['total']: score -= 0.5
if not match['fecha']: score -= 0.2
return max(0.0, score)
# Umbral: <0.95 → escala a LLM
THRESHOLD = 0.95
from dataclasses import dataclass
# Patrón para facturas españolas estándar
PATTERN = re.compile(
r"Factura\s+N[ºo°]?:?\s*(?P<num>\S+)"
r".*?Fecha:?\s*(?P<fecha>\d{1,2}[/-]\d{1,2}[/-]\d{2,4})"
r".*?NIF:?\s*(?P<nif>[A-Z]\d{7,8}[A-Z]?)"
r".*?TOTAL:?\s*(?P<total>[\d.,]+\s*€)",
re.DOTALL | re.IGNORECASE
)
def score_confidence(match) -> float:
score = 1.0
if not match['nif']: score -= 0.3
if not match['total']: score -= 0.5
if not match['fecha']: score -= 0.2
return max(0.0, score)
# Umbral: <0.95 → escala a LLM
THRESHOLD = 0.95
LLM Validator (solo edge cases)
Capa 2 — 4% casos
import anthropic
client = anthropic.Anthropic()
def validate_with_llm(doc_text, partial):
# Haiku: modelo más barato (validación)
response = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=500,
messages=[{
"role": "user",
"content": (
f"Extrae del texto: num_factura, fecha, "
f"nif, base, iva_pct, total.\n\n"
f"Texto: {doc_text}\n\n"
f"Parcial regex: {partial}\n\n"
f"Devuelve JSON corregido."
)
}]
)
return response.content[0].text
client = anthropic.Anthropic()
def validate_with_llm(doc_text, partial):
# Haiku: modelo más barato (validación)
response = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=500,
messages=[{
"role": "user",
"content": (
f"Extrae del texto: num_factura, fecha, "
f"nif, base, iva_pct, total.\n\n"
f"Texto: {doc_text}\n\n"
f"Parcial regex: {partial}\n\n"
f"Devuelve JSON corregido."
)
}]
)
return response.content[0].text
Comparativa de coste — FacturAI (2.000 docs/día)
| Escenario | Docs procesados | LLM calls/día | Tokens/mes | Coste estimado/mes | Ahorro |
|---|---|---|---|---|---|
| ❌ 100% GPT-4 (situación anterior) | 2.000 | 2.000 | ~60M tokens | 1.200 € | — |
| ⚠️ 100% Claude Sonnet | 2.000 | 2.000 | ~60M tokens | 720 € | −40% |
| ✅ Regex + Claude Haiku (pipeline híbrido) | 2.000 | 80 (4%) | ~2.4M tokens | 58 € | −95% |
| 🔧 Regex puro (sin fallback) | 1.920 (96%) | 0 | 0 tokens | ~0 € | Baja precisión en edge cases |
Mejores prácticas
Empieza siempre con regex
Aunque sea imperfecto, el regex te da una baseline medible para mejorar incrementalmente. Escribe tests para los patrones conocidos primero.
Puntúa la confianza de forma programática
No confíes en que el regex "simplemente funciona". Mide campos faltantes, longitud de texto, caracteres OCR sospechosos y asigna score 0–1.
Usa el modelo más barato para validación
Claude Haiku es suficiente para corregir campos que ya están casi bien. Reserva Sonnet/Opus solo si el documento completo es texto libre sin estructura.
Nunca mutes los objetos parseados
Usa dataclasses con frozen=True o Pydantic. Devuelve siempre nuevas instancias desde las funciones de limpieza y validación. Evita efectos laterales.
Registra métricas del pipeline
Monitoriza: tasa de éxito regex, número de llamadas LLM, coste por lote. Si el % LLM sube, el formato de los documentos está cambiando.
Anti-patrón: regex para texto libre
Si el texto es altamente variable (descripciones libres, emails narrativos, contratos con lenguaje jurídico variable), ve directamente al LLM. El regex aquí es trampa.