Step Out: Gemma와 Ollama를 활용한 오프라인 AI 휴식 계획기
요약
본 글은 Gemma와 Ollama를 활용하여 클라우드 API 없이 로컬 환경에서 작동하는 AI 야외 휴식 계획기 'Step Out' 개발 과정을 소개합니다. 사용자가 가용 시간, 공간, 목표 등 몇 가지 선호도를 선택하면, 앱이 오프라인으로 활동 지침을 생성해줍니다. 이는 직장 생활 중 짧은 시간에 할 수 있는 현실적인 야외 휴식을 돕는 데 초점을 맞추었으며, 로컬 추론 성능과 사용성을 강조합니다.
핵심 포인트
- Gemma와 Ollama를 활용한 오프라인 AI 계획기 개발 사례입니다.
- 클라우드 API 의존성 없이 로컬에서 작동하는 것이 핵심 강점입니다.
- 사용자 입력 기반으로 맞춤형 야외 활동 지침을 생성합니다.
- Apple M1 환경에서의 로컬 추론 속도 측정 결과를 공유했습니다.
This is a submission for the MLH x DEV Writing Challenge.
제가 만든 것 (What I Built)
“풀밭에 나가라(Touch grass)”는 훌륭한 조언이지만, 밖에 나가 구체적으로 주차된 차와 상당한 자신감을 가지고 후진하는 이웃을 발견할 때까지는 그렇습니다.
직장 생활과 하루 대부분을 화면 앞에서 보내는 사람에게 야외 휴식은 일상생활에 맞아야 합니다. 여유 시간이 10분 정도 있고 익숙한 안뜰이 있을 수 있습니다. 회의 두 개 사이에서 멋진 하이킹 코스가 나타날 가능성은 낮습니다.
저는 Step Out이라는 로컬 AI 야외 휴식 계획기를 만들었습니다. 이 앱은 몇 가지 선호도를 입력하면 짧은 활동 하나로 만들어줍니다. 클라우드 추론 API 없이, 앱을 실행하는 컴퓨터에서 Gemma 3 1B를 통해 Ollama를 사용하여 계획을 생성합니다.
아이디어는 간단합니다. 잠시 시간을 내어 계획하고, 그 다음 화면을 뒤에 남겨두는 것입니다.
네 가지 질문과 탈출 전략 (Four questions and an exit strategy)
사용자는 다음을 선택합니다:
- 가용 시간: 5분, 10분, 15분 또는 20분.
- 익숙한 야외 공간: 단지나 안뜰, 익숙한 거리, 또는 야외 좌석 공간.
- 목표: 조용한 휴식, 가벼운 움직임, 또는 주변 환경 관찰.
- 이동성 선호도: 걷기 또는 서 있기, 또는 앉아서 하는 활동.
Step Out은 지침, 일정, 그리고 성찰 프롬프트가 포함된 활동 카드를 반환합니다. 사용자는 이를 브라우저에 저장하거나 앱에서 벗어나 사용할 수 있도록 step-out-activity.txt를 다운로드할 수 있습니다.
계정을 만들 필요도 없고, 정확한 GPS 위치를 제출할 필요도 없으며, 내일 당신을 판단할 연속 기록(streak)도 없습니다.
데모 (Demo)
저장소 (Repository): CynthiaWahome/step-out
비디오 워크스루: Step Out 보기
현재의 워크스루는 선호도 선택, 생성 요청, 그리고 해당 요청이 완료되지 않았을 때의 오류 피드백을 보여줍니다. 아래 설명된 성공적인 생성이나 오프라인 테스트는 보여주지 않습니다.
그 차이점이 중요합니다. 로딩 버튼은 AI 계획이 완료되었다는 증거가 아니라, 단순히 로딩 중이라는 것을 보여주는 증거일 뿐입니다.
Apple M1에서의 로컬 추론 (Local inference)
제가 테스트한 결과, Gemma 3 1B를 Apple M1 노트북에서 로컬로 구동했습니다. 콜드 요청(cold request)은 7.45초가 걸렸고, 워밍업된 요청(warm requests)은 5.45초에서 7.54초 사이였습니다.
이는 제 환경에서의 측정치일 뿐이며, 모든 노트북이 동일한 성능을 보장한다는 의미는 아닙니다. 로컬 추론은 하드웨어, 메모리, 그리고 컴퓨터가 동시에 수행하는 다른 작업에 따라 달라집니다. 브라우저 탭이 47개 열린 노트북이라면 그 나름의 의견(자원 소모)이 있을 수 있습니다.
또한 Wi-Fi를 끄고 다른 인터넷 연결을 활성화하지 않은 상태에서 신선한 세대(fresh generation) 테스트도 진행했습니다. 모델과 애플리케이션 종속성(dependencies) 설치 후에도 로컬 앱은 새로운 계획을 생성할 수 있었습니다.
모델이 노트북에서 실행됩니다. 이 버전은 휴대폰에서는 실행되지 않습니다.
계획을 외부로 가져가기 (Taking the plan outside)
2026년 10월 9일, 저는 거주지 단지 안뜰에서 10분간 앉아서 할 수 있는 활동을 시도했습니다. 조용한 휴식을 선택했고, 생성된 활동은 **“야외 소리 관찰하기 (Notice outdoor sounds)”**였습니다.
일정은 다음과 같았습니다:
| 단계 (Phase) | 시간 (Time) |
|---|---|
| 준비 및 야외 장소 도착 | 1분 |
| ... |
지침은 휴대폰을 사용하지 않고 앉아 있는 동안 세 가지 소리를 관찰하라고 요청했습니다.
휴식 시간은 9분 30초가 걸렸습니다. 저는 화면을 단 한 번도 확인하지 않았습니다. 돌 벤치에 앉아 새소리와 동네의 낮은 웅성거림(hum)을 들었고, 돌아와 브라우저에 제 성찰(reflection)을 저장했습니다.
작은 휴식이었지만, 이 프로젝트에 유용한 현실 점검(reality check)을 제공해 주었습니다. 즉, 제가 인터페이스를 보는 것을 멈추면 지침이 의미가 있을 수 있는가 하는 것이었습니다.
파트너 기술 (Partner Technologies)
로컬 AI 추론을 위한 Gemma와 Ollama
저는 Google의 오픈 웨이트(open-weight) 모델인 Gemma 3 1B를 사용했으며, 모델 태그는 gemma3:1b였습니다. 이 모델은 Ollama에 의해 로컬에서 서비스되었습니다.
Next.js 백엔드는 127.0.0.1:11434의 로컬 Ollama 서비스로 생성 요청을 보냅니다. 이 노트북 설정에서는 선호도(preferences)가 같은 컴퓨터에서 처리되며, 성찰은 해당 브라우저의 로컬 스토리지에 저장됩니다.
유료 추론 API 토큰 비용은 없습니다. 하지만 하드웨어 및 전기 비용이 발생하며, 컴퓨터는 유한한 용량을 가집니다. '로컬'이라는 것이 '소망으로 구동된다'는 의미는 아닙니다.
데모는 또한 한 번에 하나의 생성만 처리합니다. 외부 제공업체의 사용 할당량(usage quota)을 피한다고 해서 애플리케이션 자체의 용량 제한이 사라지는 것은 아닙니다.
코드가 시간을 처리합니다
저는 시간 계산을 모델의 역할 설명에서 제외했습니다.
백엔드는 준비에 1분, 돌아오는 데 1~3분을 할당하고, 나머지 시간을 활동에 배정합니다. 이 단계들이 합쳐져 사용자가 선택한 총 지속 시간이 됩니다.
Gemma는 활동을 선택하고 조정합니다. 10분의 휴식이 어떻게든 14분의 걷기를 포함해야 한다고 결정하지 않습니다.
추론(inference) 전에, 백엔드는 선택된 공간, 목표 및 이동성 선호도에 따라 엄선된 5가지 활동 컬렉션을 필터링합니다. 앉아서 하는 선택은 걸어 다니는 활동을 적격 옵션에서 제외합니다.
이러한 규칙들이 모델의 선택 범위를 좁힙니다. 하지만 야외 장소의 안전성을 검증하거나 생성된 모든 문장이 적절함을 증명하지는 않습니다.
Zod와 Ollama를 사용한 구조화된 출력
작은 모델이라도 애플리케이션에는 여전히 틀린, 그럴듯해 보이는 값을 생성할 수 있습니다. seated-movement-001과 같은 활동 ID는 카탈로그에서 아무것도 가리키지 않으면서도 완벽하게 합리적으로 보일 수 있습니다.
저는 Zod 4로 생성된 JSON 스키마를 사용하여 응답을 제한합니다. 적격 활동 ID들은 응답 스키마의 열거형(enum)을 형성하며, 이는 format 매개변수를 통해 Ollama에 전달됩니다.
백엔드는 그 후 반환된 JSON을 검증하고 선택된 활동이 적격 목록과 일치하는지 확인합니다. 목적은 애플리케이션 레벨의 검사를 유지하면서 응답 구조와 허용되는 ID를 제한하는 것입니다.
그것이 신뢰성을 향상시킵니다. 하지만 모델의 지침을 보편적으로 정확하게 만들거나 생성 텍스트를 완전히 결정론적(deterministic) 시스템으로 바꾸지는 않습니다.
Next.js와 TypeScript
앱은 Next.js 16의 App Router와 TypeScript를 사용하여 인터페이스와 API 라우트를 하나의 프로젝트에 유지합니다.
요청 흐름은 다음과 같습니다:
- 브라우저가 네 가지 선호도를 수집합니다.
- 백엔드가 이를 검증하고 활동 컬렉션을 필터링합니다.
- Ollama가 해당 제약 조건을 사용하여 로컬 모델을 실행합니다.
- 백엔드가 응답을 검증하고 일정을 추가합니다.
- 인터페이스가 활동 카드를 표시합니다.
순수 CSS는 레이블이 지정된 컨트롤, 보이는 키보드 포커스 및 반응형 레이아웃을 제공합니다. 이 앱은 외부 스타일시트나 폰트 CDN에 의존하지 않습니다.
저는 깊은 청록색(deep teal), 따뜻한 크림색(warm cream) 그리고 작은 테라코타 악센트를 사용하여 인터페이스가 차분하고 환영받는 느낌을 주도록 했습니다. 메인 버튼은 찾기 쉽고, 결과는 빠르게 읽히도록 설계되었습니다.
오픈 웨이트가 중요했던 이유
오픈 웨이트 덕분에 자체 하드웨어에서 추론(inference)을 실행하고 로컬 생성 흐름을 호스팅되는 AI API와 독립적으로 유지할 수 있었습니다.
또한 작업에 맞는 모델을 선택하고, 프롬프트를 변경하며, 활동 컬렉션을 편집할 수 있게 해줍니다. 다른 개발자도 코드를 검사하여 자신의 환경에서 애플리케이션을 실행할 수 있습니다.
단점은 제가 설정 전체를 소유해야 한다는 것입니다: 모델 다운로드, 사용 가능한 메모리, 느린 시작 속도 및 연결 오류 등이 그것입니다. 데모의 오류 메시지는 그 책임감을 실질적으로 상기시켜 줍니다.
Gemma는 자체 모델 약관에 따라 사용됩니다. 애플리케이션의 라이선스가 해당 약관을 대체하지 않습니다.
해커톤 경험
저는 Hacktoberfest 2026 첫 주 동안 Step Out을 만들었습니다.
제가 배운 것들
작은 모델도 작업이 집중되어 있다면 유용할 수 있습니다. Gemma 3 1B는 제 인생 전체를 계획할 필요가 없었습니다. 몇 가지 선호도와 적격 활동들을 짧은 야외 휴식으로 변환하는 것이 필요했습니다.
애플리케이션 코드는 여전히 역할을 합니다. 입력 유효성 검사, 활동 필터링, 시간 계산 및 응답 확인은 백엔드에 속합니다. 설득력 있는 프롬프트가 그러한 제어 장치들을 대체할 수는 없습니다.
앱은 누군가 그 앱을 떠나도록 도와줌으로써 성공할 수 있다. 나는 사용자가 외부로 가져갈 수 있는 명확한 계획 하나를 원했다. 인터페이스에 더 많은 시간을 보내는 것은 그 목표에 역행한다.
안뜰 테스트(courtyard test)는 이 프로젝트가 실제로 느껴지게 만든 부분이었다. 프롬프트와 스키마 작업 후에, 나는 마침내 나 자신이 직접 지침을 따라 해보았다.
이번에는 노트북을 닫는 것 자체가 인수 테스트의 일부였다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기