Uso de IA en el trabajo

Verificar código generado por IA con datos pequeños

Comprueba una función de agregación con cuatro filas que puedes calcular manualmente y 12 unit tests. Verifica no solo valores normales, sino también entrada vacía, cero, decimales y entrada no válida.

Ver el índice

La traducción se ha realizado con IA. Comprueba el código, las unidades y los valores junto con el original. La revisión por hablantes nativos de cada idioma aún no se ha completado. English

Para quién esPrincipiantes que dudan en utilizar código Python generado por IA en el trabajo solo porque se ejecuta

Preparación
  • Instala Python 3.12 o posterior y comprueba la versión en una terminal con python --version.
  • Extrae el ZIP del ejemplo en una carpeta nueva. No ejecutes el ejemplo desde dentro del archivo ZIP.
  • Abre una terminal en la carpeta que contiene example.py. Si el comando python no está disponible en Windows, utiliza py. En macOS o Linux, utiliza python3 si tu entorno lo requiere.
  • No se necesitan paquetes externos ni cuentas. Los archivos incluidos son datos sintéticos creados para este tutorial.

01Decidir la respuesta antes de ejecutar

Que el código de una IA termine sin errores no significa que el cálculo sea correcto. Este artículo no se conecta a un servicio real de IA; practica los pasos de verificación con una función de agregación escrita de forma independiente y datos sintéticos pequeños. Puedes aplicar el mismo método a una función que necesites revisar. No se necesita ninguna API key ni paquetes externos.

  1. Lee las cuatro filas de input.csv y calcula quantity × unit price por tu cuenta.
  2. Abre expected.json y comprueba que indique 4 rows, quantity 6 y amount 11101.50.
  3. Ejecuta el comando siguiente. Primero se ejecutan los 12 unit tests, seguidos de la CSV aggregation y la comparación con los expected values.
  4. Comprueba outputs/summary.json y verification.txt, que solo se crean cuando pasan todas las comparaciones.
bash
python example.py

02Comparar el cálculo de cuatro filas en una tabla

itemquantityunit_priceImporte por fila
노트22500.005000.00
31200.503601.50
노트12500.002500.00
Sample0999.990.00

Hay 4 rows, pero la total quantity es 2 + 3 + 1 + 0 = 6. El total amount es 5000.00 + 3601.50 + 2500.00 = 11101.50. La última fila, con quantity 0, sigue contando en el número de input rows. Por item, 노트 (notebook) tiene quantity 3 y amount 7500.00, 펜 (pen) tiene quantity 3 y amount 3601.50, y 샘플 (sample) tiene quantity 0 y amount 0.00.

Por tanto, no compares únicamente el total; observa conjuntamente row count, total quantity y per-item values. Introducir el mismo item en dos filas, como notebook, también permite comprobar grouping y summing. El orden de los per-item results está ordenado por name y no representa sales rank ni input order.

03Escribir las reglas de entrada que acepta la función

ElementoRegla permitidaEjemplo rechazado
ColumnTres: item, quantity, unit_priceColumns ausentes o adicionales
itemString no vacía después de eliminar los spaces iniciales y finalesString vacía o solo whitespace
quantityInteger string de 0 a 1,000,000-1, 1.5, 1e2
unit_price0 a 1,000,000,000, hasta dos decimalesNaN, Infinity, 0.001, 1,000

Se supone que los amounts utilizan la misma moneda ficticia. No se permiten negative quantities ni unit prices, por lo que no existe una regla para representar returns. Definir primero las input rules permite saber si el código cambia silenciosamente valores a 0 o salta algunas rows. Esta función se detiene con ValueError cuando encuentra una invalid row.

04Código completo con la agregación y las pruebas

aggregate_sales devuelve únicamente el result sin modificar las input rows. La lectura de archivos y la escritura de resultados están separadas en main. De esta manera, los tests pueden pasar small dictionaries directamente y comprobar solo el cálculo. Cada expected value se compara con assertEqual, y los values que deben rechazarse se comprueban con assertRaises.

example.py
"""집계 함수를 손계산 기대값과 unittest로 검증합니다. 외부 AI 호출은 없습니다."""

import argparse
import csv
import json
import re
import sys
import unittest
from decimal import Decimal
from pathlib import Path

