Ingeniería · Visión artificial

Cada dato, tres veces

Cómo enseñamos a una IA a leer documentos aduaneros sin equivocarse en silencio

Equipo de ingeniería de Ardora AILectura de 25 minutos
+1.200correos/día en buzón compartido
≈ 500expedientes/mes gestionados
≈ 10documentos por expediente
94controles normativos en un trámite de pesca

Un despacho de importación empieza con un correo y varios documentos adjuntos (PDFs, docx, xslx, etc.). Dentro vienen facturas, packing list, conocimientos de embarque (B/L), certificados sanitarios y, si la mercancía es pesca, certificados de capturas con sus apéndices de transporte. A veces llegan en ficheros separados, y otras todos pegados en el mismo PDF.

Con esos papeles hay que validar el expediente frente a la normativa, preparar la declaración aduanera (DUA) y presentar los certificados de captura en TRACES, el sistema de la Comisión Europea. Con una agencia de aduanas de referencia construimos la plataforma que hace ese trabajo, un robot que automatiza la ingesta de los documentos, extracción y estructuración de datos, validación de los mismos contra normativas legales y generación y emisión a los sistemas de la administración aduanera española y europea. Este artículo cuenta la parte más difícil: leer los datos. Explicamos la arquitectura que tenemos hoy, los modelos que hemos usado y descartado, las medidas que nos hicieron cambiar de idea y los errores que encontramos por el camino. Todo sale del historial del proyecto.

El proceso completo en 90 segundos: del correo con la documentación a la validación, el DUA y TRACES. Las capturas son de la plataforma real, con documentos y datos ficticios.

01El problema: un dígito cuesta caro

En un documento aduanero no hay errores pequeños:

  • Un peso neto con un dígito cambiado descuadra la declaración y los controles sanitarios.
  • Un número de contenedor con una letra mal leída rompe el cruce con la naviera.
  • Una fecha leída como mes/día en vez de día/mes coloca una firma después de la salida del buque, y eso invalida un certificado.

Y los documentos reales no ayudan. Estos son los casos que nos hemos encontrado en expedientes reales:

  • Escaneos a 150 ppp, torcidos, con grano, con un sello encima de la cifra que importa.
  • Páginas de lado o del revés dentro de un PDF por lo demás correcto.
  • Documentos mezclados: un PDF de 41 páginas con 20 documentos dentro. Un certificado zoosanitario aparece dos veces, una como borrador sin firmar y otra firmada.
  • Documentos mixtos: PDFs con capa de texto donde un fragmento, a veces menos del 10 % de la página, está rasterizado y es justo el dato clave.
  • Tablas que continúan en otra página sin cabecera, y packing lists de 59 filas repartidas en cinco hojas.
  • Convenciones numéricas cruzadas en la misma página: 21995.050 sin separador, 39,643.12 con coma de miles y 50,000 CBM con la coma como decimal.
  • Ruido impreso: certificados que imprimen 3321.3900000000003 porque el sistema que los generó no redondea la coma flotante.

El riesgo que más nos preocupa no es fallar. Lo que más nos preocupa es fallar sin que nadie se entere.

Lo peligroso es una extracción que parece completa, con todos los campos rellenos, y que lleva dentro un número equivocado.

02Primera arquitectura: un modelo multimodal lo hace todo

El diseño inicial era el que hoy parece obvio. Un LLM con visión recibe la página y devuelve directamente el JSON con los campos del documento, y otro LLM valida el expediente contra las reglas del trámite. El documento de decisiones del proyecto lo justificaba así frente a Tesseract y frente a Google Vision o AWS Textract:

CriterioOCR clásico + reglasOCR en la nubeLLM multimodal
Salida estructuradaExpresiones regulares y parser propioTexto planoJSON directo desde el esquema
Sellos, manuscrito, tablas irregularesDébilSolo textoEntiende estructura y contexto
Excepciones («importe = base + IVA ± 0,01»)Hay que programarlasHay que programarlasEl modelo razona

