On Device AI 모델을 활용한
나만의 운세 앱 만들기

DevFest Incheon 2025 - 발표자: 배필주 (GDG Korea Android Organizer)

안녕하세요! GDG Korea Android Organizer 배필주입니다. 이번 DevFest Incheon 2025에서는 인터넷 연결 없이도 스마트폰 안에서 On-Device AI 운세 앱을 만드는 과정을 통해 현재 온디바이스 모델의 발전이 어디까지 왔는지 이야기 했습니다. 그 내용을 좀 더 자세히 이 블로그 포스트를 통해 공유하려 합니다.

🎯 오늘 우리가 얻어갈 것들

Intro: 오늘 발표 잘할 수 있을까? 🔮

Q. 오늘 발표 잘할 수 있을까?

"걱정하지마!
King of wands 카드는 자신감과 카리스마를 의미하거든.
네 발표는 멋지게 될 거야!"

인터넷이 끊긴 비행기 모드 상태에서도, 이렇게 온디바이스 AI가 즉시 카드를 뽑고 유쾌한 해석을 들려줍니다.

King of Wands - On Device AI Result

왜 굳이 '내 폰'인가? (Motivation)

클라우드 API가 훨씬 똑똑하고 강력한데, 왜 굳이 성능이 제한적인 폰 안(On-Device)에서 AI를 돌려야 할까요? 여기에는 두 가지 결정적인 이유가 있습니다.

1. 돈 (Cost) 💸

Generative AI API로 운세를 한 번 볼 때 약 7원 정도가 든다고 가정합니다. 싸게 느껴지시나요? 하지만 유저 1만 명이 하루에 3번씩만 물어봐도 월 서버비가 600만 원을 훌쩍 넘깁니다. 개인 개발자나 작은 스타트업이 감당하기엔 부담스러운 금액이죠.

2. 프라이버시 (Privacy) 🔒

운세 앱에는 생각보다 은밀한 질문들이 올라옵니다. "저 사실 사내 비밀 연애 중인데 들킬까요?" 같은 텍스트가 서버 로그에 남는다면 어떨까요? 온디바이스 AI는 폰 밖으로 데이터가 1비트도 나가지 않습니다. 완벽한 '대나무 숲'을 제공할 수 있죠.

Part 1. 재료 준비: 도구와 모델

도구 선택: MediaPipe 🛠️

모델을 구동하기 위한 엔진으로는 구글의 MediaPipe를 선택했습니다. 복잡한 TFLite 변환이나 C++ 코딩 없이, Gradle 라이브러리 추가만으로 GPU 가속까지 알아서 처리해주는 안드로이드 개발자의 마법 지팡이입니다.

특히 MediaPipe Studio 웹사이트를 강력 추천합니다. 코드를 짜기 전에 웹 브라우저에서 바로 모델을 다운로드하고 프롬프트를 테스트해볼 수 있어 빠른 검증이 가능합니다.

MediaPipe Studio Screenshot

점술가 후보 라인업 (The Candidates)

우리 앱에 탑재될 '점술가' 모델 후보들을 소개합니다. 구글, 마이크로소프트, 메타 등 빅테크 기업들의 경량 모델들이 면접장에 모였습니다.

모델명 용량 특징
🏋️ Heavy (2GB+)
Phi-4 Mini 3.6GB 강력한 지능, 한국어 지원 but 매우 무거움, 모바일에서 돌아갈까?
Gemma 2 2B INT8 2.4GB 더 똑똑하지만 조금 무거움 (v2), 단점 : 용량 부담
⚖️ Standard (1GB ~ 2GB)
Gemma 2B INT4 1.2GB 성실한 신입, 높은 호환성, 보급형 기기 구동 가능
Llama 3.2 1B 1GB 가벼우나 변환(Conversion) 필요, bin 파일 미제공, 번들링 수고 필요
🪶 Lightweight (Under 1GB)
Gemma 3 1B 529MB 압도적인 용량 효율
Gemma 3 270M 290MB 초경량 (IoT/구형 폰에서도 돌아갈까?)
Gemini Nano 0MB*(앱 패키지 기준) 시스템 내장(AI Core), 최신 플래그십만 지원

⚡ 최종 면접: 실전 테스트 (The Arena)

