AI가 '처리 완료'라고 한 합계가 틀렸을 때: 손 계산과 행 수 대조로 잡는 방법
AI가 써 준 스크립트가 "처리 완료"라고 출력해도 합계가 맞다는 뜻은 아닙니다. 아래 예시(AI가 써 줬다고 가정하고 직접 만든 스크립트)에서는 7행짜리 매출표를 읽고 "처리 완료: 5행, 합계 90,500원"이라고 출력했는데, 손으로 더하면 57,500원입니다. 오류 메시지는 한 줄도 없었습니다. 이런 경우를 잡는 데는 세 가지면 충분했습니다. 값 몇 개를 손으로 더해 비교하고, 입력 행 수가 "계산한 행 + 일부러 뺀 행"과 같은지 보고, 일부러 틀린 입력을 하나 넣어 보는 것입니다.
왜 '완료'가 증거가 못 되는가
AI가 낸 "완료했습니다"는 코드가 끝까지 돌았다는 뜻이지 결과가 맞다는 뜻이 아닙니다. 글쓴이의 작업 기록에도 같은 모양이 여러 번 있었습니다.
- 장부를 합치는 프로그램을 118가지 입력으로 시험했더니, 프로그램 자체의 점검 항목은 0건이라고 했는데도 합계에서 빠진 줄이 13건 나왔습니다. 날짜가 글자로 저장된 줄과 구분 이름이 비어 있는 줄이 월별 합계에서 조용히 빠졌습니다.
- 합계 줄이나 소계 줄이 날짜와 함께 들어 있으면 안내 없이 매출에 한 번 더 더해지는 결함이 있었습니다. 시험 프로그램, 직접 재현, 별도 검수로 세 번에 나눠서 찾았고 한 번에 다 찾지는 못했습니다.
- 시장 조사에서 "경쟁 상품 4개"라고 정리한 것이 검색 범위를 넓혀 다시 세어 보니 127개였습니다. AI 초안을 원문과 대조했을 때 "요금 정보를 못 찾음"이라고 적은 항목이 틀린 경우도 있었습니다.
- AI 초안의 설명 문장 중 하나는 "합계가 맞지 않는 세 경우"라고 했는데 실제로는 그중 한 시트의 합계가 맞았습니다. 실행해 보지 않은 문장은 확신이 없어서 글에서 뺐습니다.
모두 겉으로는 정상 종료였습니다. 오류가 났다면 오히려 쉽게 찾았을 것입니다.
예시: 5행, 90,500원
예시 파일은 날짜, 품목, 금액 세 열입니다. 금액 중 두 칸은 15,000처럼 쉼표가 들어간 글자이고, 마지막 줄은 엑셀에서 흔히 넣는 합계 줄입니다. 파일은 openpyxl로 만들었습니다.
AI가 이런 식으로 써 줬다고 가정한 스크립트입니다.
import pandas as pd
df = pd.read_excel("sales.xlsx")
df["금액"] = pd.to_numeric(df["금액"], errors="coerce")
df = df.dropna(subset=["금액"])
print(f"처리 완료: {len(df)}행, 합계 {df['금액'].sum():,.0f}원")
실행 결과입니다.
처리 완료: 5행, 합계 90,500원
표를 눈으로 보면 이상한 점이 바로 보입니다. 입력은 7행인데 5행을 처리했고, 합계가 개별 금액을 다 더한 값보다 큽니다. 하지만 "처리 완료"라는 말을 믿고 넘어가면 이 차이를 볼 일이 없습니다.
1단계. 손으로 몇 개 더해 본다
금액 칸을 다 더할 필요는 없습니다. 눈에 보이는 개별 줄 6개를 직접 더해 봤습니다.
12000+8000+15000+6000+9500+7000 = 57500
AI 스크립트의 90,500원은 손 계산 57,500원과 33,000원 차이가 납니다. 이 한 번의 계산으로 "합계 값을 믿으면 안 된다"는 것은 확인됩니다. 어디가 틀렸는지는 아직 모릅니다.
2단계. 행 수를 맞춰 본다
원인은 '입력 행 수 = 계산에 쓴 행 + 일부러 뺀 행 + 읽지 못한 행'이 맞는지 보면 잡힙니다. 이 식이 안 맞는 곳에서 무엇이 빠졌거나 더해졌는지 찾을 수 있습니다. 칸의 값 형태를 같이 찍어 봤습니다.
import pandas as pd
raw = pd.read_excel("sales.xlsx")
print("입력 행수:", len(raw))
print("금액 칸 타입:", raw["금액"].map(type).value_counts().to_dict())
num = pd.to_numeric(raw["금액"], errors="coerce")
print("숫자로 못 바뀐 행:"); print(raw[num.isna()])
입력 행수: 7
금액 칸 타입: {<class 'int'>: 5, <class 'str'>: 2}
숫자로 못 바뀐 행:
날짜 품목 금액
2 2026-10-02 사과 15,000
4 2026-10-03 배 9,500
원인이 두 개로 갈렸습니다.
15,000과9,500은 글자라서errors="coerce"가 조용히 빈 값으로 바꾸고,dropna가 그 줄을 지웠습니다. 두 줄, 24,500원이 사라졌습니다.합계줄 57,500원은 숫자이므로 그대로 더해졌습니다.
계산하면 33,000(AI가 더한 개별 줄 4개) 위에 57,500(합계 줄)이 얹혀 90,500이 됩니다. 첫 번째 함정은 pandas to_numeric Unable to parse string '1,000' 오류: errors='coerce'로 없애면 금액이 사라집니다 글에서 따로 다뤘습니다.
3단계. 같은 점검을 코드 안에 넣는다
고친 스크립트는 결과를 내기 전에 행 수 식을 직접 출력합니다. 이렇게 하면 다음에 입력이 바뀌어도 어긋난 곳이 바로 보입니다.
import pandas as pd
raw = pd.read_excel("sales.xlsx")
sub = raw["품목"].astype(str).str.contains("합계|소계")
body = raw[~sub].copy()
amount = pd.to_numeric(body["금액"].astype(str).str.replace(",", ""), errors="coerce")
bad = body[amount.isna()]
print(f"입력 {len(raw)}행 = 계산 {amount.notna().sum()}행 + 합계 줄 {sub.sum()}행 + 읽지 못함 {len(bad)}행")
if len(bad): print(bad)
print(f"합계 {amount.sum():,.0f}원 (파일의 합계 줄 값: {raw.loc[sub,'금액'].sum():,.0f}원)")
입력 7행 = 계산 6행 + 합계 줄 1행 + 읽지 못함 0행
합계 57,500원 (파일의 합계 줄 값: 57,500원)
손 계산 57,500원과 일치하고, 파일에 적힌 합계 줄과도 같습니다. 읽지 못한 행이 있으면 0으로 처리하지 않고 목록으로 보여 줍니다. 합계 줄을 합계|소계 낱말로 찾는 방식은 이 예시에서만 확인했습니다. 총합, Total, 건수 같은 줄은 못 잡을 수 있어서, 합계 줄이 있는 파일이라면 낱말 목록을 파일에 맞게 고치고 마지막에 "파일의 합계 줄 값"과 비교해야 합니다. 글쓴이가 만든 합계 프로그램도 처음에는 합계, 소계만 걸렀고, 시험에서 총합, 합계:, Total:, 누적 같은 줄이 더해지는 것이 나온 뒤 낱말을 늘렸습니다. 상품 코드와 구별되지 않는 건수 줄은 끝까지 못 잡아서 날짜 칸을 비워 두라고 안내하는 것으로 남겼습니다.
4단계. 일부러 틀린 입력을 넣는다
점검 코드가 정말 도는지도 확인해야 합니다. 정상 파일에서만 시험하면 점검이 아무 일도 안 해도 모릅니다. 위 예시처럼 쉼표가 든 글자 금액, 합계 줄, 날짜가 빈 줄을 일부러 넣은 파일을 만들어 점검이 숫자를 내는지 봅니다. 위에 적은 사례도 점검 결과 0건이라는 말이 틀렸다는 것을, 장부 3종에 118가지 입력을 넣어 본 뒤에야 알았습니다.
매번 AI에게 시킬 때 쓰는 요청 문구
코드를 부탁할 때 처음부터 아래 문장을 붙여 점검 줄을 함께 요청합니다. AI 도구마다 받는 코드는 다르니, 받은 뒤에는 4단계처럼 틀린 입력을 넣어 점검 줄이 실제로 반응하는지 보세요.
결과를 출력할 때 "입력 N행 = 계산 A행 + 제외 B행(이유별) + 읽지 못함 C행"을 함께 출력해 주세요.
읽지 못한 값은 0으로 바꾸거나 지우지 말고 목록으로 보여 주세요.
정리
- 합계는 손으로 몇 줄만 더해서 비교합니다.
- 행 수 식이 맞는지 봅니다. 맞지 않는 곳에 빠졌거나 더해진 줄이 있습니다.
errors="coerce"와dropna가 같이 있으면 오류 없이 줄이 사라질 수 있습니다.- 점검 코드가 있어도 틀린 입력을 일부러 넣어 반응하는지 봅니다.