El stack que se eligió inicialmente y se mantiene: Python 3.11, Apache Airflow para los pipelines, FastAPI, PostgreSQL con JSONB, React en el frontal y los modelos servidos por Ollama. Pronto aprendimos tres cosas.

Los modelos cambian por debajo de ti

Ninguno de los modelos con los que arrancamos sigue en la extracción. Una arquitectura que confía en «el modelo» queda a merced del siguiente cambio. La conclusión fue que el modelo tenía que ser una pieza sustituible y medible, no el centro del sistema.

Arranque
gemini-3-flash-preview
Primera extracción; valida minimax-m3
Primer mes
qwen3.5
El modelo anterior queda obsoleto
Larga etapa
mistral-large-3
Extracción de producción
Relevo
gemma4
Igual que en preproducción
Hoy
deepseek-v4.1-flash
Tras la comparativa medida (§11)
Contraste
un servicio de terceros especialista
Árbitro externo, no extractor principal

El modelo no avisa cuando se equivoca

Con los primeros expedientes reales aparecieron las primeras divergencias entre documentos del mismo expediente. Casi nunca eran discrepancias reales: eran malas lecturas a 150 ppp, como un lote 31690-1 leído 31590-1 o dos dígitos trasladados. El modelo devolvía cada valor con la misma seguridad. Respondimos con módulos deterministas:

  • la comprobación del dígito de control ISO 6346 de los contenedores, primero;
  • la caracterización de divergencias de un solo carácter, por confusión documentada o por transposición de adyacentes, después.

Al validador hay que darle hechos, no pedirle criterio

Después auditamos validaciones reales:

  • La pregunta «¿aparece este documento obligatorio entre los aportados?» es aritmética, y el validador fallaba en la mitad de los casos aunque el documento faltaba de verdad.
  • Una firma de inspector posterior a la fecha de salida, que es un hecho objetivo de los datos, solo se detectaba en 1 de cada 4 validaciones.

Desde entonces, todo lo que se puede comprobar con código se comprueba con código y entra en el prompt del validador como hecho ya verificado. Al modelo le queda el criterio, no la aritmética.

03El giro: digitalizar por fases y registrar cada decisión

Arreglar caso a caso sobre la extracción de una sola llamada tenía un límite: no sabíamos por qué salía cada valor. Por eso empezamos un pipeline nuevo, primero en modo de solo lectura sobre expedientes reales, con tres principios:

  1. Cada decisión queda registrada. Toda decisión, sea del modelo o determinista, se escribe en un registro con su fase, el resultado, el motivo, la evidencia, las alternativas descartadas y la fuente: regla, medida, modelo o comparacion. No hay descartes silenciosos.
  2. Nunca adivinar en silencio. Si no hay un único valor defendible, el campo queda vacío con los candidatos y el motivo, y pasa a revisión humana.
  3. Lo verificable manda sobre lo probable. Un dígito de control, la capa digital del PDF o una suma que cuadra pesan más que el consenso de un modelo.

Y una regla de método, escrita en la propia documentación del pipeline: coste y tiempo no son la restricción; el objetivo es el mínimo de errores de lectura.

1
Formato
Firma real del fichero, capa de texto, orientación del texto
2
Imagen
Render, mejoras según lo medido, giro por votación
3
OCR y fusión
Transcripción literal anclada a la capa digital
4
Clasificar y dividir
Ventanas solapadas, la numeración manda, marcas
5
Extracción
Tres lecturas ciegas y decisión numérica en código
6
Coherencia
El expediente como testigo, dígitos de control
7
Revisión externa
Un servicio de terceros solo para lo pendiente
8
Validación
94 controles con hechos ya comprobados

Cada fase es reanudable: se puede volver a ejecutar la coherencia sobre un registro ya escrito sin repetir OCR ni llamadas al modelo.

Entró en producción después de un tiempo de prueba en preproducción, con migraciones de base de datos ensayadas antes sobre una copia de producción.

04Formato e imagen: medir antes de tocar