BASE = Path(__file__).resolve().parent
OUTPUT = BASE / "outputs"
FIELDS = {"item", "quantity", "unit_price"}


def money(cents):
    return f"{cents // 100}.{cents % 100:02d}"


def aggregate_sales(rows):
    """문자열 딕셔너리 행을 검증하고 집계합니다. rows와 원본 파일을 변경하지 않습니다."""
    totals = {}
    row_count = total_quantity = total_cents = 0
    for number, row in enumerate(rows, start=1):
        if not isinstance(row, dict) or set(row) != FIELDS:
            raise ValueError(f"{number}행: item,quantity,unit_price 세 열이 필요합니다.")
        if any(not isinstance(value, str) for value in row.values()):
            raise ValueError(f"{number}행: 모든 값은 문자열이어야 합니다.")
        item, quantity_text, price_text = (row[key].strip() for key in ("item", "quantity", "unit_price"))
        if not item:
            raise ValueError(f"{number}행: 품목이 비어 있습니다.")
        if not re.fullmatch(r"[0-9]{1,7}", quantity_text):
            raise ValueError(f"{number}행: 수량은 0 이상의 정수여야 합니다.")
        quantity = int(quantity_text)
        if quantity > 1_000_000:
            raise ValueError(f"{number}행: 수량은 1,000,000 이하여야 합니다.")
        if not re.fullmatch(r"[0-9]{1,10}(?:\.[0-9]{1,2})?", price_text):
            raise ValueError(f"{number}행: 단가는 0 이상, 소수점 둘째 자리까지 입력하세요.")
        price = Decimal(price_text)  # 문자열에서 직접 생성해 float 오차를 피합니다.
        if price > Decimal("1000000000"):
            raise ValueError(f"{number}행: 단가는 1,000,000,000 이하여야 합니다.")
        cents = int(price * 100) * quantity
        bucket = totals.setdefault(item, {"quantity": 0, "cents": 0})
        bucket["quantity"] += quantity
        bucket["cents"] += cents
        total_quantity += quantity
        total_cents += cents
        row_count += 1
    return {
        "row_count": row_count,
        "quantity": total_quantity,
        "amount": money(total_cents),
        "by_item": [
            {"item": item, "quantity": totals[item]["quantity"], "amount": money(totals[item]["cents"])}
            for item in sorted(totals)
        ],
    }


def sale(item="펜", quantity="1", unit_price="1200.50"):
    return {"item": item, "quantity": quantity, "unit_price": unit_price}


