dev.to

I Played Out a Broke Student's Month 500 Times on a Budget i3 Laptop With the Wi-Fi Off. It Warned Him Ahead in 4 of 5 Bad Months.

저가형 i3 노트북에서 한 달을 500번 시뮬레이션했습니다 — 돈이 바닥난 달 5번 중 4번을 미리 경고했습니다

Broke Date는 학생의 은행 명세서를 노트북 안에서 분석해 월말까지의 지출을 500가지 시나리오로 예측하는 오프라인 앱입니다. 합성 데이터 평가에서 돈이 바닥난 달 5번 중 4번을 사전에 경고했지만, 평가 규모가 작고 중간 확률을 과소평가하는 한계도 확인했습니다.

AI 요약

개발자는 매달 한 번 용돈을 받아 생활하는 콜카타의 대학생 친구를 위해 오프라인 개인 재정 예측 앱 Broke Date를 만들었습니다. 은행 앱은 이미 쓴 돈을 보여주지만, 학생이 알고 싶은 건 오늘 얼마를 써도 다음 용돈날까지 버틸 수 있는지입니다. Broke Date는 은행 명세서를 로컬 노트북에서 분석하고, 남은 기간의 지출을 500가지 미래로 시뮬레이션해 이 질문에 답합니다. 클라우드, API 키, 계정 연동을 쓰지 않습니다. 친구는 자신의 실제 명세서로 앱을 실행했지만, 글에 공개한 차트와 수치는 모두 합성 데이터에서 나왔습니다.

예측과 시뮬레이션

TabPFN은 소량의 표 형식 데이터를 다루는 foundation model입니다. 약 300일치 자료로 모델을 처음부터 학습하기 어렵다는 점을 고려해 지출 예측에 사용했습니다. 잔액과 최근 3일·14일 지출, 요일, 용돈날까지 남은 일수, 축제·시험 기간, 예정된 청구서 등 14개 특성으로 다음 날 지출의 단일값이 아니라 분포를 예측합니다. 이때 99개 분위수를 사용합니다.

시뮬레이터는 예측 분포에서 하루씩 지출을 뽑고, 새 잔액을 다음 날 입력으로 돌려보내며 용돈날까지 500가지 경로를 만듭니다. 돈이 줄면 지출도 줄어드는 양상을 잔액 특성으로 반영합니다. 특정 계획의 비용은 같은 난수 추출값을 유지한 채 계획을 넣고 뺀 두 시뮬레이션을 비교해 계산합니다. 따라서 “토요일 영화가 여유 기간을 2.05일 줄입니다”처럼 금액이 아닌 버틸 수 있는 기간으로 결과를 보여줍니다.

‘오늘 안전하게 쓸 수 있는 금액’도 같은 방식으로 구합니다. 오늘 0원, 100원, 200원처럼 지출액을 바꿔 500개 미래를 다시 실행하고, 용돈날 전에 잔액이 바닥날 확률이 기본 설정인 10% 이하로 남는 최대액을 찾습니다. 데모 데이터에서는 700루피였습니다. 400루피짜리 영화를 토요일에 보는 질문에는 500개 경로 중 476개가 용돈날까지 버틴다고 답했습니다. 계획을 넣지 않은 경우보다 16개 적지만, 파산 확률은 5%라 설정한 기준 아래였습니다. i3 노트북에서 이 가정 변경 계산은 0.053초 걸렸습니다.

이상 지출과 모델의 말

TabPFN의 predict(output_type="full")은 예측 분포의 꼬리까지 반환합니다. 보통 쓰는 99개 분위수만 보면 1%보다 드문 지출은 모두 비슷하게 취급되지만, 전체 분포에서는 드문 정도를 더 세밀하게 계산합니다. 합성 명세서의 699루피 휴대전화 충전은 평소 지출에 비해 “이런 지출 249건 중 1건 정도”로 표시됐습니다. 개발자는 일반 지출 193건에서 이 기능이 1-in-33 수준으로 예상한 건수가 5.8건, 실제로 관측한 건수가 4건이라고 보고했습니다.

실제 명세서에는 이상 지출의 정답표가 없으므로 평범한 지출 5건씩을 골라 3배 또는 5배로 부풀린 테스트도 했습니다. 오탐은 없었고, 5배 지출은 탐지기 세 종류 모두 찾아냈습니다. 3배 지출에서는 TabPFN이 15건 중 13건을 잡아 규칙 기반 방식의 11건보다 많았습니다. 다만 개발자는 15건이라는 작은 시험이므로 결과를 제한적으로 해석해야 한다고 덧붙였습니다.

Gemma는 수치 계산을 하지 않고 설명 문장만 씁니다. 처음에는 모델이 계산 결과 전체를 바꿔 말하게 했지만, 제안 질문 14개에서 검증을 통과한 답은 2개뿐이었습니다. 숫자를 빠뜨리거나 질문에 없던 요일을 만들어내는 문제가 있었습니다. 이후 Gemma가 숫자를 보지 않은 채 짧은 반응 한 줄만 쓰게 바꾸자 14개 중 13개가 검사를 통과했습니다. 숫자나 숫자를 뜻하는 단어, 질문에 없는 요일, 판정과 모순되는 표현이 나오면 해당 문장을 버리고 계산 결과만 보여줍니다. 그래도 “여유가 있네요”처럼 모델이 알 수 없는 상황을 판단한 문장이 통과한 사례가 있어 검증에 한계가 남았습니다.

저사양 기기와 데이터 보호