El tipo real sale de la firma del fichero, no de la extensión. Hay PDFs que son JPEG renombrados y «Excel» que son HTML. Los ficheros de oficina se leen directamente de su XML o de sus celdas, sin OCR.

De cada página PDF se mide si tiene capa de texto, qué imágenes trae y con qué resolución nativa, el /Rotate declarado y la orientación del texto. Después se renderiza y se aplican mejoras condicionadas a lo medido, con registro del antes y el después:

  • Brillo: el blanco del papel está por debajo de 200.
  • Contraste: el rango entre los percentiles 2 y 98 es menor de 80.
  • Nitidez: el índice de nitidez baja de 0,16.

Una página de solo texto vectorial no se toca.

El giro: por qué preguntamos cuatro veces

La primera idea fue preguntar al modelo, con una imagen, cuántos grados había que girarla. Lo medimos con unas 700 llamadas sobre páginas reales y sintéticas:

MétodoAcierto en páginas reales
Una imagen y «¿cuántos grados hay que girarla?»67 %
Bucle cerrado: aplicar el giro y volver a preguntar85 %
Cuatro versiones barajadas (0°, 90°, 180°, 270°) y «¿cuál está derecha?»98,2 % · 100 % por mayoría

Con una sola imagen, en las páginas de lado el modelo acertaba el sentido solo el 29 % de las veces, y el bucle cerrado no convergía en un 13 % de los casos. Además, la confianza que devolvía el modelo era siempre 1,0, acertara o fallara.

Un PDF real completo de 24 páginas añadió un matiz: la votación fallaba en 3 de 17 páginas digitales de texto denso con marca de agua. La regla final quedó así:

  • Las páginas con texto horizontal legible en su capa digital no se votan.
  • El resto se vota tres veces y solo se gira con unanimidad. Sin ella, la página se queda como está y pasa a revisión.

05OCR y fusión: transcribir fiel y no fiarse del orden

El OCR es una llamada por página al modelo de visión. Se le pide una transcripción literal línea a línea, sin normalizar números ni fechas, y que marque [ilegible] en la línea concreta en lugar de dar por perdida la página.

Los bucles de repetición

En un expediente real de 55 páginas, 3 páginas devolvieron JSON roto. No eran respuestas largas: eran bucles, el modelo repitiendo líneas de una tabla de casillas vacías hasta agotar el presupuesto de tokens. La investigación dio tres lecciones:

  • temperature=0 empeora los bucles. Un estudio que consultamos mide 48 veces más bucles que con temperatura 1,0. Usamos 0,1 con penalización de repetición y una ventana amplia.
  • Un prompt de texto idéntico en cada llamada puede colisionar con la caché del servidor. Cada llamada lleva ahora una referencia aleatoria.
  • El arreglo de fondo era de prompt, no de parámetros: pedir explícitamente que no enumere casillas vacías y que nunca repita una línea ya escrita.

Con los modelos de razonamiento apareció la versión moderna del problema: deepseek y minimax piensan por defecto y se comían el presupuesto de salida antes de transcribir nada. Hay que llamarlos con think: false para el OCR.

Fusionar con la capa digital sin duplicar

Cuando la página tiene capa de texto, cada línea del OCR se ancla a la línea digital con la que más «tokens fuertes» comparte: palabras de cuatro letras o más, o números comparados sin separadores. Así no dependemos del orden de lectura, que en un formulario de dos columnas casi nunca coincide. Cada línea queda cubierta, en conflicto_cifra (se conservan las dos versiones) o huerfana, que es contenido que la capa digital no tiene, como un sello.

Una página es mixta si tiene 40 caracteres huérfanos o más, o 2 cifras huérfanas o más. El umbral es absoluto a propósito: un sello de cuatro palabras con el dato clave se diluye en cualquier porcentaje de página.

06Clasificar y dividir: la numeración manda