class TestAggregate(unittest.TestCase):
    # 기대값은 검증 대상 함수로 만들지 않고 손계산한 상수로 적습니다.
    def test_empty_input(self):
        self.assertEqual(aggregate_sales([]), {"row_count": 0, "quantity": 0, "amount": "0.00", "by_item": []})

    def test_single_row(self):
        self.assertEqual(aggregate_sales([sale(quantity="3")])["amount"], "3601.50")

    def test_zero_quantity(self):
        result = aggregate_sales([sale(quantity="0")])
        self.assertEqual((result["row_count"], result["quantity"], result["amount"]), (1, 0, "0.00"))

    def test_repeated_item(self):
        result = aggregate_sales([sale(quantity="2"), sale(quantity="1")])
        self.assertEqual(result["by_item"], [{"item": "펜", "quantity": 3, "amount": "3601.50"}])

    def test_decimal_addition(self):
        result = aggregate_sales([sale(unit_price="0.10"), sale(unit_price="0.20")])
        self.assertEqual(result["amount"], "0.30")

    def test_whitespace(self):
        result = aggregate_sales([sale(item=" 펜 ", quantity=" 1 ", unit_price=" 2.00 ")])
        self.assertEqual(result["by_item"], [{"item": "펜", "quantity": 1, "amount": "2.00"}])

    def test_bad_quantity(self):
        for value in ("-1", "1.5", "", "1000001", "1e2", "1"):
            with self.subTest(value=value), self.assertRaises(ValueError):
                aggregate_sales([sale(quantity=value)])

    def test_bad_price(self):
        for value in ("-1", "0.001", "NaN", "Infinity", "", "1,000", "1000000001"):
            with self.subTest(value=value), self.assertRaises(ValueError):
                aggregate_sales([sale(unit_price=value)])

    def test_blank_item(self):
        with self.assertRaises(ValueError):
            aggregate_sales([sale(item=" ")])

    def test_wrong_columns(self):
        for row in ({"item": "펜"}, {**sale(), "extra": "x"}):
            with self.subTest(row=row), self.assertRaises(ValueError):
                aggregate_sales([row])

    def test_non_string(self):
        with self.assertRaises(ValueError):
            aggregate_sales([sale(quantity=True)])

    def test_upper_boundary(self):
        self.assertEqual(
            aggregate_sales([sale(quantity="1000000", unit_price="1000000000")])["amount"],
            "1000000000000000.00",
        )


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--test", action="store_true", help="단위 테스트만 실행합니다.")
    args = parser.parse_args()
    # unittest의 명시적 비교는 python -O에서도 생략되지 않습니다.
    result = unittest.TextTestRunner(verbosity=2, stream=sys.stdout).run(
        unittest.defaultTestLoader.loadTestsFromTestCase(TestAggregate)
    )
    if not result.wasSuccessful():
        return 1
    if args.test:
        return 0
    if OUTPUT.exists() or OUTPUT.is_symlink():
        raise FileExistsError("outputs가 이미 있습니다. 기존 결과를 옮긴 뒤 실행하세요.")
    with (BASE / "input.csv").open("r", encoding="utf-8-sig", newline="") as stream:
        reader = csv.DictReader(stream, strict=True)
        if reader.fieldnames != ["item", "quantity", "unit_price"]:
            raise ValueError("input.csv의 열은 item,quantity,unit_price 순서여야 합니다.")
        actual = aggregate_sales(reader)
    expected = json.loads((BASE / "expected.json").read_text(encoding="utf-8"))
    if actual != expected:
        raise ValueError("예제 집계가 expected.json의 손계산 기대값과 다릅니다.")
    OUTPUT.mkdir()
    with (OUTPUT / "summary.json").open("x", encoding="utf-8") as stream:
        json.dump(actual, stream, ensure_ascii=False, indent=2)
        stream.write("\n")
    with (OUTPUT / "verification.txt").open("x", encoding="utf-8") as stream:
        stream.write(f"unittest: {result.testsRun}개 통과\n예제 기대값: 일치\n외부 AI API 호출: 없음\n")
    print(f"완료: {actual['row_count']}행, 수량 {actual['quantity']}, 금액 {actual['amount']}")
    print(OUTPUT)
    return 0


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except (OSError, ValueError, csv.Error) as error:
        print(f"중지: {error}", file=sys.stderr)
        raise SystemExit(2)

El unit price se convierte en Decimal a partir de la string, se multiplica por 100 para convertirlo en integer units y después se suma. El amount resultante también se devuelve como una string con dos decimales. Es una elección adecuada para la two-decimal unit price rule del ejemplo, no una regla universal para todos los cálculos numéricos.

05Casos normales, límite y de error que comprueban los tests

CategoríaTests integradosQué comprueba
NormalOne row, repeated item, leading and trailing spacesCálculo básico y grouping
BoundaryEmpty input, quantity 0, upper limitDefiniciones en valores pequeños y grandes
Decimals0.10 + 0.20 = 0.30Representación y suma del amount
ErrorInvalid quantity, unit price, blank item, columns, typesLos invalid values no se aceptan silenciosamente

Comprueba ok junto a cada test name y, al final, ‘Ran 12 tests’ y ‘OK’. La comparación con los CSV expected values solo ha pasado si también aparece ‘완료: 4행, 수량 6, 금액 11101.50’ (Done: 4 rows, quantity 6, amount 11101.50). Si solo pasan los unit tests y el result difiere de expected.json, la ejecución por defecto falla y no guarda nuevos resultados.

bash
python example.py --test

--test repite únicamente los unit tests y no crea outputs. Puede utilizarse aunque ya exista una results folder, por lo que resulta adecuado para comprobaciones rápidas mientras editas la función. En cambio, el comando por defecto se detiene sin sobrescribir outputs existentes.

