QC 자동화 포스트모템
— 비싸게 배운 싼 정답
구독자는 아직 25명, 운영자는 혼자, 게다가 저는 일본어가 N5~N4 수준이라 제가 만든 콘텐츠를 직접 검수하지도 못합니다. 맡길 사람도, 고용할 돈도 없었습니다. 하지만 틀린 해설 한 줄은 그대로 사용자에게 전달됩니다. 그래서 퀴즈 7,500문항·단어 15,000개를 사람 없이 검수하는 길을 팠고 — 이건 fine-tuning과 LLM 판사에 돈을 쏟은 끝에 "구조는 공짜 린터, 의미는 코딩 에이전트"라는 싼 정답에 도달한 기록입니다. 그리고 그 길에서 "크레딧이 남아 있으니 괜찮겠지"가 ₩87만 청구로 돌아온 이야기이기도 합니다.
00왜 만들었나
솔직히 말하면, 저 자신이 일본어가 N5~N4 수준입니다. 정작 제가 만든 콘텐츠의 해설이 맞는지, 문장이 자연스러운지 스스로 검증할 수가 없습니다. 그렇다고 검수를 맡길 사람을 고용할 여력도, 도와줄 사람도 없었습니다. 개인이 혼자 운영하는 앱이니까요.
그러니 선택지가 없었습니다 — 사람이 못 하면 기계가 해야 했습니다. 목표는 단순했습니다: 퀴즈 7,500문항·단어 15,000개를 사람 손 거의 없이 내부 품질 기준 4.5점 이상으로. 문제는 "어떻게"였고, 일본어를 모르는 제가 처음 잡은 답이 "그럼 똑똑한 AI한테 다 맡기자" — fine-tuning + LLM 판사였습니다. 결과적으로 그게 비싼 길이었습니다.
- 구조적 결함(중복 보기, 깨진 포맷, 정답 인덱스 오류)은 결정론 린터로 공짜로 잡힌다. LLM 불필요.
- 의미적 결함(부자연스러운 문장·해설·오역)은 모델이 필요하다. 단 judge로 재판정하지 말고 수정 에이전트를 신뢰하라 — ground truth 없는 영역을 동급 모델이 다투면 무한 핑퐁.
- 비싼 탐색의 진짜 산출물은 "수정된 데이터"가 아니라 "무엇을 검사할지에 대한 지식"이다. 그 지식을 결정론 규칙으로 굳히는 순간 비용은 0이 된다.
- 그리고 가장 비싼 교훈: 클라우드 "크레딧 잔액"은 SKU 단위로 적용된다. 이름만 보고 튜닝을 돌리면 안 된다.
01일자별 타임라인
아래 날짜는 git 커밋·CHANGELOG·학습 로그 기준 실측입니다. (전부 2026년 5월에 일어난 일 — 이 작업은 그 이전에 시작하지 않았습니다.)
맨손 검수 시절
admin에 Gemini/GPT "단건 AI 검수" 버튼을 붙여 손으로 한 문항씩 돌리던 단계(2025-10). 2026-04-26~30에 검수 페이지(단일 문항 모드·백업/undo·품질 점수)를 정비. 아직 자동화는 아님.
QC 자동 파이프라인 착수
광역 스캔 + 정적 린터 + sonnet judge 도입(Plan A). "AI한테 검수를 맡긴다"가 본격 시작된 날.
ft v1 · v2 학습
Vertex AI Gemini 2.5 Flash 파인튜닝 시작. v1 712건(jobId 765240009665019904), v2 1,244+139건(jobId 4038002340437950464). "전용 모델이면 싸게 검수되겠지"라는 가정.
품질 자동화 + 일일 검수 cron
콘텐츠 품질 린터 + 매일 04:00 무인 린트. 단어 9,348→15,310개 확장. 여기 이미 "공짜 린터($0)"의 씨앗이 있었는데, 정작 더 비싼 쪽으로 달리는 중이었다.
복수정답 대입 검증 엔진 + 피드백 자동 폴리싱
빈칸에 각 보기를 AI로 대입해 복수정답을 찾는 멀티모델 cascade. 피드백 30분 배치 파이프라인.
ft v3 학습+배포 (정점)
1,865건 학습(endpoint 3309908781361528832). 복수정답 749→1건(99.9%). 전수 sweep. CHANGELOG에 "ft v3 학습 ~$5"로 기록 — 이 추정이 한참 빗나갔다는 건 며칠 뒤 결제 메일로 알게 된다.
Snowball QC 엔진 대폭발
이름부터 거창했습니다 — "검수→수정→검토, 돌릴수록 비용↓·품질↑·엔진강화"라는 스노우볼 서사. 무인 데몬이 2시간마다 샘플을 뽑고, confident learning·weak-supervision·자동 revert·RAG까지. 5/29 하루에만 QC 커밋 69건. 밤새 데몬을 굴리며 "이게 굴러간다"고 뿌듯해하던 그때, sonnet 판사 호출이 매일 조용히 새고 있었습니다.
대전환
"구조는 엔진이, 자연스러움 판단은 코딩 에이전트(Codex)를 믿어보자" 한마디에서 시작. 엔진=탐지 전용($0), ft/sonnet 봉인, Codex 협업 하네스(Issue→PR→린터 게이트), 데이터 git 추적, 데몬 누수 차단, ft 엔드포인트 전부 undeploy.
지금 — 에이전트 2개로 검수
Codex가 고치고 Claude가 검수(머지/반려)하는 흐름으로 운영. 같은 날, GCP ₩500,000 결제 메일을 받고 Google Cloud Support 케이스를 열었습니다(아래 02장). 비싼 길을 한 바퀴 다 돌고 나서야 싼 정답이 보였습니다.
02크레딧 착시 — ₩87만의 교훈
이 글을 공개하는 가장 큰 이유입니다. 다른 분들은 같은 실수를 안 하시도록.
Google Cloud Billing 화면에 GenAI App Builder Trial Credit 잔액이 남아 있었습니다. 이름이 "GenAI"라서, 저는 이 크레딧이 Vertex AI 파인튜닝이나 Gemini 비용에도 당연히 적용될 거라 생각했습니다. 그 믿음으로 일본어 데이터 검수를 위해 Gemini 2.5 Flash tuning을 마음껏 돌렸습니다.
며칠 뒤 "₩500,000 결제 적용" 메일이 왔습니다. Billing을 열어보니 2026-05-01~26 사이에 약 ₩874,192가 발생해 있었고, 그중 ₩500,000이 이미 청구된 상태였습니다. 내역은:
- Gemini 2.5 Flash tuning SKU ≈ ₩787,525 (대부분이 모델 튜닝 그 자체)
- prediction / API 호출 ≈ ₩86,667
크레딧은 한 푼도 적용되지 않았습니다. Google Cloud Support(상담사 Vivian)의 최종 확인:
GenAI App Builder Trial Credit은 "Vertex AI Search" 전용 크레딧이며, Vertex AI · Gemini API · Gemini 2.5 Flash tuning SKU에는 적용되지 않습니다. Billing 화면에 크레딧 잔액이 보여도, 그게 모든 Google Cloud AI 서비스에 자동 적용된다는 뜻은 아닙니다.
심지어 상담 도중 지원 답변끼리 서로 충돌하기도 했습니다 — 한 답변은 "tuning에 적용 안 됨", 다른 답변은 "서비스 제한 없이 적용되어야 함". 결국 사람 상담사에게 다시 연결돼 "Search 전용"으로 정리됐습니다. 이 혼선 때문에, Vivian은 일반적인 dispute는 어렵지만 one-time service adjustment를 내부팀에 요청하겠다고 했습니다(케이스 #71690027). 확정된 환불이 아니라 검토 단계이며, 조정 금액이 전체보다 적을 수 있고 남은 잔액은 제 책임이라고 안내받았습니다.
튜닝 이후 비용에 대한 안내도 정리해 둡니다(같은 함정을 피하시도록):
- 튜닝된 모델을 보관하는 것 자체엔 별도 유지비·저장비가 없음.
- tuned model이 Endpoint에 배포돼 있어도, API 호출이 없으면 고정 시간당/월간 유지비는 없음. 비용은 prediction/호출량에 따라 발생.
- 그래도 안 쓸 거면 Endpoint에서 undeploy가 안전(실수 재배포·재호출 차단).
- Budget alert는 반드시 설정하되, GCP엔 예산 초과 시 자동 차단 기능이 없음 — 실제 차단은 별도 자동화/권한 제한이 필요.
- 지금 보유한 크레딧이 어떤 서비스/SKU에 적용되는지 (이름 말고 SKU로 확인)
- Gemini tuning SKU에 그 크레딧이 실제로 적용되는지
- 튜닝 예상 비용 추산 (tuning은 한 번에 수십만 원 단위로 튐)
- Budget alert 설정 — 단, 알림일 뿐 차단은 아님
- 튜닝 후 남은 Endpoint / API 호출 점검 → 안 쓰면 undeploy
03비용 회고 (대시보드 실측)
| 출처 | 용도 | 실측 |
|---|---|---|
| Google Vertex AI | Gemini 2.5 Flash 파인튜닝/추론 | 2026-05-01~26 ₩874,192 (tuning ₩787,525 + prediction ₩86,667). ₩500,000 청구됨. 크레딧 미적용. |
| Anthropic | sonnet judge (QC 엔진) | 이번 달 약 $313 (~₩430k). 자동 충전이 켜져 있어 조용히 누적됨. |
| OpenAI | 멀티모델 cascade + 서버 gpt-4o-mini | 5월 인보이스 합 약 $225 (~₩310k). 이후 구독 전환으로 종량 차단. |
| 합계 (2026-05) | 3사 합산(대략) | 약 ₩1.6M (~$1,200) |
CHANGELOG에 ft v3 학습을 "~$5"로 적어 뒀습니다. 엔진이 보고하는 LLM API 비용(복수정답 수정 ~$30, ft 학습 ~$5)만 보고 "싸게 했다"고 믿었던 거죠. 정작 큰 돈은 그 숫자가 닿지 않는 곳 — Vertex 튜닝 SKU(₩787,525)와, 안 쓰는데도 켜져 있던 엔드포인트 —에 있었습니다. "내 코드가 보고하는 비용"과 "결제 화면의 비용"은 다른 숫자입니다.
04자산 vs 낭비 (정직하게)
| 지출 | 판정 | 이유 |
|---|---|---|
| sonnet judge 탐색 ($300대) | 자산 | 결함 패턴 27종 + 린터 룰을 만듦 = 지금 공짜 엔진의 설계도. 지금도 PR 반려 근거로 쓰임. |
| ft v1·v2·v3 학습 (Vertex ₩87만) | 부분 자산 | 복수정답 749→1 성과는 진짜. 단 재학습은 동결, 크레딧 착시로 비용은 예상보다 큼. |
| 안 쓰는 엔드포인트 배포 유지 | 낭비 | 엔진이 ft를 더 안 쓰는데도 배포가 남아 있었음. 2026-05-30 전부 undeploy. |
| 무인 데몬의 반복 sonnet 호출 | 낭비 | 자산화 안 되는 반복 소비. "켜두면 알아서"의 대가. 차단. |
05지금의 구조
[탐지] 엔진 = 결정론 린터(무료, 외부 API 0) → 전수 린트 → "학습자 혼란" 구조 결함만 → GitHub Issue 자동 발행
[수정] Codex(코딩 에이전트, 정액 구독) → worktree 격리 작업 → 의미·자연스러움 수정 → PR
[검증] 별도 에이전트가 PR을 읽어 정답·복수정답·해설 동기화를 판정 + 구조 린터 회귀 게이트 → 머지/반려 → 배포
퀴즈 1,336개 파일을 $0에 전수 린트해 구조 결함을 탐지하고, 의미 결함은 코딩 에이전트가 고치고 다른 에이전트가 검수합니다(추가 종량 $0, 정액 구독 한도 내). 실전 검증: 자동 린터 게이트가 코딩 에이전트의 실제 회귀(보기 한국어 중복)를 머지 전에 잡아냈고, 검수 에이전트가 정답 오류·복수정답·해설 desync가 든 수정 PR을 반려해 되돌렸습니다. 두 에이전트가 서로를 견제하는 것만으로 충분했습니다.
06전수 가능한 교훈
- 결정론 먼저, LLM 마지막. 검사 항목을 "기계 판정 가능 / 판단 필요"로 나눠라.
- 비싼 탐색의 산출물은 "규칙"이다. 모델이 찾은 패턴을 결정론 룰로 굳혀라. 안 굳히면 매번 돈 내고 재발견한다.
- fixer를 judge로 재심하지 마라. ground truth 없는 영역은 동급 모델 재심 = 핑퐁. 객관 게이트(린터 회귀)만 하드룰로, 의미는 "에이전트 2개 교차검증"으로 충분했다.
- "에이전트 2개면 됐을 걸"을 더 일찍 시험하라. 무인 LLM 자동화 엔진을 짓기 전에, 싸고 단순한 교차검증부터 돌려봤어야 했다.
- 클라우드 크레딧은 SKU 단위로 적용된다. "GenAI" 같은 이름만 보고 튜닝을 돌리지 마라. 잔액 표시 ≠ 내 작업에 적용.
- 배포된 모델 엔드포인트는 안 써도 호출이 남으면 청구된다. 안 쓰면 undeploy — 가장 흔한 클라우드 누수.
- "내 코드가 보고하는 비용"을 믿지 말고 결제 화면을 봐라. Budget alert는 알림일 뿐 자동 차단이 아니다.
- 무인 운영 비용을 매일 감사하라. "켜두면 알아서"가 가장 비싸다.
07논문을 실제로 엔진에 넣어본 경험
이 논문들은 인용만 한 게 아닙니다. 2026-05-29, "QC 엔진 v2"를 만들면서 직접 코드로 구현했습니다. 일본어를 검증 못 하니, 학계가 "정답 없이 데이터 오류를 찾는" 문제를 어떻게 푸는지 그대로 가져오려 했어요:
- Confident Learning (cleanlab) →
qc-error-miner서비스. "겉보기엔 정상인데 라벨이 틀렸을 확률이 높은 항목"을 점수화. - Weak Supervision / Snorkel + Data Programming →
qc-weak-supervision. 린터·스키마검사·mixed-token 검출·LLM judge를 "약한 신호"로 보고 결합. - Dawid–Skene → 검출기마다 신뢰도를 다르게(스키마 린터 ≈ 거의 확실, LLM judge ≈ 가끔 틀림) 주는 구조.
- LLM-as-a-Judge / G-Eval / MT-Bench →
qc-gold-eval골드셋 보정 하네스. judge를 그대로 안 믿고 기준표로 캘리브레이션.
이걸 tools/qc-pipeline.mjs로 한데 묶고 docs/snowball-qc-v2.md 설계문서까지 썼습니다. 그런데 실제로 굴려보니 — 우리 데이터엔 과했습니다. 7,500문항은 ML 벤치마크처럼 거대하지도, 라벨이 마구 섞여 있지도 않았어요. 구조 오류는 결정론 린터가 확률 앙상블보다 싸고 확실하게 잡았고, 정작 의미 탐지에 쓴 LLM judge 앙상블이 바로 그 비싼 부분(데몬이 매일 새던 sonnet 호출)이었습니다.
그래서 결론은 역설적입니다 — "약한 신호를 결합한다"는 Snorkel의 문제 정의는 옳았지만, 그 풀 머신러닝 머신은 우리 규모엔 과했습니다. 우리에게 필요한 신호는 "확률 앙상블"이 아니라 "결정론 린터 1개 + 에이전트 판단 1개"로 충분했어요. 위 qc-* 서비스들은 지금도 코드에 남아 있되 운영 경로에선 빠졌습니다 — 탐색의 화석이자, "이론을 일단 끝까지 만들어봤기에 무엇이 과한지 알게 된" 증거입니다. 논문은 해답이 아니라 문제를 보는 틀을 줬습니다.
- Ratner et al. (2018). Snorkel: Rapid Training Data Creation with Weak Supervision. VLDB.
arXiv:1711.10160 - Ratner et al. (2016). Data Programming: Creating Large Training Sets, Quickly. NeurIPS.
arXiv:1605.07723 - Dawid & Skene (1979). Maximum Likelihood Estimation of Observer Error-Rates Using the EM Algorithm. JRSS-C.
- Northcutt et al. (2021). Confident Learning: Estimating Uncertainty in Dataset Labels. JAIR.
arXiv:1911.00068 - Northcutt et al. (2021). Pervasive Label Errors in Test Sets Destabilize ML Benchmarks. NeurIPS.
arXiv:2103.14749 - Zheng et al. (2023). Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena. NeurIPS.
arXiv:2306.05685 - Liu et al. (2023). G-Eval: NLG Evaluation using GPT-4 with Better Human Alignment. EMNLP.
arXiv:2303.16634 - A Survey on LLM-as-a-Judge (2024).
arXiv:2411.15594
08한 줄 결론
비싸게 한 바퀴 돌아 싼 정답을 찾았습니다. 탐색비는 규칙으로 굳어 자산이 됐지만, "이거 그냥 린터로 되는 거 아냐?"와 "에이전트 둘이면 되는 거 아냐?"를 더 일찍 물었어야 했고, 안 쓰는 엔드포인트는 더 일찍 껐어야 했고, 크레딧은 이름이 아니라 SKU로 확인했어야 했습니다. 구독자 25명이라도, 그 25명이 보는 데이터의 품질은 타협하지 않습니다. 다만 이제는 그 품질을 LLM 종량제 반복 호출이 아니라, 결정론 린터와 검증 가능한 PR 흐름으로 지킵니다. 그리고 이 기록을 공개하는 이유는 하나 — 다른 분들은 이 학습비를 안 내셔도 되도록.