Orux AI / Notas sobre modelos
Facturas y DeepSeek: valida primero el cálculo con Python
Detecta una diferencia de USD 10 oculta en una factura con Python local. Incluye código, siete pruebas negativas y un paso opcional para DeepSeek.

En este artículo
Comprueba cada línea antes de pedir a DeepSeek que la explique
Una factura de un evento puede sumar perfectamente y aun así estar mal. En el ejemplo siguiente, los tres importes de línea del proveedor suman $234.00, exactamente el total declarado. Sin embargo, una línea cobra $80.00 por dos unidades de $45.00 cada una. Al multiplicar cantidad por precio unitario, el resultado es $90.00 y el total calculado de forma independiente asciende a $244.00. Que coincidan dos totales copiados no constituye una comprobación independiente.
Esta guía ofrece a quien coordina un evento un verificador Python ejecutable para detectar esa diferencia antes de preparar una solicitud para DeepSeek V4.1 Flash. Entrega un informe de excepciones que identifica la línea y un pequeño documento de datos para redactar, que el programa se niega a crear hasta que la aritmética sea correcta. Todos los ejemplos son gastos ficticios de una conferencia y los resultados proceden de ejecutar el programa local. Ningún modelo ha generado ni aprobado una factura en este artículo.
DeepSeek puede ser un paso opcional de redacción después de que una persona resuelva la diferencia. No debe decidir qué precio se acordó con el proveedor, aprobar un pago ni sustituir una factura sin dejar constancia. El documento original, el contrato y la aclaración siguen siendo las pruebas para esa decisión. Una multiplicación correcta demuestra una relación aritmética, no que se prestara un servicio o se autorizara un cargo.

