AI 데이터 추출(Data Extraction)을 통해 부트캠프 프로젝트 예산을 절약한 방법
요약
LLM을 활용한 데이터 추출(Data Extraction) 기법을 통해 비정형 PDF 인보이스 데이터를 구조화된 JSON 형식으로 변환하는 방법을 소개합니다. 정규 표현식 대신 LLM의 함수 호출 기능을 사용하여 개발 시간을 단축하고 비용을 획기적으로 절감한 경험을 공유합니다.
핵심 포인트
- 비정형 문서(PDF 등)에서 구조화된 데이터 추출 시 LLM 활용 가능
- OpenAI SDK와 호환되는 Global API를 통한 비용 절감 효과
- 정확한 데이터 추출을 위한 temperature=0 설정의 중요성
- 함수 호출(Function Calling)을 통한 구조화된 출력 구현
솔직히 말씀드리면, 제가 어떻게 AI 데이터 추출(Data Extraction)을 사용하여 부트캠프 프로젝트 예산을 아낄 수 있었는지에 대한 이야기입니다 (이제 막 방법을 깨달은 사람의 완전한 가이드).
솔직히 고백하겠습니다. 3주 전만 해도 저는 AI 세계에서 "데이터 추출 (Data Extraction)"이 무엇을 의미하는지조차 전혀 몰랐습니다. 저는 그저... JSON 파일을 파싱 (parsing)하는 것 정도라고 생각했습니다. 제가 완전히 틀렸더군요. 부트캠프 강사님이 엉망진창인 PDF 인보이스(invoice) 더미에서 구조화된 정보를 추출해야 하는 프로젝트 개요를 던져주었을 때, 저는 눈에서 피가 날 때까지 정규 표현식 (regex)을 작성해야 할 것이라고 확신했습니다. 그러던 중 Discord의 한 시니어 개발자가 "그냥 LLM을 사용해"라고 언급했고, 제가 무엇이 가능한지에 대한 모든 이해가 완전히 뒤바뀌었습니다.
그래서 이 가이드는 제가 3주 동안 집요하게 연구하고, 테스트하고, 실수로 API 크레딧을 두 번이나 다 써버리면서 배운 모든 것을 담고 있습니다. 만약 여러분이 동료 부트캠프 졸업생이거나, 맥락 없이 "구조화된 출력 (structured output)"이나 "함수 호출 (function calling)" 같은 용어를 계속 듣게 되는 독학 개발자라면, 이 글이 도움이 될 것입니다.
처음부터 제가 왜 데이터 추출 (Data Extraction)에 관심을 가졌는가
요약하자면: 제 프로젝트는 200개 이상의 업체 인보이스(모두 형식이 다르고, 이상한 각도로 스캔된 것들)를 가져와서 PostgreSQL 테이블의 깔끔한 행(row)으로 변환해야 했습니다. 인보이스 번호, 날짜, 총액, 업체명, 품목(line items)과 같은 필드들이 필요했습니다. 사람이 인보이스 하나당 약 5~10분 정도 걸릴 법한 작업입니다. 여기에 200을 곱하면, 정신이 아득해지는 데이터 입력 작업에 일주일 전체를 써야 한다는 뜻입니다.
저는 LLM이 그냥... 문서를 읽고 구조화된 JSON을 돌려줄 수 있다는 사실을 전혀 몰랐습니다. 정말 몰랐습니다. 모델이 제가 필요로 하는 정확한 필드를 가진 완벽하게 포맷팅된 객체(object)를 반환하는 것을 처음 보았을 때, 저는 책상 앞에서 저도 모르게 "말도 안 돼"라고 소리쳤던 것 같습니다. 제 룸메이트는 제가 미쳐가는 줄 알았습니다.
저를 정말로 충격에 빠뜨린 것은 가격이었습니다. 저는 전체 배치(batch)를 처리하는 데 50달러 이상을 쓸 것이라고 예상하고 들어갔습니다. 그러다 Global API를 발견했고, 그들의 일부 모델은 호출당 말 그대로 1센트의 아주 작은 부분만큼의 비용만 발생한다는 것을 알게 되었습니다. 사용 가능한 184개 모델의 가격 범위는 100만 토큰(token)당 0.01달러에서 3.50달러 사이였으며,
문서에서 계속 보았던 40~65%의 비용 절감 수치는 마케팅용 미사여구가 아니었습니다. 저는 소위 "유명 브랜드" 솔루션을 사용했을 때 지출했을 비용과 비교하여 실제로 그만큼을 절약했습니다.
실제로 작동했던 코드 (약 6번의 실패 끝에)
제가 결국 사용하게 된 코드를 여러분께 보여드리고 싶습니다. 왜냐하면 누군가가 저에게 딱딱한 API 문서만을 가리키는 대신, 첫날부터 작동하는 예시를 보여주었더라면 좋았을 것이라고 생각하기 때문입니다. 저는 부트캠프에서 배웠던 방식대로 OpenAI Python SDK를 사용하고 있으며, Global API는 이와 완전히 호환됩니다. 말 그대로 클라이언트(client)의 베이스 URL(base URL)을 다른 곳으로 지정하고 API 키(API key)만 교체하면 됩니다.
기본 설정은 다음과 같습니다:
import openai
import os
import json
...
처음 시작했을 때는 temperature=0이라는 설정에 대해 전혀 몰랐습니다. 저는 그저 "temperature(온도)"가 어떤 이상한 공상 과학 설정인 줄로만 알았습니다. 알고 보니 그것은 기본적으로 무작위성(randomness)을 조절하는 다이얼이었고, 데이터 추출(data extraction)의 경우에는 모델이 송장 번호(invoice numbers)를 창의적으로(?) 바꾸지 않도록 0으로 설정해야 했습니다. 이 사실을 알게 되었을 때 정말 놀라웠습니다.
이제 스트리밍(streaming)과 에러 핸들링(error handling)이 추가된, 제가 실제로 프로덕션(production) 환경에서 사용한 버전을 소개하겠습니다. 스트리밍을 추가한 이유는, 스트리밍 없이 처음 200개의 송장을 처리했을 때 스크립트가 멈춘 것인지 궁금해하며 8분 동안이나 멍하니 앉아 있었기 때문입니다:
import openai
import os
import json
...
솔직히 말해서 프로젝트에 스트리밍이 엄격하게 필수적이었던 것은 아니지만, 문서에서 계속 "더 나은 UX"라고 말했기에 좋은 연습이 될 것이라고 생각하여 추가했습니다. 게다가 터미널에서 JSON이 한 글자씩 쌓여가는 것을 보는 것이 꽤 만족스러웠습니다.
모든 실수를 저지르고 나서야 알게 된 것들
다음은 제가 첫 20달러의 크레딧(credits)을 다 써가며 사실상 직접 배워야 했던 "베스트 프랙티스(best practices)"들입니다:
-
공격적으로 캐싱(Cache)하세요. 동일한 종류의 문서를 반복해서 처리하고 있다면, 시스템 프롬프트(system prompts)는 매번 동일할 것입니다. 저는 프롬프트 접두사(prompt prefixes)를 재사용할 수 있도록 구조화할 수 있다는 사실을 깨닫기 전까지, 200토큰(token) 분량의 동일한 시스템 프롬프트를 200번이나 보내고 있었습니다. 2주 차가 되기 전까지는 "프롬프트 캐시(prompt cache)"가 무엇인지조차 몰랐습니다. 이를 통해 반복되는 프롬프트에 대해 40%의 히트율(hit rate)을 달성했고, 이는 곧 직접적인 비용 절감으로 이어졌습니다.
-
응답을 스트리밍(Stream)하세요. 위에서도 언급했지만, 다시 한번 강조할 가치가 있습니다. 앱의 체감 속도는 실제 속도보다 훨씬 더 중요합니다. 사용자를 기다리게 만드는 0.8초의 응답보다, 스트리밍되는 1.2초의 응답이 더 빠르게 느껴집니다. 이에 대한 실제 연구 결과가 있는지는 모르겠지만, 제 직감으로는 이것이 사실입니다.
-
단순한 작업에는 더 저렴한 모델을 사용하세요. Global API 문서에는 "GA-Economy"라는 것이 있는데, 이는 기본적으로 예산 친화적인 모델들을 분류해 놓은 것입니다. 제 데이터 추출(data extraction) 작업의 80%에서 이 이코노미(economy) 티어가 완벽하게 작동했습니다. 비싼 모델을 기본값으로 사용하지 않는 것만으로도 해당 호출 비용의 50%를 절약했습니다. 이것이 저에게는 단일 항목 중 가장 큰 비용 절감 효과를 가져다준 승리였습니다.
-
운영 환경(production)에서 품질을 모니터링하세요. 저는 추출된 결과의 5%를 무작위로 샘플링하여 정답(ground truth, 제가 수동으로 파싱한 20개의 인보이스)과 비교하는 작은 스크립트를 만들었습니다. 시간이 지남에 따라 점수를 추적했습니다. 점수가 떨어지면 제 프롬프트나 사용 중인 모델에 문제가 생겼음을 알 수 있었습니다. 이것은 부트캠프에서는 절대 가르쳐주지 않지만, Reddit의 모든 시니어 개발자들이 입을 모아 강조하는 부분입니다.
-
폴백(fallback) 계획을 세우세요. 프로젝트 진행 중 정확히 두 번 레이트 리밋(rate limits, 호출 제한)에 걸렸습니다. 두 번 모두 이를 처리할 장치가 마련되어 있지 않았고, 제 스크립트는 그냥 충돌(crash)하며 멈춰버렸습니다. 결국 저는 추출 호출을 지수 백오프(exponential backoff)가 적용된 재시도 데코레이터(retry decorator)로 감싸는 작업을 수행했습니다. 세 번째로 레이트 리밋에 걸렸을 때, 제 스크립트는 자동으로 재시도를 수행했고 저는 눈치채지도 못했습니다.
제 프로젝트에서 실제로 중요했던 수치들
마케팅 페이지에 나오는 이론적인 이야기 말고, 제가 완료한 프로젝트의 실제 수치를 말씀드리겠습니다.
-
비용 (Cost): 218개의 인보이스(Invoice)를 처리하는 데 총 4.27달러를 사용했습니다. 이는 각 문서당 5개 이상의 필드(Field)가 포함된 218개의 문서입니다. 참고로, 이는 제가 사는 도시의 최저임금 1시간 치보다 적은 금액입니다. 만약 모든 작업에 GPT-4o를 사용했다면, 제 예상으로는 35
45달러 정도를 썼을 것입니다. 4065%의 비용 절감 주장은 사실이었습니다. -
속도 (Speed): 평균 지연 시간(Latency)은 추출당 약 1.2초였습니다. 병렬(Parallel)로 실행했을 때 처리량(Throughput)은 초당 약 320 토큰(Tokens per second)이었습니다. 두 달 전만 해도 저는 "초당 토큰"이 무엇인지조차 몰랐지만, 이제는 제 삶에서 신경 쓰는 수치가 되었습니다.
-
품질 (Quality): 테스트 세트 전체에서 첫 번째 시도(First pass) 시 84.6%의 추출 정확도(Extraction accuracy)를 달성했습니다. 실패 사례는 거의 항상 특이한 날짜 형식(예: "15/03/26" vs "March 15, 2026") 때문이었으며, 이는 시스템 프롬프트(System prompt)에 명시적인 형식 예시를 추가함으로써 해결했습니다. 프롬프트 반복(Prompt iteration) 후에 96%까지 끌어올렸습니다.
-
설정 시간 (Setup time): 첫 번째로 작동하는 추출 기능을 만드는 데 약 8분이 걸렸습니다. 그 후 프롬프트를 개선하고, 에러 핸들링(Error handling)을 추가하고, 스트리밍(Streaming) 버전을 구축하는 데 이틀을 더 보냈습니다. 하지만 초기 "이게 정말 가능한가?" 수준의 개념 증명(Proof of concept)은 10분도 걸리지 않았습니다. Global API가 제공하는 통합 SDK(Unified SDK)는 정말로 베이스 URL(Base URL)만 바꾸면 되는 수준이었습니다. 저는 어려운 부분이 나올까 봐 계속 기다렸지만, 그런 일은 일어나지 않았습니다.
첫날 누군가 나에게 말해줬으면 좋았을 것들
만약 제가 과거의 저에게 조언을 해줄 수 있다면, 이렇게 말하겠습니다:
첫째, "AI 데이터 추출 (AI data extraction)"이라는 용어에 겁먹지 마세요. 그것은 단지 추가적인 단계가 있는 패턴 매칭(Pattern matching)일 뿐입니다. 모델이 텍스트를 읽고, 당신이 어떤 필드를 찾아야 하는지 알려주면, 모델이 JSON을 돌려주는 것입니다. 그게 전부입니다. 저는 이것을 마치 박사 과정 수준의 연구 문제처럼 머릿속에서 부풀려 생각했었는데, 알고 보니 파이썬(Python) 코드 30줄 정도의 작업이었습니다.
둘째, 저렴한 모델들은 단순히 "충분히 괜찮은" 수준이 아닙니다. 특히 데이터 추출(Extraction)의 경우, 이 모델들은 플래그십(Flagship) 모델들보다 더 나은 경우가 많습니다. 왜냐하면 이들은 "친절하게" 주석을 덧붙이거나 이상한 입력을 파싱(Parsing)하기를 거부할 가능성이 더 낮기 때문입니다. DeepSeek V4 Flash가 정말로 엉망진창인 송장(Invoice) 스캔본들을 얼마나 자신 있게 처리하는지 보고 저는 충격을 받았습니다.
셋째, 프롬프트 엔지니어링(Prompt Engineering)은 실제 기술이지만 마법은 아닙니다. 저는 시스템 프롬프트(System Prompt)를 수정하는 데 몇 시간을 보낸 후에야, 가장 큰 개선은 단지 올바른 형식으로 작성된 출력 예시를 3~5개 추가하는 것에서 온다는 사실을 깨달았습니다. 퓨샷 예시(Few-shot examples) 말입니다. 저는 그런 것이 있는지조차 몰랐습니다. 지금은 당연하게 들리겠지만, 3주 전의 저라면 그 용어를 보고 멍하니 바라만 보았을 것입니다.
넷째, OpenAI SDK를 사용하세요. 특정 제공업체의 "공식" SDK가 무엇인지는 중요하지 않습니다. OpenAI Python 클라이언트는 현재 LLM(Large Language Model) 세계의 공용어(Lingua franca)이며, 한 번 배워두면 기본적으로 무엇에나 연결할 수 있습니다. Global API가 이를 네이티브로 지원하기 때문에, 저는 다른 모든 것 위에 또 다른 라이브러리를 배울 필요가 없었습니다.
제가 모든 사람에게 계속해서 말하는 놀라운 부분
이번 경험 전체를 통해 진심으로 저를 놀라게 했던 점은 이것입니다: 2026년의 AI 데이터 추출(Data Extraction)은 더 이상 "대기업"만을 위한 도구가 아닙니다. 가격은 매우 저렴하고, 설정은 매우 간단하며, 모델은 매우 유능해서, 부트캠프 교육을 받은 1인 개발자도 오후 한나절 만에 프로덕션급(Production-grade) 추출 파이프라인을 구축할 수 있습니다. 왜 더 많은 사람이 이에 대해 이야기하지 않는지 모르겠습니다.
저는 예전에 "AI 기반" 기능이란 머신러닝(Machine Learning) 박사 학위와 서버 팜(Server farms)이 필요한, 도달할 수 없는 기업용 기술 같은 것이라고 생각했습니다. 알고 보니 그것은 단돈 몇 푼이면 되는 API 호출이었습니다. 저는 전혀 몰랐습니다. 정말로 전혀 몰랐습니다.
만약 여러분이 송장(invoices), 계약서(contracts), 영수증(receipts), 이메일(emails), 설문 응답(survey responses) 등 무엇이든 비정형 소스(unstructured sources)로부터 구조화된 데이터(structured data)를 추출하는 프로젝트를 진행하고 있다면, 이는 반드시 탐구해 볼 가치가 있습니다. 비용(소규모 프로젝트의 경우 사실상 무료), 속도(1초 미만의 응답), 그리고 품질(95% 이상의 정확도가 현실적임)의 조합은 제가 지금까지 구현한 것 중 가장 높은 ROI(투자 대비 수익)를 가진 것 중 하나로 만들어 주었습니다.
다른 부트캠프 졸업생들에게 구체적으로 해주고 싶은 말
보세요, 우리 모두 같은 처지라는 것을 알고 있습니다. 빠듯한 예산, 가면 증후군(imposter syndrome), 불합리하게 느껴지는 마감 기한까지 말이죠. 제 솔직한 의견은 이렇습니다. 제가 파트타임으로 3주 동안 이 작업을 구축할 수 있었다면, 여러분도 할 수 있습니다. 솔직히 가장 어려웠던 부분은 단순한 버전이 실제로 작동할 것이라고 믿는 것이었습니다. 저는 계속해서 예상치 못한 문제(gotcha)가 터지기만을 기다렸습니다.
하지만 예상치 못한 문제는 나타나지 않았습니다. 위에서 보여드린 코드는 제가 실제로 출시한 것의 약 90%에 해당합니다. 나머지는 전부 에러 처리(error handling)와 프론트엔드를 위한 Flask 래퍼(wrapper)일 뿐이었습니다.
동료 학습자들을 위한 몇 가지 구체적인 팁:
- DeepSeek V4 Flash로 시작하세요. 저렴하고 빠르며 놀라울 정도로 유능한 최적의 지점을 공략합니다.
- 추출 작업에는
temperature=0을 사용하세요. 타협 불가능한 사항입니다. - JSON 검증(validation) 단계를 추가하세요. 모델 출력값을 try/except로 감싸고, 실패할 경우 재시도(retry)하도록 만드세요.
- 프롬프트(prompts)를 별도의 파일이나 상수(constant)로 유지하세요. 생각보다 훨씬 더 많이 반복(iterate)하게 될 것입니다.
- 매우 특정한 이유가 없다면 GPT-4o에 비용을 지불하지 마세요. 추출 작업에서 9배의 비용 차이는 미미한 품질 향상을 감수할 만큼의 가치가 없습니다.
내가 최종적으로 도달한 곳
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기