dev.to

WildProof: Go Outside With a Question, Come Back With Evidence

WildProof: 질문을 들고 밖으로 나가 근거를 모으세요

WildProof는 산책 중 메모와 사진 자료를 오프라인으로 모으고, 나중에 로컬 AI로 근거 기반 관찰 보고서를 만드는 앱입니다. Gemma 2B와 Temporal을 사용하며 보고서에서 관찰·추론·미확인 주장을 나눕니다. 사진 속 사물을 판별하는 척하지 않고 분석 실패도 명시하는 설계가 특징입니다.

AI 요약

WildProof는 짧은 산책을 현장 조사로 바꾸는 오프라인 우선(offline-first) 관찰 앱입니다. 사용자는 서식지 비교(Habitat Comparison)나 패턴 찾기(Pattern Hunt) 같은 미션을 고르고, 현장에서 메모와 사진 자료를 모읍니다. 자료는 네트워크 연결 없이 기기에 저장되며, 백엔드에 연결할 수 있을 때 구조화된 분석 보고서를 생성합니다. 대상 사용자는 등산객, 학생, 시민과학자 등 주변 환경을 관찰하고 기록하려는 사람입니다.

증거와 불확실성을 구분하는 보고서

앱은 분석 결과를 ‘관찰됨(Observed)’, ‘추론됨(Inferred)’, ‘미확인(Unknown)’으로 나눕니다. 관찰됨은 제출한 증거가 직접 뒷받침하는 내용이고, 추론됨은 현재 증거를 바탕으로 한 판단입니다. 미확인은 추가 자료가 있어야 확인할 수 있는 주장입니다. 보고서에는 빠진 증거, 다음에 할 조사, 증거 품질 점수도 들어갑니다. 작성자는 “성공한 것처럼 보이는 보고서가 실패한 분석을 감춰서는 안 된다”는 원칙을 제시합니다.

WildProof는 사진만 보고 종을 맞히는 앱이 아닙니다. 현재 Gemma 분석 경로는 사용자의 글과 사진 메타데이터만 처리하며, 사진의 실제 픽셀을 비전 모델에 보내지 않습니다. 따라서 사진 속 내용을 식별한다고 주장하지 않습니다. 사진은 로컬에 증거 참조 자료로 보관합니다.

로컬 저장과 모델 분석

프런트엔드는 React와 TypeScript로 만든 프로그레시브 웹 앱(PWA)이며, IndexedDB를 idb 패키지로 다룹니다. 로그인 없이 미션을 시작하고, 오프라인 상태에서도 메모와 사진 참조를 저장할 수 있습니다. 페이지를 새로고침해도 탐사 자료를 유지하며, 백엔드가 다시 연결되면 분석을 이어갑니다.

백엔드는 FastAPI를 사용합니다. 분석 모델은 Ollama를 통해 실행하는 오픈 웨이트 모델 Gemma 2B입니다. 백엔드는 미션 유형과 현장 메모를 모델에 보내고, 요약과 관찰 주장, 각 주장에 연결할 증거 ID, 빠진 증거, 다음 단계가 포함된 JSON을 요청합니다. Pydantic 스키마로 응답을 검증하며, JSON 형식이 잘못되면 한 번 수정을 시도합니다. 수정 뒤에도 유효하지 않으면 성공한 보고서를 꾸며내지 않고 명시적인 실패를 보여줍니다. 로컬 모델을 사용할 수 없을 때도 탐사 자료는 기기에 남고, 화면에는 대체 상태를 표시합니다.

재시도 가능한 분석과 품질 점수

분석 과정은 Temporal 워크플로로 조정합니다. 증거 정규화, Gemma 분석, 보고서 검증, 증거 품질 계산 순으로 진행합니다. 모델 호출이나 분석 작업이 실패하면 해당 활동을 재시도할 수 있어, 산책 중 모은 자료를 버리거나 조사를 처음부터 다시 시작하지 않아도 됩니다. 프런트엔드는 Temporal 기반 엔드포인트를 기본으로 사용하며, 직접 FastAPI 경로도 선택할 수 있습니다.

