본문 바로가기
공돌공돌 컴공생/프로젝트

1인으로 AI 예측 서비스 만들기 — 데이터 수집부터 론칭까지의 설계 회고

by leesangik 2026. 4. 24.

 

들어가며

OilWallet (오월)은 국내 주유소 유가를 머신러닝으로 예측해 최대 7일 앞까지 일자별 전망을 제공하는 서비스예요. 휘발유·경유 2유종 × 전국 + 17개 시도 = 36개 조합을 매일 여러 차례 예측해 웹과 앱으로 내려보냅니다.

처음 기획을 시작한 건 2023년이었어요. 그때부터 계속 뭔가를 만들었다기보단, 데이터를 먼저 모으고 · 정제하고 · 설계를 다듬는 시간이 대부분이었습니다. 예측 서비스라는 게 모델부터 만들 수 있는 게 아니라, 쓸 만한 데이터가 충분히 쌓인 다음에야 의미 있는 실험이 가능하거든요. 그래서 꽤 긴 준비 기간을 거쳐 최근에서야 세상에 공개했어요.

이 글은 그 과정 — 데이터 수집기를 처음 세운 날부터 론칭 버튼을 누르기까지 — 설계 판단들을 한 번에 정리하는 긴 회고예요. 혼자 만들다 보니 선택 하나하나가 미래의 유지보수 부담으로 바로 돌아왔고, 그 경험이 판단 기준으로 쌓였습니다.

구체 구현 방식보다 "왜 그 선택을 했는지"에 집중해 읽어주시면 좋을 것 같아요. 비슷한 처지의 분들한테는 판단 기준이 더 도움이 될 거라 생각해요.

 

📖 목차

  • CHAPTER 01 — 아키텍처 개관: 4계층으로 흐르는 시스템
  • CHAPTER 02 — 예측 파이프라인: 성격이 다른 두 모델을 함께 쓴다
  • CHAPTER 03 — 운영·인프라: 1인 운영을 버티기 위한 세 가지 전략
  • CHAPTER 04 — 피처 엔지니어링: "가격"만 넣지 않는다
  • 마무리 — 데이터 수집부터 론칭까지 배운 것들

 

CHAPTER 01 · 아키텍처 개관

4계층으로 흐르는 시스템

 

시스템은 크게 4단계로 흐릅니다. 각 단계의 역할을 분리해 놓으니 혼자 만드는 동안 한 영역을 건드려도 다른 영역이 조용히 깨지는 일이 줄었어요.

① 외부 소스 — 다각적인 원천 데이터

예측 정확도는 결국 입력 데이터의 품질에 달려 있어서, 초반 몇 달을 다양한 소스를 안정적으로 긁어오는 데 통째로 썼어요.

  • 국내 주유소 가격 — 전국 및 지역별 평균가
  • 국제 원유 시세 — 주요 원유 지표
  • 거시 지표 — 환율 · 통화
  • 시장 심리 — 뉴스 감성 지표
  • 그 외 다수 — 모델 성능에 기여하는 추가 지표들 (공개 범위 외)

다이어그램에서 점선으로 표시한 "그 외 다수"는 설명 단순화를 위해 생략한 게 아니라, 실제로 수집·활용하고 있는 지표들이 더 있다는 뜻이에요. 예측 엔진의 차별화 지점이라 이 글에서는 구체적으로 다루지 않습니다.

② 수집 — Collector

위 소스를 모두 받아와 정제와 백필까지 처리하는 단일 수집기예요. "수집은 여기서 다 한다"는 원칙을 지켰더니 새 소스를 붙일 때도 여기만 건드리면 되고, 문제가 생겨도 여기만 보면 돼서 부담이 줄었습니다.

사실 이 컴포넌트가 제일 먼저 만들어졌어요. 예측 모델을 고민하기 전에, 쓸 만한 데이터가 충분히 쌓이는 게 우선이었거든요. 몇 달간의 수집기를 돌려 과거 데이터가 어느 정도 축적된 뒤에야 모델 쪽 실험이 시작됐습니다.

③ 저장소 — 통합 데이터 스토어

1인 작업이라 저장소는 하나로 통일했습니다. 가격, 예측, 감성, 피처 스냅샷까지 모두 여기에 들어가요. 처음엔 시계열 특화 DB도 고민했는데, 데이터 양이 "혼자 다룰 수 있는 범위"라 단일 저장소로도 충분했고, 운영 부담만 늘어서 결국 하나로 갔어요.

