> ## Content Index
> Fetch the complete content index at: https://www.popit.kr/llms.txt
> Use this file to discover other available public pages before exploring further.

# AI로 장소 검색 서비스 만드는 중입니다 (기술 2) — 기능마다 다른 모델: 비용·지연·품질을 표로
- URL: https://www.popit.kr/ai-place-search-tech-2-model-per-feature-cost-latency-quality/
- Published: 2026-07-28T22:33:55.000Z
- Updated: 2026-08-17T10:58:33.000Z
- Author: 김형준
- Tags: ai, #서비스소개, LLM

![t2-cost-input](https://www.popit.kr/content/images/wp/2026/07/t2-cost-input-600x276.png)

> 기술 1편은 "로컬 LLM은 벽에 부딪혔고, 클라우드로 가되 기능마다 다른 모델을 쓰기로 했다"로 끝났습니다. 이번 글은 그 **라우팅의 근거가 된 실제 숫자**입니다.  
>  
>  
>  
> 그리고 여기엔 처음에 제가 갖고 있던 두 가지 착각이 나옵니다 — **"AI 서비스는 부를 때마다 돈이 나간다"** 와 **"상위 티어 모델이 더 낫다"**. 둘 다 틀렸습니다.  
>  
> 요금은 벤더 공개가(2026-07 기준·변동 가능), 지연·품질은 유추카 자체 A/B 실측입니다.

## 왜 "한 모델로 통일"이 아닌가

먼저 왜 굳이 나누느냐부터. 유추카가 LLM을 부르는 지점은 크게 여섯 곳입니다.

| 기능              | 언제            | 성격                        |
| --------------- | ------------- | ------------------------- |
| **검색어 파싱**      | 검색할 때마다       | 온라인·짧음·**틀리면 검색 전체가 무너짐** |
| **리랭크**         | 검색할 때마다       | 온라인·**동기 병목** (사용자가 기다림)  |
| **검색 이유**       | 검색 후          | 온라인·**비동기** (늦어도 화면은 안 빔) |
| **영상 장소 추출**    | 채널 추가 시       | 오프라인 배치·대량                |
| **속성 채점(188개)** | 신규 장소 · 야간 배치 | 오프라인 배치·**초대량**           |
| **속성·공간·리뷰요약**  | 신규 장소 · 야간 배치 | 오프라인 배치                   |

**세로로 읽으면 성격이 전부 다릅니다.**

파싱은 문장 한 줄을 다루는 짧은 작업이지만 **여기서 틀리면 뒤가 아무리 좋아도 소용없습니다.** 반대로 속성 채점은 한 곳쯤 틀려도 티가 잘 안 나지만 **6천 곳을 돌려야** 합니다. 리랭크는 품질보다 **지연**이 지배적이고, 검색 이유는 비동기라 느려도 됩니다.

여기서 통일하면 두 방향 다 손해입니다.

- **가장 좋은 모델 하나로 통일** → 6천 곳 배치에서 비용이 터집니다.
- **가장 싼 모델 하나로 통일** → 파싱에서 품질이 무너지고, 그러면 검색 전체가 무너집니다.

그래서 **비용·지연·품질** 세 축을 각각 재고, 기능마다 다른 모델을 붙였습니다.

## 축 1 — 비용

100만 토큰당 가격입니다.

| 모델                        | 입력        | 출력        | 메모                    |
| ------------------------- | --------- | --------- | --------------------- |
| **qwen-flash**            | **$0.05** | **$0.40** | 최저가 (배치 분류·요약)        |
| **gemini-2.5-flash-lite** | **$0.10** | **$0.40** | 채택 (리랭크·추출·속성채점·이유)   |
| gemini-3.1-flash-lite     | $0.25     | $1.50     | 2.5보다 빠르나 **비용 \~3배** |
| gemini-2.5-flash          | $0.30     | $2.50     | **출력비 6배** · 느림       |
| qwen-plus                 | $0.40     | $1.20     | 배치 실험용                |
| text-embedding-v4 (임베딩)   | —         | —         | 질의당 \~$0.000002       |

> **표를 볼 때 주의**: 입력과 출력 가격이 다르고, 대체로 **출력이 4\~8배 비쌉니다.** 그래서 "어떤 모델이 싼가"는 그 기능이 **입력을 많이 먹는지 출력을 많이 뱉는지**에 따라 답이 달라집니다. `gemini-2.5-flash`의 입력은 flash-lite의 3배지만 출력은 **6배**입니다 — 이유 생성처럼 출력이 긴 작업에서 격차가 훨씬 벌어집니다.

### 착각 하나 — "부를 때마다 돈이 나간다"

이 숫자를 실제 규모로 옮겨봤습니다.

**검색 1회 비용**: 질의 임베딩 \~$0.000002 + 리랭크(입력 몇 천 토큰, 출력 \~230 토큰). 합쳐서 **1센트도 안 됩니다.** 사용자가 하루에 검색을 100번 해도 커피값이 안 나옵니다.

**진짜 비용은 배치였습니다.**

| 작업                          | 비용               |
| --------------------------- | ---------------- |
| 속성 188개를 전체 6,041곳에 채점 (1회) | **169분 · 약 $31** |
| 위 작업 표본 631곳                | 약 $0.5 · 5분      |
| 코퍼스 전체 재임베딩 (1회)            | \~$0.3           |
| 청크 임베딩 백필 (1회, 540만 토큰)     | 수천 원             |

**운영비의 대부분이 "가끔 한 번 도는 배치"** 이고, 사용자 트래픽 단가는 사실상 무시할 수준이었습니다.

이게 처음 예상과 정반대였습니다. "AI 서비스는 사용자가 늘수록 돈이 무섭게 나간다"고 걱정했는데, 실제로 아팠던 건 **초기 라벨링 배치 몇 번**이었습니다. 그리고 배치는 **한 번 하면 끝**이고, 언제 돌릴지 우리가 정할 수 있고, 실패하면 다시 돌리면 됩니다.

> **설계에 미친 영향**: 이 사실을 안 뒤로 원칙이 하나 생겼습니다. **"검색할 때마다 하는 일"을 최대한 "색인할 때 한 번 하는 일"로 옮긴다.** 기술 4·6편의 "무거운 LLM 판단은 색인 시점에" 원칙이 여기서 나왔습니다. 품질에도 좋고(더 큰 입력을 줄 수 있으니) 비용에도 좋고 속도에도 좋습니다.

## 축 2 — 지연

리랭크는 **검색 응답을 붙잡는 동기 병목**이라 지연이 가장 중요합니다. 두 층위로 나눠 쟀습니다.

- **순수 LLM 지연** — 엔드포인트를 직접 3회 찔러본 값
- **앱 레벨** — 파싱 + 임베딩 + 리랭크 전부 포함한 실제 응답

| 모델                        | 순수 LLM (3회)                   | 앱 레벨        | A/B 평균         |
| ------------------------- | ----------------------------- | ----------- | -------------- |
| **gemini-2.5-flash-lite** | **\~2.0초** (2.0/2.2/2.0)      | 3.2초 / 3.5초 | \~5초           |
| qwen-flash                | \~2.5초 (2.5/2.8/2.2)          | —           | \~10초          |
| qwen-plus                 | —                             | —           | \~15초          |
| gemini-3.1-flash-lite     | —                             | —           | \~3.5초 (비용 3배) |
| gemini-2.5-flash          | **\~9.8초** (7.8/11.8/**9.8**) | —           | ⚠️ 편차 큼        |

> **왜 두 층으로 재나**: 순수 LLM만 재면 "이 모델이 얼마나 빠른가"는 알 수 있지만, 우리 코드가 얼마나 느린지는 안 보입니다. 앱 레벨만 재면 그 반대고요. **둘 다 재야 "모델을 바꿀 문제"인지 "코드를 고칠 문제"인지 구분됩니다.** 기술 9편에서 진범이 썸네일이었던 걸 찾아낸 것도 이 방식이었습니다.

### 착각 둘 — "상위 티어 모델이 더 낫다"

표에서 눈에 띄는 건 `gemini-2.5-flash`입니다. 이름만 보면 `flash-lite`의 상위 모델인데, **4\~6배 느리고 편차도 큽니다.**

원인은 기술 1편에서 본 그것 — **thinking(추론) 모드**입니다. 답하기 전에 혼자 생각을 길게 쓰고, 그 생각이 전부 출력 토큰이라 지연이 늘어납니다. 리랭크처럼 짧은 판정을 대량으로 하는 작업에서는 **순수한 손해**입니다.

게다가 사고가 하나 났습니다. 특정 검색어에서 **추천 이유가 전부 빈 값**으로 돌아왔습니다. thinking이 출력 예산을 다 써버려서 정작 답할 자리가 안 남은 것으로 보입니다. 추론 강도를 강제로 끄는 옵션을 줘야 겨우 정상화됐습니다.

정리하면 이렇습니다.

|         | flash-lite | flash (상위 티어) |
| ------- | ---------- | ------------- |
| 지연      | 2.0초       | 9.8초          |
| 출력 비용   | $0.40      | $2.50         |
| 품질(P@8) | 동등         | 동등            |
| 안정성     | 항상 이유 생성   | ⚠️ 빈 값 반환 사례  |

**더 비싸고, 더 느리고, 품질은 같고, 덜 안정적.** 모델 티어는 **추론 난도**에 대한 등급이지 **모든 작업에 대한 우열**이 아니었습니다.

### 그리고 "8배 빨라졌다"는 버그였다

측정 얘기가 나온 김에 하나 고백하면, 초기에 **"리랭크가 1초로, 8배 빨라졌다"** 고 기록한 적이 있습니다.

알고 보니 **폐기된 모델명(2.0 계열)** 을 부르고 있었고, API가 404를 뱉어 **LLM을 아예 안 타고 폴백**하고 있었습니다. 빨라진 게 아니라 일을 안 한 거였죠. 정직한 개선은 "2배쯤"이었습니다.

**교훈 둘**: 개선폭이 예상 범위를 크게 넘으면 축하하기 전에 버그를 의심할 것. 그리고 **모델명은 반드시 검증할 것** — 오타나 폐기된 이름을 조용히 폴백으로 삼키는 구조는 위험합니다.

## 축 3 — 품질, 그리고 딱 하나의 예외

리랭크 품질은 A/B 결론이 **"거의 동등"** 이었습니다. 상위 8건 정밀도도, 부적합으로 걸러낸 개수도 세 모델이 엇비슷했습니다.

**품질이 같으면 가장 싸고 빠른 걸 고르면 됩니다.** → `gemini-2.5-flash-lite` 채택.

(다만 `qwen-flash`는 추천 이유 문장이 가장 생생하고 구체적이었습니다 — "루프탑", "통창", "능선" 같은 단어를 살려 씁니다. 요금도 최저고요. 문구 품질을 더 원하면 갈아탈 대안으로 남겨뒀습니다.)

### 파싱만은 비싼 모델을 남겼다

전부 저렴한 모델로 내리는 흐름에서 **딱 한 곳만 예외**로 뒀습니다. **검색어 파싱**입니다.

파싱은 검색어를 지역·업종·의도로 쪼개는 단계입니다. 여기에 flash-lite를 붙여 8개 검색어로 테스트했더니 **2개가 치명적으로 깨졌습니다.**

| 검색어                | 기대                         | flash-lite의 해석           |
| ------------------ | -------------------------- | ------------------------ |
| **역삼역 10분 이내 파스타** | 지역=역삼역 / 이동시간=10분 / 메뉴=파스타 | **문장 전체가 가게 이름**         |
| **스타벅스 강남**        | 상호=스타벅스 / 지역=강남            | **"스타벅스 강남"이 통째로 가게 이름** |

**문장을 쪼개지 않고 통째로 상호명으로 읽어버립니다.** 그러면 지역 조건도, 시간 조건도, 업종 조건도 전부 사라집니다. 검색은 "역삼역 10분 이내 파스타"라는 이름의 가게를 찾다가 아무것도 못 찾고 끝납니다.

**8개 중 2개면 25% 실패율입니다.** 다른 단계라면 감수할 수도 있는데, 파싱은 다릅니다.

> **파이프라인의 앞단일수록 실패 비용이 큽니다.** 뒤에서 아무리 좋은 하이브리드 검색(기술 3편)과 하드게이트(기술 4편)를 돌려도, **입력이 이미 틀렸으면 전부 무의미**합니다. 그리고 앞단 실패는 뒤에서 복구할 방법이 없습니다 — 잃어버린 조건은 어디에도 안 남아 있으니까요.

그래서 파싱만은 **`claude-haiku-4-5`(상위 모델)를 유지**했습니다. 실측 결론은 이랬습니다 — **"경량 모델은 빠르고 싸지만 복합 구문 분해에 약하다."**

여기에 하나 더 얹었습니다. **규칙 기반 사전 분류기**를 앞에 둬서, 명백한 검색어("강남 카페" 같은)는 LLM을 부르기 전에 규칙으로 처리합니다. **비싼 모델을 남기되 호출 횟수를 줄이는** 방향입니다. 비용과 신뢰성을 동시에 잡는 흔한 패턴이고, 부수 효과로 그 경로는 **완전히 결정적**이 됩니다(기술 7편에서 중요해집니다).

## 최종 라우팅

| 기능              | 모델                         | 근거                           |
| --------------- | -------------------------- | ---------------------------- |
| **검색어 파싱**      | claude-haiku-4-5           | 신뢰성 최우선. lite는 8중 2 치명 실패    |
| **리랭크**         | gemini-2.5-flash-lite      | 동기 병목. \~5초 · 품질 동등 · 저렴     |
| **검색 이유**       | gemini-2.5-flash-lite      | 비동기 (대안: qwen-flash, 문구가 생생) |
| **속성 채점(188개)** | gemini-2.5-flash-lite      | 대량 배치                        |
| **속성·공간·리뷰요약**  | qwen-flash                 | 배치 · 최저가                     |
| **임베딩**         | text-embedding-v4 (2048차원) | 교체 시 전량 재임베딩이라 사실상 고정        |

마지막 줄에 주석이 필요합니다. **임베딩은 다른 축과 성질이 다릅니다.** 리랭크 모델은 오늘 바꾸면 오늘부터 적용되지만, 임베딩을 바꾸면 **저장된 벡터 전부가 무의미해집니다.** 검색어는 새 모델로, 문서는 옛 모델로 만든 좌표라 같은 공간이 아니거든요. 그래서 임베딩 교체는 **전체 재임베딩과 세트**이고, 다른 모델 선택보다 훨씬 무겁게 결정해야 합니다.

**기각한 모델도 기록해 둡니다**: `gemini-2.5-flash`(느림·비쌈·빈 이유), `gemini-2.0` 계열(폐기·404), `gemini-3.1-flash-lite`(빠르지만 3배 비쌈), 로컬 리랭커 전부(코사인을 못 이김 — 기술 1편), `exaone3.5:7.8b`(형식 미준수).

## 갈아타기를 쉽게 만든 것

이렇게 기능마다 다른 모델을 붙이려면, **모델을 바꾸는 게 쉬워야** 합니다. 안 그러면 A/B를 못 하고, A/B를 못 하면 이 표의 근거가 안 생깁니다.

문제는 로컬과 클라우드가 **말하는 방식이 다르다**는 점이었습니다.

|       | Ollama (로컬)              | Gemini · Qwen (클라우드)         |
| ----- | ------------------------ | ---------------------------- |
| 경로    | 네이티브 /api/chat           | OpenAI 호환 /chat/completions  |
| 고유 옵션 | think: false             | —                            |
| 인증    | 없음                       | Bearer 토큰                    |
| 응답 구조 | message.content          | choices\[0\].message.content |
| 잘림 판정 | done\_reason == "length" | finish\_reason == "length"   |

그래서 클라이언트를 **프로토콜을 아는 구조**로 만들었습니다. 프롬프트와 JSON 파싱은 **완전히 공유**하고, 프로토콜에 따라 달라지는 것(경로·인증·응답 꺼내는 위치·잘림 판정)만 분기합니다. **모델을 바꾸는 일이 환경변수 네 개를 바꾸는 일**이 됐습니다.  

```
YOUCHUCA_EXTRACT_LLM_PROTOCOL=openai
YOUCHUCA_EXTRACT_LLM_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
YOUCHUCA_EXTRACT_LLM_MODEL=gemini-2.5-flash-lite
YOUCHUCA_EXTRACT_LLM_API_KEY=...
```

여기에 설정 설계를 하나 더 얹었습니다. **각 기능의 기본값이 공용 설정으로 폴백**됩니다. 즉 아무것도 설정 안 하면 예전 그대로 로컬로 돌고, 원하는 기능만 환경변수를 얹으면 그 기능만 클라우드로 갑니다.

> **비파괴적 전환**: 새 기능을 추가할 때 "설정 안 하면 예전과 완전히 동일"을 보장하면, 배포와 전환을 분리할 수 있습니다. 코드를 먼저 배포해 두고(아무 일도 안 일어남), 나중에 환경변수만 켜서 전환하고, 문제가 생기면 환경변수만 되돌립니다. **롤백에 배포가 필요 없습니다.**

클라우드 경로에는 **지수 백오프 재시도**(3회, 500ms 시작)를 붙여 일시적인 429·503을 흡수합니다. 로컬 경로엔 안 붙였고요 — 로컬은 일시 오류가 아니라 진짜 고장이니 빨리 실패하는 게 낫습니다. (다만 기술 9편에서 보듯, 재시도는 외부 장애가 길어질 때 **지연을 증폭**시키기도 합니다. 공짜가 아닙니다.)

## 보너스 — 영상 추출: 10시간을 15분으로

![영상 추출 총 처리시간: 10시간 → 15분](img/t2-extract-time.png)

전환 효과가 가장 극적이었던 건 **영상에서 장소를 뽑는 추출**이었습니다.

|              | 로컬 qwen3:14b | 클라우드 gemini-2.5-flash-lite |
| ------------ | ------------ | -------------------------- |
| 영상당 처리       | **\~45초**    | **1초 미만**                  |
| GPU          | **100% 점유**  | 불필요                        |
| 736영상 채널 총시간 | **\~10시간**   | **\~15분**                  |
| 품질           | 기준           | 구조화 설명 추출엔 **동급 이상**       |
| 영상당 비용       | 전기 + 밤잠      | **1센트 미만**                 |

**반나절 배치가 커피 한 잔 시간이 됐습니다.**

여기서 놓치기 쉬운 부분이 하나 더 있습니다. **로컬 GPU는 하나뿐이라 병렬화가 불가능**했습니다(기술 6편에서 병렬이 오히려 35% 느렸던 이유죠). 클라우드는 동시 호출이 자유롭습니다. 지금은 아직 직렬로 돌고 있어서, **병렬화하면 15분도 더 줄일 여지**가 있습니다. 로컬에서는 애초에 존재하지 않던 선택지입니다.

그리고 이 변화가 만든 진짜 차이는 시간이 아니라 **태도**였습니다. 배치가 10시간이면 **돌리기 전에 망설이게 됩니다.** 프롬프트를 고쳐볼까 하다가도 "또 10시간"이 떠올라 그만둡니다. 15분이면 그냥 돌려봅니다. **기술 9편에서 평가 러너를 479초에서 7초로 줄인 것과 정확히 같은 효과** — 사이클이 짧아지면 시도 횟수가 늘고, 시도 횟수가 품질을 만듭니다.

## 이 글의 결론

- **"모델을 크게"가 아니라 "기능별 적정 모델"** — 파싱엔 신뢰할 모델, 리랭크엔 빠른 모델, 대량 배치엔 최저가.
- **검색 트래픽 단가는 1센트 미만**이고 비싼 건 일회성 배치($31)뿐이었습니다. "부를 때마다 돈"이라는 공포는 사실과 달랐고, 이 사실이 **"무거운 판단은 색인 시점에"** 라는 설계 원칙을 낳았습니다.
- **상위 티어 모델이 더 낫다는 보장은 없습니다.** flash는 flash-lite보다 5배 느리고 6배 비싸고 품질은 같았습니다. 모델 티어는 추론 난도의 등급이지 작업 적합도가 아닙니다.
- **파이프라인 앞단일수록 실패 비용이 큽니다.** 파싱 25% 실패는 뒤 단계 전부를 무의미하게 만들기에, 여기만 비싼 모델을 남겼습니다.
- 그리고 **바꾸기 쉽게 만들어 두는 것 자체가 품질 투자**였습니다. 프로토콜을 추상화하고 설정을 폴백 구조로 두니, 모델 교체가 환경변수 네 줄이 됐고 그래서 A/B를 할 수 있었습니다.

다음 글(기술 3)부터는 이렇게 고른 모델들 위에서 **검색 품질을 어떻게 올렸는지**를 기법별로 깊게 봅니다. 먼저 "임베딩이 놓친 콩국수를 형태소로 잡은" 하이브리드 검색입니다.

- [유튜버추천카페로 이동하기](https://youchuca.popit.kr/?ref=popit.kr)