06Probar a crear una prueba fallida una vez

  1. Prepara una copia de example.py en una carpeta recién extraída. Conserva el archivo original para poder restaurarlo.
  2. En la calculation line int(price * 100) * quantity, elimina únicamente el último * quantity para crear un error que ignore quantity.
  3. Ejecuta python example.py --test y comprueba que fallen tests como one-row quantity 3 y repeated-item.
  4. Restaura la calculation line original y vuelve a ejecutar --test para comprobar que los 12 pasan.

El propósito de este experimento es confirmar que los tests detectan errores. Durante la creación de este ejemplo se introdujo el mismo tipo de error en una temporary copy para verificar que los tests fallaran y que no se escribieran resultados. Ver un fallo significativo una vez facilita evitar una situación en la que el test code se ejecuta pero no comprueba nada.

07Pasos para aplicarlo a una función obtenida de IA

Para código nuevo, fija primero ejemplos de input y output. Si alguna parte escribe en original files, limítala a copies y separa primero la función que realiza el cálculo. Prepara un conjunto de normal data, empty data, 0, repeated items y values que no deberían permitirse, y calcula tú mismo los expected values.

  1. Escribe las business rules de la función como frases. Por ejemplo, decide si returns se rechazan o se calculan como negative amounts.
  2. Escribe un small input y expected value para cada rule. Compara conjuntamente overall total y per-item results.
  3. Introduce el mismo input en la función que estás revisando y lee las differences de los results. No cambies primero los expected values para hacer desaparecer los fallos.
  4. Después de volver a ejecutar los existing tests con el revised code, conserva también los nuevos error cases en los tests.

Si sustituyes input.csv por tus propios data, también debes calcular y actualizar expected.json por separado. No concluyas que una diferencia con los expected values es un code defect después de cambiar solo el input. Comprobar qué rules y qué data cambiaron es el inicio de una reproducible verification.

08Leer el mensaje de fallo y acotar la causa

ResultadoSignificadoSiguiente comprobación
FAIL or FAILEDEl calculated result difiere del expected value del testLee el name del failed test y los dos values.
Stopped due to input rulesUn CSV value está fuera del allowed rangeComprueba la row indicada y los original data.
Differs from the hand-calculated expected valueLa CSV aggregation no coincide con expected.jsonVuelve a comprobar tanto si cambiaron los data como el hand calculation.
outputs already existsExiste un successful result anteriorEjecuta únicamente los checks con --test o mueve los results a otro lugar para conservarlos.

Superar los tests de este ejemplo es evidencia para las rules indicadas. No es una medida del performance de ningún AI model real ni una garantía de accuracy para todo el trabajo contable. Taxes, discounts, exchange rates, returns, multiple currencies y performance con large data necesitan rules y tests separados. Cuantos más failure cases añadas, más claramente podrás explicar el rango de aplicación.

Registro de ejecución y verificación

2026-09-19 · Windows 11 · CPython 3.12.14 · Sin paquetes adicionales · Ejecutado en una temporary copy de la distribución

  • Pasaron los 12 tests integrados de unittest
  • Las 4 rows del CSV sintético coinciden con el expected value calculado manualmente de 11101.50
  • Se detiene antes de crear resultados cuando input y expected values no coinciden
  • Los tests detectaron un calculation error deliberado que ignora quantity
  • Se confirmaron ejecuciones repetidas de --test y la conservación del SHA-256 original
Límites de la verificación
  • No se llamó a ninguna API real de IA.
  • No se incluyen tax, exchange rate, returns ni performance verification.
  • Resultados de ejecución en Windows CPython 3.12.14.

Criterios de redacción y verificación de todo el sitio

Archivos de ejemplo para ejecutar

Incluye código, datos de entrada e instrucciones de ejecución. Extrae el ZIP y lee primero README.txt.

Descargar ZIP de ejemplo

El código de ejemplo, los nombres de archivo y las claves de entrada se mantienen como en el original. Consulta también los comandos y los pasos de comprobación del texto traducido.

Material de práctica original · Guarda los archivos originales por separado antes de ejecutarlo.

Fuentes de referencia

Las explicaciones y los ejemplos son de elaboración propia. Puedes consultar los comportamientos y conceptos relacionados en las siguientes fuentes oficiales.