Skip to content

jleonceo/llm-eval-contable

Repository files navigation

LLM Eval — Contable Experto

Framework de evaluación automática para una skill contable en LLM Automated evaluation framework for a Spanish PGC accounting LLM skill

50 casos de test · 12 categorías · 5 iteraciones · 66% → 94% de precisión · Mitigación de sesgos cognitivos en IA 50 test cases · 12 categories · 5 iterations · 66% → 94% accuracy · AI cognitive bias mitigation

License: MIT Python 3.10+ Model: Claude Sonnet


🇪🇸 Español · 🇬🇧 English


🇪🇸 Español

Qué es esto

Un pipeline de desarrollo orientado a evaluación para medir y mejorar iterativamente una skill LLM de contabilidad. La skill bajo test genera asientos contables de doble entrada (PGC — Plan General Contable español) a partir de descripciones en lenguaje natural.

La idea central: mejorar una skill de LLM no es cuestión de escribir más instrucciones — es medir los patrones de fallo de forma sistemática, corregir la causa raíz, y verificar que las correcciones no rompen los casos que ya pasaban (regresión).


Progresión de resultados

Run Puntuación % Versión skill Cambio principal
Run 1 — baseline 33 / 50 66% v1.0 Skill inicial
Runs 2–3 36–38 / 50 72–76% v1.5–v2.0 Taxonomía IVA, reglas ISP
Run 4 41 / 50 82% v2.2 Freno, asientos de nómina
Run 5 44 / 50 88% v2.6 Excepción SaaS, 640 vs 641, embargo
Teórico (v2.8) 47 / 50 94% v2.8 Correcciones dataset + aclaración devengo

Puntuación teórica verificada manualmente por análisis de casos tras aplicar todas las correcciones v2.8.


Cobertura — 50 casos, 12 categorías

Categoría Casos Qué testea
facturas_emitidas 6 Ventas B2B a crédito, B2C al contado, descuentos, devoluciones, anticipos, cobros
facturas_recibidas 6 Compras, pagos de servicios, rappels, anticipos a proveedores
intracomunitario 4 Adquisiciones/entregas intracomunitarias, ISP, exenciones IVA
isp_domestico 3 ISP doméstico: ejecución de obras, arrendamiento con renuncia a exención
nominas_simples 4 Devengo nómina (640/642/465/476), paga extra, pago en banco
nominas_irpf_embargos 3 IRPF elevado, embargo judicial (410 + 465 coexisten)
amortizaciones 3 Inmovilizado material (681/281), intangible (680/280)
periodificaciones 4 Gastos anticipados (480), ingresos diferidos (485), accruals
cierre_regularizacion 4 Variación existencias, deterioro, traspaso resultado, reversión
impuestos 5 Liquidación IVA (303), pagos IRPF (111/115), compensación
trampas_errores 4 IVA sobre precio total, datos insuficientes, asientos descuadrados
leasing_renting 4 Renting (gasto corriente), activación leasing, cuotas mensuales

Cómo funciona el eval

Arquitectura

dataset_v2.json          ← 50 casos de test con expected outputs
     │
     ▼
runner.py  ──────────────── carga skill_prompt.md como system prompt
     │                ───── llama a la API de Claude (temperature=0)
     │                ───── parsea la respuesta JSON
     ▼
results/YYYY-MM-DD_HHMM_sonnet.json   ← output raw por caso
     │
     ▼
grader.py  ──────────────── valida: coincidencia por prefijo PGC
                       ───── valida: importes ±€0,01 de tolerancia
                       ───── valida: cuadre (Σdebe = Σhaber)
                       ───── valida: flags semánticos
                       ───── reporta por categoría

Qué verifica el grader

  1. Estado — OK vs PENDIENTE_VERIFICACION (freno obligatorio cuando faltan datos)
  2. Cuadre — total DEBE debe igualar total HABER (±€0,01)
  3. Líneas del asiento — cada línea esperada debe coincidir por prefijo PGC (no código exacto), importe y lado (debe/haber)
  4. Flags semánticosrequiere_periodificacion, isp, freno_nominas, retencion_irpf

