10만 건을 LLM으로 분류하고 $125를 썼다 — 가장 싼 호출은 하지 않은 호출이다
지금까지 이 시스템은 공시와 뉴스 104,659건을 LLM으로 분류했습니다. 다섯 달 동안 든 실비용은 $125.66 입니다. 하루 평균 800원 정도입니다.
전부 상용 API로 보냈다면 $786 이었을 겁니다.
차이를 만든 건 더 싼 모델도, 프롬프트 압축도 아닙니다. 호출을 하지 않는 것입니다.
문제의 모양
한국 시장에는 하루에 공시가 수백 건에서 천 건 넘게 올라옵니다. 이 중 주가에 의미가 있는 것은 극소수입니다. 나머지는 법이 내라고 해서 내는 행정 문서입니다.
문제는 읽기 전에는 어느 쪽인지 모른다는 것입니다. 그래서 처음엔 전부 LLM에 넣었습니다.
3/26 69건 $0.33
3/27 917건 $5.92
3/30 2,024건 $6.76 ← 하루 만원
하루 만 원이면 감당 못 할 금액은 아닙니다. 문제는 이 곡선이 오른쪽으로 갈수록 가팔라진다는 것이었습니다. 수집 소스를 늘릴수록, 시장이 바쁠수록 비용이 따라 올라갑니다. 개인이 혼자 굴리는 시스템에서 비용이 트래픽에 비례하면 확장을 스스로 막게 됩니다.
3단 라우팅
3월 30일에 구조를 바꿨습니다. 모든 입력이 같은 경로를 타지 않게 했습니다.
공시/뉴스 도착
│
├─ 1단 규칙 매칭? ──예──▶ 분류 확정, LLM 호출 없음 비용 $0
│ 아니오
├─ 2단 로컬 모델(EXAONE-32B) 분류 비용 $0
│ confidence ≥ 임계값 ──▶ 로컬 결과 채택
│ confidence < 임계값
└─ 3단 상용 API 승격 비용 발생
다섯 달치 실적은 이렇게 나뉩니다.
| 경로 | 처리 건수 | 비중 | 비용 |
|---|---|---|---|
| 1단 규칙 | 62,053 | 59.3% | $0.00 |
| 2단 로컬 모델 | 25,871 | 24.7% | $0.00 |
| 3단 상용 API | 16,735 | 16.0% | $125.66 |
전체의 84%가 돈을 쓰지 않고 처리됐습니다. API 호출 1건당 평균 $0.00751이니, 10만 건 전부를 3단으로 보냈다면 $786입니다.
1단이 이기는 이유
여기서 중요한 건 1단과 2단의 성격이 다르다는 점입니다.
2단(로컬 모델)은 하드웨어를 이미 샀기 때문에 공짜입니다. 한계비용이 0에 가까울 뿐 전기와 시간은 씁니다. 처리량 한계도 있습니다.
1단(규칙)은 일 자체를 하지 않습니다. 정규식 한 번이면 끝나고, 밀리초 단위이며, 처리량 한계가 사실상 없습니다. 그래서 어떤 항목을 1단으로 내릴 수 있으면 그건 언제나 이깁니다.
문제는 “규칙으로 내려도 되는가”를 어떻게 판단하느냐입니다.
여기서 제가 세운 기준은 문서 종류가 아니라 판단의 종류였습니다. “이 서식은 안 중요하다”가 아니라 “이 서식에서 중요한 경우는 텍스트에 반드시 특정 표현이 나타난다” 여야 규칙으로 내릴 수 있습니다.
정기보고서 규칙이 그렇게 생겼습니다.
// 정기보고서 (감사/사업/반기/분기보고서)
if (/감사보고서|사업보고서|반기보고서|분기보고서/.test(title)) {
// 감사의견에 이상이 있으면 규칙을 포기하고 LLM으로 넘긴다
if (/의견거절|한정의견|부적정의견|감사의견 거절|한정 의견/.test(text)) {
return null; // ← 탈출구
}
return { eventTags: ['정기보고서'], confidence: 0.1, ... }; // LLM 스킵
}
return null 한 줄이 이 설계의 전부입니다. 정기보고서는 대부분 아무 일도 아니지만, 감사의견 거절이 붙은 정기보고서는 그 회사에서 그 해에 벌어질 수 있는 가장 큰 사건입니다. 규칙이 그것까지 삼켜버리면 비용을 아끼는 대신 시스템의 존재 이유를 버리는 겁니다.
그래서 규칙은 “이 서식은 건너뛴다”가 아니라 “이 서식은, 중요해지는 조건이 없을 때만 건너뛴다” 로 씁니다. 조건은 규칙보다 훨씬 좁고 명시적이어야 합니다. 못 쓰겠으면 그 서식은 규칙 대상이 아닙니다.
결과: 같은 양, 1/7 비용
배포 전후 일주일입니다.
| 날짜 | 처리 건수 | API로 간 건수 | 비용 |
|---|---|---|---|
| 3/30 (도입일) | 2,024 | 1,874 | $6.76 |
| 3/31 | 1,770 | 647 | $4.43 |
| 4/01 | 1,766 | 243 | $1.64 |
| 4/02 | 1,936 | 175 | $1.22 |
| 4/06 | 1,860 | 140 | $0.97 |
처리량은 그대로입니다. 2,024건에서 1,860건. 그런데 비용은 $6.76에서 $0.97로 떨어졌습니다. 줄인 건 일의 양이 아니라 비싼 경로로 흘러간 비율입니다. API로 간 건수가 1,874 → 140으로 줄었습니다.
이 지점에서 제가 배운 것 하나. 비용을 토큰 단위로 보면 최적화할 게 별로 없습니다. 프롬프트를 30% 줄여봐야 30%입니다. 반면 호출 여부 단위로 보면 자릿수가 바뀝니다.
그리고 넉 달 뒤, 새는 곳을 찾았다
여기까지가 1막입니다. 2막은 이 구조가 조용히 새고 있었다는 이야기입니다.
규칙은 제가 아는 서식에만 붙습니다. 모르는 서식은 계속 2·3단으로 흘러갑니다. 그래서 정기적으로 비용을 서식별로 귀속시켜 봅니다. “얼마 썼나”가 아니라 “무엇에 썼나”를 묻는 것입니다.
SELECT si.title, COUNT(*), SUM(lr.cost_estimate_usd)
FROM llm_run lr JOIN source_item si ON si.id = lr.source_item_id
WHERE lr.model LIKE 'claude%'
GROUP BY 1 ORDER BY 3 DESC;
8월에 이걸 돌렸더니 두 서식이 위에 올라와 있었습니다.
| 서식 | 누적 건수 | 누적 비용 |
|---|---|---|
| 지급수단별·지급기간별 지급금액 및 분쟁조정기구에 관한 사항 | 999 | $6.56 |
| 동일인등출자계열회사와의 상품·용역거래(변경) | 889 | $6.22 |
| 합계 | 1,888 | $12.78 |
$12.78. 누적 분류비용의 10.2% 를 이 두 서식이 쓰고 있었습니다. 하도급법상 대금 결제조건 공시와 공정거래법상 대규모내부거래 의결 공시입니다. 둘 다 주가와 아무 관계가 없습니다.
더 나쁜 건 이겁니다.
이 1,888건 중 97.1%가 3단(상용 API)까지 올라갔습니다.
가장 지루한 문서가 가장 비싼 경로로 간 겁니다. 처음엔 이상해 보였는데, 생각해보면 당연합니다. 로컬 모델은 판단이 어려울 때 낮은 confidence를 냅니다. 그런데 정형 행정 문서는 “주가 영향이 없다”는 것이 명백한 게 아니라 판단할 내용 자체가 없습니다. 모델 입장에서 확신할 근거가 없으니 낮은 점수가 나오고, 그러면 자동으로 비싼 경로로 승격됩니다.
confidence 기반 라우팅은 “어려운 것”과 “내용이 없는 것”을 구분하지 못합니다. 그리고 후자는 규칙으로 잡아야 하는 것들입니다. 이 구조적 사각지대가 제가 이번에 실제로 배운 것입니다.
이틀 차이
규칙 2개를 추가해 8월 12일 저녁에 배포했습니다.
그런데 첫 번째 서식은 반기 종료 후 45일이 마감입니다. 그해 마감일이 8월 14일이었습니다.
| 날짜 | 해당 공시 유입 | 비용 |
|---|---|---|
| 8/12 (배포 전) | 316 | $2.02 |
| 8/13 | 568 | $0.00 |
| 8/14 (마감일) | 850 | $0.00 |
| 8/17 | 26 | $0.00 |
마감일에 850건이 한꺼번에 들어왔습니다. 배포 전 단가($0.00677/건)로 환산하면 그 하루에만 $5.75입니다. 제 운영 비용 상한은 일 $3인데, 그 두 배에 가깝습니다.
이틀 차이로 피했습니다. 자랑할 일은 아니고, 운이 좋았다고 쓰는 게 맞습니다. 8월 12일에 비용 귀속 쿼리를 돌린 건 계획된 점검이 아니라 다른 걸 보다가 눈에 걸린 것이었습니다.
효과를 얼마로 적을 것인가
여기서 숫자를 정직하게 쓰는 게 까다로웠습니다.
가장 쉬운 방법은 배포 전후 일평균 비용을 비교하는 것입니다.
배포 전 (8/3~8/12 평일) $1.574 / 일
배포 후 (8/13~8/21 평일) $0.685 / 일 → −56.5%
이 숫자를 그대로 쓰면 안 됩니다. 같은 시기에 하도급 공시 러시가 끝났기 때문입니다. 마감이 지나면 그 서식은 어차피 사라집니다. 즉 이 −56.5%에는 규칙의 효과와 계절성의 종료가 섞여 있습니다.
그래서 반사실(counterfactual)로 다시 셌습니다. 배포 후 규칙이 흡수한 건수 × 배포 전 실측 단가입니다.
1,455건 × $0.00677 = $9.85 (7 영업일) → $1.41 / 일
그런데 이 값이 관측된 감소분($0.89/일)보다 큽니다. 규칙이 없었다면 배포 후 비용은 $0.685 + $1.41 = $2.09/일 이었을 것이고, 이는 배포 전 $1.574/일보다 높습니다.
즉 순진한 전후 비교는 효과를 과대평가한 게 아니라 과소평가하고 있었습니다. 마감이 다가오면서 유입량이 늘고 있었기 때문입니다. 제 직관은 반대였습니다 — 계절성이 효과를 부풀렸을 거라고 예상하고 확인하러 갔다가 부호가 반대인 걸 봤습니다.
전후 비교가 위험한 건 결과가 부풀려져서가 아니라, 어느 쪽으로 틀렸는지 알 수 없기 때문입니다.
규칙의 값
규칙 기반 선처리는 공짜가 아닙니다. 대가는 이렇습니다.
정규식은 부서집니다. 공시 서식명이 바뀌면 규칙이 조용히 빗나가고, 그 결과는 오류가 아니라 비용 증가로만 나타납니다. 앞 글에서 다룬 것과 같은 종류의 침묵하는 실패입니다.
오탐은 되돌릴 수 없습니다. 규칙이 잘못 잡으면 그 문서는 LLM을 아예 안 거치고, 놓친 신호는 나중에 세어볼 수도 없습니다. 그래서 규칙을 추가할 때는 배포 전에 누적 수집분 전체 제목과 대조해서 의도한 것만 매칭되는지 확인합니다. 이번 2건은 18만 건 넘는 수집 이력에 정규식을 돌려 매칭된 제목이 의도한 6개 변형뿐임을 확인하고 넣었습니다.
탈출구는 아직 시험받지 않았습니다. 앞서 자랑한 의견거절 탈출구는 규칙 도입 이후 지금까지 사실상 발동한 적이 없습니다. 감사의견 거절은 3월 결산 시즌에 몰리는데, 규칙을 3월 30일에 넣었기 때문입니다. 이 안전장치의 진짜 시험은 2027년 3월입니다. 그때까지는 “작동한다”가 아니라 “작동할 것으로 설계했다”까지만 쓸 수 있습니다.
남는 것
건당 비용은 도입 초기 $0.00370에서 지금 $0.00141까지 내려왔습니다. 62% 감소인데, 이 숫자는 사실 별로 중요하지 않습니다. 중요한 건 비용이 유입량에 대해 거의 평평해졌다는 것입니다. 8월 14일에 850건이 한꺼번에 와도 $0이 나옵니다. 이제 소스를 늘리는 결정이 비용 걱정 없이 가능합니다.
정리하면 세 가지입니다.
모델을 바꾸기 전에 경로를 나누세요. 더 싼 모델을 찾는 건 상수배 개선이고, 호출을 없애는 건 자릿수 개선입니다. 그리고 대부분의 실무 데이터에는 “LLM이 필요 없는 게 명백한” 다수가 있습니다.
비용은 총액이 아니라 귀속으로 보세요. “이번 달 $17 썼다”는 아무 행동도 유발하지 않습니다. “이 서식 하나가 $12.78 썼다”는 즉시 코드 한 줄로 이어집니다. 같은 데이터인데 집계 축만 다릅니다.
그리고 아끼는 쪽으로 기울 때 무엇을 놓치는지 명시적으로 적어두세요. 규칙은 본질적으로 “안 읽고 결정하는 것”입니다. 그 판단이 언제 틀리는지 조건을 코드에 적어둘 수 없다면, 그 항목은 아직 규칙으로 내릴 준비가 안 된 겁니다.