La diferencia de $10 que oculta un total coincidente
La exportación ficticia contiene acreditaciones, señalización de salas y servicios de subtitulado. Las cantidades corresponden a unidades enteras de servicio. El verificador aplica el mismo esquema de cinco columnas a cada fila y recibe por separado el total de la factura. Ese valor separado importa: comparar la suma consigo misma produciría otra comprobación tranquilizadora pero inútil.
| Línea | Cantidad | Importe unitario | Importe indicado | Cálculo independiente |
|---|---|---|---|---|
| L1: Acreditaciones | 40 | USD 2.50 | USD 100.00 | USD 100.00 |
| L2: Señalización de salas | 3 | USD 18.00 | USD 54.00 | USD 54.00 |
| L3: Servicio de subtitulado | 2 | USD 45.00 | USD 80.00 | USD 90.00 |
| Total | — | — | USD 234.00 | USD 244.00 |
Desliza horizontalmente para ver toda la tabla.
Esto no significa automáticamente que falten $10 por pagar. Quizá el proveedor pretendía aplicar un descuento a la línea, o quizá la cantidad o el precio unitario son incorrectos. El programa no puede elegir entre esas explicaciones. Su conclusión es más concreta y útil: L3 no cumple la regla declarada de cantidad por precio unitario. Por tanto, hay que aclarar la factura antes de que este flujo cree un documento normal para redactar.
Conserva ambas versiones si el proveedor corrige la exportación. El caso corregido de esta guía cambia L3 a USD 90.00 y el total a USD 244.00 a la vez. Es una reparación construida deliberadamente para probar el programa, no una afirmación sobre la intención de un proveedor real. Para una factura real, la persona revisora sigue necesitando la corrección efectivamente aprobada.
Define el formato monetario sin adivinar la configuración regional
El código acepta importes USD no negativos con exactamente dos decimales y cantidades enteras positivas. Convierte las cadenas de importe en centavos enteros y utiliza multiplicación y suma de enteros. No hay comparación de coma flotante binaria ni tolerancia capaz de ocultar una diferencia de un centavo. Es un contrato de entrada deliberadamente limitado, no un lector universal de facturas.
Se rechazan valores como 2.500, -2.50, 234,00 y la notación científica. También se rechazan espacios al principio o al final de los campos numéricos. Una exportación europea no es incorrecta por usar otra convención: necesita una normalización separada y revisada antes de entrar en este verificador. No adivines si un separador representa decimales o miles.
La documentación CSV de Python explica que los delimitadores y las convenciones de comillas varían. El programa utiliza el analizador CSV en vez de dividir filas por comas y abre su flujo en memoria con el tratamiento de saltos de línea de la documentación. Una descripción entrecomillada que contenga una coma puede seguir siendo un solo campo. Se rechazan columnas inesperadas e identificadores de línea duplicados en vez de ignorarlos silenciosamente.
Quedan fuera de este contrato las cantidades fraccionarias, impuestos, descuentos, transporte, varias monedas y notas de abono. Si una factura incluye esos elementos, detente y define sus reglas aritméticas antes de utilizar el resultado. Eliminar filas no admitidas para obtener un estado válido anularía el propósito de la conciliación.
Ejecuta el verificador completo en local
Guarda lo siguiente como check_invoice.py y ejecuta python3 check_invoice.py. Solo usa la biblioteca estándar de Python, no necesita API Key ni realiza solicitudes de red. Los datos de ejemplo y las aserciones forman parte de la entrega: puedes reproducir tanto la diferencia oculta como el caso corregido sin comprar una llamada a un modelo.
"""Offline synthetic invoice check. No model/API request; USD integer cents only."""
import csv
import io
import json
import re
HEADER = ['line_id', 'description', 'qty', 'unit_usd', 'line_usd']
CSV = '''line_id,description,qty,unit_usd,line_usd
L1,Name badges,40,2.50,100.00
L2,Room signage,3,18.00,54.00
L3,Captioning service,2,45.00,80.00
'''
def cents(value):
if not isinstance(value, str) or not re.fullmatch(r'[0-9]+\.[0-9]{2}', value):
raise ValueError('Use unsigned USD amounts with exactly two decimals')
whole, fraction = value.split('.')
return int(whole) * 100 + int(fraction)
def check(text, invoice_total):
reader = csv.reader(io.StringIO(text, newline=''), strict=True)
if next(reader, None) != HEADER:
raise ValueError('Unexpected CSV header')
seen, rows, issues = set(), [], []
for fields in reader:
if len(fields) != len(HEADER):
raise ValueError('Unexpected column count')
ident, description, quantity, unit, quoted = fields
if not ident or ident in seen or not description.strip():
raise ValueError('Missing or duplicate line identity')
if not re.fullmatch(r'[0-9]+', quantity) or int(quantity) < 1:
raise ValueError('Quantity must be a positive whole number')
seen.add(ident)
expected, stated = int(quantity) * cents(unit), cents(quoted)
rows.append(dict(line_id=ident, expected_cents=expected, stated_cents=stated))
if expected != stated:
issues.append(dict(line_id=ident, expected_cents=expected, stated_cents=stated))
if not rows:
raise ValueError('No invoice lines')
declared = cents(invoice_total)
expected_total = sum(x['expected_cents'] for x in rows)
stated_sum = sum(x['stated_cents'] for x in rows)
return dict(currency='USD', line_count=len(rows), line_issues=issues,
expected_total_cents=expected_total, stated_line_sum_cents=stated_sum,
declared_total_cents=declared, declared_matches_lines=declared == stated_sum,
eligible_for_draft=not issues and declared == expected_total)
def draft_brief(report):
if not report['eligible_for_draft']:
raise ValueError('Resolve arithmetic before creating a drafting brief')
return {k: report[k] for k in ['currency', 'line_count', 'expected_total_cents']}
def planned_microcredits(inputs, outputs, rate_in, rate_out):
if any(type(x) is not int or x < 0 for x in [inputs, outputs, rate_in, rate_out]):
raise ValueError('Planning quantities and rates must be nonnegative integers')
numerator = inputs * rate_in + outputs * rate_out
return (numerator + 999999) // 1000000
if __name__ == '__main__':
bad = check(CSV, '234.00')
assert bad['declared_matches_lines'] and not bad['eligible_for_draft']
assert bad['expected_total_cents'] - bad['declared_total_cents'] == 1000
try:
draft_brief(bad)
except ValueError:
pass
else:
raise AssertionError('Bad invoice became a drafting brief')
fixed = check(CSV.replace('45.00,80.00', '45.00,90.00'), '244.00')
assert draft_brief(fixed) == dict(currency='USD', line_count=3, expected_total_cents=24400)
rejected = 0
for text, total in [
(CSV.replace('L2,', 'L1,'), '234.00'),
(CSV.replace(',40,', ',0,'), '234.00'),
(CSV.replace(',40,', ',1e2,'), '234.00'),
(CSV.replace('2.50', '2.500'), '234.00'),
(CSV.replace('2.50', '-2.50'), '234.00'),
(CSV.replace('L1,Name badges,', 'L1,Name badges,EXTRA,'), '234.00'),
(CSV, '234,00'),
]:
try:
check(text, total)
except ValueError:
rejected += 1
else:
raise AssertionError('Invalid fixture accepted')
rates = {'catalog_low': (18333360, 73333440), 'catalog_high': (36666720, 146666880)}
plans = {key: planned_microcredits(1000, 300, *value) for key, value in rates.items()}
assert plans == {'catalog_low': 40334, 'catalog_high': 80667}
print(json.dumps(dict(bad=bad, corrected_brief=draft_brief(fixed),
negative_fixtures_rejected=rejected, planned_microcredits=plans), indent=2))El script devuelve deliberadamente un informe cuando hay discrepancias aritméticas, pero genera un error si la entrada está mal formada. Son situaciones distintas: una factura interpretable puede contener una diferencia que deba investigarse; unas filas mal formadas no pueden interpretarse de manera fiable bajo el contrato definido. Una importación de producción también necesitaría límites de tamaño, controles de acceso, convenciones contables y revisión operativa adecuados a su entorno.
Lee el informe sin convertirlo en una decisión de pago
El resultado ejecutado muestra declared_matches_lines: true y eligible_for_draft: false. El total esperado es de 24 400 centavos, mientras que tanto el total declarado como la suma de líneas indicadas son de 23 400. La excepción identifica L3 con 8 000 centavos declarados y 9 000 esperados. Esos valores exactos, no una advertencia genérica, explican por qué se bloqueó un total aparentemente coherente.
El programa también intentó crear el documento de redacción a partir del informe incorrecto y confirmó que la función lo rechazaba. Con los datos explícitamente corregidos devolvió {"currency":"USD","line_count":3,"expected_total_cents":24400}. Ese objeto compacto es la entrega local satisfactoria. No es una respuesta del modelo, una prueba de cumplimiento fiscal ni una autorización para pagar USD 244.00.

