스마트폰에서 LLM 성능을 자동으로 측정하는 여정 - On-Device LLM Tester 제작기
- TecAce Software
- 6월 5일
- 5분 분량

"스마트폰에 AI를 올린다고요?" — 시작된 무모한 도전
테크에이스 AI Supervision 팀의 On-Device LLM Tester 제작기
"저... 스마트폰에서 LLM 성능을 자동으로 측정하고 싶어요."
회의실에 잠깐의 침묵이 흘렀다.
우리 팀은 자체 온디바이스 AI 챗봇을 개발 중이었다. 문제는 모델을 바꿀 때마다 테스트하는 사람이 직접 폰을 붙들고, 프롬프트를 하나씩 보내고, 시간을 손으로 재야 했다는 것. 그 과정이 무려 60분 넘게 걸렸다.
당시 챗봇에는 3B 파라미터 모델이 탑재되어 있었는데, Phi-4 Mini(3.8B), Gemma 3(4B), Llama 3.2(3B), Qwen 3(4B) 같은 신모델들이 쏟아지고 있었다. 이 모델들을 일일이 수동으로 테스트하다간 모델 비교만 하다가 한 달이 지나가는 상황.
"그냥 자동화합시다."
그렇게 On-Device LLM Tester 프로젝트가 시작됐다.
목표는 딱 세 가지였다.
Hugging Face에서 최신 모델을 자동으로 받아서 스마트폰에 올리기
폰에서 추론을 돌리고 성능 지표를 자동으로 수집하기
"이 모델이 저 모델보다 빠른가? 정확한가?"를 한눈에 볼 수 있게 데이터 정리하기
핵심 가치는 세 단어로 요약됐다.
효율성(Efficiency): 수동 작업을 자동화해서 시간 절약.
데이터 기반(Data-Driven): 기기마다 다른 하드웨어 환경에서 객관적인 성능 데이터 확보.
보안(Security): 사내 보안 요건 충족 및 NPU 최적화 지원.
측정할 지표들
단순히 "빠른가 느린가"만 보려는 게 아니었다.
성능: TTFT(Time to First Token), TPS(Tokens Per Second), 피크 메모리
정확도: 골든 데이터셋 대비 Context Fidelity
배터리 소모율, 할루시네이션 비율 (궁극적 목표)
"ADB로 스마트폰을 원격 조종한다" — 시스템 아키텍처 설계
뭔가 만들려면 먼저 어떻게 만들지를 정해야 한다.
On-Device LLM Tester의 가장 큰 난관은 "PC에서 명령을 내리고, 스마트폰에서 AI가 돌아가고, 그 결과를 다시 PC로 가져오는" 흐름을 어떻게 자동화하느냐였다. 답은 의외로 단순했다. ADB(Android Debug Bridge) — 개발자라면 익숙한, 안드로이드 디바이스를 USB로 제어하는 도구다.
Host와 Target으로 나눈 파이프라인
전체 시스템은 크게 Host(PC/서버)쪽과 Target(스마트폰)쪽으로 나뉜다.
Host 컴포넌트
Model Controller — Hugging Face에서 모델 다운로드 및 양자화(Quantization) 변환
Orchestrator — GitHub Actions를 통해 전체 프로세스 트리거 및 ADB로 폰 제어
Data Collector — 테스트 로그 파싱, DB 저장, 리포트 생성
Target (스마트폰)
Lightweight Test App — 모델 로드 및 추론 실행을 담당하는 단순한 안드로이드 앱
기술 스택 선택기
팀 내에서 가장 많은 토론이 벌어진 부분이 바로 기술 스택이었다.
추론 엔진: Google MediaPipe — 모바일 AI 추론의 사실상 표준, .task 포맷으로 패키징
CI/CD: GitHub Actions(Self-hosted) — 물리적 USB 연결 폰 접근을 위해 직접 Runner 설치
데이터 분석: Pandas/Python
품질 평가: 내부 GPT Tester API
리포트 시각화: Streamlit / Plotly
MVP는 10일 안에
"일단 작동하는 것부터 만들자"는 원칙 아래, MVP 범위를 딱 네 가지로 잡았다.
Deploy: Python 스크립트 + ADB로 모델을 폰에 전송
Run: adb shell로 테스트 앱 실행
Collect: adb logcat으로 레이턴시 데이터를 CSV로 추출
Result: 터미널에 요약 지표 출력 및 엑셀 리포트 생성
"60분짜리 테스트를 5분 안에 끝내자" — 이게 MVP의 진짜 목표였다.
"데이터가 쌓이기 시작했다" — 대시보드와 DB의 탄생
MVP가 돌아가기 시작하자, 새로운 문제가 생겼다.
"테스트 결과가 CSV 파일로 쌓이는데... 어떻게 비교하지?"
Gemma vs Qwen, CPU vs GPU, 삼성 S25 vs S26. 조합이 늘어날수록 엑셀 파일만 쌓여갔다. 뭔가 제대로 된 시각화 도구가 필요했다.
대시보드 아키텍처: FastAPI + React
단순히 JSON 파일을 직접 서빙하는 방법도 있었지만, 나중에 DB를 교체하거나 AI Quality Eval을 붙일 때를 생각하면 API 레이어를 두는 게 맞았다.
결론은 FastAPI 백엔드 + React(Vite + TypeScript) 프론트엔드 조합이었다.
FastAPI: 기존 report.py 파싱/통계 로직 재사용, 자동 Swagger 문서, 멀티디바이스 확장에 유리
React + TypeScript: 복잡하게 중첩된 JSON 메트릭 구조를 타입 안전하게 처리
대시보드 5개 페이지
Overview
KPI 카드(총 테스트 수, 성공률, 평균 레이턴시, 평균 Decode TPS)와 모델별 레이턴시 박스플롯, 카테고리별 성공률 차트. 전체 상황을 한눈에 파악하는 랜딩 페이지.

