DabbaETA: 고객 주소 정보를 클라우드로 전송하지 않는 '이 도시락은 늦을까?' 예측기
요약
DabbaETA는 작은 배달 사업자를 위해 설계된 로컬 우선(local-first) 디스패치 어시스턴트입니다. 이 도구는 고객의 민감한 주소 정보를 클라우드에 전송하지 않고, 오직 현지 노트북에서 실행됩니다. TabPFN과 Gemma를 활용하여 예상 도착 시간(ETA) 및 지연 위험도를 예측하며, 데이터 보안과 비용 효율성을 극대화했습니다.
핵심 포인트
- 고객 정보가 로컬 기기에 머물러 개인정보 보호에 강점
- 클라우드 API 의존 없이 오프라인으로 작동 가능
- 메시지당 비용이 없어 소규모 사업체에 경제적
- 모델 교체가 쉬워 지속적인 업그레이드가 용이
본 글은 HF26 Challenge: Side Hustle에 제출하는 내용입니다.
오후 1시, 전화벨이 멈추지 않는다
인도에서 작은 도시락(tiffin service) 가게를 운영한다면 이 날을 경험해 봤을 겁니다. 12시에 비가 오기 시작했습니다. 배달 기사 한 명이 신참입니다. 총 8개의 주문이 나갔습니다. 오후 1시쯤 되자 고객들이 전화를 걸어옵니다: "Bhaiya, khana kab aayega?" (형님, 밥 언제 와요?).
가게 주인은 수개월간의 배달 기록을 노트나 스프레드시트에 가지고 있습니다. 하지만 아무도 이 데이터를 활용해서 이런 상황을 미리 예측해 본 적이 없습니다. Swiggy 같은 곳에는 이를 위한 ML(머신러닝) 팀이 있습니다. 하지만 40개 주문 규모의 주방에는 그런 팀이 없고, 그 주인은 고객 이름, 전화번호, 집 주소를 임의의 SaaS(Software as a Service)에 업로드할 생각이 없습니다.
그래서 저는 그들이 이미 가지고 있는 노트북에서 실행되는 버전을 만들었습니다.
제가 만든 것
DabbaETA는 작은 배달 사업체(도시락 서비스, 빵집, 지역 택배사 등)를 위한 로컬 우선(local-first) 디스패치 어시스턴트입니다.
- 과거 배송 기록을 CSV 파일로 업로드합니다 (스키마가 검증되어 로컬 SQLite 파일에 저장됩니다).
- TabPFN이 보류 중인 모든 주문의 예상 도착 시간(ETA)과 지연 위험도를 예측하며, 이는 HIGH / MODERATE / LOW 배지로 표시됩니다.
- Gemma는 동일한 기기의 Ollama에서 실행됩니다.
• 고객 데이터는 제자리에 머뭅니다. 이름, 전화번호, 주소는 LLM API로 절대 전송되지 않습니다. Gemma가 로컬에서 실행됩니다. 기기 밖으로 나가는 유일한 것은 숫자(거리, 교통량, 날씨, 준비 시간) 테이블이며, 이는 TabPFN으로 전송됩니다. 예측기는 이미 tabpfn-client API와 로컬 tabpfn 패키지를 모두 지원하는 BasePredictor 인터페이스 뒤에 자리 잡고 있어, 완전히 오프라인으로 전환하는 것은 재작성(rewrite)이 아닌 설정 변경(config change)만으로 가능합니다.
• 메시지당 비용 없음. 모든 ETA 질문과 측정된 API에서 작성되는 메시지는 비용이 발생합니다. 티핀 소유주에게는 이것이 빠르게 누적됩니다. 로컬에서는 한계 비용(marginal cost)이 0입니다.
• 한 줄로 모델 교체 가능. OLLAMA_MODEL은 환경 변수(env var)입니다. 더 나은 작고 힌디어 지원 모델이 출시되면, 소유주는 코드를 건드리지 않고도 업그레이드할 수 있습니다.
• 종속성 없음 (No lock-in). 가격 변경만으로 고객의 일일 워크플로우를 중단시킬 수 있는 공급업체는 없습니다.
벤치마크(그리고 이것이 보여주지 않는 것)
저는 실제 티핀 데이터셋을 가지고 있지 않았기 때문에, Kaggle의 Food Delivery Times 데이터셋 스키마와 일치하는 5,000개의 합성 주문을 생성했습니다: 거리, 교통량, 날씨, 차량 유형, 준비 시간, 배달원 경험, 저녁 러시아워 및 몬순 효과. 이 숫자들을 실제 주방에 대한 주장이라기보다는 파이프라인이 작동한다는 것을 확인하는 수단으로 간주해 주세요.
전체 데이터 (4,000개 학습 / 1,000개 테스트):
| 모델 | MAE (분) | RMSE | R² | 적합 시간 |
|---|---|---|---|---|
| TabPFN | 3.60 | 6.05 | 0.937 | 0.39초 |
| ... |
하지만 작은 가게 주인은 수천 개의 행을 가지고 있지는 않습니다. 그들은 몇 주간의 기록만 가지고 있죠. 이것이 벤치마크 스크립트가 50개, 100개, 그리고 200개의 학습 행에 대해 소규모 데이터 실험을 수행하는 이유이며, 예측기가 교체 가능하다는 이유입니다. 만약 XGBoost가 사용자의 데이터 크기에 더 적합하다면, 단 한 줄로 그것으로 전환할 수 있습니다. 전체 결과와 차트는 리포지토리의 docs/benchmark.json과 docs/benchmark.png에서 확인할 수 있습니다.
작동 방식 (How it works)
flowchart TD
A[사장이 CSV 업로드] --> B[(SQLite, 로컬)]
B --> C[TabPFN: ETA + 지연 위험]
...
네이티브 툴 호출에 의존하지 않는 Gemma 에이전트. 소규모 로컬 모델들은 이 기능에서 신뢰성이 떨어지기 때문에, Gemma에게 {"tool": ..., "args": ...}를 방출하도록 프롬프팅하고 저는 이를 정규표현식 추출과 재시도 루프(retry loop)로 파싱합니다. 세 가지 툴이 있습니다: predict_eta, list_risky_orders, draft_message. 휴리스틱 라우팅은 모델의 JSON 형식이 잘못되었을 때조차 _"Aaj kaunsi orders late hongi?"_와 같은 Hinglish(힌글리시) 질의를 포착합니다.
오전 실행을 위한 Temporal. 디스패치 실행(dispatch run)은 예측 단계와 여러 LLM 호출을 연결하며, 이 중 어느 하나라도 중간에 실패할 수 있습니다. 각 단계는 지수 백오프 재시도(exponential-backoff retries)가 있는 활동(activity)이므로, 한 번의 불안정한 호출 때문에 전체 실행을 다시 할 필요가 없습니다. Temporal에 접근할 수 없다면, 앱은 인프로세스(in-process) 실행으로 폴백하여 데모를 어떤 노트북에서도 작동하게 합니다.
가시성을 위한 Sentry. 모든 Gemma 및 TabPFN 호출 주위에 사용자 지정 스팬(custom spans)을 추가하여 latency_ms, tokens_in, tokens_out을 기록하며, 이를 통해 디스패치 실행이 느리게 느껴질 때 시간이 어디에 쓰이는지 명확하게 알 수 있습니다.
테스트. 8개의 pytest 테스트가 주문 스키마 유효성 검사, 예측기 인터페이스, 에이전트 JSON 추출, 힌디어 질의 라우팅, 메시지 초안 작성, 워크플로우 행복 경로(happy path), 그리고 API 엔드포인트를 포괄합니다.
누가 돈을 지불할 것이며, 얼마나 많이 (Who would pay, and how much)
아직 검증되지 않은 가설입니다: 도시락이나 빵집 주인은 고객이 전화하기 전에 '어떤 주문이 지연될지 알려주고, 대신 메시지를 작성해 주는' 서비스에 대해 소액의 월정액 또는 일회성 설치비를 지불할 것입니다. 여기서 핵심 판매 포인트는 'AI'가 아니라, 전화를 아끼고 화난 고객을 줄이는 것입니다. 추론(inference)이 로컬에서 이루어지기 때문에 고객당 비용이 거의 0에 가깝습니다. 따라서 아주 적은 가격만 책정해도 마진이 남습니다. 만약 클로즈드 API 버전으로 출시한다면, 토큰 비용을 충당하기 위해 더 높은 요금을 부과해야 할 것입니다.
첫 사용자 (First user)
아직 실제 유료 사용자를 확보하지 못했습니다. 가짜 사용자를 만들어내기보다는 이 사실을 말하는 편이 낫겠습니다. 위에 설명된 모든 것은 합성 데이터(synthetic data)로 구동되므로, 다음으로 할 일은 실제 사장님의 CSV 파일에 적용해 보고 어디서 문제가 생기는지 확인하는 것입니다.
제한 사항 (Limits)
- 데모 데이터셋은 합성 데이터이므로, 실제 환경에서의 정확도는 다를 수 있습니다.
- 표에서 볼 수 있듯이, 대용량 데이터에서는 XGBoost가 TabPFN보다 우수합니다.
- TabPFN의 무료 API 키는 비상업적입니다. 이를 판매하려면 Prior Labs로부터 상업적 라이선스를 받거나, 자체 조건 하에 로컬
tabpfn패키지를 실행해야 합니다. - Gemma는 짧은 초안 작성에는 적합하지만 힌디어 문법에는 완벽하지 않으므로, 사장님들은 메시지 전송 전에 내용을 검토(skim)해야 합니다.
수상 부문 (Prize categories)
- TabPFN의 최적 활용: TabPFN은 예측 핵심(ETA 및 지연 위험)이며, XGBoost 및 선형 회귀와 비교되었고, 이 예측을 행동으로 전환하는 더 넓은 에이전트 내에 포함되어 있습니다.
- Gemma의 최적 활용: Gemma는 Ollama를 통해 로컬에서 실행되며, 채팅 에이전트, JSON 도구 라우팅, 그리고 힌글리시/힌디어/영어 메시지 초안 작성 기능을 구동합니다.
- Temporal의 최적 활용: 아침 배차(morning dispatch)는 지수 백오프 재시도(exponential-backoff retries)가 포함된 다섯 가지 활동으로 구성된
DispatchWorkflow입니다. - Sentry Agent Tracing의 최적 활용: 사용자 정의된
llm.gemma및tabpfn.predict스팬이 지연 시간과 토큰 수를 기록합니다.
다음 계획 (What's next)
실제 사장님의 데이터에 적용하고, 라이더 수준의 기능을 추가하며, 원터치 WhatsApp 전송 흐름을 구축하고, 새로운 배달 건이 기록될 때마다 자동으로 재학습할 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기