Se rechazaron realmente siete casos negativos: identificador duplicado, cantidad cero, cantidad con exponente, precisión monetaria excesiva, precio unitario negativo, columna adicional y total con coma decimal. Es una cobertura específica del contrato del ejemplo, no una prueba de que cualquier exportación sea segura. Los errores de sintaxis CSV también pueden detener el análisis; el script no promete recuperar automáticamente archivos dañados de cualquier tipo.
Dale a DeepSeek una tarea resuelta y un límite explícito
Una vez que el proveedor o la persona responsable resuelva la discrepancia, la coordinación puede pedir a DeepSeek un acuse de recibo neutral utilizando solo hechos aprobados. Una posible solicitud sería: «Redacta un breve acuse de recibo de la factura USD corregida de tres líneas, con total conciliado de 244.00. No afirmes que el pago está aprobado ni programado. Pide a la persona revisora que confirme el número de referencia antes de enviar». Esta solicitud no se ha ejecutado aquí.
El formulario actual de Orux expone messages, max_tokens y una opción de respuesta como objeto JSON para deepseek-v4.1-flash. Eso verifica los controles disponibles, no la ejecución satisfactoria de esta tarea de redacción. Usa el alias exacto de Orux que aparece en la página del modelo. El nombre en el servicio propio de DeepSeek es un identificador de otro servicio y no debe copiarse suponiendo que sea un alias de Orux.
La referencia Chat Completions de DeepSeek documenta los datos de uso. Para una solicitud ejecutada, cuenta el uso realmente devuelto: ni los caracteres del CSV ni el número de líneas determinan los tokens consumidos. Si necesitas un objeto JSON, valida después sus campos y valores. Una opción del formulario o una respuesta de aspecto correcto no sustituye esa comprobación.
Como lectura complementaria, el caso JSON del museo examina la validación de salidas, y la guía de resumen de soporte prepara otra clase de entrada restringida. Este flujo de facturas aporta conciliación aritmética, sin repetir sus comprobaciones de extracción o privacidad.
Compara las dos filas de tarifas publicadas por Orux
El catálogo público del 2 de noviembre de 2026 contiene dos filas dailytimeband para este alias. La tabla solo utiliza las tarifas de entrada sin caché y salida. No presupone que una factura repetida reciba precio de caché ni deduce del reloj qué franja se aplica a una cuenta. Confirma el presupuesto actual y las condiciones aplicables antes de autorizar una solicitud.
| Condición publicada | Credits de entrada / 1M tokens | Credits de salida / 1M tokens | Plan: 1 000 de entrada + 300 de salida |
|---|---|---|---|
dailytimeband=offpeak | 18.33336 | 73.33344 | 0.040334 Credits |
dailytimeband=peak | 36.66672 | 146.66688 | 0.080667 Credits |
Desliza horizontalmente para ver toda la tabla.
La última columna es un cálculo de planificación, no uso de tokens medido ni una factura prometida. El programa redondea cada solicitud prevista hacia arriba a un micro-Credit entero. Mil solicitudes con exactamente esas cantidades supondrían, bajo esa convención, 40.334 u 80.667 Credits. El uso real, las condiciones o intentos adicionales cambian el resultado. No se midió ningún cargo de cuenta para este artículo.
La página de precios del proveedor describe sus propias versiones y horarios. Esas condiciones no establecen el horario ni el presupuesto de una cuenta Orux. No afirmamos que este flujo supere la precisión de otro modelo con facturas ni que un servicio sea más barato en todas las condiciones. El calculador permite inspeccionar un plan explícito antes de cualquier solicitud opcional.
Conserva conciliación, redacción y aprobación por separado
Guarda el CSV original, su total declarado, el informe de excepciones y la corrección aprobada. Ejecuta de nuevo el verificador con los datos corregidos y registra el documento exacto suministrado al paso opcional del modelo. Así mantienes la diferencia entre lo escrito por el proveedor, lo calculado por el programa y lo aprobado por una persona. Un acuse generado no debe sobrescribir ninguno de esos registros.
Si la redacción añade una fecha de pago, datos bancarios, referencia o aprobación no autorizados, rechaza esa adición y resuélvela con la persona responsable. La guía no presenta un ejemplo generado ni afirma que un prompt concreto evite esas adiciones. Su aportación terminada es el control aritmético local y su evidencia reproducible, preparados para una comunicación revisada por separado.
Precios y formulario comprobados el 2026-11-02. Fuentes: modelo Orux, catálogo público, CSV de Python, tipos numéricos Python, referencia DeepSeek, precios DeepSeek.
FAQ
¿Un total coincidente demuestra que todas las líneas son correctas?
No. El total mostrado coincide con las líneas indicadas aunque L3 incumple cantidad por precio unitario. Compara los importes calculados independientemente por línea además del total general. El programa identifica esa contradicción exacta; una persona debe determinar qué valor de origen corregir.
¿DeepSeek encontró la diferencia de USD 10?
No. La encontró el programa Python local y no se llamó a ningún modelo. DeepSeek es un paso opcional posterior de redacción, con controles actuales de Orux verificados y tarifas de planificación fechadas. El artículo no evalúa su precisión en facturas, calidad, latencia ni fiabilidad.
¿Puedo usarlo para impuestos o varias monedas?
No bajo el contrato actual. Cubre cantidades enteras positivas e importes USD sin signo y con dos decimales, sin lógica fiscal, descuentos ni conversión. Amplía y prueba explícitamente esas reglas con la especificación contable aprobada correspondiente, en vez de eliminar filas incómodas o adivinar una convención regional.
¿Los Credits de la tabla son el precio de comprobar este CSV?
No. Ejecutar el verificador local no hace solicitudes a Orux ni consume Credits del sitio. La tabla estima una solicitud posterior opcional con cantidades de tokens supuestas. El uso real del modelo y el presupuesto vigente aplicable determinan el cargo, no el número de filas CSV.
¿Qué debe revisarse antes de enviar un acuse generado?
Contrástalo con la corrección aprobada y la autoridad real para comunicar. Un total conciliado no autoriza un pago ni una fecha. Conserva el informe de origen por separado, rechaza detalles sin respaldo y confirma referencia y destinatario antes de enviar cualquier mensaje.
Usa estos modelos con una sola API
Una API compatible con OpenAI para modelos de chat, imagen, vídeo y audio, facturada en Credits.
Artículos relacionados
Ver todos los artículos →
gpt-6-luna: preparar un resumen sin mensajes originales
Prepara 4 consultas para gpt-6-luna sin mensajes brutos. Incluye lista de permitidos, Python local, JSON real, casos rechazados y tarifas Orux Credits.

Calculadora de costes RAG con Qwen3: embeddings y candidatos de reranking
Compara el coste de 20, 50 y 100 candidatos con los precios de Orux en Credits, estimaciones en USD y una calculadora Python offline verificada.

Extracción JSON con Claude: null, cero, conflictos y un validador ejecutable
Dos llamadas reales sobre cuatro registros ficticios detectan nombres abreviados y comprueban una corrección. Incluye JSON completo, código Node y nueve errores rechazados.