$0.77 in API bills to read 89,000 planning PDFs
API 비용 77센트로 계획 허가 PDF 8만 9,000건 읽기
2017년 조립한 PC와 로컬 언어 모델로 영국 지방의회의 계획 허가 결정 8만 9,000건을 처리한 사례입니다. API 비용은 77센트이며, 문서별 레이아웃 정리와 고정 평가 세트로 추출 품질을 관리합니다.
- 주제
에디터 노트
이 사례의 성과는 저렴한 모델보다 재현 가능한 문서 처리 절차에 있습니다. 리즈 문서 218건에서 주소와 페이지 머리말을 잘라내자 프롬프트를 그대로 둔 채 성공률이 63%에서 72%로 올랐고, 작성자는 원본 스냅샷과 고정 평가 세트를 이용해 추출 규칙을 다시 검증합니다. 댓글에서 바로잡은 수치도 구분해야 합니다. 92.9%는 6,577건 결과이며 218건 비교는 Haiku 68.8%, Qwen3.5 87.6%입니다. 전체 재처리는 한 버전의 결과를 일관되게 공개하려는 선택이지만 20시간이 듭니다. 댓글에서 실패 문서만 다시 처리하자는 제안이 나왔고 작성자도 아직 시험하지 않았다고 답했습니다. 또한 모델과 프롬프트의 해시를 기록하지 않는다는 점을 인정하고 보완을 계획했습니다. 보고서의 정확성을 좌우하는 데이터 정리와 버전 추적은 구체적으로 설명되어 있지만, 29파운드 상품의 고객 수요와 실제 구매자 구성은 결제 시작 직후라 아직 확인되지 않았습니다.
AI 요약
작성자는 2017년에 조립한 Ryzen 5 1600, GTX 1060 6GB PC에 Ubuntu를 설치해 개발 작업을 맡기려 했지만, 서버에 할 일이 없자 영국 지방의회의 계획 허가 결정문을 처리하기 시작했습니다. 각 의회는 결정 결과를 공개하고, 허가 거부 건에는 이유를 적은 PDF가 붙습니다. 자료는 수백 곳의 의회 웹사이트에 흩어져 있으며, 다락방 증축 같은 신청이 통과될지 알아보려면 컨설턴트에게 비용을 내거나 추측해야 하는 경우가 있습니다.
PC는 결정문을 가져와 사본을 보관하고, 거부 통지서의 이유를 그래픽카드에서 실행하는 소형 언어 모델로 읽습니다. 서비스 Plan Forecast는 무료 예측을 제공하며, 주변의 유사 결정 사례를 담은 보고서는 29파운드입니다. 현재 6개 의회 자료를 판매하고 5곳의 과거 기록을 처리하고 있습니다.
API에서 로컬 모델로 바꾼 이유
처음에는 Claude Haiku API로 거부 통지서를 읽었습니다. 결과는 대체로 쓸 만했고 비용도 몇 푼 수준이었지만, 프롬프트를 바꾸거나 의회별 문서 레이아웃을 처리할 때마다 전체 문서를 다시 읽어야 했습니다. 작성자는 프롬프트를 자주 바꿔 현재 24번째 버전을 쓰고 있습니다. API를 쓰면 실행할 때마다 비용이 들지만, 로컬 실행은 전기료만 들기 때문에 반복 작업 부담이 적다고 설명합니다.
9B 모델을 4비트 양자화하고 컨텍스트 길이를 2만 토큰으로 잡으면 6GB VRAM에 전부 들어가지 않습니다. Ollama는 모델 층의 약 3분의 2를 GPU에, 나머지를 CPU에 올립니다. 시스템 RAM 16GB는 Postgres, 크롤러, GitHub Actions 러너도 함께 씁니다. 메모리가 부족해 잘못된 프로세스를 종료하는 earlyoom 문제로 밤을 보낸 적도 있다고 합니다. CPU만 쓸 때 통지서 하나를 처리하는 데 약 38초가 걸렸고, GPU와 CPU를 나눠 쓰면 약 13초가 걸립니다. 전체 재처리는 약 20시간입니다.
문서 정리가 모델만큼 중요합니다
평가에는 Claude Haiku로 이미 처리했던 리즈(Leeds) 거부 통지서 218건을 사용했습니다. 모델이 올바른 문장을 찾고 코드가 의회 문구를 정확히 잘라내야 읽은 것으로 기록합니다. 잘못 읽은 통지서는 틀린 인용을 내놓는 대신 미처리 상태로 둡니다.
문제의 상당 부분은 모델보다 PDF 정리 코드에 있었습니다. 리즈 의회 문서에는 페이지가 넘어가는 위치마다 "Page 1 of 2"와 레터헤드가 이유 문장 중간에 들어갔습니다. 처음 저장한 206건 중 26건에는 의회 주소가 문장 한가운데 섞였습니다. 잘라내기 규칙을 고친 결과 프롬프트를 바꾸지 않고도 한 무료 모델의 성공률이 63%에서 72%로 올랐습니다. 현재 버전은 6,577건에서 92.9%를 기록합니다. 다만 같은 218건을 대상으로 한 비교에서 Claude Haiku는 68.8%, Qwen3.5 9B는 87.6%였다고 작성자가 댓글에서 수치를 바로잡았습니다. 새 버전은 480건으로 구성한 고정 평가 세트에서 이전 버전을 이겨야 기본 버전이 됩니다. 지금까지 API 비용은 77센트이며 로컬 모델 호출은 3만 4,000회를 넘었습니다.
수집과 개인정보 처리
신청인, 대리인, 담당자의 이름은 저장하지 않습니다. 테스트 자료에도 이름을 넣지 않으며, 이름이 발견되면 파이프라인을 중단합니다. 크롤러는 의회별로 한 번에 요청 하나만 보내고, 이름을 밝힌 User-Agent와 서비스 설명 페이지를 사용합니다. 새 의회는 20초에 한 번 요청하는 속도로 시작해 점차 요청 간격을 조정합니다. Retry-After를 따르며, 403 응답을 받으면 한 시간, 여섯 시간, 하루 순으로 멈춘 뒤 작성자가 직접 확인할 때까지 중단합니다. IP를 바꾸지 않고 CAPTCHA가 있는 사이트는 다루지 않습니다. 사전 허가를 요구하는 의회에는 이메일을 보내고 답을 기다립니다.
9월 이후 29개 의회 호스트에 약 17만 건의 요청을 보냈고, 17개 호스트에서 403 응답을 받았습니다. 크롤러는 해당 의회의 수집을 즉시 멈췄습니다. 한 의회는 16건을 요청한 뒤 거부 응답을 보내므로 16건마다 30분을 쉬며, 과거 기록 수집에 몇 주가 걸렸습니다.
버전 관리와 서비스 운영
댓글에서 작성자는 원본 HTML과 PDF 응답을 파싱 전에 콘텐츠 주소 기반 스냅샷 저장소에 보관한다고 설명했습니다. 파생 데이터는 저장한 원본을 다시 처리해 만들며, 추출기 버전은 입력별로 기록하고 덮어쓰지 않습니다. 의회별 레이아웃 차이는 코드 변경보다 제목과 잘라내기 규칙을 담은 데이터 항목으로 처리합니다. PDF는 개인정보 보호를 위해 12개월 뒤 삭제하지만, 저장한 텍스트로 다시 처리하는 경로는 유지합니다.
모델 버전마다 프롬프트 해시와 Ollama 모델 다이제스트도 기록하자는 댓글 제안에 작성자는 현재 버전만 추적하고 해시와 다이제스트는 기록하지 않는다고 답했습니다. 같은 태그로 모델을 다시 받아도 가중치가 바뀔 수 있다는 지적을 반영해 두 항목을 추가할 계획이라고 했습니다. 전체 재처리는 평가 세트에서 새 버전이 이긴 뒤 진행합니다. 실패한 문서만 골라 재처리하는 방법은 아직 시험하지 않았으며, 작성자는 전체 8만 9,000건 대신 실패 사례만 다시 처리하면 20시간 작업을 몇 시간으로 줄일 수 있다는 제안을 검토하겠다고 답했습니다.
사업 단계
결제는 게시 시점 기준 이달 7일에 시작했습니다. 작성자는 본업을 유지하면서 의회 자료를 늘리고 있으며, 다음 단계로 전문 사용자를 위한 의회별·작업 유형별 판례 검색을 구상합니다. 댓글에서는 개인 주택 소유자보다 반복적으로 여러 신청을 다루는 컨설턴트가 재구매 고객이 될 수 있다는 의견과, 거부 직후 또는 신청 직전처럼 사용자가 유사 사례를 급히 찾는 시점에 맞춰야 한다는 제안이 나왔습니다. 작성자는 아직 결제 고객의 유형을 판단하기 이르다고 답했고, 유입 시점별 페이지 구성도 검토하겠다고 했습니다.
Indie Hackers 반응
- @eloguidici — 오래된 PC를 서버로 쓰고 PDF 8만 9,000건 처리에 API 비용을 1달러도 쓰지 않은 사례는 시작부터 비싼 하드웨어가 필요하지 않다는 좋은 예입니다. 문서 시스템에서 어려운 부분은 PDF를 읽는 일이 아니라 출처마다 다른 레이아웃의 텍스트를 정규화하는 일이었습니다. 원본 HTML과 PDF를 보관해 나중에 다시 처리하나요, 아니면 최종 추출 결과만 보관하나요?
- @John Anderson — 모든 작업을 최신 프런티어 모델에 맡기고 싶은 유혹이 있는데 좋은 교훈을 얻었습니다. 질문에 답하면 원본을 보관하고 나중에 다시 처리합니다. 파싱 전에 모든 응답 본문, HTML과 PDF를 콘텐츠 주소 기반 스냅샷 저장소에 넣고, 파생 데이터는 그 스냅샷에서 다시 만듭니다. 그래서 레이아웃 문제를 고치거나 추출기를 바꿔도 의회 사이트에 다시 요청하지 않고 전체 기록을 재처리할 수 있습니다. 추출기 버전은 입력별로 기록하며 덮어쓰지 않습니다. 새 버전은 라벨이 붙은 평가 세트에서 기존 버전을 이길 때만 기본값이 됩니다. 의회별 레이아웃 처리는 제목과 잘라내기 규칙을 데이터로 관리합니다. 새 레이아웃은 코드 변경 대신 작은 항목을 추가하고 다시 처리하면 됩니다. 개인정보 보호를 위해 통지서 PDF는 12개월 뒤 삭제하지만 비식별 처리한 텍스트는 보관하며, 저장한 텍스트에서 다시 처리하는 경로는 유지합니다.
- @zaneberg — 사용 시점은 이미 데이터에 있습니다. 읽은 거부 결정마다 결정일이 있고, 주택 소유자가 항소하려면 그 날짜부터 12주 안에 해야 합니다. 거부 직후 몇 주가 "왜 거부됐고 항소하면 될까"라는 질문이 절실한 시점입니다. 많은 통지서에는 신청인 대리인도 나오며, 대개 매달 거부 사례를 겪는 작은 건축 또는 도면 사무소입니다. 이들이 반복 구매자가 될 것 같습니다. 새 거부 사례를 매주 알려주면 누구에게 연락할지 알 수 있습니다.
- @John Anderson — 감사합니다. 그런 관점은 생각하지 못했는데 맞습니다. 살펴보겠습니다.
- @marc_kumiko123 — 제가 가장 좋아하는 수치는 프롬프트를 한 글자도 바꾸지 않고 정리 규칙만 고쳐 63%에서 72%로 올린 부분입니다. 저희 앱에서는 모델을 호출할 때마다 프롬프트 해시와 실제 응답 모델을 작은 기록으로 남깁니다. 아무도 수동으로 버전을 올리지 않고, 문제가 생긴 실행에서 어떤 프롬프트를 썼는지도 확인할 수 있습니다. 로컬 PC라면 Ollama 다이제스트도 저장하겠습니다. 같은 태그를 다시 받아도 가중치가 바뀔 수 있기 때문입니다. v25가 480건 평가에서 v24를 이기면 8만 9,000건을 전부 다시 읽나요, 아니면 v24가 읽지 못한 문서만 처리하나요?
- @John Anderson — 감사합니다. 저라면 프롬프트가 원인이라고 생각했을 텐데요. 문서별 기록은 좋은 생각이며 아직 제대로 하지 않고 있습니다. 버전은 추적하지만 프롬프트 해시나 Ollama 다이제스트는 기록하지 않습니다. 같은 태그를 받아도 가중치가 달라질 수 있다는 점은 생각하지 못했습니다. 두 항목을 추가하겠습니다. 질문에 답하면 전체를 다시 읽습니다. 공개하는 모든 행이 한 버전에서 나왔으면 하기 때문입니다. 프롬프트가 바뀔 때는 어떻게 하시나요? 지금은 큰 작업이 아니지만 규모가 커지면 문제가 될 것 같습니다.
- @usetether — 누군가 다락방 증축을 결정할 때 참고할 통지서라면 잘못 인용하는 대신 읽지 않은 상태로 두는 게 맞습니다. 거부 이유 하나를 틀리면 누락 하나보다 신뢰를 더 잃습니다. 지금까지 누가 사용했나요? 주택 소유자인가요, 아니면 원래 비용을 내고 찾아갈 컨설턴트인가요?
- @John Anderson — 신뢰에 관한 말씀에 동의합니다. 그 점이 이 서비스의 이유입니다. 솔직히 말하면 사용자가 누구인지 판단하기에는 아직 이릅니다. 결제는 이달 7일에 시작했으니 고객 구성을 아는 척하지 않겠습니다. 이 서비스는 신청을 앞둔 주택 소유자와 소규모 개발자, 예를 들어 증축, 다락방 공사, 용도 변경을 준비하는 사람을 위해 만들었습니다. 다음으로 시험하려는 대상은 컨설턴트입니다. 의회와 작업 유형별 선례 검색을 매일 쓸 수 있기 때문입니다. 컨설턴트라면 어떤 기능이 필요한지 알려주세요.
- @usetether — 컨설턴트는 주택 소유자보다 여러 번 이용하므로 고객 확보 비용도 낮아질 가능성이 큽니다. 저는 미국에 살아서 대상 시장과는 조금 다릅니다.
- @capo689 — 보고서가 사전 상담이나 거부된 신청을 대신한다면 29파운드는 쉽게 낼 만합니다. 추측의 비용이 훨씬 크기 때문입니다. 가격보다 구매가 필요한 순간을 시험해보겠습니다. 신청 직전이나 거부 직후에 팔아야 합니다. 그때는 "비슷한 신청이 승인됐나"가 가장 절실한 질문입니다. 그 순간이 일반적인 랜딩 페이지보다 가치가 큽니다.
- @John Anderson — 더 좋은 관점입니다. 감사합니다. 가격을 생각하고 있었는데, 말씀대로 사용자가 검색하는 순간이 중요합니다. "신청이 왜 거부됐나"와 "이 신청은 승인될까"라는 질문을 일반 랜딩 페이지보다 앞세워야겠습니다. 직접 그런 유입 시점을 시험해보셨나요? 거부 직후와 사전 신청 단계 중 어느 쪽이 더 구매로 이어질지 궁금합니다.
- @VeloquentLabs — 리즈 사례에서 Haiku의 68.8%가 Qwen3.5의 92.9%로 오른 것은 좁고 반복적인 문서 묶음에서 로컬 모델이 유용하다는 강한 사례입니다. 우편 주소를 잘라내는 규칙만으로 무료 모델이 63%에서 72%로 오른 부분도 예상하지 못했습니다. 전체 재처리에 20시간이 걸린다면 성공적으로 파싱한 통지서를 캐시해 새 문서나 실패한 문서만 다시 처리해봤나요?
- @John Anderson — 감사합니다. 수치는 바로잡겠습니다. 92.9%는 현재 버전이 6,577건에서 기록한 값입니다. 같은 리즈 문서 218건을 비교하면 Haiku는 68.8%, Qwen3.5 9B는 87.6%입니다. 캐시 관련 질문도 좋습니다. 원본 페이지는 파싱 전에 이미 저장하므로 다시 가져오지는 않습니다. 20시간은 모델을 다시 실행하는 데 걸리는 시간입니다. 프롬프트가 바뀌면 이전 프롬프트로 만든 파싱 결과가 오래된 결과가 됩니다. 그래서 고정한 480건에서 버전을 비교하고 새 버전이 이길 때만 전체 재처리를 합니다. 실패한 문서만 다시 처리하는 방법도 괜찮은 생각이지만 아직 해보지 않았습니다. 실패 사례만 바꾸는 버전이라면 20시간 작업이 몇 시간으로 줄어들 수 있습니다. 본인 파이프라인에서 비슷한 방식을 써보셨나요?
원문: Indie Hackers / 번역·요약: Trawling