공정한 비교를 위해 Google Pixel 9 (Tensor G4) 환경에서 똑같은 질문을 던졌습니다.
질문: "타로 태양 카드 설명해줘" .
(👇 각 카드를 클릭하면 상세 결과를 볼 수 있습니다)

📱 Gemini Nano Click ▾

소요 시간 19,903ms
응답 길이 398자
생성 속도 20.00 자/초
응답:

타로 태양 카드 설명

태양 카드는 타로 카드 중에서도 긍정적이고 희망찬 에너지를 강력하게 보여주는 카드입니다.

태양 카드의 이미지:

  • 밝고 뜨거운 태양: 카드의 중심에 위치한 태양은 빛을 뿜어내며 모든 것을 비추고 있습니다.
  • 황금빛 빛: 태양 주변으로 빛이 뻗어 나가며, 풍요로움과 긍정적인 에너지를 상징합니다.
  • 행복한 사람들: 태양 주변에는 웃으며 춤을 추는 사람들이 있습니다. 이들은 행복하고 자유로운 모습을 보여줍니다.
  • 푸른 잔디밭: 태양 아래 푸른 잔디밭이 펼쳐져 있습니다. 이는 풍요와 번영을 의미합니다.

태양 카드의 의미:

  • 자신감과 긍정적인 에너지: 태양 카드는 자신감, 희망, 긍정적인 에너지를 상징

참조 (Reference): 시스템 내장 모델이라 별도 다운로드가 필요 없습니다. 품질이 훌륭하지만 최신 기기만 지원됩니다.

⌛ Phi-4 Mini Click ▾

소요 시간 Timeout
응답 길이 -
생성 속도 -
응답 없음 (No Response):

(장시간 대기 하였으나 응답이 돌아오지 않음...)

모델 파일(3.6GB)은 기기에 넣을 수 있었으나, 실제 로드하여 추론을 시작하자 앱이 멈추거나 응답하지 않았습니다.

원인 분석: 3.6GB의 큰 모델을 모바일 RAM에 올리고 연산하기에는 리소스가 부족했던 것으로 보입니다.

강력한 모델이지만, 모바일 환경에서는 무거워서 구동에 실패했습니다. Timeout!

❌ Gemma 2B INT4 Click ▾

소요 시간 14,958ms
응답 길이 384자
생성 속도 25.67 자/초
응답:

요.

태양카드는 태양의 일관적인 과정인해 생어질은 대중히 자연히 거칠 것입니다. 태양카드는 태양의 자연적인 변화와 발전을 담당합니다.

태양카드는 물, 기, 지형, 생명의 다양한 요소를 포함하여 있습니다. 물은 태양카드의 기관이며, 기는 태양카드의 표면과 표면에 다른 물을 포함합니다. 지형은 태양카드의 지형적 변화와 발전을 담당합니다. 생명은 태양카드의 생명적 요소와 변화를 담당합니다.

태양카드는 태양의 중요한 과정입니다. 태양카드는 태양의 자연적인 변화와 발전을 담당하여 생어질은 대중히 자연히 거칠 것입니다.

태양카드는 태양의 다른 과정들과 연결되어 있습니다. 태양카드는 태양의 지형적 변화와 발전에 관한 기관이며, 태양의 물, 기, 지형, 생명 요소와 연결되어 있습니다.

속도는 빠르지만, 한국어 문장이 붕괴되는 이른바 '왈도체'가 등장했습니다. 탈락!

❌ Gemma 2 2B INT8 Click ▾

소요 시간 33,004ms
응답 길이 583자
생성 속도 17.66 자/초
응답:

요.

일반적인 설명:

태양은 신체의 씨앗 혹은 내부 자리에 나타난다는 해석을 받아 유용한 정보를 제공합니다.

관련된 카드:

  • 타일러 카드: 어우러진 신체의 씨앗 혹은 내부 자리에 대한 정보를 제공하며 각 카드의 의미는 신체의 씨앗에 대한 해석을 통해 얻습니다.
  • 지구 카드: 신체의 씨앗 혹은 내부 자리에 대한 정보를 제공하며, 씨앗과 내부 자리와 같은 부분에서의 연결을 보여줍니다.
  • 마오 카드: 신체의 씨앗 혹은 내부 자리에 대한 정보를 제공하며, 특히 신체의 특성을 강화하는 데 사용됩니다.

