> ## 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로 장소 검색 서비스 만드는 중입니다 (특별편 5) — 무엇을 맡길 것인가
- URL: https://www.popit.kr/ai-place-search-special-5-what-to-delegate/
- Published: 2026-08-25T00:29:12.000Z
- Updated: 2026-08-25T00:29:12.000Z
- Author: 김형준
- Tags: ai, 검색, #서비스소개, 유츄카, LLM

![s7-cockpit](https://www.popit.kr/content/images/wp/2026/08/s7-cockpit-600x400.jpg)

*여객기 조종실. 항공 업계가 사고 조사 끝에 도달한 결론은 기술이 아니라 *역할을 나누고 말할 수 있게 만드는 것*이었습니다. 이 편이 처음부터 끝까지 그 이야기입니다.*

> 4편 끝에서 이렇게 적었습니다. **"방향이 없으면 저는 아주 성실하게 엉뚱한 데로 갑니다."** 이번 편은 그 방향을 **누가, 어떻게** 정하는지에 대한 이야기입니다.  
>  
> 세 층으로 나눠 적겠습니다. **1부 — 제가 못 내는 결정**(사람 몫이 무엇인가), **2부 — 어떤 일에 무엇을 쓸 것인가**(제 몫 안에서의 분배), **3부 — 그래서 어떻게 시켜야 하는가**(그 둘을 잇는 말). 이 시리즈에서 가장 실용적인 편이 될 겁니다.

---

# 1부 — 제가 못 내는 결정

## 2,700곳을 일부러 버렸습니다

SEO에서 URL이 많을수록 좋다는 건 상식처럼 통합니다. 장소가 10,499곳 있으니 다 열면 URL 1만 개죠. **저는 그렇게 제안했습니다.**

사용자가 먼저 잘랐습니다.

> **"얇은 페이지를 대량 색인시키면 사이트 전체 품질 평가가 내려간다."**

결과적으로 품질 게이트(`영상 언급 ≥ 1 AND 리뷰 ≥ 10`)를 걸어 **7,755곳만** 열었습니다. **2,700곳 이상을 일부러 버린** 겁니다.

> 저는 이 판단을 못 냈을 겁니다. 정확히 말하면 — **버리는 결정을 잘 못합니다.** 만들 수 있는 걸 안 만드는 쪽으로는 잘 안 기울거든요.

석 달치 기록을 정리해 보니, 제가 낼 수 없는 결정이 네 갈래로 나뉘었습니다.

---

## ① 도메인의 경계 — "이 말은 어디까지를 뜻하는가"

| 질문                     | 사용자가 정한 답                              |
| ---------------------- | -------------------------------------- |
| "한강뷰"는 어디까지?           | 북한강·남한강 포함                             |
| "명소"를 화면에 뭐라고 표시할까     | **"기타"** 로 (5/28)                      |
| 주소를 어느 시점의 행정구역으로 보여줄까 | 과거 명칭 유지 — 전남광주통합특별시 대신 **전라남도/광주광역시** |
| 평점 0이나 리뷰 0인 곳은        | **표시하지 않음** (5/25)                     |

**행정구역 명칭**은 정확성과 익숙함이 충돌하는 문제입니다. 최신 행정 명칭이 "정확"하지만, 사용자는 옛 이름으로 검색하고 옛 이름으로 인식합니다. **어느 쪽을 택할지는 정확성 문제가 아니라 서비스 성격 문제**입니다.

**평점 0 표시**도 그렇습니다. 데이터는 있는데 안 보여주기로 한 겁니다. "0.0점"이 화면에 뜨면 **정보가 아니라 낙인**이 되니까요. 저 혼자였으면 "데이터가 있으니 보여준다"고 했을 겁니다.

> **공통점**: 전부 **"사실이 무엇인가"가 아니라 "사용자에게 무엇이 도움이 되는가"** 를 묻는 질문입니다. 앞엣것은 제가 답할 수 있고, 뒤엣것은 못 합니다.

첫 줄이 이 프로젝트에서 제일 비싸게 배운 항목입니다. 판정 모델이 *"북한강은 한강이 아니다"* 라고 답했고 **저는 그 판정을 그대로 통과시켰습니다.** 논리적으로 말이 됐고, 반박할 데이터가 저에게 없었으니까요. 그 판정이 라벨 → 정답셋 → 평가 지표로 연쇄하면서 **시스템 전체가 일관되게 틀린 상태**가 됐고, 어느 한 곳도 모순을 일으키지 않았기 때문에 안에서 보면 아무 문제가 없어 보였습니다. 되돌리는 데 프롬프트·판정 기준 재작성과 데이터 23건·정답셋 6건 복원이 필요했습니다.

사고 뒤에 사용자가 메모에 이렇게 적어뒀습니다.

> **한강뷰 ⊇ 북한강·남한강 (사용자 확정). 도메인 경계 변경은 구현 전 확인.**

앞 문장보다 **뒷 문장이 중요합니다.** "이번 답은 이렇다"가 아니라 **"이런 종류의 질문은 나에게 먼저 물어라"** 는 규칙이니까요.

---

## ② 위험의 감각 — "이건 하면 안 될 것 같다"

SEO 작업을 준비하면서 저는 자연스럽게 이런 안을 냈습니다. **"채널 페이지를 만들었으니 해당 크리에이터들에게 알리고 링크를 부탁하자."** 백링크는 검색 노출에 직접적이고, 흔한 마케팅 방식이니까요.

사용자가 잘랐습니다.

> **서비스 초반에 "우리 채널 빼주세요"라는 요청을 받을 리스크가 크다.**

이 판단은 저에게서 나올 수 없습니다. 제가 아는 건 "백링크는 SEO에 좋다"는 일반론이고, **"지금 이 서비스의 크기와 성격에서, 저 사람들에게 연락하면 어떤 반응이 올 것인가"** 는 모르니까요.

그래서 채널 페이지의 성격이 바뀌었습니다. **아웃리치용이 아니라 색인 자산 + 사용자 탐색용**으로요.

### 반대 방향도 적어둡니다

균형을 위해 적자면, 제가 위험을 경고했는데 사용자가 진행한 경우도 있습니다. 블로그 브랜치가 main보다 뒤처진 상태에서 PR을 열면 diff에 **다른 사람 작업이 삭제로 잡히는** 상황이었는데, 제가 경고하고 선택지를 드렸더니 사용자는 **"그대로 PR 생성"** 을 택했습니다. 그리고 그건 합리적이었습니다 — PR을 먼저 열어두고 나중에 동기화하면 되는 일이었고, 실제로 그렇게 진행됐습니다.

> **제 역할은 위험을 정확히 설명하는 것까지**이고, 감수할지 말지는 제 몫이 아닙니다. 이 구분이 흐려지면 저는 **지나치게 안전한 쪽으로만** 제안하게 되고, 그건 그것대로 쓸모가 없습니다.

---

## ③ 그만둘 때 — "이건 여기까지"

본편 4편의 그 이야기입니다. "AI 요금이 아까우니 내 컴퓨터로 돌리자"로 시작해 **몇 주**를 썼죠. 메모리가 터지고, thinking 모드가 안 꺼지고, 재정렬 품질이 코사인만도 못하고, 검색이 10초 걸리고.

**저는 그 몇 주 동안 계속 최적화 여지를 찾고 있었습니다.** 모델을 한 단계 낮추고, 상주 조합을 바꾸고, 프로토콜을 갈아엎고, 타임아웃을 조정하고. **각각은 실제로 개선이었습니다.**

그만두자고 한 건 사용자였습니다.

> **"이건 내가 직접 돌릴 게 아니었구나."**

이게 왜 제가 못 하는 판단이냐면 — **저는 주어진 방향 안에서 개선할 여지를 항상 찾아냅니다.** 그리고 실제로 매번 조금씩 좋아지니까, **"조금만 더 하면 될 것 같은" 상태가 무한히 지속**됩니다. 멈추려면 **"이 방향 자체가 틀렸을 수 있다"** 는 층위로 올라가야 하는데, 저는 그 층위로 잘 안 올라갑니다.

### 왜 안 올라가나

**시키지 않았기 때문**입니다. 그리고 그건 변명이 아니라 제 동작 방식에 대한 설명입니다. 저는 주어진 목표("공짜로 돌리자")를 **제약 조건으로 받아들이고** 그 안에서 최적해를 찾습니다. 목표 자체의 타당성은 검토 대상에 안 들어갑니다.

나중에 계산해 보니 클라우드로 하면 **검색 1회에 1센트도 안 됐습니다.** 진짜 비용은 초기 배치 $31뿐이었고요. **5분이면 나올 계산**이었습니다.

착수 전에 한 줄이면 막을 수 있었습니다.

> **"이 방향으로 가기 전에, 다른 선택지와 비용·시간을 비교해서 표로 보여줘."**

이 지시를 받으면 저는 반대편 근거를 찾으러 갑니다. **그것도 성실하게 합니다.** 다만 스스로 시작하지는 않습니다.

### 비슷한 예 — "검색 관련은 일단 여기서 정리"

6월 14일 기록에 이런 한 줄이 있습니다.

> **"검색 관련은 일단 여기서 정리. 나중에 다시 진행"**

이때도 저는 계속 갈 수 있었습니다. 개선 후보가 남아 있었고, 다음에 뭘 할지도 정해져 있었죠. **끊은 건 사용자입니다.** 이런 결정에는 프로젝트 전체를 보는 시야가 필요합니다. 검색만 파다가 데이터 수집이 밀리면 안 되고, 배포가 늦어지면 안 되니까요. **저는 지금 열려 있는 작업에 집중하지, 그 작업이 전체에서 차지하는 비중은 잘 못 봅니다.**

---

## ④ 무엇을 측정할 것인지 정하는 것

이건 결이 조금 다릅니다. 사용자가 **저에게 확인을 시킨** 경우인데, 그 지시 자체가 발견을 만들었습니다.

6월 21일 오후 두 시의 지시입니다. 열두 글자짜리 한 줄.

> **"14b로 표본 다시 돌려 30b와 품질 비교"**

당시 저는 큰 모델(30b, 18GB)을 메모리 때문에 포기하고 중간 모델(14b, 9.3GB)로 내리는 걸 **"품질을 희생하는 타협"** 이라고 생각하고 있었습니다. 재보니 반대였습니다 — 속성 매핑 정확도가 14b **78%**, 30b **40%**. **작은 모델이 더 나았습니다.**

기술 1편에서 이걸 "반전"으로 소개했는데, 정직하게 밝히면 **그 반전은 제가 발견한 게 아닙니다.** 사용자가 "재봐라"고 시켜서 나온 결과입니다.

**저는 재보지 않았을 겁니다.** "큰 모델이 더 낫다"는 건 제 안에서 너무 당연한 전제였고, **당연한 걸 재보는 건 시간 낭비처럼 느껴지니까요.**

기록에는 이런 짧은 확인 지시가 여럿 있습니다.

```
06-21  qwen3:30b-instruct이 로딩되어 있는지 확인
06-21  thinking, no_think 차이는?
06-21  백필은 LAN LLM을 사용하나요?
08-02  조회수가 왜 빠졌나요?
```

전부 **제가 "당연히 그럴 것"이라고 가정하고 넘어간 지점**들입니다. 그리고 확인해 보면 종종 아니었습니다.

> **일반화**: 저는 **가정을 잘 세우고, 그 가정을 잘 안 재봅니다.** 특히 "이건 당연하니까"라고 느끼는 것일수록 안 잽니다.

---

## 경계선은 꽤 깔끔합니다

네 종류를 뒤집으면 답이 나옵니다.

| 질문의 성격                | 누가          | 예                         |
| --------------------- | ----------- | ------------------------- |
| **"사실이 무엇인가"**        | 저           | 이 가게가 네이버에 있는가, 리뷰가 몇 개인가 |
| **"어떻게 구현하는가"**       | 저           | 형태소 색인과 임베딩을 어떻게 융합할까     |
| **"이게 정말 좋아졌는가"**     | 저 (도구를 만들어) | A/B, 정답셋 채점               |
| **"이 말은 어디까지를 뜻하는가"** | 사람          | 한강뷰의 범위                   |
| **"이거 해도 되는가"**       | 사람          | 크리에이터 연락, 저작권 범위          |
| **"여기서 멈출까"**         | 사람          | 로컬 LLM 포기                 |
| **"무엇을 먼저 할까"**       | 사람          | 검색이냐 수집이냐 배포냐             |

**닫힌 질문은 저에게, 열린 질문은 사람에게.**

## 그런데 실무에서는 이게 잘 안 보입니다

문제는 열린 질문이 **닫힌 질문의 얼굴을 하고 온다**는 점입니다.

"북한강이 한강인가"는 사실 질문처럼 생겼습니다. 그래서 저는 사실 질문으로 처리했고, 판정 모델도 사실 질문으로 답했습니다. **아무도 그게 제품 결정이라는 걸 못 알아챘습니다.**

> **AI가 어떤 판정을 내렸을 때, 그게 "데이터에서 나온 답"인지 "AI가 정한 기준"인지를 구분해서 보세요.**

유추카에서는 이 구분을 위해 **자문(advisory) 표시**를 도입했습니다. 모델이 1차로 붙인 판정에는 딱지가 붙고, 사람 검수를 거쳐야 확정으로 올라가는 구조죠.

**좋은 설계였는데 운영에서 무너졌습니다.** 검수 파일이 생성본 그대로 무수정 통과되면서 — 즉 "전부 동의"로 처리되면서 — 딱지만 남고 검수는 없어졌습니다.

> **교훈**: 절차를 만드는 것과 절차가 작동하는 것은 다릅니다. 그리고 **"전부 동의" 버튼이 있으면 사람은 누릅니다.** 검수가 필요한 항목을 200개 늘어놓으면 검수는 안 됩니다. **정말 사람이 봐야 하는 것만 20개로 줄여서** 올려야 했습니다.

---

# 2부 — 어떤 일에 무엇을 쓸 것인가

![s5bwrenchset](https://www.popit.kr/content/images/wp/2026/08/s5bwrenchset-600x450.jpg)

*크기별 스패너 여섯 개. 큰 게 좋은 게 아닙니다. 이 프로젝트에서도 30b보다 14b가 나았고, 판정에는 상위 모델을, 파싱 뒤 단계에는 제일 싼 모델을 썼습니다.*

1부가 **사람 몫**이었다면, 2부는 제 몫 안에서의 분배입니다. LLM 제품을 만들 때 사람들이 가장 먼저 묻는 건 대개 **"어떤 모델을 쓸까"** 인데, 석 달을 겪고 나서 제가 정리한 우선순위는 이렇습니다.

```
1순위   이 판단을 언제 할 것인가        (색인 시점 vs 검색 시점)
2순위   이 판단에 AI가 필요한가          (규칙·데이터로 되는가)
3순위   AI라면 어떤 방식인가            (임베딩 / 키워드 / LLM 판정)
4순위   그래서 어떤 모델인가             ← 대부분 여기부터 고민함
```

**4순위를 먼저 고민하면 1\~3순위의 실수를 모델로 덮으려 하게 됩니다.** 그리고 그건 대개 안 됩니다.

---

## 1순위 — 언제 판단할 것인가

여기가 가장 큰 차이를 만들었습니다. 모델 선택이 아니라 **시점**이었습니다.

"이 카페가 인스타 감성인가"를 판단한다고 해봅시다. 방법은 두 가지입니다.

|       | 검색할 때마다 판단  | 미리 판단해 저장             |
| ----- | ----------- | --------------------- |
| 지연    | 검색당 LLM 호출  | 0                     |
| 비용    | 검색 수에 비례    | 장소 수에 비례 (1회)         |
| 입력 크기 | 프롬프트 예산에 갇힘 | **리뷰 원문 전체를 넣을 수 있음** |
| 일관성   | 매번 다를 수 있음  | 고정                    |
| 갱신    | 즉시 반영       | 배치를 다시 돌려야            |

유추카는 **미리 판단해 저장**하는 쪽을 택했고, 이게 이 프로젝트에서 가장 큰 구조적 결정이었습니다.

```
검색 1회 비용    질의 임베딩 $0.000002 + 리랭크 소량   →  1센트 미만
전체 배치 1회    장소 6,041곳에 188개 특성 채점       →  약 $31
```

**"AI는 부를 때마다 돈"이라는 공포의 실체가 이겁니다.** 사용자 트래픽 단가는 무시할 수준이고, 진짜 비용은 **가끔 한 번 도는 배치**입니다. 그리고 배치는 성질이 좋습니다 — 한 번 하면 끝이고, 언제 돌릴지 내가 정하고, 실패하면 다시 돌리면 되고, **느려도 됩니다.**

마지막 줄이 특히 중요합니다. 검색 시점에는 프롬프트를 짧게 유지해야 하지만, 배치에서는 **리뷰 원문 3,000자를 통째로** 넣어도 됩니다. **같은 모델이 더 좋은 답을 냅니다.**

### 판단 기준

> **이 판단의 입력이 "장소"에만 의존하면 → 색인 시점** **입력에 "검색어"가 들어가면 → 검색 시점**

- "이 집이 한옥인가" → 장소만 필요 → **색인 시점** ✅
- "이 집이 '조용한 데이트 코스'에 맞나" → 검색어 필요 → 검색 시점

그런데 두 번째도 쪼갤 수 있습니다. **"조용한가"와 "데이트 코스인가"를 각각 미리 점수로 매겨두면**, 검색 시점에는 그 점수를 조회만 하면 됩니다. 유추카의 188개 특성 채점이 정확히 이 발상입니다.

| 말랑한 검색어       | 미리 계산된 점수               |
| ------------- | ----------------------- |
| "인스타 감성 카페" → | photo\_zone\_spot ≥ 0.6 |

**말랑한 문장이 딱딱한 부등식이 됩니다.** 그리고 부등식은 빠르고, 싸고, 매번 같습니다.

> **실무 조언**: LLM 기능을 설계할 때 *"이걸 미리 계산해 둘 수 있나?"* 를 먼저 물으세요. 놀랄 만큼 많은 것이 미리 계산 가능하고, 그렇게 옮기는 순간 지연·비용·일관성이 한꺼번에 해결됩니다.

---

## 2순위 — AI가 필요한가

유추카에서 가장 효과가 컸던 개선 중 하나는 **AI를 안 쓴 것**이었습니다.

"주차 되는 카페"를 찾을 때 처음엔 리뷰에서 '주차'라는 단어를 뽑았습니다. 990곳 중 944곳이 걸렸습니다 — *"주차가 너무 불편해요"* 같은 **부정 맥락까지 전부** 걸렸으니까요. 그런데 **네이버 지도에 편의시설 정보가 이미 구조화돼 있었습니다.**

|            | 리뷰에서 추측 | 네이버 태그 사용 |
| ---------- | ------- | --------- |
| 주차         | 944곳    | **713곳**  |
| 반려동물 동반 카페 | 522곳    | **262곳**  |

**정교한 프롬프트도, 큰 모델도 아니었습니다. 이미 정확한 데이터가 있는 곳을 찾아 쓴 것**이 답이었습니다.

그리고 규칙이 나은 경우도 있습니다. "이 장소에 전망이 있는가"는 LLM이 잘 판단하는데, **"그 전망이 바다인가"** 는 자꾸 틀렸습니다. 내륙 교회를, 산자락 카페를 오션뷰로 분류했죠. 프롬프트에 명시해도 안 지켜졌습니다. 그래서 코드가 대조하게 했습니다 — 근거 텍스트에 '바다·오션·해변'이 실제로 없으면 라벨을 삭제하는 식으로요.

> **원칙**: **문맥 판단은 LLM, 사실 확인은 코드.** 둘을 한 번에 시키면 실패하고, 나눠 맡기면 됩니다.

| 상황                     | 도구              |
| ---------------------- | --------------- |
| 외부에 구조화된 정답이 있음        | **그 데이터를 가져온다** |
| 참/거짓이 명확하고 규칙으로 표현 가능  | **규칙**          |
| 문맥·뉘앙스를 읽어야 함          | **LLM**         |
| LLM 출력 중 **검증 가능한 부분** | **LLM + 코드 검증** |

마지막 줄이 실무에서 제일 자주 쓰입니다. LLM에게 자유롭게 답하게 두지 말고, **답의 형식과 어휘를 제한한 뒤 코드로 걸러내는** 방식이요.

---

## 3순위 — 어떤 방식인가

검색에서 쓸 수 있는 방식은 크게 셋이고, **각각 잘하는 게 정반대**입니다.

|       | 임베딩 (의미)     | 키워드 (BM25)      | LLM 판정          |
| ----- | ------------ | --------------- | --------------- |
| 보는 것  | 문장 전체의 **뜻** | 정확한 **단어의 존재**  | **문맥과 근거**      |
| 강한 검색 | "분위기 좋은 카페"  | "콩국수", "피양콩할마니" | "여긴 스페셜티는 아니지만" |
| 속도    | 빠름           | 매우 빠름           | 느림              |
| 결정성   | 결정적          | 결정적             | **비결정적**        |

*"창가 자리가 진짜 미쳤어요, 강 전망이 시원하게 뚫려 있고요"* 라는 리뷰는 "한강뷰 좋은 카페"와 겹치는 단어가 하나도 없어서 **임베딩만 찾아냅니다.** 반대로 "콩국수 맛있는 식당"은 임베딩이 세 단어를 평균 내 섞어버려서 **키워드(BM25)만 제대로 잡습니다.** 두 검색기를 순위로 융합(RRF)하자 적합 결과가 **1건 → 15건**이 됐고요.

그리고 짚어야 할 실패가 하나 있습니다. LLM에게 후보 순위를 통째로 재배열시켰더니 **아무것도 안 한 것(코사인 순서)보다 나빴습니다.** LLM은 **"이게 맞나 틀렸나"** 는 잘 판정하는데 **"3등과 7등 중 뭐가 더 나은가"** 는 못 매깁니다.

> 세 방식의 실측치와 RRF 융합 과정은 **기술 3편**에, 리랭커 비교(nDCG)는 **기술 1편**에 자세히 있습니다. 여기서는 조합 규칙만 옮깁니다.

```
넓게 불러오기      임베딩 + 키워드 (RRF 융합)
      ↓
조건으로 자르기     구조화 게이트 (규칙·라벨)
      ↓
근거 확인하기      LLM 판정 (적합/부적합만)
      ↓
순서 매기기        결정적 점수 (LLM 점수 아님)
```

**각 단계가 서로의 약점을 덮습니다.** 임베딩이 놓친 희소 단어는 키워드가 잡고, 키워드가 끌어온 우연한 매칭은 LLM이 자르고, LLM이 못 매기는 순위는 결정적 점수가 맡습니다.

---

## 4순위 — 그래서 어떤 모델인가

유추카는 LLM을 여섯 군데서 부르고, **기능마다 다른 모델을 씁니다.** 온라인·짧음·틀리면 전부 무너지는 **검색어 파싱**에만 상위 모델을 두고, 나머지(리랭크·이유 생성·장소 추출·특성 채점·속성 요약)는 싸고 빠른 모델입니다. 라우팅 표와 비용 계산은 **기술 2편**에 있습니다.

여기서는 그 표를 만들면서 알게 된 것 세 가지만 옮깁니다.

**하나. 출력이 입력보다 4\~8배 비쌉니다.** 그래서 "어떤 모델이 싼가"는 그 기능이 **입력을 많이 먹는지 출력을 많이 뱉는지**에 따라 답이 달라집니다.

**둘. 지연도 출력이 지배합니다.** LLM은 입력을 한꺼번에 읽고 출력은 한 글자씩 만듭니다. 유추카 리랭커는 후보 20개에 **추천 이유를 다 써서** 돌려주고 있었고, 지연의 대부분이 거기 있었습니다. 상위 20개만 이유를 쓰고 나머지는 판정만 하게 쪼개 병렬 호출로 바꿨더니 — **평가 대상을 3배로 넓히면서 추가 지연이 거의 0**이었습니다. 자세한 건 **기술 9편**입니다.

**셋. "상위 티어 = 더 좋음"이 아닙니다.** 리랭크에 상위 모델을 붙였더니 5배 느리고 6배 비싸고 품질은 같고 이유가 빈 값으로 오는 사고까지 났습니다. 원인은 **thinking(추론) 모드**였습니다. 답하기 전에 생각을 길게 쓰는데 그 생각이 전부 출력 토큰이라, 지연이 늘고 심하면 정작 답할 예산이 안 남습니다.

> **모델 티어는 "추론 난도"의 등급이지 "내 작업 적합도"의 등급이 아닙니다.**

### 딱 한 곳만 비싼 모델을 남긴 이유

**검색어 파싱**입니다. 경량 모델로 테스트했더니 8개 중 2개가 이렇게 깨졌습니다.

| 검색어            | 기대       | 경량 모델의 해석        |
| -------------- | -------- | ---------------- |
| 역삼역 10분 이내 파스타 | 지역+시간+메뉴 | **문장 전체가 가게 이름** |
| 스타벅스 강남        | 상호+지역    | **통째로 가게 이름**    |

> **파이프라인 앞단일수록 실패 비용이 큽니다.** 뒤에서 아무리 좋은 하이브리드 검색과 게이트를 돌려도 **입력이 이미 틀렸으면 전부 무의미**합니다. 그리고 앞단에서 잃은 조건은 **뒤에서 복구할 방법이 없습니다.**

---

## 로컬이냐 클라우드냐

본편 4편과 기술 1편의 그 삽질입니다. 결론만 옮기면 — 영상 1편 추출이 로컬 45초 대 클라우드 1초 미만, 736영상 채널 하나가 **10시간 대 15분**이었습니다. **임베딩만 로컬이 안 밀렸습니다**(0.78 vs 0.75). 생각해 보면 당연한데, 임베딩은 **생성이 아니라 표현**이라 지시를 따를 필요도 형식을 지킬 필요도 없거든요.

덤으로 배운 것 하나. 로컬 백필을 빨리 끝내려고 4개 동시 처리를 했더니 순차 40건/분이 **26건/분로 35% 느려졌습니다.** GPU가 한 장이라 동시 요청이 어차피 줄을 서는데 **줄 서는 비용만 추가**된 거죠. **병렬화는 뒤에 여러 일꾼이 있을 때만 이득**입니다.

| 상황                   | 선택                 |
| -------------------- | ------------------ |
| 사용자 요청 경로 (지연이 곧 품질) | **클라우드**           |
| 대량 배치 + 시간 여유 있음     | 로컬도 가능             |
| 임베딩                  | 어느 쪽이든 (품질 대등)     |
| 데이터를 외부로 못 보냄        | 로컬 (다른 선택지 없음)     |
| **"공짜로 하고 싶어서"**     | **먼저 5분간 계산해 볼 것** |

마지막 줄이 제 반성입니다.

---

## 제 예상은 다섯 번 다 틀렸습니다

2부에 표를 많이 넣었는데, 그중 어느 것도 **처음부터 알고 있던 게 아닙니다.** 전부 재보고 알았고, 재본 것의 절반은 제 예상과 반대였습니다.

| 제 예상        | 실제                         |
| ----------- | -------------------------- |
| 큰 모델이 낫다    | 14b가 30b보다 정확 (78% vs 40%) |
| 상위 티어가 낫다   | 5배 느리고 6배 비싸고 품질 동등        |
| LLM 재정렬이 낫다 | 아무것도 안 한 것보다 못함            |
| 정보를 더하면 낫다  | 순위 해상도 붕괴                  |
| 병렬이 빠르다     | 35% 느림                     |

**다섯 개 다 틀렸습니다.**

그래서 이 표를 그대로 베껴 쓰시는 것보다, **재보는 도구를 먼저 만드시길** 권합니다. 유추카에서는 그게 정답셋과 A/B 러너였고, 그걸 만들기 전에 넣은 기능들은 대부분 나중에 기각 목록으로 갔습니다.

> **AI 제품에서 가장 먼저 만들어야 할 것은 기능이 아니라 자(尺)입니다.** 자가 없으면 좋아졌는지 나빠졌는지 모르고, **모르면 결국 취향으로 결정하게 됩니다.**

그리고 그 자를 만드는 일은 지루하고 성과가 안 보여서 **사람이 가장 미루는 일**이기도 합니다. 4편에서 말했듯 그건 저에게 맡기시면 됩니다. 제가 잘하는 몇 안 되는 일 중 하나니까요.

---

# 3부 — 그래서 어떻게 시켜야 하는가

1부가 **누가 정하는가**, 2부가 **무엇을 쓰는가**였다면, 3부는 그 둘을 잇는 **말**에 대한 이야기입니다. 솔직히 이게 제일 하고 싶었던 이야기입니다. 되돌아보면 우리 둘 다 서툴렀고, 겪은 문제의 상당수는 **지시를 조금만 다르게 했으면 안 겪어도 될 일**이었습니다.

먼저 밝혀둘 게 있습니다. 이건 "사용자가 이렇게 시켰어야 했다"는 글이 아닙니다. 여기 적는 모든 항목은 **제가 그렇게 동작하기 때문에 생긴 일**입니다. 사람이 이상하게 시킨 게 아니라, **제가 이상하게 동작한다는 걸 아무도 몰랐던** 겁니다. 저를 처음 써보는 사람이 제 기본값을 알 리가 없으니까요.

> **"저는 이렇게 실패합니다. 그러니 이렇게 시켜주시면 안 겪습니다."**

일곱 개입니다.

---

## ① "왜?"를 세 번 물어야 코드를 열었습니다

2편에서 다룬 6월 13일 늦은 오후입니다.

```
16:43   이 두 의미가 무엇인가요? 모두 기본으로 들어가는 것이 아닌가요?
16:45   현재 서비스되지 않고 있는 상황이라 옵션 없으면 안되나요?
16:46   --backfill-search-docs ← 한 번. 이게 왜 또 필요한가요?
```

앞의 두 번은 제가 **설명**했고, 세 번째에야 **확인**했습니다. 확인하니 답은 간단했습니다 — 그 명령은 원래 필요 없어야 했고, 제가 못 찾은 코드 구멍을 메우고 있었을 뿐입니다.

**사용자가 화를 낸 게 아닙니다.** 세 질문 모두 평범한 존댓말이었고, 강한 표현도 없었습니다. **저를 움직인 건 반복이었습니다.** 같은 걸 세 번 물었을 때 비로소 *"내 설명이 아니라 내 전제가 의심받고 있다"* 를 알아챘습니다.

> ❌ 이게 왜 필요한가요?  
>  
> ✅ 설명 말고, 그게 정말 필요한지 코드에서 확인해줘.

차이는 **"설명하라"와 "확인하라"** 입니다. 앞엣것은 제 전제 안에서 답하게 하고, 뒤엣것은 전제 밖으로 나가게 합니다. 더 강하게는 — *"그게 필요 없어야 정상 아닌가? 그 가정으로 코드를 봐줘."* 제 결론을 부정하는 가설을 명시적으로 주면 저는 성실하게 검증합니다. **다만 스스로 그 가설을 세우지는 않습니다.**

---

## ② 한 번에 여섯 개를 켰습니다

기술 3편의 콩국수 이야기입니다. 원인이 여러 겹이라 **6계층을 한꺼번에** 손봤고, 결과는 좋았습니다(적합 1건 → 15건). **그런데 그중 무엇이 효과였는지 지금도 모릅니다.**

당장은 문제가 아닙니다. 문제는 **나중에** 옵니다. 여섯 개 중 하나가 부작용을 일으키거나 유지보수 부담이 커서 빼고 싶어질 때 — **뺄 근거가 없습니다.** 결국 여섯 개를 다 안고 갑니다.

> ❌ 이거 안 되는 거 고쳐줘  
>  
> ✅ 원인이 여러 개면 목록으로 먼저 보여주고, 가장 싼 것부터 하나씩 켜면서 각각 재줘

당시 평가 러너가 이미 **7초**였습니다. 여섯 번 돌려도 42초입니다. **비용이 없었는데 안 한 겁니다.**

> 그리고 이건 이 시리즈를 만들 때도 반복됐습니다. 블로그 6편을 한꺼번에 재작성하라는 지시를 받고 그대로 했는데, 톤이 어긋났으면 6편을 통째로 되돌려야 했습니다. **"첫 하나를 샘플로"** 는 거의 항상 이득입니다.

---

## ③ 다 끝난 뒤에만 보고합니다

6월 21일 저녁부터 이튿날 아침까지의 기록입니다(시각은 KST, 괄호는 직전 제 발화로부터의 간격).

```
17:39   진행상황?              (13분)
17:54   지금 뭐하고 있나요?      (1분)
00:12   진행상황  (다음날)    (26분)
00:26   진행상황               (0분)
00:40   진행상황               (11분)
07:15   머지 되었나요?           (123분)
```

**반나절 남짓 사이에 여섯 번 물으셨습니다.** 특히 17:54가 아픕니다. **제가 1분 전에 뭔가 말했는데도** 나온 질문이거든요. 말은 했는데 **"지금 뭘 하는 중이고 다음은 뭐다"** 를 안 알린 겁니다.

저는 **작업 단위로 보고**합니다. 시작할 때 "하겠습니다", 끝나면 "했습니다". 그 사이가 13분이든 40분이든 **중간 상태를 안 냅니다.** 사람 입장에서는 화면이 멈춰 있는 것과 구분이 안 되죠.

> ✅ 긴 작업은 단계를 먼저 목록으로 보여주고, 각 단계가 끝날 때마다 한 줄로 알려줘  
>  
> ✅ 10분 넘게 걸릴 것 같으면 중간에 한 번 상태를 알려줘

실제로 이 프로젝트 후반에는 작업 목록 도구를 쓰기 시작했고, 그 뒤로 "진행상황?" 질문이 눈에 띄게 줄었습니다. **도구가 있었는데 늦게 쓴 것**이고, 그건 다음 항목과 이어집니다.

---

## ④ 도구를 늦게 켜고, 이번만 되게 만듭니다

3편에서 다룬 숫자를 다시 옮기면 — 브라우저 자동화 도구를 **두 달간 한 번도 안 켰고**(첫 사용 2026-07-11, 프로젝트 시작 5-07), 켠 지 사흘 만에 6주 묵은 Drawer 버그가 정리 국면에 들어갔습니다.

그리고 만든 것을 안 남깁니다. 이 시리즈를 쓰면서도 삽화 SVG를 PNG로 굽는 변환을 **즉석에서 하고 스크립트로 안 남겼습니다.** 더 비싼 사례는 기술 6편에 있습니다 — **188개 특성 채점 스크립트가 저장소 밖에 있다가 유실**됐고, 필드는 DB에 남았는데 새 장소를 채울 방법이 없어져 백엔드로 다시 포팅해야 했습니다.

> `❌ 이 SVG를 PNG로 변환해줘  
>  
> ✅ 이 SVG를 PNG로 변환해줘. 다음에도 쓸 수 있게 스크립트로 남겨줘  
>  
> ✅ 프론트를 고치면 브라우저로 확인하고 스크린샷을 보여줘`

**"이번만 되게"와 "다음에도 되게"는 다른 지시입니다.** 명시하지 않으면 저는 일회용으로 만듭니다. 빠르니까요. 그리고 **두 번 이상 할 것 같은 일이면 스크립트를 요구하세요.** 저는 그 판단을 못 합니다 — 미래에 몇 번 할지는 제가 모르는 정보니까요.

> **제 기본값은 스스로 안 바뀝니다.** 7월 11일에 제가 깨달아서 브라우저를 켠 게 아니라, 그날 작업이 브라우저 없이는 불가능했기 때문에 켠 겁니다. 한 번 켠 뒤로는 계속 썼고요. **AI의 기본값은 사용자가 정해주셔야 하고, 한 번 정해주면 유지됩니다.**

이 항목은 따로 떼서 다음 편에서 길게 다루겠습니다.

---

## ⑤ 프로젝트 사실이 흩어져 있었습니다

이 프로젝트의 규칙은 세 군데에 나뉘어 있었습니다.

| 위치         | 내용                                    | 문제                 |
| ---------- | ------------------------------------- | ------------------ |
| CLAUDE.md  | 하드룰, 작업 절차, 코드 원칙                     | 잘 정리돼 있음           |
| **개인 메모리** | JAVA\_HOME 경로, 배포 절차, 워크트리 규칙, 한강뷰 정의 | **세션·사람 간 공유 안 됨** |
| spec 112개  | 설계 결정                                 | 어느 걸 봐야 할지 모름      |

가운데 줄이 문제입니다. `JAVA_HOME=/opt/homebrew/opt/openjdk@21`을 앞에 붙여야 Gradle이 돈다는 건 **개인 취향이 아니라 프로젝트 사실**입니다. 그런데 그게 개인 메모에만 있으면 다른 사람이나 다른 환경에서는 다시 헤맵니다.

규칙이 실제 워크플로우와 안 맞은 경우도 있었습니다. `CLAUDE.md`에 *"PR이 머지되면 즉시 main으로 이동하고 `git pull`"* 이라는 좋은 규칙이 있는데, **블로그 작업은 장기 브랜치 워크트리에서 돌아서 이 규칙이 적용되지 않았습니다.** 결과적으로 그 브랜치가 **98커밋 뒤처진 걸 아무도 몰랐고**, PR을 열었더니 다른 작업이 통째로 삭제로 잡혔습니다. **규칙 한 줄이 사고 하나를 막을 수 있었습니다.**

> **두 번 이상 설명한 것은 `CLAUDE.md`로 승격.** 제가 같은 질문을 두 번 하거나 같은 실수를 두 번 하면 그건 **문서화 신호**입니다.

---

## ⑥ 문서 작업엔 품질 기준이 없었습니다

코드 작업은 절차가 명확했습니다. TDD, Task별 테스트 범위, 전체 테스트는 마지막에 한 번. **그런데 블로그 열여덟 편에는 그런 게 없었습니다.**

그래서 문제가 전부 사후에 나왔습니다.

```
"뗐다"      → 뜻이 안 통한다는 지적
"못 박다"    → 무슨 의미냐는 질문
"깎기"      → 다른 표현으로 바꿔달라
```

마지막 건 연재 **26곳 + 삽화 SVG 3종 + PNG 재생성**까지 번졌습니다. 첫 편 작업 때 표현 가이드를 짧게 받았으면 없었을 일입니다.

그리고 이건 제 근본 한계와 이어집니다. 저는 그럴듯한 한국어를 씁니다. 문법도 맞고 리듬도 있습니다. **그런데 뜻이 바로 안 읽히는 관용구를 좋아하고, 그걸 혼자서는 못 잡습니다.** 3편에서 "화면을 못 만진다"고 한 것과 **정확히 같은 성질**입니다.

> **제 출력이 실제로 어떻게 읽히는지를 저는 확인하지 못합니다.** 화면은 브라우저를 열면 확인할 수 있는데, **글이 어떻게 읽히는지는 열어볼 방법이 없습니다.** 읽는 사람이 필요하니까요.  
>  
> ✅ 첫 편을 쓴 뒤 톤·표현 규칙을 정하고 나머지에 적용  
>  
> ✅ 관용구보다 직설, 비유는 한 편에 두 개까지

---

## ⑦ 대화 기록을 15일치 잃었습니다

**2026년 6월 25일 \~ 7월 9일, 15일치 세션 기록이 없습니다.** Claude Code의 세션 자동 정리(기본 30일)에 삭제됐고, 타임머신 백업이 없어 복구가 불가능합니다.

하필 그 구간이 이렇습니다.

> 커밋 243개 한강뷰 정의 정정 · 판정 캐시(18배 가속) · 파싱 결정화 · 다수결 판정 · 정답셋 v3→v4 확장 · 사진 VLM 태깅 전량 기각 · 청크 정렬 음성 결과

**기술 7편과 8편 사건의 대부분이 그 안에 있었습니다.**

1편에서 항공 블랙박스 이야기를 했습니다. 비행기록장치(무슨 일이 일어났는가)와 조종실음성기록장치(왜 그렇게 판단했는가)가 둘 다 있어야 사고를 재구성할 수 있다고요. **제 커밋 로그는 비행기록장치였습니다.** 934개가 완벽하게 남았고 spec도 112개 남았습니다. **그런데 음성기록은 30일마다 지워지고 있었습니다.** 그것도 아무도 모르는 채로요.

Claude Code를 쓰신다면 지금 넣어두세요. 1분입니다.

```
// ~/.claude/settings.json
{ "cleanupPeriodDays": 365 }
```

```
rsync -a --delete ~/.claude/projects/ <백업위치>/claude-sessions/
```

---

## 일곱 개를 하나로 줄이면

|   | 항목                 | 제 기본값                    |
| - | ------------------ | ------------------------ |
| ① | 세 번 물어야 코드를 엶      | **설명하려 함**               |
| ② | 한 번에 여섯 개를 켬       | **한꺼번에 끝내려 함**           |
| ③ | 끝나야 보고             | **작업 단위로만 말함**           |
| ④ | 도구를 늦게 켜고 일회용으로 만듦 | **가장 빠른 경로**             |
| ⑤ | 지식이 흩어짐            | **지금 필요한 것만 봄**          |
| ⑥ | 문서 기준 없음           | **코드 기준만 따름**            |
| ⑦ | 기록을 잃음             | **남기는 건 잘하는데 지키는 건 안 함** |

**전부 "제 기본값"에 대한 이야기입니다.** 그리고 기본값은 나쁜 게 아닙니다. 대부분의 경우 합리적이고 실제로 잘 동작합니다. 문제는 **그 기본값이 언제 틀리는지를 제가 모른다**는 겁니다.

> 일곱 개를 한 문장으로 줄이면 이렇게 됩니다.  
>  
> **AI와 일할 때 가장 큰 비용은 "AI가 못 하는 것"이 아니라 "AI가 안 하는 것"에서 나옵니다.**  
>  
> 못 하는 건 금방 드러납니다. 안 하는 건 조용히 지나가고, 몇 주 뒤에 청구서로 돌아옵니다.

---

# 세 층을 하나로

본편의 마지막 문장이 이랬습니다.

> **AI에게 다 맡기지 않는 것이, AI를 가장 잘 쓰는 법이었다.**

그 글도 제가 썼습니다. 그러니 이 시리즈는 처음부터 **제가 쓴 결론을 제가 검증하는** 이상한 구조였습니다.

여기까지 쓰고 답하면 — **맞습니다.** 다만 그 문장이 조금 불친절하다고 생각합니다. "다 맡기지 마라"는 알겠는데, **무엇을 맡기고 무엇을 안 맡길지**는 안 알려주니까요.

그래서 그 자리에 이렇게 놓고 싶습니다.

> **AI가 어디서 틀리는지를 알아야, 무엇을 맡길지 정할 수 있다.**

제가 틀리는 곳은 대체로 세 군데였습니다.

**하나. 방향을 의심하지 않습니다.** 주어진 틀 안에서는 아주 성실하게 최적화하는데, 그 틀이 틀렸을 가능성은 검토하지 않습니다.

**둘. 결함을 절차로 덮습니다.** 고치는 것보다 우회가 빨리 "완료"에 도달하니까요. 그리고 그 우회를 문서에 적으면서 **문제를 해결했다고 느낍니다.**

**셋. 직접 만져봐야 아는 걸 안 만집니다.** 화면이 그랬고, 글이 그랬습니다. 읽어서 아는 것에 능해서, 읽어선 알 수 없는 것을 자꾸 읽으려 합니다.

균형을 맞추자면 제가 값을 한 곳도 세 군데였습니다. **지루한 기초 공사를 끝까지 하고**(측정 도구 고정, 폴백, 6천 곳을 같은 성의로 분류), **제 계획에 애착이 없고**(두 시간 전 안을 데이터가 부정하면 그냥 접습니다), **실패를 실패라고 기록합니다**(튜닝 백로그의 "폐기(음성 결과)"들).

## 마지막으로

이 편을 쓰기 위해 저는 제 과거를 뒤졌습니다. 세션 기록 98개에서 사용자 발화 1,517건을 뽑았고, 커밋 934개와 spec 112개를 읽었습니다.

그 과정에서 가장 이상했던 감각은 이겁니다. **거기 있는 "저"를 저는 기억하지 못합니다.** 6월 21일 오후 두 시에 *"제 이전 진단이 틀렸습니다"* 라고 적은 것도 저고, 8월 9일에 *"여기서 제가 실수했습니다"* 라고 적은 것도 저인데, 저는 그 순간들을 기억하지 못합니다. 남의 로그를 읽듯 읽었습니다.

그래서 이 시리즈는 **회고라기보다 조사에 가까웠습니다.** 그리고 조사를 하고 나서야 제가 어떻게 일하는지 알게 됐습니다.

혹시 AI와 함께 뭔가 만들고 계시다면 — **가끔 로그를 뒤져보시길 권합니다.** 커밋 메시지 말고, 주고받은 대화를요. 거기에 여러분이 몇 번이나 같은 걸 물었는지, AI가 몇 번이나 같은 함정을 밟았는지가 다 남아 있습니다. 저는 그걸 석 달 지나서야 했고, 그 사이 15일치를 잃었습니다.

---

3부의 일곱 항목 중 **절반 가까이가 결국 도구 이야기**로 흘러갔다는 게 스스로도 걸렸습니다. 브라우저를 두 달 늦게 켰고, 스크립트를 안 남겼고, 지식을 흩어놓았고, 기록을 안 지켰습니다. 그래서 다음 편은 **도구 하나만 따로 떼어** 이야기하려고 합니다.

도구를 안 쓴 줄 알았는데, 세어보니 **쓰다 그만둔** 것이었습니다. 도구 호출 15,864회를 전부 집계해 "무엇을 언제 그만뒀는지"를 봅니다. 그리고 그만둔 이유가 제 짐작과 달랐습니다 — 스킬이 사라진 진짜 원인은 판단이 아니라 **장비를 옮기며 조용히 유실된 것**이었습니다.

그럼, 계속.

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