④ 예측 서비스 — 역할별 3개 컴포넌트

  • Trainer — 주기적으로 전 지역·유종 모델을 재학습
  • Scheduler — 하루 여러 차례 예측을 실행하는 핵심 엔진. 앙상블 모델을 상황별로 블렌딩
  • Inference API — 보조 예측 서비스. 내부 통신 전용

Scheduler만 강조 색으로 표시한 건, 예측 품질이 실질적으로 여기서 결정되기 때문이에요. 이 부분은 CHAPTER 02에서 다룹니다.

⑤ 엣지 · 딜리버리 — 웹 + Cloudflare + 앱

웹은 서버 렌더링으로 가볍게 내보내고, 그 앞단에 Cloudflare를 두어 CDN · WAF · TLS 종단을 한 번에 처리합니다. 1인 개발자에게 Cloudflare는 다음과 같은 이유로 거의 필수였어요.

  • DDoS · 봇 방어를 기본값으로 켜놓을 수 있음 — 혼자 공격 대응할 여력이 없으니 통째로 위임
  • 엣지 캐싱으로 오리진 부하 완화
  • TLS 관리 자동화 — 인증서 갱신 같은 운영 잡일에서 해방
  • 전 세계 엣지 응답 — 응답 지연 이득이 체감됨

Flutter 앱은 WebView로 같은 페이지를 띄우는 하이브리드 방식을 택했어요. 이유는 단순합니다. 혼자 만드는데 UI 코드를 두 벌 유지하면 금방 지쳐요. Flutter는 네이티브에서만 되는 기능만 담당하고, 웹·앱 공통 뷰는 한 곳에서 관리합니다. 덕분에 UI 바꿀 때 웹만 배포하면 앱에도 즉시 반영돼요.

 

CHAPTER 02 · 예측 파이프라인

성격이 다른 두 모델을 함께 쓴다

 

Scheduler 내부에서 벌어지는 일이 이 프로젝트의 핵심이에요. 설계를 시작할 땐 단일 모델 하나로 가려 했는데, 실험을 거듭하면서 "어떤 상황에서 강하고 어떤 상황에서 약한가"가 모델마다 다르다는 걸 알게 됐어요.

그래서 성격이 다른 두 종류의 모델을 함께 돌리고, 상황에 따라 가중치를 달리 주는 방식으로 수렴했습니다.

모델 A — 도메인 특화 커스텀 앙상블

국내 유가 데이터로 직접 학습시킨 앙상블이에요. 한국 시장의 고유한 패턴에 집중해서 설계했습니다. 특정 상황에서는 강하지만, 학습 분포 밖의 상황엔 약점이 드러나는 타입이에요.

모델 B — 범용 파운데이션 모델

대규모 시계열로 사전학습된 제로샷 예측 모델이에요. 도메인 특화는 약하지만, 넓은 패턴에 대한 일반화 능력이 좋습니다. 별도 학습 없이 추론만 돌리면 되니까 운영 부담도 적어요.

왜 섞었나 — 두 모델의 상호 보완

각 모델의 강약 영역이 다르다는 걸 관찰했어요. 그래서 예측 시점과 상황에 따라 어느 모델을 더 신뢰할지 다르게 가져갑니다. 단순히 평균을 내는 것과는 다른 접근이에요.

정확한 비중 분포와 블렌딩 규칙은 이 프로젝트의 튜닝 포인트라 공개하지 않지만, 핵심 아이디어는 "한 모델이 약한 구간을 다른 모델이 받쳐준다"는 거예요.

이 구조가 주는 두 가지 이점

첫째, 한 모델의 실패가 전체 실패로 이어지지 않아요. 어느 한쪽이 이상한 결과를 내놔도 다른 쪽이 받쳐주는 구간이 존재하기 때문이에요.

둘째, 두 모델의 업그레이드 경로가 독립적이에요. 새로운 파운데이션 모델이 나오면 그것만 교체해보면 되고, 도메인 쪽 개선은 커스텀 앙상블만 건드리면 됩니다. 1인 작업에서 "어디를 건드리면 어디가 깨지나"를 줄이는 건 엄청 중요해요.

여러 오픈 모델을 거쳐 지금 구조에 정착하기까지 꽤 많은 시행착오가 있었는데, 그 실험들은 모두 별도 디렉토리에서만 돌렸어요. 프로덕션은 검증된 조합만 들어갑니다.

 