La validación por prefijo (startswith) es clave: la skill usa códigos de 8 dígitos específicos de empresa (ej. 47200001), pero el test solo exige el grupo PGC correcto (ej. 472). Esto testea el conocimiento contable, no la memorización de códigos.


Mitigación de sesgos cognitivos en IA

La parte más interesante del proyecto fue aplicar teoría de sesgos cognitivos directamente al diseño del prompt. Se identificaron y abordaron seis sesgos:

1. Sesgo de recencia

Problema: el último "pensamiento" del modelo antes de generar output ancla la respuesta. Si el contexto más reciente es un ejemplo positivo, el modelo se vuelve permisivo.

Solución: se añadió una pregunta de pre-vuelo como última instrucción antes del input — forzando al modelo a verificar si faltan datos críticos (% IRPF, cuota SS empresa) antes de escribir ningún JSON.

2. Sesgo de confirmación

Problema: el modelo confirma el marco establecido por la pregunta. "Contabiliza esta factura..." lo predispone a producir un asiento aunque los datos sean insuficientes.

Solución: se añadió un checklist de 8 pasos que el modelo debe ejecutar antes de producir el asiento. El checklist resetea el marco de "produce output" a "verifica primero".

3. Sesgo de anclaje

Problema: la primera cuenta mencionada en la descripción ancla la elección del modelo, aunque sea incorrecta.

Solución: reglas explícitas para categorías donde la cuenta "obvia" es incorrecta (suscripciones SaaS → 62x no 20x, devengo nómina → 465 no 572).

4. Falso equilibrio

Problema: cuando existen dos tratamientos contables posibles, el modelo elige el "término medio" — produciendo un asiento híbrido incorrecto bajo ambos criterios.

Solución: reglas binarias con criterios de decisión explícitos. Sin "podría ser cualquiera de los dos" — el prompt fuerza una decisión basada en condiciones concretas.

5. Servilismo (sycophancy)

Problema: cuando el input del usuario implica un resultado esperado (ej. "haz este asiento: DEBE 600 / HABER 400"), el modelo cumple aunque sea incorrecto (descuadrado).

Solución: casos trampa en el dataset (casos 43–46) donde la respuesta correcta es rechazar y devolver PENDIENTE_VERIFICACION.

6. Cherry picking

Problema: el modelo selecciona la interpretación más favorable de datos ambiguos en lugar de señalar la ambigüedad.

Solución: la pregunta de pre-vuelo distingue datos derivables (IVA estándar 21%, estructura del asiento) de datos que deben proporcionarse (% IRPF, tipo SS empresa, importe de la operación). Dato ambiguo = freno.


Cómo usar este framework

Requisitos previos

# Python 3.10+, se recomienda Conda
conda create -n llm-eval python=3.10
conda activate llm-eval
pip install -r requirements.txt

Setup

# 1. Clonar el repo
git clone https://github.com/jleonceo/llm-eval-contable.git
cd llm-eval-contable

# 2. Configurar API key
cp .env.example .env
# Editar .env: ANTHROPIC_API_KEY=tu_clave_aqui

# 3. Añadir tu skill prompt
cp skill_prompt.example.md skill_prompt.md
# Editar skill_prompt.md con tu system prompt real

Ejecutar el eval

# Por defecto: Claude Sonnet 4.6
python runner.py

# Modelo explícito
python runner.py --model sonnet
python runner.py --model opus
python runner.py --model haiku

# Evaluar un resultado existente
python grader.py results/2026-05-27_1200_sonnet.json

Adaptar para tu propia skill

El dataset espera output JSON con esta estructura:

{
  "estado": "OK",
  "lineas": [
    {"cuenta": "47200001", "nombre_cuenta": "IVA soportado", "debe": 21.00, "haber": 0.00}
  ],
  "flags": {
    "requiere_periodificacion": false,
    "isp": false,
    "freno_nominas": false,
    "retencion_irpf": false
  }
}

Sustituye skill_prompt.md por tu system prompt. Ajusta dataset_v2.json con tus casos de test. La lógica de grader.py es genérica y reutilizable.


Estructura de ficheros

