전체 생성 완료까지 기다리지 않고 Day 1 말하기 문장부터 먼저 열었습니다.
PROJECT NOTE · AI FRONTEND
LLM 레이턴시를
기다림이 아니라 진행감으로.
localingo는 여행 일정 이미지를 읽어 장소별 회화를 생성하는 AI 서비스입니다. 핵심 과제는 빠른 모델을 고르는 데서 끝나지 않았습니다. 긴 이미지 판독, 모델별 환각, JSON 안정성, 비용, 대기 UX를 함께 보며 AI 서비스의 긴 레이턴시를 제품 흐름 안에 녹이는 것이었습니다.
- 0초 이미지 업로드
- 4초 크롭 도착, Day 1 미리보기
- 7~10초 튜토리얼 시작
- 진행 중 튜토리얼 중 전체 Day 생성
PROBLEM
AI 서비스의 병목은
느린 모델만이 아니었습니다.
AI 응답을 기다리는 시간이 사용자 경험의 병목이 됐습니다.
일정 이미지를 읽고 회화를 생성하는 동안 사용자는 20초 이상 결과를 기다려야 했습니다. 아무 피드백 없이 멈춰 있으면 느린 처리보다 먼저 실패처럼 느껴지는 흐름이었습니다.
하나의 요청으로 묶을수록 진행감이 사라졌습니다.
추출, 생성, 검증을 한 번에 끝내려 하면 사용자는 완료 시점까지 기다릴 수밖에 없습니다. 그래서 첫 피드백, 전체 추출, Day별 생성을 나누어 화면에 보이는 진행 상태를 만들었습니다.
빠르게 보이는 것만으로는 충분하지 않았습니다.
LLM 결과는 자연스러워 보여도 교통수단을 임의로 가정하거나 일정 밖 목적지를 섞을 수 있습니다. 기다린 결과를 믿을 수 있도록 판사 LLM으로 실패 패턴을 분류했습니다.
MODEL SELECTION
모델은 속도표가 아니라
실패 방식으로 골랐습니다.
먼저 OCR과 GPT 계열을 실제 이미지로 검증했고, 이후 Gemini 계열 안에서 추출, 생성, 판사 역할을 분리했습니다. 긴 레이턴시를 줄이는 시도와 품질을 지키는 선택이 계속 충돌했습니다.
Tesseract 68% · EasyOCR 42%
OCR 파이프라인 제외
OCR은 장소명 오타가 많고 아이콘, 색상, 레이아웃 정보를 잃었습니다. 결국 LLM 보정이 필요해져 OCR+regex+퍼지매칭+LLM으로 복잡해지는 구조라 제외했습니다.긴 이미지가 96~175px 폭으로 압축
GPT 계열 제외
트리플 일정 이미지는 1:11 이상으로 깁니다. GPT 계열은 긴 이미지를 좁게 축소해 글자를 읽지 못했고, 실제 테스트에서 존재하지 않는 장소를 만들어냈습니다.타일링으로 원본 판독 유지
Gemini 계열 선택
Gemini는 긴 이미지를 타일로 나누어 원본 해상도에 가깝게 읽을 수 있었습니다. 그래서 장소 추출과 회화 생성의 기반 모델군을 Gemini로 좁혔습니다.16개 모델 벤치
역할별 모델 분리
추출, 생성, 판사 역할을 분리했습니다. 빠른 모델은 커버리지가 낮고, 안정적인 모델은 느렸기 때문에 속도 하나가 아니라 장소 커버리지, JSON 안정성, 비용을 함께 보았습니다.긴 여행 이미지 판독에서 GPT 계열보다 안정적이었습니다.
크롭/전체 추출을 나누어 빠른 미리보기와 전체 정확도를 분리했습니다.
속도보다 장소 커버리지와 JSON 안정성을 함께 비교했습니다.
사람 평가와 맞춘 판사로 실패 패턴을 수치화했습니다.
APPROACH
레이턴시를 작업 구조로 나눴습니다.
전체 작업을 하나의 요청으로 묶으면 사용자는 20초 이상 결과 없는 대기 상태에 머물게 됩니다. 그래서 크롭 미리보기로 첫 피드백을 열고, 튜토리얼형 온보딩으로 대기 시간을 채운 뒤, 전체 추출과 Day별 생성을 백그라운드에서 이어가게 만들었습니다.
- 01
크롭 미리보기
전체 이미지를 기다리기 전에 상단 3000px만 먼저 읽어 Day 1 장소를 빠르게 보여줍니다. 크롭 결과는 온보딩 샘플을 만드는 용도로만 사용하고, 전체 결과가 도착하면 교체합니다.
- 02
튜토리얼형 온보딩
크롭에서 얻은 장소 2~3개로 샘플 문장을 만들고, 따라 읽기, 듣기, 답변 선택을 진행합니다. 결과 생성 시간을 서비스 사용법을 익히는 튜토리얼 시간으로 바꿨습니다.
- 03
백그라운드 생성
사용자가 온보딩을 진행하는 동안 전체 일정 추출과 Day별 회화 생성을 백그라운드에서 병렬로 처리합니다.
- 04
순차 공개
Day 결과는 병렬로 만들되 화면에는 순서대로 열어 줍니다. 사용자는 결과 없는 대기 상태에 머물지 않고 준비되는 흐름을 따라가게 됩니다.
DECISIONS
프론트엔드에서 다룬 결정들.
AI 기능을 붙이는 것보다 중요했던 것은 긴 비동기 작업을 제품의 언어로 정리하는 일이었습니다.
느린 모델을 무리하게 숨기지 않기
빠른 모델이 항상 좋은 선택은 아니었습니다. 3.x 계열은 빠르지만 structured JSON 출력과 장소 커버리지가 약했고, 2.5 계열은 느리지만 출력량과 커버리지가 안정적이었습니다.
모델 선택과 UX를 같이 설계하기
모델 자체의 지연을 없애지 못한다면 제품 흐름을 바꿔야 합니다. 크롭 미리보기, 전체 추출 병렬 처리, Day별 필요한 시점 생성을 묶어 체감 대기 시간을 낮췄습니다.
대기 시간을 튜토리얼형 온보딩으로 바꾸기
크롭 장소로 샘플을 만들고, 따라 읽기와 듣기, 답변 선택을 먼저 경험하게 했습니다. 사용자는 사용법을 익히는 동안 기다림을 체감하지 않고, 전체 추출과 Day 생성은 백그라운드에서 진행했습니다.
품질 검증을 경험의 일부로 설계하기
검증은 사용자가 기다린 결과를 신뢰하게 만드는 과정입니다. 판사 LLM으로 실패 패턴을 분류하고, 개선 여부를 반복해서 확인했습니다.
운영 비용까지 같이 보기
모델 선택은 품질만의 문제가 아니었습니다. 크롭, 전체 추출, Day별 생성, TTS까지 합쳐 세션당 비용과 월 사용량을 계산하며 MVP에서 감당 가능한 구조를 골랐습니다.
METRICS
빠른 시작과 결과 신뢰도를
함께 관리했습니다.
사용자가 기다리는 시간은 첫 피드백과 Day별 생성 흐름으로 줄이고, 결과 신뢰도는 별도의 판사 LLM 루프로 끌어올렸습니다.
전체 일괄 생성 대신 Day 1 말하기 문장을 먼저 생성해 학습 시작 시간을 앞당겼습니다.
- 양호율 55% → 99%
- 사람 일치율 93.2%
- F1~F14 실패 패턴
- 교통수단 가정 탐지
- 플레이스홀더 탐지
FRONTEND SCOPE
AI 기능을 화면에서
다루기 위해 나눈 범위입니다.
비동기 UX 설계
LLM API의 긴 작업을 사용자가 따라올 수 있는 상태 모델과 화면 피드백으로 나눴습니다.
모델 성능 비교
16개 모델 벤치, 실패 패턴, 판사 양호율을 비교하며 모델과 프롬프트를 조정했습니다.
상태 전이 설계
크롭 추출, 전체 추출, Day별 생성, shimmer, 캐시, 실패 Day를 독립된 전이 상태로 바라봤습니다.
판단 근거 문서화
모델 선택 기준, 벤치 결과, UX 타임라인을 문서로 남겨 다음 판단이 가능하게 했습니다.
SCREENS
업로드부터 공유까지
대기 상태가 보이도록 구성했습니다.
사용자는 이미지를 올린 뒤 첫 피드백, 장소별 회화 결과, 공유 흐름까지 같은 맥락 안에서 이어서 확인합니다.