Automatizar listas de precios: lo que se rompe cuando el proveedor cambia el Excel A developer from Varka detailed an approach to automating price list ingestion for Argentine SMEs, using an LLM to map column headers rather than parse every row, which reduces errors and costs. The process includes deterministic table extraction, LLM-based column mapping on a sample, and validation steps to handle mismatched codes, decimal separators, IVA, and scanned PDFs. The developer emphasized that the model interprets while code decides, and that no flow should write without the ability to undo. Hace un tiempo escribí sobre automatizar una distribuidora y puse la carga de listas de precios como el proceso con mejor retorno. Me preguntaron por el detalle, así que va la implementación, con las partes que se rompen. El escenario: el proveedor manda una lista cada dos o tres semanas. PDF o Excel, formato distinto según quién la exportó ese día. Alguien la abre y carga cientos de artículos a mano en el sistema de gestión. Lo primero que uno intenta es pasarle el PDF al LLM y pedirle el JSON de las 800 filas. Funciona en la demo con 20 filas y se cae con el archivo real: se saltea filas del medio, inventa códigos que no existen, y el costo por corrida sube sin necesidad. El modelo no tiene que leer las 800 filas. Tiene que leer el encabezado . Archivo del proveedor │ ▼ Extracción determinística de la tabla pdfplumber / openpyxl │ ▼ LLM sobre las primeras ~15 filas → mapeo de columnas │ {codigo: "B", precio: "F", bulto: "D"} ▼ Aplicar ese mapeo a las 800 filas con código común │ ▼ Matching contra el maestro → validaciones → escritura por lote El LLM se usa una vez por archivo, no una vez por fila. Lo variable es el layout, no los datos. El código del proveedor casi nunca coincide con el tuyo. Van tres intentos, en orden: Lo que no matchea no se crea . Va a una bandeja de revisión y alguien la mira. Un flujo que da de alta productos solo te llena el maestro de duplicados en tres meses, y eso no se limpia nunca más. Cuando el humano resuelve un caso de la bandeja, se guarda la equivalencia. La bandeja del segundo mes es la mitad que la del primero. Determinísticas, en código, después del modelo: Ese último es el que salva. Si el proveedor manda una lista parcial con 60 artículos y tu flujo asume que es la lista completa, cualquier lógica de "lo que no vino se discontinúa" te apaga el catálogo. Separador decimal. 1.234,56 y 1,234.56 según quién exportó. Si lo parseás con la config local y el archivo vino de otro lado, cambiás precios por mil. IVA. Algunos proveedores mandan con IVA, otros sin, y el mismo proveedor cambia de criterio cuando cambia de sistema. No se deduce del número: se guarda como atributo del proveedor y se valida contra el margen resultante. Precio por bulto. La columna dice "precio" y es por caja de 12. Si tu maestro lo lleva por unidad, todo entra multiplicado por 12. PDFs escaneados. Alguno llega como imagen. Ahí sí va OCR antes, y ahí sí conviene revisión humana del lote completo: el OCR confunde 0 con 8 y ese error pasa todas las validaciones porque es un número plausible. Dos cosas que parecen de más hasta la primera vez que las necesitás: El proceso pasa de media jornada a un par de minutos, más el rato de la bandeja de revisión, que se achica sola. Pero lo que realmente cambia no es el tiempo: es que los precios de la góndola y los del e-commerce dejan de estar desfasados respecto del sistema, porque ahora se actualizan en el mismo movimiento. Dos reglas que me quedaron de esto y valen para cualquier automatización que escriba en un sistema de producción: el modelo interpreta y el código decide, y ningún flujo escribe sin poder deshacerse. Escribo sobre automatización con IA para pymes argentinas desde Varka. La versión no técnica de esta nota, para dueños de negocio, está en el blog.