상황 설명:

1. 장애물

  • 카드 : 태양
  • 상황 : 장애물이 생기고, 힘든 일에 직면하게 되는 상황

2. 성장

  • 카드 : 태양
  • 상황 : 새로운 시작이나 힘든 시기에서도 이성적인 성장 가능성을 보여주고, 자신을 더욱 발전시키고 성장할 수 있는 기회를 제공합니다.

태양 카드는 신체의 씨앗 혹은 내부 자리에 대한 정보를 제공하는 카드입니다.

주의:

이 설명은 일반적인 해석으로, 상황에 따라 달라질 수 있습니다.

너무 무거워서 느리고, 엉뚱한 소리(Hallucination)를 합니다. 탈락!

❌ Gemma 3 270M Click ▾

소요 시간 6,446ms
응답 길이 387자
생성 속도 60.04 자/초
응답:

네, 타로 태양카드를 설명해 드릴게요.

타로 태양카드는 초고에 100카트(1000원)를 가진 종교적이고 전통적인 태양카드입니다. 태양카드는 태양을 태워 수명 1000시간을 유지하는 데 사용됩니다. 연이든 잃어버리지 않도록 주의해야 합니다.

타로 태양카드는 다양한 모양과 색깔을 가지고 있으며, 태양과 관련된 의미를 담고 있습니다. 태양과 관련된 의미를 담은 타로 태양카드는 100카트의 태양 카트입니다. 이 카트에는 태양의 빛을 태우는 능력을 나타내는 특정 카트의 모양이 포함되어 있습니다. 100카트의 태양 카트에는 태양의 빛을 태우는 능력을 나타내는 카트의 모양이 포함되어 있습니다. 100카트의 태양 카트에는 태양의 빛을 태우는 능력을 나타내는 카트의 모양이 포함되어 있습니다

엄청나게 빠르지만(60자/초) 지능이 너무 낮아 동문서답을 합니다. 탈락!

👑 Gemma 3 1B INT4 Click ▾

소요 시간 16,023ms
응답 길이 851자
생성 속도 53.11 자/초
응답:

타로 태양카드(Taurus Bull Card)는 태양신(Bull)을 상징하는 타로 카드 중 하나로, 입니다. 태양신은 힘, 열정, 발전과 연결되어 있으며, 타로에서 비전 (Vision)을 나타냅니다.

타로 태양카드 설명

  • 기원과 의미: 타로에서 태양신은 비전과 연결되어 있을 뿐 아니라, 비전이 바로 태양신을 생각할 때 나타난다고 합니다. 태양신은 모든 것을 소유할 수 있도록 하라는 의미를 담고 있으며, 비전을 통해 삶에서 더 나은 방향으로 나아갈 수 있도록 연관됩니다.
  • 주요 특징: 태양신은 끊임없는 열정, 강한 의지, 자신을 믿고 열정적으로 열어가는 태도를 상징합니다.
  • 상징: 태양신은 강렬한 에너지와 긍정적인 변화를 나타냅니다. 특히, 열정적인 자신을 믿고 어떤 일에도 충실할 수 있음을 상징합니다.
  • 비전과 연관: 타로에서 비전은 "나는 생각하는 대로 할 수 있다", "나는 모든 것을 만들 수 있다" 라는 말로 자주 사용됩니다. 태양신은 이러한 비전을 실현할 수 있도록, 동기 부여와 열정적 활동을 요청하는 동기 부여를 위한 기구와 연결됩니다.

Winner! 529MB의 초경량 사이즈임에도 53자/초의 빠른 속도와 준수한 한국어 답변을 보여줍니다. 속도, 품질, 용량 3박자를 모두 갖춘 그래도 그중에 가장 괜찮아 보이는 후보입니다.

📊 한눈에 비교하기 (Benchmark)

다양한 모델의 성능을 그래프로 시각화했습니다. Gemma 3 270M이 가장 빠르지만, 실질적인 답변 품질과 속도의 균형은 Gemma 3 1B가 가장 괜찮아 보입니다.

