문제: 해변에서 "스티로폼"이라고 말했는데 앱이 못 알아듣는다
2026년 4월, 해변에서 플로깅 중이던 사용자에게서 피드백이 왔다.
"스티로폼 같은 거 같은 데요 — 인식하지 못했어요. 이렇게 떠요."
단순한 UX 버그처럼 보였다. 하지만 파고들수록, 이건 해양 쓰레기 시민과학의 근본적인 문제였다.
왜 "스티로폼"이 인식 안 됐나
우리 시스템은 해변 쓰레기를 ICC(International Coastal Cleanup) 표준 기반 25종으로 분류한다. 해변에서 스티로폼은 3종으로 세분화된다:
- 스티로폼 부표 — 양식장에서 떠내려온 것
- 스티로폼 용기 — 컵라면, 도시락
- 스티로폼 파편 — 부서진 조각
음성 인식 키워드에 "스티로폼 부표", "스티로폼 용기", "스티로폼 파편"은 있었지만, 단독 "스티로폼"은 없었다.
시민은 분류학자가 아니다. "스티로폼 부표"라고 정확히 말할 사람은 없다. 그냥 "스티로폼"이라고 한다.
첫 번째 수정: 역방향 매칭
기존 매칭은 "사용자가 말한 텍스트가 키워드를 포함하는지" 확인했다. "스티로폼"(4글자)이 "스티로폼 부표"(6글자)를 포함할 수 없다.
// 단방향 (기존)
"스티로폼".includes("스티로폼 부표") → false
// 역방향 (추가)
"스티로폼 부표".includes("스티로폼") → true
코드 3줄 추가로 "스티로폼"이 부표, 용기, 파편 모두에 후보 매칭된다.
두 번째: 팝업은 행정이다
인식 실패 시 "확인" 버튼만 있는 모달 팝업이 떴다. 해변에서 바람 소리 속에 장갑 끼고 서 있는 사용자에게, 이건 포기 유도 UX다.
팝업을 제거했다. 대신 플로팅 카드가 뜬다:
"스티로폼 부표인가요?" — "네"라고 말하면 등록된다.
손을 안 쓴다. 전부 입으로.
세 번째: 모든 음성은 학습 데이터
실패한 음성 인식은 버그가 아니라 데이터다.
시민이 해변에서 쓰레기를 부르는 방식 — 이건 어떤 논문에도, 어떤 데이터베이스에도 없는 정보다. voice_litter_log 테이블에 모든 음성 시도를 기록한다.
매주 일요일, cron이 돌아간다. "하얀 공"이 10회 중 9회 부표로 매칭되면, 자동으로 키워드에 승격된다. 다음 주부터 "하얀 공"은 0ms에 매칭된다.
사람이 가르치지 않는다. 사람이 쓰면 기계가 배운다.
저울이 높고 앱이 낮은 게 아니다
처음에 우리는 "저울 = 정밀도 95%, 패드 탭 = 정밀도 30%"로 설계했다. 틀렸다.
분류와 무게는 다른 차원이다.
앱으로 ICC 분류한 것은 — 사용자가 눈으로 보고 확인한 것이므로 — 항상 정확하다. 저울은 "무게"라는 추가 차원을 더한 것이지, 앱 기록의 상위가 아니다.
분류 (classifyMethod) → 항상 정확 (사용자 확인)
무게 (weightMethod) → 방법에 따라 다름 (분류와 별개)
3계층 방어
해변은 인터넷이 없는 곳이다. 음영지역에서도 작동해야 한다.
Layer 1: Static 키워드 ~460개 (0ms, 오프라인 OK)
Layer 2: AI Fallback — Claude Haiku (1~2초, 온라인)
Layer 3: 직접 선택 패드 + 학습 데이터 수집
1억 명을 위한 음성
음성은 "환경운동가의 도구"가 아니다. 음성은 양손이 막힌 보통 사람의 유일한 입력 수단이다.
아이 안은 엄마. 반려견 줄 잡은 산책자. 장갑 낀 정화자. 달리는 조깅러. 숯 묻은 캠핑족. 이 사람들이 쓸 수 있는 유일한 방법이 음성이다.
시민이 말하면 기계가 배운다. 해변에서 시작해서 글로벌로.