Clasificar transacciones con un LLM¶
Esta página cubre el flujo de clasificación asistida por LLM: configurar un proveedor, obtener una vista previa de una sugerencia para una transacción, el bucle de revisión (aplicar, rechazar o anular), saturar los campos fiscales de IVA y leer una factura adjunta con un modelo, en tu propia máquina o, con consentimiento explícito, a través de un proveedor en la nube. La sugerencia es siempre un punto de partida: tú la confirmas o la corriges, y el modelo nunca fija un importe en euros.
La clasificación no contacta con la AEAT ni presenta nada. La CLI del proveedor puede contactar con tu propio servicio externo según cómo hayas configurado el proveedor; consulta el límite de privacidad antes de usar datos reales de un contribuyente.
Las órdenes de LLM y de visión de esta página necesitan una CLI de proveedor o un modelo de visión local que el entorno de pruebas de la documentación no ejecuta, así que se muestran como paneles solo ilustrativos. Las órdenes locales que las rodean se ejecutan en directo al construir la documentación.
Antes de empezar¶
Necesitas:
Un perfil activo, consulta configurar tu perfil de contribuyente, y al menos una transacción en tu ledger para clasificar. Consulta Importar y gestionar transacciones.
La frase de contraseña de tu clave maestra. La orden abre el ledger cifrado, así que te pide la frase de contraseña.
Una CLI de proveedor instalada, en el
PATHy con la sesión iniciada.
El entorno de ejecución emite la ayuda, las peticiones y los mensajes en español.
Configura un proveedor¶
aeat no almacena credenciales de LLM y no tiene una configuración de cuenta de LLM aparte. Ejecuta una CLI de proveedor que ya esté instalada y autenticada en tu sistema. La orden de clasificación acepta nombres de proveedor como claude, antigravity y codex; antigravity usa la CLI agy de Google, el sucesor con soporte de la retirada CLI independiente gemini.
Compruebe qué CLI de proveedores están visibles en PATH con aeat config check. Muestra cada proveedor como disponible o ausente con la solución para cada problema, junto a las capacidades del servicio de perfil. Esto informa solo de la detección, no del inicio de sesión. El lector de visión local también aparece ahí: muestra ausente hasta que el entorno de ejecución responde. aeat config provision status informa en detalle del entorno de ejecución y de cada modelo lector.
Instala y autentica el proveedor con tu propia CLI o su flujo de cuenta. La orden de inicio de sesión y los ajustes de retención de datos pertenecen al proveedor, no a aeat. Después haz una prueba rápida con una vista previa, que no guarda nada:
aeat app ledger classify <transaction-id> --llm claudeaeat app ledger classify <transaction-id> --llm claudeUn proveedor con la sesión cerrada hace que la orden se niegue y transmita el propio error del proveedor (por ejemplo La clasificacion por LLM fallo: claude CLI exited with 1: 'Not logged in ...'). Completa el inicio de sesión de ese proveedor y vuelve a intentarlo.
Pide una sugerencia¶
Localiza una fila que aún necesite clasificación y examínala. Después envía esa única fila al proveedor para una vista previa:
aeat app ledger list --filter classification=NOT_YET_PROCESSEDaeat app ledger list --filter classification=NOT_YET_PROCESSEDACCOUNTING LEDGER TRANSACTIONS id full_id date amount description IVA category review_status 71a5db2b 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518 2026-02-10 1210 Cobro factura F-2026-001 servicios de consultoria pending e3eeac5e e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d 2026-02-11 605 Compra de material de oficina proveedor local pending
aeat --format json app ledger view e3eeac5eaeat --format json app ledger view e3eeac5e{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "605", "attachment_ids": [], "booked_date": "2026-02-11", "business_classification": "NOT_YET_PROCESSED", "business_pct": null, "category_id": null, "classification_confidence": null, "classification_reason": "", "classified_at": null, "classified_by": "auto", "counterparty": "", "counterparty_country": null, "counterparty_identification_state": null, "created_at": "2026-04-01T09:00:00+00:00", "currency": "EUR", "date": "2026-02-11", "description": "Compra de material de oficina proveedor local", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": null, "iva_category": null, "iva_rate": null, "lifecycle_state": "ACTIVE", "m210_income_classification": null, "modified_at": "2026-04-01T09:00:00+00:00", "notes": "", "prorrata_reference": null, "purchase_invoice_evidence_id": null, "source_jurisdiction": null, "taxable_base": null, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "usage_ratio_id": null, "value_date": "2026-02-11", "value_in_eur": null }, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" }, "schema_version": "2", "status": "success" }
Confirm the unclassified row is ready to send for a suggestion.
aeat app ledger classify e3eeac5e --llm claudeaeat app ledger classify e3eeac5e --llm claudeaeat envía esa única fila a la CLI del proveedor seleccionado, que sugiere una clasificación (BUSINESS, PERSONAL o MIXED), una categoría de gasto cuando puede elegir una de la lista permitida, una confianza y un motivo breve. En modo de vista previa no se guarda nada. Para el registro completo legible por máquina, incluidos los campos provenance (llm:<provider>) y persisted, pon la opción global de JSON antes del subcomando:
aeat --format json app ledger classify <transaction-id> --llm claudeaeat --format json app ledger classify <transaction-id> --llm claudeUsa la descripción, el importe, la dirección, la contraparte y los documentos de origen de la fila para decidir si la sugerencia tiene sentido. Para los conceptos manuales subyacentes, consulta Clasificar transacciones.
Revisar, aplicar, rechazar o anular¶
El bucle de revisión tiene cuatro finales:
Revisar. Vista previa sin
--apply. No se guarda nada; si te vas, la fila queda sin cambios.Aplicar. Persiste la sugerencia tras revisarla. La salida de aplicar muestra el id de la transacción,
clasificado-por llm:<provider>y el nuevo estado de revisión; la procedencia, la confianza y el motivo se registran junto con el evento de clasificación.Rechazar. Deja constancia de que el modelo se equivocó, con tu motivo, como un evento de auditoría; la fila sigue sin clasificar y el registro permanece en el historial.
--rejectno se puede combinar con--apply. Hacer una vista previa e irte tampoco cambia nada, pero--rejectes lo que escribe el rastro de auditoría.Anular. Clasifica a mano siempre que la sugerencia sea incorrecta o incompleta. La clasificación manual siempre prevalece y sustituye a un valor derivado o aplicado por el modelo.
Tanto aplicar como rechazar ejecutan el proveedor, así que se muestran como paneles solo ilustrativos:
aeat app ledger classify <transaction-id> --llm claude --applyaeat app ledger classify <transaction-id> --llm claude --applyaeat app ledger classify <transaction-id> --llm claude --reject --reason \
this is personalaeat app ledger classify <transaction-id> --llm claude --reject --reason `
this is personalAnular se ejecuta por completo en tu máquina. Clasifica la fila a mano con la clasificación y la categoría que elijas:
aeat --format json app ledger classify e3eeac5e --classification BUSINESS --category-id \
material_oficinaaeat --format json app ledger classify e3eeac5e --classification BUSINESS --category-id `
material_oficina{ "active_profile": "docs-sequence-sandbox", "command": "ledger.classify", "notices": [], "result": { "bucket_event_ids": [ "cf03296ca740dd5d6130ecd3349d24ea25d09a125819597f400d0489945da3ab" ], "bucket_id": "<bucket-id>", "review_status": "reviewed", "transaction": { "amount": "605", "attachment_ids": [], "booked_date": "2026-02-11", "business_classification": "BUSINESS", "business_pct": null, "category_id": "material_oficina", "classification_confidence": "1", "classification_reason": "aeat app ledger classify", "classified_at": "2026-04-01T09:00:00+00:00", "classified_by": "manual", "counterparty": "", "counterparty_country": null, "counterparty_identification_state": null, "created_at": "2026-04-01T09:00:00+00:00", "currency": "EUR", "date": "2026-02-11", "description": "Compra de material de oficina proveedor local", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": null, "iva_category": null, "iva_rate": null, "lifecycle_state": "ACTIVE", "m210_income_classification": null, "modified_at": "2026-04-01T09:00:00+00:00", "notes": "", "prorrata_reference": null, "purchase_invoice_evidence_id": null, "source_jurisdiction": null, "taxable_base": null, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "usage_ratio_id": null, "value_date": "2026-02-11", "value_in_eur": null }, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" }, "schema_version": "2", "status": "success" }
Confirm the manual override classifies the row.
Si la fila es de uso mixto, la sugerencia del LLM por sí sola no basta; aporta el porcentaje de la actividad a través del flujo de uso mixto habitual. Después de correcciones importantes, vuelve a ejecutar la comprobación previa del periodo:
aeat --format json app ledger preflight --year 2026 --period 1Taeat --format json app ledger preflight --year 2026 --period 1T{ "active_profile": "docs-sequence-sandbox", "command": "ledger.preflight", "notices": [], "result": { "bucket_id": "<bucket-id>", "checked_transaction_count": 2, "issues": [], "period": { "code": "1T", "filing_year": 2026 }, "ready": true }, "schema_version": "2", "status": "success" }
Confirm the period preflight reads ready after corrections.
Rellena los campos fiscales automáticamente¶
Una sugerencia aplicada sin más guarda la clasificación y la categoría de gasto; no rellena los campos fiscales regulados. Añade --saturate para seleccionar además una categoría de IVA y derivar la base imponible, el tipo de IVA y la cuota de IVA. El modelo nunca inventa un número: solo selecciona la categoría de IVA; el tipo procede del registro, y la base y la cuota de IVA se calculan a partir del total de la transacción:
aeat app ledger classify <transaction-id> --llm claude --saturateaeat app ledger classify <transaction-id> --llm claude --saturateaeat app ledger classify <transaction-id> --llm claude --saturate --applyaeat app ledger classify <transaction-id> --llm claude --saturate --applyLa vista previa añade la categoría de IVA seleccionada y, cuando la categoría tiene un tipo español, las cifras derivadas; la base y el IVA siempre suman el total de la transacción. Una categoría sin un tipo español simple (una entrega intracomunitaria, una compra con inversión del sujeto pasivo) muestra una nota en lugar de números, y esos los completas a mano. El modelo también puede declinar y devolver unknown en vez de adivinar; vuelve a ejecutar, o elige tú mismo la categoría.
Cuando ya conozcas la categoría de IVA, o el modelo haya devuelto unknown, clasifica primero la fila como de la actividad y luego deja que el sistema derive los números sin ningún --llm. Esto deriva las cifras del tipo oficial exactamente igual que la vía del modelo y las registra como derivadas por el sistema. Solo toca los campos de IVA, y la fila ya debe estar clasificada como de la actividad o mixta:
aeat --format json app ledger classify e3eeac5e --iva-category domestic_general \
--saturateaeat --format json app ledger classify e3eeac5e --iva-category domestic_general `
--saturate{ "active_profile": "docs-sequence-sandbox", "command": "ledger.classify", "notices": [], "result": { "bucket_event_ids": [ "61e7203679a2689c9a11cf6a24ddaa370cfcbd16cad1a677ef3aa2dc14e52433", "017f5fb8270351a164fc4a36993989c06504305ae5dcf0d07335084d30267c75" ], "bucket_id": "<bucket-id>", "review_status": "reviewed", "transaction": { "amount": "605", "attachment_ids": [], "booked_date": "2026-02-11", "business_classification": "BUSINESS", "business_pct": null, "category_id": "material_oficina", "classification_confidence": "1", "classification_reason": "aeat app ledger classify --iva-category --saturate", "classified_at": "2026-04-01T09:00:00+00:00", "classified_by": "derived:iva-category", "counterparty": "", "counterparty_country": null, "counterparty_identification_state": null, "created_at": "2026-04-01T09:00:00+00:00", "currency": "EUR", "date": "2026-02-11", "description": "Compra de material de oficina proveedor local", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": "105", "iva_category": "domestic_general", "iva_rate": "0.21", "lifecycle_state": "ACTIVE", "m210_income_classification": null, "modified_at": "2026-04-01T09:00:00+00:00", "notes": "", "prorrata_reference": null, "purchase_invoice_evidence_id": null, "source_jurisdiction": null, "taxable_base": "500", "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "usage_ratio_id": null, "value_date": "2026-02-11", "value_in_eur": null }, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" }, "schema_version": "2", "status": "success" }
Confirm the derived IVA fields land without any provider.
Para anular a mano cualquier campo, clasifica manualmente con las cifras tú mismo. La base imponible más el IVA debe ser igual al total de la transacción hasta el céntimo:
aeat --format json app ledger classify {transaction_id} --classification BUSINESS \
--iva-category domestic_reduced --taxable-base 110.00 --iva-rate 0.10 --iva-amount \
11.00aeat --format json app ledger classify {transaction_id} --classification BUSINESS `
--iva-category domestic_reduced --taxable-base 110.00 --iva-rate 0.10 --iva-amount `
11.00{ "active_profile": "docs-sequence-sandbox", "command": "ledger.classify", "notices": [], "result": { "bucket_event_ids": [ "4709827e7a2d385fce18501344d5594c060f64e17ce7aefa6b7aa52adbb1a268", "2e292ca6b3c73c0340365ffeadcb123a7e8b8993a025610e198a38e59902c2d9" ], "bucket_id": "<bucket-id>", "review_status": "reviewed", "transaction": { "amount": "121", "attachment_ids": [], "booked_date": "2026-03-10", "business_classification": "BUSINESS", "business_pct": null, "category_id": null, "classification_confidence": "1", "classification_reason": "aeat app ledger classify", "classified_at": "2026-04-01T09:00:00+00:00", "classified_by": "manual", "counterparty": "", "counterparty_country": null, "counterparty_identification_state": null, "created_at": "2026-04-01T09:00:00+00:00", "currency": "EUR", "date": "2026-03-10", "description": "Compra tipo reducido", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": "11", "iva_category": "domestic_reduced", "iva_rate": "0.1", "lifecycle_state": "ACTIVE", "m210_income_classification": null, "modified_at": "2026-04-01T09:00:00+00:00", "notes": "", "prorrata_reference": null, "purchase_invoice_evidence_id": null, "source_jurisdiction": "ES", "taxable_base": "110", "transaction_id": "b0a6349c28d268e65a577b9709ab304661cd8f8a3f29a7acd5527adfd1f8740c", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "b0a6349c28d268e65a577b9709ab304661cd8f8a3f29a7acd5527adfd1f8740c" }, "schema_version": "2", "status": "success" }
Confirm the hand-entered IVA figures land on the row.
La categoría de IRPF sigue introduciéndose a mano en Clasificar transacciones. Usa Revisar y aportar los datos de cálculo cuando más adelante un modelo informe de valores que faltan.
Lee la factura adjunta¶
Adjunta una factura de compra o un recibo a una transacción (consulta Adjuntar facturas y recibos) y luego deja que el modelo la lea mientras clasificas con --read-evidence. El modelo elige la categoría de gasto y la situación de IVA a partir de lo que lee; aeat deriva cada importe en euros del registro. Cómo se lee el documento depende del archivo:
Un PDF escaneado o una imagen los lee en tu propia máquina un modelo de visión local. Nada sale de la máquina, no hace falta ninguna confirmación, no hace falta ningún proveedor
--llmy funciona en despliegues de gestor y profesionales.Un PDF con capa de texto tiene su texto extraído y enviado a un proveedor en la nube (los mismos proveedores
--llm). Esto envía el texto fuera de tu máquina, así que está desactivado de forma predeterminada, prohibido para despliegues de gestor y sujeto a una confirmación explícita por cada ejecución.
Prefiera la vía local en el equipo. Aprovisione primero el entorno de ejecución local: instálelo con aeat config provision install, inícielo con aeat config provision start y descargue el modelo de visión con aeat config provision pull, acotado al rol de visión con --role. Consulte Configurar una estación de trabajo para ver la secuencia completa.
El modelo de visión predeterminado, qwen3-vl:2b, ocupa unos 2 GB y funciona en una GPU de consumo o en CPU. Para usar un modelo mayor en una GPU con espacio suficiente, indíquelo con la opción --model del comando de descarga. Luego clasifique a partir de la imagen adjunta, con una vista previa primero. Anule el modelo de visión para una sola ejecución con --vision-model qwen2.5vl:7b:
aeat app ledger classify <transaction-id> --read-evidence --saturateaeat app ledger classify <transaction-id> --read-evidence --saturateaeat app ledger classify <transaction-id> --read-evidence --saturate --applyaeat app ledger classify <transaction-id> --read-evidence --saturate --applyLas evidencias se leen solo en el equipo. No existe ninguna ruta que envíe una factura fuera de la máquina: una transacción sin evidencia adjunta tampoco envía nada adicional, así que el proveedor recibe únicamente la fila de la transacción, igual que en el flujo de sugerencia simple.
Divide automáticamente una factura de varias líneas¶
Cuando el modelo lee una factura con varias líneas a distintos tipos o categorías, la vista previa añade una nota split recommended con la orden exacta para separarlas. Cada línea debe convertirse en tu propia entrada para que su IVA deducible y su gasto al tipo base se declaren de forma independiente. Para actuar en un solo paso, añade --auto-split. --auto-split requiere --read-evidence y no se puede combinar con las opciones de anulación manual:
aeat app ledger classify <transaction-id> --read-evidence --auto-splitaeat app ledger classify <transaction-id> --read-evidence --auto-splitaeat app ledger classify <transaction-id> --read-evidence --auto-split --applyaeat app ledger classify <transaction-id> --read-evidence --auto-split --applyUna factura de varias líneas muestra en la vista previa una transacción hija por línea, cada una con tu propia categoría, categoría de IVA y base e IVA derivados del registro; las hijas suman exactamente el importe original. Una factura de una sola línea se clasifica en el sitio sin división.
Cómo protege aeat los documentos que lee¶
Los bytes de las facturas residen únicamente en el almacenamiento seguro cifrado. La lectura los descifra en memoria para esa única llamada y nunca los escribe en un archivo temporal, un registro o una caché.
Una lectura de escaneo o imagen envía la imagen solo al modelo local a través de una conexión de bucle invertido en tu máquina. Nada sale de la máquina.
Una lectura de capa de texto envía solo el texto extraído, y solo a un proveedor en la nube que hayas permitido y confirmado explícitamente. Nunca envía los bytes del PDF.
El modelo selecciona únicamente la clasificación, la categoría, la categoría de IVA y una proporción de división.
aeatderiva cada tipo, base y cuota de IVA del registro, y se niega a persistir un resultado cuyas partes no cuadren. Cuando el IVA impreso no coincide con el IVA calculado, la revisión muestra un aviso para que puedas comprobarlo antes de presentar.
Ajustes de despliegue de la evidencia¶
Los ajustes de consentimiento y de modelo son configuración de despliegue, desactivados de forma predeterminada y administrados fuera de este flujo. La lista completa está en la referencia de anulaciones de entorno.
Ver cómo se produjo cada sugerencia¶
Cada resultado aplicado registra cómo se produjo, así que una revisión posterior muestra la fuente:
llm:local-vision:<model>: leído en el propio equipo por el modelo de visión local.llm:<provider>:<model>: clasificado por un proveedor en la nube.derived:iva-category: elegiste la categoría de IVA yaeatderivó el resto.manual: estableciste la clasificación a mano.
Examina una transacción y su historial en cualquier momento:
aeat app ledger view e3eeac5eaeat app ledger view e3eeac5eID e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d Date 2026-02-11 Value date 2026-02-11 Amount 605 Currency EUR Direction OUTGOING Description Compra de material de oficina proveedor local Counterparty - Classification NOT_YET_PROCESSED Business % - Category - Usage ratio id - Taxable base - IVA rate - IVA amount - IVA category - Established in - VAT identified in - IRPF category - Notes - Purchase invoice evidence - Attachments - Lifecycle state ACTIVE Classified by auto Classified at - Classification confidence - Classification reason - Review status pending
aeat --format json app ledger history e3eeac5eaeat --format json app ledger history e3eeac5e{ "active_profile": "docs-sequence-sandbox", "command": "ledger.history", "notices": [], "result": { "bucket_id": "<bucket-id>", "event_count": 1, "events": [ { "actor": "<profile-id>", "bucket_id": "<bucket-id>", "event_id": "216049abc14de7287f01ae4f31b75e164a3ae520c7ae88ea7bc6b9ac017cef30", "event_type": "ledger.transaction.imported", "object_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "object_type": "ledger_transaction", "occurred_at": "2026-04-01T09:00:00Z", "payload": { "import_batch_id": "644ceb0a0aa9829b9cd0bf4d3a2ba43ce73f7ab6b333d46776496818650a0816", "imported_count": "2", "provider_name": "CSV provider", "skipped_count": "0", "source_command": "aeat app ledger import", "source_format": "csv", "source_row_index": "3" }, "payload_version": 1 } ], "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" }, "schema_version": "2", "status": "success" }
Confirm the transaction's history records its events.
Límites y alternativas en bloque¶
La ruta con LLM funciona solo con una transacción; no puede combinarse con --file ni con indicadores manuales --classification. Para trabajo por lotes use la ruta manual basada en CSV (aeat app ledger classify --file ./classifications.csv) o reglas deterministas almacenadas (aeat app ledger rule add, después rule apply --dry-run y luego rule apply); ambas se explican en Clasificar transacciones.
Límite de privacidad¶
La clasificación por LLM llama a la CLI del proveedor seleccionado en tu máquina. Esa CLI puede enviar los datos del prompt al servicio en la nube del proveedor, según cómo funcione ese proveedor y cómo esté configurada tu cuenta. Trata las descripciones de las transacciones, las contrapartes, los importes, las categorías y cualquier contexto de perfil incluido en el prompt como datos de un contribuyente. No uses datos de producción con un proveedor de LLM a menos que la configuración de tu proveedor y su política de privacidad lo permitan.