🚀 생성 속도 (Speed) - 높을수록 좋음

Gemini Nano
20.0 t/s
Phi-4 Mini
❌ Timeout (구동 실패)
Gemma 2B INT4
25.7 t/s
Gemma 2 2B INT8
17.7 t/s
Gemma 3 270M
60.0 t/s
Gemma 3 1B
53.1 t/s

⏱️ 전체 소요 시간 (Latency) - 낮을수록 좋음

Gemini Nano
19.9s
Phi-4 Mini
❌ Timeout (측정 불가)
Gemma 2B INT4
15.0s
Gemma 2 2B INT8
33.0s
Gemma 3 270M
6.4s
Gemma 3 1B
16.0s
⚠️ 주의: 속도가 전부는 아닙니다! (Quality Matters)
위 그래프에서 Gemma 3 270M이 가장 압도적인 속도(60 t/s)를 보여주지만, 앞선 면접 결과에서 보셨듯 동문서답을 하거나 한국어를 제대로 이해하지 못했습니다.
반면 Gemma 3 1B는 준수한 속도(53 t/s)와 더불어 (현재까지 비교한 버전에서는) 훨씬 안정적이고 똑똑한 답변 품질을 보여주었습니다. 따라서 속도와 품질의 균형(Trade-off)을 고려할 때 1B 모델이 최적의 선택지(Winner)가 되었습니다.

Part 2. 봉인 해제: 구현 (Implementation)

1. 아키텍처 및 파일 포맷

On-Device AI 개발 시 가장 헷갈리는 것이 바로 파일 포맷입니다. 저도 관련 내용을 확인하면서 각 파일 포멧이 어떻게 다른지 비유로 Gemini 에게 물어봤던 내용을 추가해둡니다.

MediaPipe Architecture Workflow

.tflite, .task, .bin 파일은 모두 AI 모델과 관련이 있지만, "누가 사용하느냐(프레임워크)""무엇이 담겨 있느냐(포함 범위)"에 큰 차이가 있습니다. 핵심 차이를 한눈에 보시기 쉽게 정리해 드립니다.

1. .task 파일: "올인원 밀키트" (MediaPipe)

Google의 MediaPipe 프레임워크에서 사용하는 최신 포맷입니다.

2. .bin 파일: "원재료 (고기/야채)" (PyTorch / ncnn 등)

주로 PyTorchncnn 같은 다른 프레임워크에서 보게 되는 파일입니다. (TensorFlow Lite의 표준 포맷이 아닙니다.)

3. .tflite 파일: "조리 도구" (TensorFlow Lite)

앞서 설명드린 표준 파일입니다.

⚡ 요약 비교표

확장자 주 사용처 포함 내용 전/후처리
.tflite TensorFlow Lite 모델 구조 + 가중치 직접 코딩 (필수)
.task MediaPipe .tflite + 메타데이터 자동 (API)
.bin PyTorch, ncnn 등 주로 가중치(값)만 별도 구현 필요
answered by Gemini3 pro

💡 참고: Gemini Nano는 다릅니다!

우리가 사용하는 커스텀 모델(Gemma)은 MediaPipe를 쓰지만, 시스템 내장 모델인 Gemini NanoGoogle AI Edge SDK (AICore)를 통해 안드로이드 시스템 레벨에서 관리됩니다.

Gemini Nano Architecture (ML Kit)

2. 모델 로딩 (ADB 활용)

530MB 모델을 앱에 포함(assets)시키면 앱 용량이 너무 커집니다. 실무에서는 다운로드 방식을 쓰지만, 개발 단계에서는 ADB로 기기에 밀어넣습니다.

/**
 * 파일 넣기
 * adb push gemma3-1B-it-int4.task /data/local/tmp/
 * 권한 설정
 * adb shell chmod 644 /data/local/tmp/gemma3-1B-it-int4.task
 * 잘 들어갔는지 확인
 * adb shell ls -lh /data/local/tmp/
 */

3. 추론 엔진 코드 (Kotlin)

LlmInference를 빌드할 때 중요한 건 옵션입니다. TopKTemperature 값을 높여 약간의 '광기'와 '창의성'을 허용해야 신비로운 점괘가 나옵니다.