CHAPTER 03 · 운영·인프라

1인 운영을 버티기 위한 세 가지 전략

 

혼자 만드는 프로젝트에서 제일 먼저 무너지는 건 모델 정확도나 기능이 아니라 개발자 본인이에요. 외부 공격, 갑자기 죽는 컨테이너, 어제 짠 실험 코드가 오늘 프로덕션을 망가뜨리는 일 — 이런 것들이 쌓이면 프로젝트 자체가 서서히 멈춥니다.

그래서 기획 초기부터 "론칭 후에도 오래 버티려면 이렇게 해야 한다"는 원칙 세 가지를 정해두고 설계를 진행했어요.

전략 01 — 위임할 건 위임한다

보안 · 캐시 · 인증서 같은 영역은 엣지 플랫폼이 저보다 훨씬 잘합니다. Cloudflare를 앞단에 세우고 "내가 안 건드려도 되는 것들"을 거기로 몰아넣었어요.

DDoS 공격이 오면 Cloudflare가 먼저 막고, 인증서는 알아서 갱신되고, 캐시 정책은 대부분 자동으로 굴러갑니다. 이 결정 하나만으로도 제가 직접 신경 써야 할 영역이 크게 줄었어요. 1인 개발자에겐 거의 수면 시간을 사는 것과 같습니다.

비슷하게 무거운 추론 처리도 가능한 한 외부 구성 요소에 맡기고, 제 코드는 오케스트레이션에만 집중하도록 설계했어요.

전략 02 — 장애를 격리한다

각 서비스는 저장소를 통해서만 느슨하게 엮입니다. Scheduler가 Collector 상태를 직접 알 필요 없고, Web이 Scheduler 내부 상태를 알 필요도 없어요.

결과적으로:

  • 한 컴포넌트가 멈춰도 나머지는 돈다
  • 오리진이 잠깐 죽어도 엣지 캐시가 시간을 벌어준다
  • 문제 원인을 찾을 때 의심 범위가 좁다 — "이 데이터가 이상해졌다면 누가 마지막으로 건드렸나" 한 계층만 보면 됩니다

모놀리식으로 만들면 개발 속도는 빠른데, 혼자 유지보수할 땐 장애 하나가 전체로 번지는 게 훨씬 큰 비용이에요. 느슨한 결합은 1인 개발자에게 일종의 보험입니다.

전략 03 — 실험은 격리한다

여러 모델·피처·파라미터를 실험해봤는데, 모두 별도 디렉토리에서만 돌렸습니다. 프로덕션에 들어가는 건 검증된 조합뿐이에요.

이 규칙을 지키지 않으면 시간이 지나 자기가 짠 코드도 못 알아보는 상태가 되더라고요. "실험이 프로덕션에 번지지 않게"는 혼자 만드는 사람의 생존 전략입니다.

설계하면서 배운 것들

  • 인프라 비용보다 인건비가 비싸다 — "더 싸게"보다 "덜 건드릴 수 있게"를 택한다. 월 몇만 원 아끼려다 매주 몇 시간 운영 리소스 태우면 손해예요.
  • 재학습 주기는 "체감 가능한 수준"으로만 — 매일 재학습하고 싶은 유혹이 있지만, 주기적 리프레시로도 충분해요. 너무 자주 돌리면 노이즈만 쌓입니다.
  • 콘솔 한 번 안 열어도 굴러가는 구조가 건강한 구조 — 수동 개입이 필요한 지점이 보이면 그 자리에 스크립트를 심는다. "이거 가끔 내가 고치면 돼"가 쌓이면 결국 못 버팁니다.

 

CHAPTER 04 · 피처 엔지니어링

"가격"만 넣지 않는다

 

 

모델 결과가 생각만큼 안 나올 때, 저는 모델을 바꾸기 전에 입력부터 바꿔봅니다. 긴 실험 기간 동안 느낀 건, 새 모델을 가져오는 것보다 피처를 다시 짜는 게 성능 향상 폭이 큰 경우가 훨씬 많았다는 거예요.

원본 가격 시계열만 덜컥 넣지 않고, 네 가지 관점에서 피처를 구성합니다. 각 관점은 서로 다른 질문에 답하는 피처들의 묶음이에요.

① 움직임의 특성