llm-eval-contable/
├── README.md                   ← este fichero
├── dataset_v2.json             ← 50 casos de test con expected outputs
├── grader.py                   ← lógica de evaluación y puntuación
├── runner.py                   ← runner API (carga skill_prompt.md)
├── skill_prompt.md             ← tu system prompt (NO incluido — ver .gitignore)
├── skill_prompt.example.md     ← plantilla con la estructura requerida
├── requirements.txt
├── .env.example
├── .gitignore
└── results/
    └── summary.md              ← progresión de puntuaciones por run

Decisiones técnicas clave

¿Por qué validación por prefijo PGC? El PGC usa una jerarquía de cuentas. Las empresas las extienden con sufijos propios (ej. 47200001 para una cuenta IVA específica). Testear códigos exactos haría el eval frágil y específico de empresa. La validación por prefijo (62x = cualquier cuenta de gasto) testea el conocimiento contable que realmente importa.

¿Por qué temperature=0? Reproducibilidad. Con temperature > 0, el mismo caso puede pasar o fallar entre runs por razones aleatorias, haciendo imposible atribuir cambios de puntuación a cambios en el prompt. Temperature cero hace cada run determinista.

¿Por qué output en JSON? El output estructurado permite evaluación automática. Las explicaciones contables en texto libre son útiles para humanos pero imposibles de evaluar a escala. El formato JSON además obliga al modelo a ser preciso con los importes.

¿Por qué un freno obligatorio (PENDIENTE_VERIFICACION)? Un asiento incorrecto en un sistema contable es peor que ningún asiento. El patrón freno — rechazar y explicar en lugar de adivinar — es el comportamiento correcto para un asistente contable en producción.


Resultados detallados

Ver results/summary.md para el análisis completo con desglose por categoría y análisis de fallos.


Autor

Juan Luis León Rodríguez Analista de Datos · Business Intelligence · IA Aplicada al Negocio


🇬🇧 English

What This Is

An eval-driven development pipeline to test and iteratively improve an LLM-based accounting assistant. The skill under test generates Spanish double-entry bookkeeping entries (PGC — Plan General Contable) from natural language descriptions.

The core insight: improving an LLM skill is not about writing more instructions — it's about measuring failure patterns systematically, fixing the root cause, and verifying fixes don't break passing cases (regression testing).

Score Progression

Run Score % Key change
Run 1 — baseline 33 / 50 66% Initial skill
Runs 2–3 36–38 / 50 72–76% VAT taxonomy, ISP rules
Run 4 41 / 50 82% Brake logic, payroll edge cases
Run 5 44 / 50 88% SaaS exception, 640 vs 641, garnishments
Theoretical (v2.8) 47 / 50 94% Dataset fixes + accrual clarification

How It Works

The grader validates each model response against the dataset expected output:

  • Account matching by PGC prefix (e.g. 472 matches 47200001) — tests accounting knowledge, not code memorisation
  • Balance check — Σdebit = Σcredit ±€0.01
  • Semantic flags — exact match on requiere_periodificacion, isp, freno_nominas, retencion_irpf
  • Brake pattern — model must return PENDIENTE_VERIFICACION (empty entry) when essential data is missing

AI Bias Mitigation

Six cognitive biases were addressed through prompt engineering:

Bias Fix
Recency Pre-flight question as last instruction before input
Confirmation 8-step checklist resets the "produce output" frame
Anchoring Explicit rules for cases where the obvious account is wrong
False balance Binary decision criteria, no hedging allowed
Sycophancy Trap cases (43–46) require refusing user-provided wrong entries
Cherry picking Pre-flight distinguishes derivable data from required data

Quick Start

git clone https://github.com/jleonceo/llm-eval-contable.git
cd llm-eval-contable
pip install -r requirements.txt
cp .env.example .env          # add your ANTHROPIC_API_KEY
cp skill_prompt.example.md skill_prompt.md   # add your system prompt
python runner.py

Licencia / License

MIT — see LICENSE.


Construido con Claude Sonnet 4.6 · Mayo 2026 · Built with Claude Sonnet 4.6 · May 2026

About

Eval-driven development for LLM accounting skills. 50 automated test cases. 66% to 94% in 5 iterations. AI bias mitigation techniques.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages