en una función en la que tuve que transformar 100 archivos PDF de cumplimiento desordenados en reglas JSON estructuradas.
El enfoque de fuerza bruta era obvio: darle al agente el texto fuente, explicarle la tarea, proporcionarle ejemplos y pedirle que genere las reglas. Como era la fruta más fácil, la probé primero.
A primera vista, el resultado parecía bueno. El JSON de salida era válido y coincidía con lo que esperaba.
Pero mientras tomaba muestras manualmente de los resultados para comprobar su precisión, aparecieron las grietas. Algunas reglas eran demasiado amplias y otras no se cumplieron. Algunas reglas no lograron preservar los matices del texto original. Intenté utilizar otro agente para detectar y corregir los errores, pero con un corpus tan grande, fue imposible verificar el resultado con confianza.
Esa fue la parte frustrante. Los errores no fueron obvios. Esta fue una implementación demasiado frágil a escala.
Aunque no puedo compartir los detalles exactos de la implementación, lo que sí puedo compartir son las lecciones de arquitectura que aprendí y cómo finalmente las implementé. Con suerte, estos conocimientos serán útiles si está creando sistemas de inteligencia artificial que necesitan escalar, seguir siendo confiables y manejar datos confusos. Y si tienes mejores formas de hacer las cosas, ¡comunícate para chatear!
Bien, vayamos a ello.
el problema
Los 100 archivos PDF con los que trabajé ya habían sido analizados y fragmentados antes de que me llegaran. Pero el contenido en bruto seguía siendo confuso. Había viñetas, tablas, artefactos de OCR, secciones traducidas, títulos semiestructurados, pies de página, encabezados, formatos inconsistentes y peculiaridades específicas de los documentos.
Elegí utilizar un agente porque decidir qué importaba requería juicio semántico. Los documentos no seguían un patrón consistente, por lo que la relevancia no podía determinarse únicamente mediante reglas simples.
Había que entender el contexto circundante. Nada de esto fue difícil cuando se hizo con una pequeña cantidad de datos. El desafío era realizar esto de manera confiable a escala.
Luego, estas reglas fueron procesadas por otro sistema posterior para ser evaluadas de manera determinista.
Lo que finalmente funcionó
Después de algunos experimentos, me di cuenta de que la mayor mejora no provino de un mejor mensaje, una nueva herramienta, un servidor MCP o un arnés de agente más sofisticado.
Provino de cambiar la forma del problema.
En lugar de intentar que el agente fuera más inteligente, reduje el trabajo del agente.
El primer cambio fue preparar los datos de origen por adelantado. En lugar de pedirle al agente que consultara una base de datos, recuperara registros, decidiera si tenía las entradas correctas y luego realizara la extracción, le di un punto de partida más controlado.
En mi caso, eso significó almacenar temporalmente los datos sin procesar relevantes localmente.
Puede que esto no siempre sea práctico. Pero el principio subyacente es reducir la cantidad de incertidumbre de recuperación que el agente tiene que manejar. Si el trabajo del agente es razonar sobre el contenido, no le haga responsable también de averiguar si ha encontrado el contenido correcto.
Otra opción sería preparar la consulta con antelación.
También utilicé una secuencia de comandos para eliminar metadatos y campos innecesarios antes de pasar el contenido sin procesar al agente. Un contexto menos irrelevante significó menos distracciones, menos oportunidades para que el agente se aferrara a los detalles incorrectos y una tarea de razonamiento más limpia en general.
Pero el cambio más importante fue la unidad de trabajo.
En lugar de procesar todo a la vez, hice las cosas de forma iterativa y procesé un documento a la vez.
Eso hizo que cada trabajo fuera más pequeño, más fácil de inspeccionar, más fácil de reintentar y más fácil de auditar. Puse en marcha cinco subagentes para procesar documentos en paralelo, y cada agente registraba su progreso en un archivo.
Si un documento fallaba, solo podía volver a intentarlo. Si una salida tuviera problemas de formato, podría solucionar ese caso específico sin volver a ejecutar todo el lote. Si la canalización se detenía a mitad de camino, el progreso almacenado en caché significaba que podía reanudarse desde el último punto de control exitoso.
Aquí también se hizo más clara la separación de responsabilidades.
El agente se encargó del trabajo semántico: comprender el contenido, identificar las partes relevantes y escribir la salida JSON.
El código circundante manejaba las partes mecánicas: paralelizar trabajos, hacer cumplir el esquema, generar ID, escribir archivos, almacenar en caché el progreso, validar referencias y verificar si la salida podía rastrearse hasta la fuente original.
También tuve un orquestador que vigilaba el progreso del guión.
Hacer que la salida sea auditable
Una decisión de diseño útil fue agregar ID de referencia a cada regla generada. Esto significaba que cada elemento de salida apuntaba a una fuente específica.
Esto hizo que el resultado fuera más fácil de auditar. En lugar de preguntar “¿Parece correcta esta regla generada?”, Podría hacer preguntas más precisas como: ¿existe el fragmento fuente al que se hace referencia? ¿El texto fuente citado está realmente presente en ese fragmento?
También podría conseguir que otro agente realizara auditorías selectivas en documentos más grandes y complejos para garantizar que se preservaran los matices importantes.
Además de eso, hice una versión ligera de evaluaciones. Ejecuté un pequeño lote de documentos sin procesar a través del flujo de trabajo y revisé manualmente los resultados para determinar su cobertura y precisión. Un conjunto de datos completo no era práctico para el alcance de esta tarea, pero aún necesitaba una manera de demostrarme a mí mismo que el flujo de trabajo estaba funcionando.
Mi objetivo no era crear un punto de referencia perfecto, sino hacer que el sistema fuera lo suficientemente auditable como para poder inspeccionar los resultados, detectar fallas e iterar hacia una barra de precisión más alta.
Si tienes ideas sobre cómo podría haberlo hecho mejor, ¡déjamelo saber!
Mi mayor comida para llevar
El patrón que funcionó fue dejar de tratar el LLM como un sistema completo.
El sistema se volvió más confiable no porque el agente se volviera perfecto, sino porque el flujo de trabajo hizo que sus resultados fueran más fáciles de rastrear, validar y recuperar.
Casualmente, estaba construyendo esto poco antes de asistir a la conferencia inaugural de AI Engineer Singapore, que se celebró del 15 al 17 de mayo de 2026.
El último día, JJ Geewax, director de IA aplicada en Google DeepMind, compartió un encuadre que capturaba lo que había estado aprendiendo por las malas: debemos dejar de utilizar los LLM como gigantescos solucionadores de problemas.
Eso me impactó porque es muy fácil caer en una trampa. Es fácil simplemente darle al modelo los datos, el esquema, las reglas comerciales, los casos extremos y la responsabilidad de verificarse a sí mismo. Luego frustrarse cuando el resultado sea inconsistente.
Pero para sistemas de producción confiables, el mejor patrón suele ser un híbrido. Deje que el agente maneje las partes que requieren juicio semántico y deje que el código maneje las partes que requieren estructura, validación y control.
Compartiré más reflexiones de AI Engineer Singapore y los talleres a los que asistí. El fragmento de YouTube del discurso de JJ aquí.
Eso es todo de mi parte. Espero que esto haya ayudado y nos vemos en el próximo artículo 🙂