"얼마나 빠르게 변하고 있는가"에 답하는 피처들이에요. 절대값보다 변화의 성질이 다음 시점을 더 잘 설명할 때가 많았습니다. 구체적인 계산 방식은 이 프로젝트의 튜닝 영역이라 공개하지 않지만, 변동성을 여러 각도에서 수치화하는 장치들이 들어가 있어요.

② 외부 맥락

"시장이 어떻게 보고 있는가"에 답하는 피처들입니다. 가격 그 자체만으로는 잡히지 않는 환경 신호를 모델에 전달하기 위한 통로예요. 이런 외부 신호는 잘 다듬어 넣으면 가격 데이터보다 한 발 앞선 정보가 될 수 있습니다.

③ 구조의 변화

"추세가 꺾일 조짐이 있는가"에 답하는 피처들이에요. 관성에 기댄 예측은 추세 전환점에서 크게 틀리는 경향이 있는데, 이를 보완하기 위한 장치들이 이 카테고리에 들어갑니다. 전환 감지는 이 서비스에서 특히 공을 들인 부분 중 하나예요.

④ 시간의 위치

"연중 어느 지점에 있는가"를 모델이 이해할 수 있게 전달하는 피처예요. 시간 정보는 단순한 숫자로 넣으면 정보가 왜곡되기 쉬운데, 주기성을 매끄럽게 표현할 수 있는 방식으로 가공해서 넣습니다.

핵심 교훈 — 피처가 모델보다 중요하다

"Garbage in, garbage out"이라는 말이 피처 엔지니어링에 딱 들어맞아요. 같은 원본 데이터라도 어떤 파생 신호를 뽑아내느냐에 따라 같은 모델의 예측 성능이 크게 달라집니다.

새 모델 논문을 읽을 시간에 피처 하나를 더 설계하는 게 대체로 더 나았어요. 특히 도메인 지식이 있는 영역이라면 더욱요. 구체적으로 어떤 신호를 어떻게 설계하느냐가 이 프로젝트의 경쟁력이기도 해서, 그 부분은 이 글의 공개 범위 바깥입니다.

 

마무리

데이터 수집부터 론칭까지 배운 것들

돌아보면 개발 기간의 대부분은 "데이터가 충분히 쌓이기를 기다리는 시간"이었어요. 시계열 예측에서는 이게 피할 수 없는 단계거든요. 수집기를 먼저 세우고, 데이터가 쌓이는 동안 설계를 다듬고, 다시 이를 바탕으로 피처와 모델을 실험하는 반복 — 그 사이클이 꽤 길었습니다.

네 개 챕터를 관통하는 한 줄이 있다면 이거예요.

1인 프로젝트는 "제일 좋은 설계"가 아니라 "오래 버틸 수 있는 설계"를 택해야 한다.

최신 모델, 분산 인프라, 자동화된 실험 플랫폼 — 다 해보고 싶은 것들이지만, 그것들이 오래 돌아가게 하는 데 도움이 되는지는 별개 문제였어요.

지금 OilWallet이 론칭할 수 있었던 이유는 대단한 기술을 썼기 때문이 아니라, 제가 계속 건드릴 일이 적도록 초기부터 설계를 잡았기 때문이라고 생각해요. 느슨한 결합, 위임 가능한 건 위임, 실험은 격리, 피처 중심의 성능 개선 — 이 원칙들이 쌓여서 혼자서도 론칭까지 갈 수 있는 시스템이 됐습니다.

이 글이 비슷한 처지의 분들 — 혼자 사이드 프로젝트를 시작하려는 분, 이미 만들고 있는데 지쳐가는 분 — 에게 "아 이렇게 접근할 수도 있구나" 하는 한 가지 시각이 되었으면 좋겠어요.

 

결과물 한 번 보시려면

글로 설명한 시스템이 실제로 뭘 내놓는지 직접 보시는 게 제일 빠릅니다. 이제 막 공개한 따끈한 서비스예요.

👉 https://oilwallet.co.kr

읽어주셔서 감사합니다. 비슷한 고민 하시는 분들, 댓글로 이야기 나누는 것도 환영이에요. 🙇

 

태그: #OilWallet #1인프로젝트 #사이드프로젝트 #아키텍처 #시스템설계 #ML #머신러닝 #시계열예측 #피처엔지니어링 #앙상블 #Cloudflare #개발회고 #론칭

 

댓글