오늘은 영수증 사진이 쌓인 폴더를 넣으면 expense.csv, review-needed.json, 미리보기 HTML까지 뽑아주는 로컬 도구를 만듭니다. 완성되면 회계팀에 넘길 초안이 바로 생기구요. 지난 편에서 Git worktree로 안전 실험실을 만들었으니, 오늘은 그 안에서 진짜 회사 일을 하나 끝내보면 됩니다.
매달 구독료 내는 입장에선 영수증 한 장씩 엑셀에 옮기는 시간이 더 아깝더라구요. 이런 건 AI가 제일 잘하는 쪽입니다.
먼저 적고 시작할 감독 메모
업무를 한 번에 시키지 말고 산출물 이름부터 못 박습니다.
모르면 추측하지 말라고 적어야 숫자가 덜 망가집니다.
수정은 전체 재작성보다 한 줄 요구가 잘 먹힙니다.
마지막 검수는 다른 LLM에게 맡겨야 놓친 구멍이 보입니다.
오늘 쓸 두 도구
작업은 Codex CLI로 갑니다. 지금 문서 기준으로 Codex는 터미널에서 폴더를 읽고, 파일을 바꾸고, 명령을 실행할 수 있구요. 영수증처럼 이미지가 있으면 --image로 같이 넣을 수 있고, 자동화할 때는 codex exec --json으로 기계가 읽기 쉬운 결과를 받을 수 있습니다. 또 AGENTS.md를 먼저 읽고 시작하니 규칙 고정이 편합니다.
검수는 Claude Code로 붙입니다. Claude 쪽은 CLAUDE.md에 프로젝트 규칙을 남기거나, 이미 AGENTS.md를 쓰는 저장소라면 @AGENTS.md를 불러와 같은 규칙을 같이 읽게 만들면 됩니다. 마지막 확인은 claude -p처럼 짧은 검수 명령으로 돌리세요. Claude 쓰는 분은 이 흐름을 반대로 써도 됩니다. 오늘은 Codex가 만들고 Claude가 따지는 조합으로 갑니다.
손으로 하지 말고 흐름으로 묶기
1
결과물 이름부터 박아두기
AI에게 보낸 프롬프트
프로젝트 이름은 receipt-to-csv 입니다. Node.js 로컬 도구를 만들어 주세요. receipts/ 폴더의 jpg,png 영수증을 읽어 output/expense.csv, output/review-needed.json, preview/index.html을 생성합니다. 컬럼은 date,vendor,total,currency,vat,category,payment_method,confidence,source_file 입니다. 못 읽은 값은 추측하지 말고 null 로 두세요. 완료조건은 npm install 뒤 npm run demo 한 번으로 샘플 결과가 생기는 것입니다. 먼저 AGENTS.md 를 만들고, 그 다음 최소 파일만 생성해 주세요.
왜 이렇게 시켰나: 목표, 제약, 완료조건을 같이 넣어야 AI가 갑자기 대시보드 욕심을 부리지 않습니다. 파일명과 컬럼명을 먼저 박아두면 뒤에서 덜 흔들립니다.
이렇게 나오면 정상입니다. AGENTS.md, package.json, 샘플 폴더 구조가 먼저 잡혀 있습니다.
여기서 “보기 좋게 알아서” 같은 말만 쓰면 안 됩니다.
2
영수증 한 장으로 먼저 통과시키기
AI에게 보낸 프롬프트
sample1.jpg 한 장만 기준으로 추출 흐름을 연결해 주세요. Codex가 이미지에서 읽은 내용을 JSON으로 정리하고, confidence 가 낮은 필드는 이유를 같이 남겨 주세요. 날짜는 원문 그대로 두고, 통화는 KRW 같은 코드로 바꿔 주세요. 아직 배치 처리와 CSV 합치기는 하지 마세요.
왜 이렇게 시켰나: 처음부터 폴더 전체를 돌리면 어디서 틀렸는지 안 보입니다. 한 장만 통과시키면 필드 정의가 맞는지 바로 확인할 수 있죠.
이렇게 나오면 정상입니다. vendor, total, source_file 이 채워지고, 애매한 값은 confidence 와 함께 따로 표시됩니다.
여기서 낮은 confidence 값을 억지로 숫자로 채우면 안 됩니다.
3
배치 처리와 내보내기 붙이기
AI에게 보낸 프롬프트
이제 receipts/ 폴더 전체를 처리해 주세요. 정상 항목은 output/expense.csv 로 모으고, confidence 가 낮거나 필수값이 비어 있는 항목은 output/review-needed.json 으로 분리하세요. 콘솔에는 처리한 파일 수, 실패 수, 검수 필요 수만 짧게 보여 주세요. npm run demo 한 번으로 끝나게 스크립트를 정리해 주세요.
왜 이렇게 시켰나: 결과를 두 갈래로 나누면 바로 쓰는 파일과 사람이 보는 파일이 섞이지 않습니다. 실무에선 이 분리가 진짜 편합니다.
이렇게 나오면 정상입니다. CSV는 바로 열리고, review-needed 파일엔 애매한 영수증만 남습니다.
여기서 모든 예외를 한 파일에 덤프하면 안 됩니다.
4
한 군데만 집어서 고치기
AI에게 보낸 프롬프트
날짜 포맷만 YYYY-MM-DD 로 바꿔 주세요. VAT 가 안 찍힌 영수증은 vat 를 빈칸으로 두고 total 은 건드리지 마세요. 나머지 파일 구조와 컬럼 순서는 그대로 유지해 주세요. 마지막에 바꾼 이유를 5줄 이하로 적어 주세요.
왜 이렇게 시켰나: 수정 요청은 좁을수록 좋습니다. “전체적으로 더 정확하게”보다 “날짜만 바꿔”가 훨씬 덜 망가집니다.
이렇게 나오면 정상입니다. 날짜만 정리되고 CSV 구조는 그대로 남습니다.
여기서 여러 조건을 한 번에 더 얹으면 안 됩니다.
5
다른 LLM으로 검수 돌리기
AI에게 보낸 프롬프트
output/expense.csv, output/review-needed.json, 샘플 영수증 이미지를 보고 검수해 주세요. 잘못 뽑힐 가능성이 큰 행 5개만 골라 이유를 적어 주세요. 그다음 프롬프트를 어떻게 바꾸면 실수가 줄어드는지 수정안만 제안해 주세요. 코드 수정은 하지 마세요.
왜 이렇게 시켰나: 만드는 모델과 검수 모델을 분리하면 자기 실수를 자기 논리로 덮는 일이 줄어듭니다. 여기서 Claude를 쓰면 꽤 냉정하게 잡아줍니다.
이렇게 나오면 정상입니다. “이 행이 왜 위험한지”와 “프롬프트를 어떻게 바꿀지”가 같이 나옵니다.
여기서 바로 코드를 다시 맡기면 안 됩니다. 먼저 지시서를 고치세요.
막히는 지점 세 군데
총액과 VAT를 뒤집어 읽는 경우 — 프롬프트에 “vat 가 없으면 null, total 재계산 금지”를 넣으세요. 여기서 AI가 합계를 다시 계산하게 하면 안 됩니다.
상호명 대신 카드사명을 잡는 경우 — “merchant 우선, card issuer 는 payment_method 로”를 규칙에 추가하세요. 여기서 예시 없이 맡기면 안 됩니다.
CSV는 멀쩡한데 검수 파일이 비는 경우 — low confidence 기준을 숫자로 적으세요. 예를 들면 0.8 미만은 review-needed 로 보내라고 못 박으면 됩니다. 여기서 ‘애매하면’ 같은 말로 넘기면 안 됩니다.
여기서 한 걸음 더
한 걸음 더
시간이 남으면 review-needed.json만 다시 돌리는 재검수 명령을 붙여보세요. 그다음엔 이 CSV를 Google Sheets나 Notion DB로 넘기면 팀용 경비판이 됩니다. 다음 편은 여기서 바깥 서비스 하나 붙이는 흐름으로 넘어가도 재밌겠더라구요.