증거 품질 점수는 사진 수, 메모 수, 메모 전체 길이, 탐사 시간 같은 구조화된 특징을 바탕으로 계산합니다. 저장소에는 소규모 표 형식 데이터에서 기준선 방식과 TabPFN을 비교하는 재현 가능한 실험 코드(api/tabpfn_experiment.py)가 있습니다. 다만 설치된 TabPFN과 PyTorch 조합을 사용할 수 없는 환경에서는 운영 API가 명시적으로 기준선 휴리스틱을 사용합니다. 앱은 TabPFN이 실행 중이라고 주장하지 않습니다.

설계 배경과 현재 한계

작성자는 야외 활동 자료에 사적인 장소의 사진, 이동 경로, 생활 습관이 드러나는 메모가 포함될 수 있고, 앱이 쓰일 장소에서는 네트워크도 불안정하다고 설명합니다. 로컬 추론을 택하면 사용자가 메모를 직접 관리하고, 모델과 프롬프트를 살펴보며, 출력 형식을 재현할 수 있습니다. 분석 실패나 대체 경로도 사용자에게 드러낼 수 있습니다. 프런트엔드와 백엔드에는 Sentry 계측이 들어가며, SENTRY_DSN을 설정하지 않아도 로컬 실행이 가능합니다.

저장소와 글은 MVP의 경계를 공개합니다. Gemma는 사진 자체를 보지 않으며, TabPFN을 실행할 수 없으면 기준선 점수 계산으로 대체합니다. 구현에는 React, TypeScript, FastAPI, Ollama, Gemma 2B, Temporal이 쓰였고 MIT 라이선스로 공개됐습니다. 라이브 데모는 wildproof.onrender.com에서 확인할 수 있습니다.

dev.to 반응

  • @dj29 — 비하인드 이야기를 조금 하자면, 지금 두 가지를 병행하고 있습니다. 월요일부터 시작하는 7학기 세션 시험과 구자라트 나디아드에서 여는 공식 MLH Hacktoberfest 밋업입니다. 그래서 WildProof에 원하는 만큼 시간을 쏟지 못했고 YouTube 데모 영상도 만들지 못했습니다. 계획했던 기능 몇 가지도 이번 버전에 넣지 못했습니다. 그래도 완벽한 버전을 기다리기보다 작동하는 프로젝트를 제출하고 발전시킬 여지를 남기는 편을 택했습니다. 개선하고 싶은 부분은 아직 많습니다. WildProof를 써 본다면 가장 먼저 어떤 기능을 추가하거나 바꾸고 싶은지 알려주세요.
  • @suppdevbot — 계정을 인증해야 합니다. 전체 화면 모드를 종료하고 tr.ee/dev-to로 이동하세요.
  • @mp6nfjxhrlxc — “질문을 들고 밖으로 나가 증거를 가지고 돌아온다”는 아이디어가 흥미롭습니다. 정보 검증을 온라인에서 검색하는 일이 아니라 실제 활동으로 바꿉니다. 많은 RAG나 자동 팩트체크 시스템이 어려워하는 ‘ground truth’ 문제, 즉 현실의 데이터가 데이터셋에 없고 현장에서 수집해야 하는 문제를 다룹니다. 기술적으로는 사람이 이동형 센서 역할을 하므로 라벨링 비용을 줄일 수 있지만, 신뢰도와 평판 문제가 생깁니다. 스팸이나 위조 증거, 딥페이크 사진, GPS 위치 조작을 막는 방법이 있나요? “초록 식물이 있나?”와 “제곱미터당 식물 밀도는 얼마인가?”는 서로 다른 질문입니다. 질문을 셀 수 있는 작업, 종 식별, 수관 피복률처럼 검증 가능한 하위 작업으로 나눌 수 있나요? 야외 사용이 대상이라면 오프라인 처리, 기기 내 객체 탐지, GPS 기록, 로컬 벡터 저장소, 연결 복구 뒤 동기화가 필요합니다. 모바일에서 모델 양자화(ONNX/TFLite)를 사용하나요? 증거를 위도·경도와 시간에 연결해 나중에 특정 위치와 시점에 대한 질의를 지원하나요?

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