Las páginas se clasifican por texto en ventanas de 6 páginas con paso 3, de forma que casi cada página se juzga dos veces. El desacuerdo entre esas dos lecturas es una señal de calidad gratuita. El corte entre documentos se decide con campos literales, en este orden de autoridad:

  1. Numeración: dos páginas con numeración coherente nunca se separan aunque el modelo les asigne tipos distintos. Se asume que se equivocó la etiqueta.
  2. Identificador distinto, o un inicio de documento declarado.
  3. Que el modelo diga «no es continuación», como último recurso.

Cada documento sale con un estado documental (provisional, copia, definitivo, anulado o sin marca), sacado de las marcas estampadas. Una marca solo cuenta si ocupa ella sola su línea, para no confundir la palabra «Sello» de una casilla vacía con un sello real. En un expediente de 41 páginas y 20 documentos detectó las 6 páginas marcadas sin ningún falso positivo.

La división genera un PDF por documento copiando las páginas originales sin volver a renderizarlas, así que la capa de texto llega intacta a las fases siguientes.

07Extracción: tres lecturas ciegas y una decisión por campo

Este es el núcleo, y el diseño cambió tres veces: una lectura; dos lecturas con una tercera «dirigida» al campo en discusión; y, por último, tres lecturas independientes y ciegas, en las que ninguna ve lo que respondieron las otras y cada campo se decide por mayoría. Las tres se guardan siempre. Si las tres difieren, el campo va a revisión con las tres a la vista.

Dos lecturas que coinciden no son dos lecturas que aciertan.

Por eso descartamos leer los campos de lista página a página, que hacía converger lecturas en el mismo valor incorrecto, y por eso la mayoría no es la última palabra.

Los números se deciden en código, no en el modelo

Para los campos numéricos al modelo se le pide el literal tal como está impreso. Si le pides el número ya «decidido», normaliza, y lo hace también donde la convención real era otra. La decisión la toma una cascada determinista que se detiene en el primer criterio que deja un solo candidato:

ReglaCriterio
R1Literal inequívoco
R2Identidades aritméticas del propio documento (cantidad × precio = importe, Σ = total)
R3Mayoría por fuentes distintas, no por apariciones
R4Rango plausible del campo
R5Convención del documento, solo como desempate
R6Vacío con motivo y candidatos, nunca un valor adivinado

La convención de miles y decimales no es del documento, es de cada campo. Sobre esa base hay comprobaciones que ya han cazado errores reales:

  • Cuadre por testigo: la suma de una columna se confirma contra el total impreso.
  • Fechas por columna: DD/MM o MM/DD se decide para toda la columna, nunca celda a celda.
  • Bultos leídos como kilos: un packing list cuyo desglose eran 1.998 cartones se había leído como kilos. Si la suma de pesos por línea coincide con el total de bultos y diverge de los pesos conocidos del expediente, se anulan esos pesos.

Un caso que nos enseñó a medir con el pipeline completo

Un certificado escaneado de 7 páginas salió con 15 partidas cuando eran 9, y las tres lecturas traían las 15. La causa estaba en nuestro troceo:

  • Las imágenes se mandan en lotes de como mucho 4 imágenes o 4 MB, y el texto OCR de todas las páginas viajaba pegado solo al primero.
  • El primer lote ya veía las 9 filas a través del texto, y el segundo volvía a leer las de sus páginas desde la imagen.
  • La marca delatora: las filas que venían del OCR tenían coma decimal y las que venían de la imagen, punto.

El primer arreglo corregía ese certificado, pero hacía que un packing list de 59 filas perdiera las 11 de su última página, una continuación sin cabecera, en torno a un 30 % de las veces. Con un aviso en el texto del lote («extrae también las filas de las páginas que no se muestran como imagen») falló 0 de 28 veces (prueba exacta de Fisher, p ≈ 0,002). Añadimos un árbitro: si las lecturas difieren en número de filas, gana la que cuadra con el total impreso. «Gana la más larga» se descartó porque en el histórico, sobre 1.192 tablas, la más larga no acertó ni una vez en los desacuerdos.

La capa digital prevalece

