이것을 사고 저것은 사지 말고, 여기에 이것을 버려라: 제가 이해하기 쉽게 만들었습니다
요약
Nikal은 복잡하고 구두로 전달되는 가족 심부름 요청을 구조화된 휴대용 카드로 변환하는 시스템입니다. 오픈 웨이트 Gemma 모델과 ElevenLabs Scribe v2를 활용하여 음성 메모나 텍스트 메시지를 전사 및 추출합니다. 이 시스템의 핵심은 AI가 목록을 생성하는 것이 아니라, 취소 사항, 수량, 불확실성을 보존하며 사람이 최종적으로 검토하고 승인하는 데 있습니다.
핵심 포인트
- AI를 활용해 구두 요청을 구조화된 심부름 목록으로 변환합니다.
- 취소/수량 등 중요한 정보를 누락시키지 않고 시각적으로 유지하는 것이 핵심입니다.
- 자율 에이전트가 아닌, 인간의 최종 검토와 승인을 거치는 시스템입니다.
- Gemma 모델과 ElevenLabs Scribe v2를 활용한 프로토타입입니다.
_본 글은 Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass에 제출하는 내용입니다.
요약
집에 있는 누군가가 당신이 이미 문을 나서기 직전에 빠르게 여러 가지 목록을 말해줍니다:
“우유 1리터 가져와. 빵은 사지 마—이미 있어. 소포는 우체국에 맡겨라. 그리고 공책 세 권도 가져오고.”
대부분의 할 일(task) 앱들은 메시지를 받는 사람이 모든 작업을 수행하도록 만듭니다: 멈추고, 입력하고, 분리하고, 기억하고, 취소 사항을 정확하게 해석해야 합니다.
Nikalll은 이 복잡한 가족 요청을 검토된 휴대용 카드로 바꿉니다. 말하거나 요청을 붙여넣으면, 오픈 웨이트 Gemma 모델이 심부름 목록을 제안하고, 모든 항목을 검토하며, 목적지를 확인하고, 최종 카드를 들고 집 밖으로 나갈 수 있게 합니다.
중요한 점은 AI가 목록을 만들었다는 것이 아닙니다. 중요한 것은 취소된 항목이 계속 보이게 하고, 수량이 붙어있게 하며, 불확실성이 보이게 유지하고, 모델이 아닌 사람이 집을 나가는 것에 대해 승인한다는 것입니다.
제가 만든 것
Nikal은 원래 시끄러운 음성 메모나 혼합된 Hindi/Hinglish/English 메시지로 도착하는 작고 실제적인 가족 심부름 전송 시스템입니다.
이것은 집에 있는 사람이 다른 사람에게 무엇을 사 오거나, 수거하거나, 맡겨야 하는지 기억해야 할 때를 위한 것입니다.
흐름은 의도적으로 짧습니다:
- 캡처(Capture) — 짧은 음성 메모를 녹음하거나 원본 메시지를 붙여넣습니다.
- 전사(Transcribe) — ElevenLabs Scribe v2가 음성을 편집 가능한 텍스트로 변환합니다.
- 추출(Extract) — Backboard를 통해 호출된 Gemma가 구조화된 심부름, 수량, 취소 사항, 목적지 힌트 및 명확화 질문을 제안합니다.
- 검토 및 할당(Review & assign) — 원본 요청은 보이게 유지되는 동안 사람이 각 항목을 편집하거나, 취소하거나, 연기하거나, 할당할 수 있습니다.
- 휴대용 카드(Pocket card) — Nikal이 승인된 작업을 목적지별로 그룹화합니다.
- 외부(Outside) — 사람이 각 항목을 완료됨, 이용 불가, 연기됨 또는 미해결로 표시합니다.
Nikal은 자율 쇼핑 에이전트가 아닙니다. 아무것도 구매하지 않으며, 누구에게도 메시지를 보내거나, 가게를 발견하거나, GPS를 추적하거나, 모델의 유효한 JSON이 요청이 이해되었다는 것을 의미한다고 가장하지 않습니다.
방지하도록 설계된 실패
가장 위험한 실패는 충돌(crash)이 아닙니다. 중요한 부분을 조용히 누락시키는 그럴듯해 보이는 목록입니다:
- “빵 사지 마세요”가 “빵 사기”로 바뀝니다.
- “2리터”에서 수량 정보가 사라집니다.
- “우체국에 이것 맡겨라”에서 목적지가 사라집니다.
- 불분명한 가게가 자신감 있는 추측으로 변합니다.
- 이용 불가능한 품목이 조용히 완료된 것으로 계산됩니다.
Nikal은 이러한 것들을 엣지 케이스(edge cases)가 아닌 제품 상태로 취급합니다.
카드가 보존하는 것
- 포함된 심부름 목록.
- 명시적으로 취소된 심부름 목록.
- 보류되거나 해결되지 않은 심부름 목록.
- 수량 및 단위.
- 사용자의 원래 원문 텍스트.
- 목적지 지정 및 수동 수정 사항.
- 정직한 완료 결과.
준비된 작업 공간은 버전 관리되는 브라우저 스토리지에 저장됩니다. AI 요청은 온라인에서 호스팅되며, 준비된 로컬 카드(local card)는 결과를 표시하기 위해 또 다른 모델 호출을 필요로 하지 않습니다. 이 프로토타입이 완전한 오프라인 AI 애플리케이션이나 검증 가능한 설치형 PWA라는 것을 저는 주장하지 않습니다.
데모
실시간 데모: nikalll.onrender.com
비디오 데모:
영상 워크스루는 기능 소개가 아닌 전체 스토리를 보여줍니다:
- 어수선한 가족 요청으로 시작합니다.
- 취소 및 수량 정보를 보이게 유지합니다.
- Gemma가 초안을 생성하도록 합니다.
- 검토 단계에서 목적지를 수정하거나 확인합니다.
- 포켓 카드를 준비합니다.
- 하나의 작업은 완료로 표시하고, 이용 불가능/보류 상태를 보이게 남겨둡니다.
호스팅 제공업체가 이용 불가능할 경우, 앱은 원문을 유지하고 성공적인 AI 결과를 만들어내기보다는 수동 경로를 제공합니다.
코드
GitHub logo taqui-786 / nikalll
🚶 Nikalll (WalkRecall)
혼란스러운 현관 앞 음성 메모를 구조화되고 오프라인 사용 가능한 심부름 카드로 변환합니다.
집을 나서기 전에 한 번 말하고, 몇 초 만에 검토하며, 완전히 오프라인에서 작동하는 한눈에 볼 수 있는 동네 체크리스트를 들고 나설 수 있습니다.
💡 문제점: '현관 앞 음성 메모'의 혼란스러움
집을 나설 때마다 어머니, 룸메이트 또는 파트너가 빠르고 혼란스러운 심부름 목록을 외칩니다:
"아레 수노! 밖에 갈 거면 채소 시장에서 감자 1kg랑 고수도 좀 사 오고... 근데 토마토는 가져오지 마, 집에 이미 있어... 그리고 식료품점에서 우유 2리터랑 요거트 좀 사 오고, 근데 빵은 절대 사 오지 말고... 그리고 약국에서 혈압 시럽 좀 사 오고, 반창고는 사 오지 마, 서랍에 있잖아!"
app/page.tsx— 캡처, 검토 및 포켓 카드 흐름 처리.app/api/extract/route.ts— 경계가 지정되고 동의된 텍스트 추출 영역.app/api/transcribe/route.ts— 경계가 지정된 오디오 업로드 영역.lib/server/backboard.ts— 명시적인 Backboard 제공자/모델 요청.lib/server/elevenlabs.ts— ElevenLabs Speech-to-Text 어댑터.lib/domain/— 스키마 및 결정론적 카드/증거 로직.tests/— 도메인 및 제공자 정규화 회귀 테스트.
구축 과정 (How I Built It)
오픈 웨이트 AI가 핵심이며, 장식이 아니다
Gemma가 중심 해석 작업을 수행합니다. 즉, 대화적이고 혼합 언어의 가정 내 지침을 경계가 지정된 추출 초안으로 변환하는 것입니다.
브라우저는 제공자나 모델을 선택하지 않습니다. 서버가 환경 설정에서 이를 선택하고 다음 내용이 포함된 고정 프롬프트를 전송합니다:
- 명시적인 제공자 및 모델 이름;
- 스트리밍되지 않는 출력;
- 형식 보조 수단으로 요청되는 JSON 출력;
- 메모리 비활성화;
- 웹 검색 비활성화;
- 도구나 자율적인 동작 없음.
기본 저장소 설정은 Backboard에서 openrouter 제공자를 통해 Gemma를 사용합니다. 정확한 모델은 서버에서 구성 가능하며, 저장소 기본값은 google/gemma-3-27b-it입니다. 클라이언트에게 API 키는 전송되지 않습니다.
Gemma의 출력물이 JSON이기 때문에 신뢰되는 것은 아닙니다. Zod가 응답을 검증하고, 서버는 모든 증거 인용문이 원본 소스에 문자 그대로 존재하는지 확인합니다. 모델은 신뢰할 수 있는 목적지 ID, 애플리케이션 ID, 타임스탬프, 완료 상태 또는 승인 결정을 반환할 수 없습니다.
ElevenLabs는 집중된 입력 경계이다
음성은 원래 문제가 종종 음성으로 시작하기 때문에 유용합니다. ElevenLabs Scribe v2가 전사(transcription)를 처리하며, Nikal은 추출 전에 편집 가능한 텍스트로 스크립트를 보여줍니다.
오디오 업로드는 크기가 제한되며, 서버 경로를 통해서만 허용되고 애플리케이션 데이터로 저장되지 않습니다. UI는 항상 텍스트 입력으로 폴백(fallback)할 수 있습니다.
결정론적 코드가 신뢰 민감 결정을 소유한다
일반 TypeScript—모델이 아닌 것이 소유합니다:
- 스키마 유효성 검사(schema validation);
- 증거 일치(evidence matching);
- 목적지 별칭 일치(destination alias matching);
- 포함/취소/보류 상태(inclusion/cancellation/deferment state);
- 카드 준비 규칙(card preparation rules);
- 로컬 영속성(local persistence);
- 결과 추적(outcome tracking).
확정된 목적지가 없는 포함 항목은 준비된 카드에 들어갈 수 없습니다. 해결되지 않은 항목은 반드시 해결되거나 명시적으로 보류되어야 합니다. 사용 불가능한 항목은 절대 조용히 완료 처리되지 않습니다.
스택 (Stack)
- Next.js 16 App Router
- React 19 및 엄격 TypeScript(strict TypeScript)
- Tailwind CSS 4와 기존 shadcn/Base UI 설정
- Hugeicons
- 런타임 계약을 위한 Zod
- 추출을 위한 Backboard를 통한 Gemma
- 녹취록 작성을 위한 ElevenLabs Scribe v2
- 공개 배포를 위한 Render
첫 번째 시도에서 배운 점 (What I Learned From the First Attempt)
이전 해커톤 프로젝트는 세련된 인터페이스와 긴 기능 목록이 핵심 문제가 해결되었다는 증거가 아님을 가르쳐 주었습니다.
그래서 이 프로젝트는 의도적으로 범위를 좁혔습니다. 데모에는 하나의 완전한 스토리만 있습니다: 지저분한 요청, 출처 연결 AI 초안, 인간 검토, 포켓 카드, 그리고 정직한 결과. 추출된 내용이 올바르게 보여도 틀릴 수 있기 때문에 원본 텍스트를 보이게 유지했습니다. 취소와 불확실성을 일급 상태(first-class states)로 유지한 것도 숨기는 것이 불완전한 결과를 보여주는 것보다 나쁘기 때문입니다.
또한 입증할 수 없는 주장들은 제거했습니다:
- 호스팅된 Gemma가 오프라인 AI라고 설명되지 않음;
- 브라우저 영속성이 완전히 오프라인 PWA(Progressive Web App)라고 설명되지 않음;
- 모델의 JSON이 승인이라고 설명되지 않음;
- 목적지 레이블이 실시간 상점 발견이라고 설명되지 않음;
- 표준화된 평가를 거치지 않은 정확도 백분율은 주장하지 않음;
- 사용 불가능한 업무가 성공 상태로 변환되지 않음.
가장 유용한 엔지니어링 결정은 제공업체 출력을 작고 지루한 경계(boundary)를 넘게 한 것입니다: 이를 검증하고, 원본 메시지에 대한 증거와 비교하며 확인한 다음, 결정론적 애플리케이션 코드가 사용자가 무엇을 승인할 수 있는지 결정하도록 했습니다.
Open Innovation은 왜 중요한가요? (Why Does Open Innovation Matter?)
오픈 모델이 유용한 이유는 Nikal이 불투명한 어시스턴트로 사람을 대체하려 하지 않기 때문입니다. 대신, 지저분한 인간의 인계(handoff) 과정을 검사하고 수정할 수 있도록 만들려고 합니다.
추출 단계의 중심에 오픈 가중치 모델(open-weight model)이 있기 때문에 다음과 같은 이점이 있습니다:
- 모델과 제공업체는 제품 워크플로우를 다시 작성하지 않고도 변경할 수 있으며;
- 추출 프롬프트와 JSON 계약을 검사할 수 있고;
- 실패 사례를 채팅 인터페이스 뒤에 숨기는 대신 수동 기준선(manual baseline)과 비교할 수 있으며;
- 애플리케이션이 승인, 증거, 완료 상태를 모델 외부로 유지할 수 있고;
- 미래의 자체 호스팅 Gemma 배포는 민감한 가계 메시지에 대한 호스팅 데이터 경계를 줄일 수 있으며;
- 동일한 안전 계약(safety contract)으로 다양한 오픈 모델을 검증할 수 있습니다.
Backboard는 애플리케이션에 브라우저 측 공급업체 종속성 대신 명시적인 모델 경계(model boundary)를 제공합니다. 저는 서버에서 Gemma 제공업체/모델을 선택하고, 메모리와 웹 검색 기능을 끄고, 나머지 앱은 그 선택과 독립적으로 유지할 수 있습니다.
ElevenLabs는 의도적으로 범위가 작습니다. 음성 캡처 문제를 해결한 다음, 편집 가능한 텍스트를 동일한 검토 파이프라인으로 전달합니다. 스스로 두 번째 의사 결정자가 되지 않습니다.
주의해야 할 중요한 점이 있습니다: 현재 공개 배포판은 호스팅 서비스를 사용합니다. 오픈 혁신(Open innovation)은 모델 계층을 교체 가능하고 검사할 수 있게 만들지만, 호스팅 추론(hosted inference) 자체를 마법처럼 비공개로 만들어주지는 않습니다. Nikal은 요청이 전사(transcription) 또는 추출을 위해 전송될 때 사용자에게 알려줍니다.
내 에이전트 세션
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기