측정은 통합 그래픽을 쓰는 Intel Core i3-1215U에서 진행했습니다. TabPFN이 지출 모델을 적합하고 2,280개 상태의 예측값을 계산한 뒤 500개 경로를 만드는 전체 예측은 47초, 최대 메모리 사용량은 1.0GB였습니다. 이후 가정 변경은 브라우저에서 실행합니다. Gemma 3 1B는 초당 22토큰을 생성하며, 앱은 5GB의 여유 메모리가 있을 때만 4B 모델을 불러옵니다. 모델이 메모리에 오래 남아 다른 작업을 방해하지 않도록 5분 동안 사용하지 않으면 내리고, 동시에 하나의 모델만 실행합니다.

개발자는 테스트에서 로컬호스트를 제외한 네트워크 소켓을 차단했고, 앱의 Content Security Policy도 자기 자신과 로컬 엔진만 연결하도록 설정했습니다. 빌드 과정에서 외부 URL이 묶음에 들어오면 실패하게 했으며, 앱은 노트북 밖으로 나간 요청 수를 표시합니다. 데모와 스크린샷 제작 과정에서 외부 요청은 0건이었습니다. 이 구성은 개인정보 보호를 설명으로만 약속하는 대신 네트워크 접근을 제한하고 확인하려는 설계입니다.

평가 결과와 한계

개발자는 평가 규칙을 먼저 문서화하고 과거 데이터만 사용해 다음 날을 예측하는 walk-forward 방식으로 합성 학생 데이터를 재생했습니다. 10개월, 평가일 138일 가운데 돈이 용돈날 전에 바닥난 달은 5번이었습니다. 앱은 그중 4번을 27일, 21일, 5일, 4일 전에 경고했고, 한 번은 바닥난 당일에야 경고했습니다. 돈이 바닥나지 않은 달 2번에는 오경보를 냈습니다.

‘용돈날 전에 돈이 바닥나는가’ 예측 오차는 Broke Date가 0.207이었습니다. 최근 14일 지출 속도를 유지하는 기준선은 0.441, 지난달을 복사하는 방식은 0.340, LightGBM은 0.248이었습니다. 다만 10개월은 표본이 작고 오차 차이의 신뢰구간이 겹쳐, 개발자가 정한 기준으로는 성능 차이가 유의하지 않았습니다. 명확한 개선으로 보고한 결과는 별도의 TabPFN 모델을 기준점으로 활용한 경우로, 오차가 0.096 줄었고 구간은 -0.163에서 -0.025였습니다. 정확한 용돈날 잔액 예측에서는 LightGBM이 더 가까웠습니다.

확률 보정도 완벽하지 않습니다. 극단적인 확률대에서는 예측 확률과 실제 결과가 대체로 맞았지만, 약 33%라고 예측한 경우 실제로는 79%의 달에 돈이 바닥났습니다. 즉 중간 위험을 지나치게 낮게 잡았습니다. 결과는 한 학생을 흉내 낸 합성 데이터에 기반하며, 친구의 실제 명세서는 아직 같은 방식으로 평가하지 않았습니다. 개발자는 실제 자료의 결과를 공개할 경우 친구가 허용한 범위에서 월별 결과와 사전 경고 일수만 공유하고 금액은 공개하지 않겠다고 밝혔습니다.

dev.to 반응

  • @dronzer2code — 저도 이런 걸 오래 원했습니다. 용돈을 받을 때마다 온라인 도구를 많이 써봤지만 전부 은행 정보를 요구해서 쓰지 않았고, 돈 쓴 내역도 계속 놓쳤습니다. 이제 매일 쓰겠습니다. 고맙습니다, 형🫶🏻
    • @soumyadeepdey — 형, 이 말은 정말 큰 힘이 됩니다🫶🏻 사실 바로 이런 문제를 생각하며 만들었습니다. 예산 관리나 지출 기록 도구가 내 지출을 파악하는 데 은행 정보나 계좌 연결, 금융 데이터 접근을 요구하는 걸 계속 봤습니다. 저도 그런 도구는 마음 놓고 쓰기 어려웠습니다. 은행 정보를 넘기지 않고도 돈을 관리할 수 있어야 한다고 생각했습니다. 은행 연결도 복잡한 설정도 없이 열어서 매일 쓸 수 있는 도구를 만들고 싶었습니다. 용돈을 받은 뒤 쓰고 매일 이용하겠다는 말을 들으니 들인 노력이 보람 있습니다. 며칠 지나 잊어버리지 않고 계속 쓸 만큼 간단한 돈 관리 도구를 만드는 게 목적이었습니다. 써보고 알려줘서 정말 고맙습니다, 형 ❤️
    • @dronzer2code — 🫂
  • @alejandro356bce — 좋네요. 이것도 확인해 보세요: dev.to/alejandro356bce/hola-hang-t...
  • @ssapable — “절대 잔소리하지 않는다”는 설계 결정을 가장 먼저 가져오고 싶습니다. 글을 바탕으로 손으로 그린 55초짜리 만화를 만들었습니다. 한 번의 용돈으로 한 달을 보내는 이야기, 와이파이를 끈 채 자기 i3에서 돌린 500회 시뮬레이션, 돈이 바닥난 달 5번 중 4번을 미리 경고한 결과, i3에서 AI가 돌아갈 거라 생각하지 못했다는 친구의 말까지 그대로 담았습니다. 강요는 없고, 써도 되고 무시해도 됩니다. 가입 없이 볼 수 있는 페이지입니다: ssap-pa.github.io/scripttoon-samples/ 숫자나 표현이 틀렸다면 어느 장면인지 알려주시면 다시 만들겠습니다. 자체 평가 부분에 질문이 있습니다. 합성 연도를 재생했을 때 “나쁜 달”은 잔액이 0원이 된 날을 뜻했나요, 아니면 어떤 최소 잔액 아래로 내려간 경우였나요?

원문: dev.to / 번역·요약: Trawling