Un valor que aparece literalmente en la capa de texto del PDF, o en las celdas de un Excel, no ha pasado por un reconocimiento óptico y no puede tener un carácter cambiado. Cada valor lleva su procedencia (digital, OCR o conflicto) y, cuando dos documentos se contradicen, manda el digital sin votación. La procedencia se comprueba por valor, no por página, porque una página mixta tiene parte digital y parte escaneada.

Después lo extendimos por un caso real: una guarda no reconoció un packing list titulado «Certificado de empaque» y las tres lecturas salieron vacías, mientras la capa digital traía todos los datos. Ahora la capa digital prevalece también cuando el modelo no devuelve nada.

08Zonas: saber de qué casilla sale cada cifra

Un OCR por página devuelve una lista plana de líneas, y en un formulario de dos columnas las etiquetas contiguas se funden:

I.24. Número total de bultos I.25. Cantidad total
I.26. Peso neto total I.26. Peso bruto total
1320 Caja de cartón
22440 kg 23760 kg

El extractor reconstruía por contexto cuál era el neto y cuál el bruto. Acertaba, pero no era auditable. La fase de zonas divide la página antes de leer, con tres detectores en orden:

  1. Bloques de la capa de texto, exactos y gratuitos donde la hay.
  2. Morfología con OpenCV sobre la imagen girada. En un certificado real saca sus 39 casillas, y en un packing list sin líneas no inventa ninguna.
  3. El modelo señalando la tabla sobre una rejilla de referencia, aceptado solo si tres rejillas distintas coinciden.

09Coherencia: el expediente como testigo

Cuando las tres lecturas no dan mayoría, el resto del expediente suele tener la respuesta. A partir de un catálogo de 41 cruces candidatos, la coherencia aplica decisores deterministas sobre el conjunto de candidatos. Nunca inventa un valor que ninguna lectura dio:

  • Dígito de control ISO 6346 del contenedor.
  • Código de nomenclatura contra la especie declarada.
  • Identificadores con formato rígido que se validan solos, como los códigos REX o el del puesto de inspección fronterizo.
  • Mayoría entre documentos distintos, no entre lecturas del mismo. Con dos declarantes un desacuerdo nunca tiene mayoría, así que buscamos declarantes nuevos, como el B/L escondido en una casilla del certificado sanitario.

En la demo que grabamos con documentos ficticios, el apéndice escaneado leyó el contenedor como CCVU4182735. No cumple el dígito de control, y otros cuatro documentos declaran OCVU4182735, que difiere en una sola letra. La plataforma lo corrige y deja el campo marcado para revisión.

Aplicar correcciones sin perder información

  1. Catálogo explícito de decisiones que pueden corregir. Lo demás no toca nada.
  2. Correcciones aditivas: la lectura original nunca se sobrescribe, así que siempre se puede decir qué leyó la extracción y qué aplicó la coherencia.
  3. Compare-and-swap: solo se corrige donde el valor sigue siendo el que examinó el cruce. Protege celdas con dos códigos, como un precinto legítimo junto a una mala lectura.
  4. Aplicar no es cerrar la revisión. La revisión solo se cierra cuando el código verifica el valor. Una corrección por corroboración o por juicio de un modelo se aplica con reservas y el campo sigue en la cola.

10Un árbitro externo como fallback: un servicio de terceros especialista

Los campos que siguen pendientes de revisión al terminar la coherencia se mandan a la API de un servicio especialista en extracción y estructuración de datos con el esquema del propio tipo de documento: una sola llamada parsea y extrae. Ese contraste destapó un fallo en nuestro esquema. Decía «8 dígitos» para el código de nomenclatura, y ante un certificado que lo imprime a 6 (030743), cualquier extractor lo inflaba a 03074300 para cumplir la instrucción.

El árbitro hace una llamada por página, cacheada por hash, y solo sustituye los campos que estaban en revisión. En la misma página y con el mismo esquema, devolvió una descripción correcta en 3 de 5 llamadas y confundió la columna en las otras 2. Sobrescribirlo todo habría importado ese ruido.

Que las cuentas cuadren, sin tolerancia