Performance
레이턴시 히스토그램, p50/p95/p99 분포, 카테고리별 TPS 분석, TTFT 비교, 메모리 사용량 상세 분석.

Compare
두 모델을 드롭다운으로 선택해 나란히 비교. 동일 프롬프트 대비 레이턴시·TPS·실제 응답 텍스트를 side-by-side로, 레이더 차트로 카테고리별 강약점 시각화.

Validation

Responses
실제 응답 텍스트 뷰어. 나중에 AI 품질 평가 점수가 붙을 자리도 미리 마련.
Raw Data
전체 데이터 테이블에 정렬/필터/검색과 CSV 다운로드 기능.
SQLite에 저장되는 정보
기기 정보: 제조사, 모델명, SoC, Android 버전, CPU 코어 수
모델 정보: 이름, 경로, 백엔드
메트릭: TTFT, prefill/decode TPS, 피크 메모리, ITL의 p50/p95/p99
데이터가 쌓이기 시작하자, 비로소 "비교"가 의미를 갖기 시작했다.
"버튼 하나로 벤치마크가 돌아간다" — CI/CD 자동화의 현실
MVP가 완성되고, 대시보드도 생겼다. 그런데 여전히 불편한 점이 있었다.
"테스트하려면 터미널 열고, 스크립트 실행하고, 폰 연결 확인하고..."
진짜 자동화라면 GitHub에서 버튼 하나만 누르면 전부 돌아가야 하지 않을까?
왜 Self-hosted Runner인가?
GitHub Actions를 도입할 때 가장 먼저 부딪힌 벽은 "클라우드 Runner는 물리적 폰에 접근할 수 없다"는 것이었다. 해답은 Self-hosted Runner — 개발 PC에 GitHub Actions Runner를 직접 설치해서, GitHub이 우리 PC를 CI 서버처럼 쓰는 방식이다.
트리거는 workflow_dispatch(수동 실행)만으로 제한했다. 커밋 때마다 LLM 벤치마크가 자동으로 돌아가면 폰이 종일 테스트만 하게 되니까.
파이프라인 흐름
GitHub Actions 트리거
↓
Self-hosted Runner (개발 PC, USB 폰 연결)
↓
Step 1: runner.py — ADB로 폰에 테스트 명령 전송
↓
Step 2: sync_results.py — 폰의 JSON 결과를 PC로 수집
Step 3: ingest.py — JSON → SQLite DB 적재 + runs 테이블 기록
↓
Step 4: GitHub Artifact — .db 파일 업로드 (90일 보존)
↓
GitHub Step Summary에 결과 요약 출력
특히 신경 쓴 부분은 동시 실행 방지였다. 실수로 "Run workflow"를 두 번 누르면, ADB 명령이 겹쳐서 테스트가 완전히 망가진다. concurrency 설정으로 동일 그룹 내에서는 한 번에 하나만 실행되도록 했다.
팀의 코드 리뷰 문화
이 과정에서 팀 동료 Luke가 아키텍처 문서를 꼼꼼히 리뷰해 줬다.
"timeout 초과 시 부분 결과가 로컬에만 남는다는 걸 명시해야 한다"
"commit_sha 주입 방법이 YAML에 안 보인다"
"upload-artifact 실패 처리가 문서 설명과 YAML이 불일치한다"
Andrew는 유효한 피드백은 즉시 반영하고, 범위를 벗어난 것은 이유와 함께 정중히 거절했다.
좋은 기술 문서는 이런 주고받음으로 만들어진다.
"GGUF도 돌려라!" — llama.cpp 멀티엔진으로 진화하다
MediaPipe + .task 포맷으로 시작한 우리 파이프라인에 드디어 한계가 왔다.
Hugging Face에 올라오는 최신 모델들은 대부분 GGUF 포맷이었다. llama.cpp가 밀어붙이고 있는 이 포맷은 PC/서버용으로는 사실상 표준이 됐고, 양자화 옵션이 다양해서 비교 실험에 아주 유리하다. 그런데 우리 앱은 .task 밖에 못 읽었다.
"llama.cpp도 안드로이드에서 돌릴 수 있지 않을까요?"
엔진 추상화: Strategy 패턴의 도입
단순히 if-else로 엔진을 분기하는 건 금방 한계가 온다. 세 번째, 네 번째 엔진(MLC LLM, ExecuTorch, Qualcomm QNN...)이 추가될 때마다 코드가 엉망이 된다.
그래서 InferenceEngine 인터페이스를 도입했다. MediaPipeEngine과 LlamaCppEngine이 이 인터페이스를 구현하고, MainActivity는 엔진 타입에 따라 적절한 구현체를 선택한다. 전형적인 Strategy 패턴이다.
interface InferenceEngine { val engineName: String // "mediapipe" | "llamacpp" suspend fun init(modelPath: String, maxTokens: Int, params: Map<String, String>) suspend fun generate(prompt: String, inputTokenCount: Int): InferenceMetrics fun close()}핵심은 결과 JSON 포맷을 통일한 것이다. 어떤 엔진으로 돌리든 engine 필드 하나만 추가되고, 나머지 구조는 완전히 동일하다. 덕분에 downstream 파이프라인(sync → ingest → dashboard)은 거의 건드릴 필요가 없었다.
llama.cpp를 안드로이드에 올리는 방법
세 가지 방법을 검토한 결과:
HTTP 서버 모드: 별도 프로세스 관리 복잡, ADB 포워딩 꼬임 → 탈락
Termux + llama-cli: PoC용으로는 쉽지만 CI 자동화 불가 → 탈락
JNI 바인딩: llama.cpp를 C++ 네이티브 라이브러리로 빌드해서 안드로이드 앱에 직접 내장 → 선택
llama.cpp를 git submodule로 추가하고, CMake로 arm64-v8a용 .so를 빌드해서 앱에 포함시켰다.
Chat Template 처리
MediaPipe .task 모델은 chat template이 내부 포함 → raw 텍스트를 넣으면 알아서 처리. GGUF 모델은 호출자가 직접 적용 필요. llama_chat_apply_template() API가 GGUF 메타데이터의 template을 자동으로 읽어 처리해줬다.
가능해진 비교 예시
{ "engine": "llamacpp", "model_name": "qwen2.5-1.5b-instruct-q4_k_m.gguf", "backend": "CPU", "metrics": { "ttft_ms": 120, "decode_tps": 4.49, "peak_native_memory_mb": 890 }}test_config.json 하나에 .task 모델과 .gguf 모델을 섞어 넣으면, 파이프라인이 알아서 엔진을 선택해서 돌린다. Q4_K_M vs Q5_K_M vs Q8_0 양자화 비교도 가능해졌다.
앞으로의 로드맵
Phase 6: CPU/GPU/메모리 상세 프로파일링
Phase 6.5: 양자화 비교 파이프라인
Phase 7: 클라우드 배포 아키텍처
가장 기대되는 것은 AI Supervision 연동이다. 폰에서 생성된 응답을 PC로 가져와, AI Supervision에 넘겨 할루시네이션/정확도를 검사하고, 성능 점수와 품질 점수를 합산한 Final Score를 내는 것. 그 점수 하나로 "이 모델이 우리 챗봇에 적합한가"를 객관적으로 판단할 수 있게 된다.
60분짜리 수동 테스트를 5분짜리 자동화로 만들기 위해 시작한 여정이, 멀티엔진 벤치마크 플랫폼으로 성장했다.
About TecAce
테크에이스(TecAce)는 AI/ML 기술 기반의 소프트웨어 개발사로, AI 평가 자동화 및 온디바이스 AI 최적화 분야를 연구합니다. 이 시리즈는 실제 컨플루언스 개발 기록을 바탕으로 작성되었습니다.




댓글