val options = LlmInferenceOptions.builder()
    .setModelPath("/data/local/tmp/gemma3-1B-it-int4.task") // 모델 경로 (.bin 또는 .task)
    .setMaxTokens(1024)   // 생성할 최대 토큰 수 (답변 길이 제한)
    .setTopK(40)          // 확률이 높은 상위 K개의 토큰 중에서만 샘플링 (다양성 조절)
    .setTemperature(0.8f) // 생성의 무작위성 (높을수록 창의적/랜덤, 낮을수록 결정적/반복적)
    .setRandomSeed(101)   // 결과 재현을 위한 시드값 (테스트용)
    .setResultListener { partialResult, done ->
        // 부분 결과 수신 (스트리밍 UI 업데이트)
    }
    .build()

val llmInference = LlmInference.createFromOptions(context, options)

Part 3. 한국어 능력 검증과 '페르소나' (Prompt Engineering)

Gemma는 기본적으로 영어 원어민입니다. 한국어를 할 수는 있지만, 그냥 물어보면 번역기 같은 말투가 나옵니다. 특히 Gemma 2B, 9B 같은 소형 언어 모델(SLM)은 '눈치'가 적고 학습 데이터가 적기 때문에, "네가 누구이고, 어떻게 말해야 하는지"를 아주 구체적으로 정의해 주지 않으면 가장 확률이 높은(평범하고 재미없는) 답변을 내놓습니다.

Before 😓

"너의 운명은 태양이다."

(건조한 번역투)

After (Persona) 😎

"운명의 수레바퀴가 돌기 시작했군요... 붉은 태양의 기운이 느껴집니다."

(컨셉에 충실한 답변)

🚀 소형 모델(SLM) 핸들링 가이드 (Practical Tips)

작은 모델의 성능을 200% 끌어올리기 위한 실전 팁 5가지를 공유합니다.

1. 강력한 페르소나(Persona) 주입: "빙의 시키기"

작은 모델은 모호한 지시를 힘들어합니다. 단순히 "친절하게 말해줘"보다는 구체적인 상황, 직업, 말투를 지정해야 합니다.

2. Cross-Lingual Prompting: "지시는 영어로, 답변은 한국어로"

대부분의 모델은 영어 데이터 비중이 압도적입니다. 논리적인 추론이나 복잡한 지시는 영어로 할 때 훨씬 잘 알아듣습니다.

Tip: 시스템 프롬프트에 Thinking Process는 영어를 사용하게 하고, 최종 Output만 한국어로 변환하도록 유도하세요.

"Think step-by-step in English to ensure logical consistency, then translate the final answer into natural, native-level Korean."

3. 퓨샷 러닝(Few-Shot Learning): "예시 보여주기"

작은 모델에게 긴 설명보다 강력한 것은 '예시(Example)'입니다. 원하는 말투를 1~3개 보여주세요.

User: 안녕?
Assistant: 어서 오게, 운명을 엿보고 싶은가? (신비로운 톤)

User: 오늘 점심 뭐 먹지?
Assistant: 붉은 기운이 감도는 음식이 자네의 기운을 북돋아 줄 걸세. (제육볶음 추천)

User: (실제 질문 입력)

4. 복잡한 지시는 쪼개기 (Chain of Thought)

한 번에 여러 제약사항(말투 + 포맷 + 논리)을 주면 과부하가 걸려 일부를 무시합니다. 시스템 프롬프트 단계에서 1. 내용 요약 -> 2. 말투 변환 순서로 사고하도록 유도하세요.

5. 매개변수(Parameter) 조절

창의성을 높이려고 Temperature를 너무 높이면(1.0 이상) 횡설수설(Hallucination)할 수 있습니다.
추천: 0.7 ~ 0.8 (창의적 글쓰기), 0.2 ~ 0.5 (논리적 태스크)

💡 요약: 작은 모델은 '똑똑한 신입사원'

대충 말하면 못 알아듣지만, 1) 역할을 확실히 주고(페르소나), 2) 업무 매뉴얼을 보여주면(퓨샷), 3) 영어로 지시했을 때 대형 모델 못지않은 가성비 최고의 성능을 보여줍니다.

마무리 🌌

📚 함께 해보기 (Codelabs)