Facturas y packing lists se comprueban por su propia aritmética. Si las lecturas divergen o no cuadran, se contrasta con el fallback: si lo suyo cuadra se graba, y si no queda en revisión. La tolerancia es la del redondeo de lo impreso y nada más. Con el 0,5 % que usábamos antes pasaba un error de 5.000 sobre 5,8 millones.

El caso que nos hizo cambiar fue un escaneo en el que las tres lecturas eran idénticas y llevaban un dígito de más en el total.

Ni la mayoría ni la unanimidad garantizan nada; la aritmética, sí.

11Qué modelo, y cómo lo elegimos

Más tarde comparamos tres candidatos con el pipeline completo sobre un expediente de 7 documentos y 79 páginas, usando el fallback como árbitro (había acertado 24 de 24 campos verificados a mano):

gemma4deepseek-v4.1-flashminimax-m3.1-flash
Campos de certificados escaneados (de 60)24–255956
Giro con ángulo conocido (de 24)172224
Certificados mal partidos (de 11)4–5110
Tiempo total56–57 min47 min74 min
Reintentos de OCR1–2017

gemma4 leía mal el año de las fechas en 18 o 19 de 20 casos, y entre dos pasadas suyas solo coincidía en el 86 % de los campos. Un segundo contraste, con 40 ficheros de 5 emisores, nos obligó a matizar:

  • En precisión hubo empate, en torno al 88–90 %.
  • Donde hubo desacuerdo estable, deepseek acertó 53 veces y gemma4, 20.
  • deepseek deja sin rellenar un 18 % más de valores, lo que para nosotros es mejor que rellenarlos mal.

Hoy la extracción usa deepseek-v4.1-flash con think: false. Antes de adoptarlo hubo que corregir nuestro parser, que descartaba sus respuestas cuando devolvía un objeto suelto en vez de una lista. Antes de culpar al modelo, conviene leer lo que contesta.

También probamos un modelo decisor externo, pplx-decider: acertó 24 de 24 orientaciones y 22 de 24 clasificaciones, con un error dado con confianza 0,93. No le dimos autoridad. Un decisor seguro de sí mismo y equivocado es justo lo que intentamos evitar.

12El método

  1. Siempre con expedientes reales, procesados de punta a punta en preproducción. Las cifras sintéticas solo orientan.
  2. Diagnosticar contra el papel: antes de corregir se relee el literal crudo del registro y, si hace falta, se vuelve a renderizar la página al mismo DPI que ve el modelo.
  3. Medir con el pipeline completo y con varios tipos de documento. Un arreglo correcto para un documento puede romper otro.
  4. Revisión de diseño independiente: ante una duda real consultamos a un segundo modelo, siempre un Frontier MoE, y verificamos su propuesta contra el código y los datos antes de aplicarla.
  5. Cada commit cuenta el caso real que lo motivó. Así, más de mil commits se leen como un cuaderno de laboratorio.

13Lo que aún no está resuelto

  • La cobertura de los documentos mixtos por regiones: corroborar por la posición real de cada imagen en la página, no solo por línea.
  • Más casos con verdad conocida: expedientes con cada campo verificado a mano, que son los que permiten medir de verdad cada cambio.
  • Las zonas como fuente de cada valor en todos los tipos de documento, no solo en los formularios de casillas.

Conclusiones

Los modelos de visión son excelentes leyendo y malos avisando de que se han equivocado. El sistema que los rodea tiene que hacer esa segunda parte: medir antes de transformar, leer más de una vez sin contaminar las lecturas, preferir lo verificable a lo probable, usar el expediente entero como testigo y dejar escrita cada decisión. Lo que no puede resolver con certeza, lo pone delante de una persona con la evidencia al lado.

Hay una distancia tecnológica importante entre la lectura de un documento cualquiera que te hace una aplicación de IA (como un ChatGPT, Claude, u otras) y un robot Agente de Extracción de Datos que automatiza el proceso industrial de miles de documentos heterogéneos, y garantiza fiabilidad, trazabilidad, seguridad y escalabilidad.