> ## 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로 장소 검색 서비스 만드는 중입니다 (기술 4) — 구조화 하드게이트: '비슷함'을 '조건'으로 고정하다
- URL: https://www.popit.kr/ai-place-search-tech-4-structured-hard-gate/
- Published: 2026-07-30T22:11:38.000Z
- Updated: 2026-07-30T22:11:38.000Z
- Author: 김형준
- Tags: ai, 검색, #서비스소개

![t3-before-after](https://www.popit.kr/content/images/wp/2026/07/t3-before-after-600x318.png)

> 기술 3편에서 "임베딩은 뜻은 잡지만 정확한 단어는 못 잡는다"를 봤습니다. 이번엔 한 걸음 더 들어갑니다 — **단어가 맞아도 여전히 틀리는** 경우, 그리고 그걸 막기 위해 '비슷함'을 아예 '조건'으로 고정한 이야기입니다.  
>  
>  
>  
> 수치는 유추카 자체 A/B(사람 라벨 정답셋) 실측입니다.

## 감자탕집을 찾았는데 한옥 카페가 나온다

먼저 실제로 겪은 장면부터.

**"감자탕집"** 을 검색했더니 결과 상단에 **한옥 카페**가 올라왔습니다. 처음엔 버그인 줄 알았는데, 아니었습니다. 기술 3편에서 본 임베딩의 좌표 비유를 떠올려 보면 이유가 보입니다 — 감자탕집 문서와 한옥 카페 문서는 좌표상 **정말로 가깝습니다.** 둘 다 "한국적", "전통", "투박하고 정겨운", "어르신들이 좋아하는" 같은 말로 설명되니까요. 임베딩이 고장 난 게 아니라, **임베딩이 시키는 대로 정확하게 일한 결과**가 한옥 카페였습니다.

같은 종류의 사고가 곳곳에서 났습니다.

- **"인스타 감성 카페"** → 평범한 동네 카페가 섞입니다. "카페"라는 거대한 의미가 "인스타 감성"이라는 미묘한 축을 덮어버립니다. 좌표는 결국 "카페 동네"에 찍히거든요.
- **"스페셜티 커피"** → 스페셜티가 아닌 곳이 들어옵니다. 리뷰에 *"여긴 스페셜티는 아니지만 가성비가 좋아요"* 라고 적혀 있어도, 텍스트로는 "스페셜티"가 있는 문서니까요. **부정문을 긍정으로 읽는 셈**입니다.
- **"멕시칸 음식점"** → 치킨집이 나옵니다. 메뉴 목록에 "멕시칸치폴레치킨"이 있었거든요.
- **"회"** → 회식 장소, 회전초밥, 심지어 "OO회 정기모임" 후기가 걸립니다.

앞의 둘과 뒤의 둘은 성격이 다릅니다. 앞은 **뜻이 너무 가까워서** 생긴 사고고, 뒤는 **글자가 우연히 겹쳐서** 생긴 사고입니다. 그런데 사용자 입장에선 구분이 없습니다. 그냥 **"틀린 결과"** 죠.

## 리랭커를 붙이면 되지 않나

이쯤에서 자연스럽게 나오는 답이 있습니다. **리랭커(reranker)** 를 붙이자.

> **리랭커**: 검색이 뽑아온 후보 수십 개를 LLM에게 통째로 보여주고 "이 검색어에 이 장소가 맞습니까?"를 하나하나 판정·재정렬시키는 단계. 임베딩은 좌표만 보지만 LLM은 문장을 읽으므로, *"스페셜티는 아니지만"* 같은 부정문을 이해할 수 있습니다.

실제로 유추카도 리랭커를 씁니다. 그리고 잘 동작합니다. 그런데 이것만으로는 부족했습니다. 이유가 셋입니다.

1. **리랭커는 자기한테 온 것만 봅니다.** 후보 목록에 애초에 감자탕집이 없으면, 리랭커가 아무리 똑똑해도 감자탕집을 만들어낼 수 없습니다. 기술 3편에서 본 그 깔때기 문제죠.
2. **느리고 비쌉니다.** 검색할 때마다 LLM을 부르는 구조라, 후보를 무한정 늘릴 수 없습니다. 창을 60개로 제한하는 이유가 그겁니다.
3. **그리고 확률적입니다.** "주차 가능한 곳"이라는 요청에 대해 LLM은 대체로 맞히지만 **가끔 틀립니다.** 주차장 유무는 취향 문제가 아니라 사실 문제인데, 사실 문제를 확률에 맡길 이유가 없습니다.

기술 1편에서 로컬 리랭커가 코사인 유사도조차 못 이겼던 경험도 있었고요. 결론은 이랬습니다 — **리랭커는 정밀도의 주역이 아니라 보조여야 한다.**

## 발상의 전환 — '정렬'에서 '필터'로

그래서 접근을 바꿨습니다.

기존 검색은 전부 **정렬(ranking)** 문제였습니다. 모든 장소에 점수를 매기고 높은 순으로 보여주는 것. 이 틀에선 감자탕집도 한옥 카페도 "점수가 조금 다를 뿐 둘 다 후보"입니다. 점수가 아슬아슬하면 언제든 뒤집힐 수 있죠.

바꾼 틀은 **필터(filtering)** 입니다. **조건을 만족 못 하면 점수를 볼 것도 없이 후보에서 뺍니다.** 한옥 카페는 업종이 '카페'이므로 "감자탕집" 검색에선 **점수 계산 자체를 시작하지 않습니다.** 이게 **하드게이트**입니다.

> **하드게이트(hard gate)**: 통과 못 하면 후보에서 완전히 제외되는 결정적 관문. 점수를 낮추는 게 아니라 **아예 없는 셈 치는** 것이 핵심입니다. 반대말은 순위에 반영만 하는 **소프트게이트**(뒤에 다시 나옵니다).

|         | **정렬로 푼다**    | **필터로 푼다(하드게이트)** |
| ------- | ------------- | ----------------- |
| 틀린 후보   | 점수를 낮춘다       | 목록에서 없앤다          |
| 결과      | 확률적 — 가끔 올라온다 | 결정적 — 절대 안 올라온다   |
| 결과가 없으면 | 뭐라도 채워서 보여준다  | **빈 결과를 보여준다**    |
| 비용      | 검색할 때마다 LLM   | 색인할 때 한 번         |

여기서 세 번째 줄이 중요합니다. 하드게이트를 도입한다는 건 **"조건에 맞는 게 없으면 없다고 말하겠다"** 는 선언이기도 합니다. 예전엔 "분당 파인다이닝"에 결과가 없으면 분당 식당을 아무거나 채웠습니다. 지금은 빈 결과를 냅니다. 기술 3편의 "분당 콩국수 → 0건"과 같은 철학이고, 사실 그게 이 하드게이트 작업에서 먼저 자리 잡은 원칙이었습니다.

## 조건을 '축'으로 쪼개다

그럼 무엇을 필터할 것인가. 여기서 "검색 조건"을 **축(axis)** 단위로 분해했습니다.

"주차 되는 한옥 카페"라는 검색어에는 서로 **성격이 완전히 다른 세 조건**이 섞여 있습니다.

- **업종**: 카페 — 객관적 분류. 네이버가 이미 정해놨습니다.
- **시설**: 주차 — 사실 정보. 있거나 없거나 둘 중 하나입니다.
- **공간 스타일**: 한옥 — 사진과 리뷰를 봐야 아는, 판단이 필요한 정보.

이걸 하나의 임베딩 벡터로 뭉뚱그려 처리하던 게 문제였습니다. **축마다 필요한 정보의 성격이 다르니, 축마다 가장 정확한 출처를 따로 쓰기로 했습니다.**

| 축                        | 라벨 출처                        | 왜 이 출처인가              |
| ------------------------ | ---------------------------- | --------------------- |
| **업종**                   | 네이버 카테고리                     | 네이버가 이미 분류해 둔 권위 있는 값 |
| **요리 종류**(멕시칸·일식)        | 네이버 카테고리                     | 메뉴명으로 판단하면 오염됨 (아래)   |
| **요리명**(타코·삼겹살·라멘 \~45종) | 네이버 카테고리 **또는** 메뉴 토큰        | 카테고리가 없는 집도 메뉴로 구제    |
| **시설**(주차·반려동물·단체)       | 네이버 편의시설 태그                  | 사실 정보라 LLM보다 태그가 정확   |
| **품질**(파인다이닝·미슐랭·스페셜티)   | LLM 색인-시 검증                  | 텍스트 신호는 노이즈, 문맥 판단 필요 |
| **공간/뷰**(한옥·정원·루프탑·한강뷰)  | LLM 분류(venueStyles)          | 사진·리뷰 문맥에서 판별         |
| **추상 의도**(인스타·데이트·조용)    | LLM 188-feature 점수(concepts) | 미묘한 맥락 축              |

결정 규칙은 한 줄로 요약됩니다. **네이버가 구조화해서 주는 것(업종·시설)은 네이버를 쓰고, 안 주는 주관적·품질·공간 정보만 LLM이 판단한다.** 그리고 그 LLM 판단은 **검색할 때마다가 아니라 색인할 때 딱 한 번** 합니다. 검색 시점엔 미리 저장된 라벨과 결정적으로 매칭만 하면 되니 빠르고, 같은 질문을 매번 다시 묻지 않으니 쌉니다.

### "LLM이 만능"이 아니라 "출처가 정확한 데이터가 먼저"

시설 축에서 이 원칙의 효과가 가장 선명했습니다. 원래는 리뷰 텍스트에서 "주차" 신호를 뽑았는데, **990곳 중 944곳이 걸렸습니다.** 거의 전부죠. 왜냐면 *"주차가 불편해요"*, *"주차장이 없어서 근처에 댔어요"* 같은 **부정 맥락까지 전부 걸렸기 때문**입니다. 앞의 "스페셜티는 아니지만"과 정확히 같은 실패입니다.

네이버 편의시설 태그를 우선하도록 바꾸니 **713곳(그중 권위 태그 572곳)** 으로 정리됐습니다. "반려동물 동반"도 **522 → 262곳**이 됐고요. 정교한 프롬프트도, 큰 모델도 아니고 **이미 정확한 데이터가 있는 곳을 찾아 쓴 것**이 답이었습니다.

다만 공짜는 아니었습니다. 이 태그는 네이버 장소 페이지 안에 있어서 다시 긁어와야 했는데, 전체 재수집은 장소당 리뷰 스크롤까지 도느라 **13초 × 6,138곳 ≈ 22시간**에 중간 재개도 안 됐습니다. 그래서 **편의시설만 필요하니 홈 화면만 파싱하는** 경량 백필을 따로 만들었습니다. **약 3시간**으로 줄었고, 이미 받은 장소는 건너뛰니 중간에 끊겨도 이어서 돌 수 있습니다. 최종적으로 6,138곳 중 **4,844곳**이 시설 정보를 갖게 됐습니다.

### 요리 종류에서 배운 것 — 메뉴판을 믿지 마라

"멕시칸 음식점"에 치킨집이 나오던 사고, 기억하시죠. 원인은 메뉴 토큰이었습니다. 그 치킨집 메뉴판에 **"멕시칸치폴레치킨"** 이 있었거든요. 글자만 보면 완벽한 "멕시칸" 매칭입니다.

그래서 **요리 종류(멕시칸·이탈리안·일식…)는 메뉴를 아예 안 보고 네이버 카테고리만** 쓰도록 바꿨습니다. 반대로 **요리명(타코·삼겹살·라멘)은 카테고리에 안 잡히는 집이 많아** 메뉴 토큰을 함께 봅니다 — 축마다 최선의 출처가 다르다는 원칙이 같은 "요리"라는 큰 덩어리 안에서도 갈린 셈입니다.

"회"는 아예 특별 취급이 필요했습니다. **회식·회전초밥·OO회**까지 걸려서, 구체적인 회 요리 이름으로만 매칭하도록 좁혔습니다. 한국어 검색에서 짧은 단어는 거의 항상 이런 대가를 치릅니다.

## "정밀도 0%" — 텍스트 신호를 통째로 버린 날

숫자 이야기를 하기 전에 지표부터 짚고 갑니다.

> **P@8 (Precision@8, 정밀도)**: 상위 8개 결과 중 **실제로 맞는 것의 비율**. P@8 = 29%면 8개 중 2\~3개만 정답이라는 뜻이고, 100%면 8개 전부 정답입니다. 유추카는 사람이 라벨링한 정답셋과 Claude 판정을 함께 씁니다.

품질 축에서 가장 인상적인 실패가 **파인다이닝**이었습니다. 리뷰·본문 텍스트에서 "파인다이닝" 신호로 거르니 정밀도가 **0%** 였습니다. 하나도 못 맞혔다는 뜻입니다.

리뷰를 열어보고 이유를 알았습니다.

> *"여긴 파인다이닝급은 아니지만 가성비가…"* *"파인다이닝 부럽지 않은 플레이팅"* *"파인다이닝 가기 전에 여기서 한잔"*

**"파인다이닝"이라는 단어가 나온다는 건 오히려 그 집이 파인다이닝이 아니라는 신호에 가까웠습니다.** 진짜 파인다이닝 리뷰엔 그 단어를 굳이 안 씁니다. 당연하니까요. 단어를 세는 방식으로는 절대 풀 수 없는 문제였습니다.

스페셜티 커피에서도 같은 벽에 부딪혔습니다. 처음엔 신호를 정교하게 다듬어 보려 했습니다. 키워드를 좁히고, 베이커리 카테고리를 제외하고… 두 번 시도했고 **두 번 다 폐기했습니다.** 빵집인데 커피가 유명한 곳(트웰브 같은), 핸드드립만 하는 동네 카페 — 이런 오탐이 **구조적으로** 계속 나왔기 때문입니다. 규칙을 하나 더 붙이면 다른 구멍이 열렸습니다.

그래서 **텍스트 신호를 통째로 버렸습니다.** 대신 색인 시점에 LLM이 문맥을 읽고 판정한 **품질 라벨만** 게이트로 썼습니다. 결과:

> **스페셜티 커피 P@8: 29% → 100%**

여기서 진짜 교훈은 "LLM이 좋다"가 아닙니다. **신호가 애초에 잘못된 신호였다는 것**입니다. 잘못된 신호는 아무리 정교하게 다듬어도 잘못된 신호입니다. 그럴 땐 다듬지 말고 버려야 합니다.

## 말랑한 검색을 숫자로 고정하기

업종·시설·품질은 그래도 경계가 뚜렷합니다. 문제는 **"인스타 감성", "데이트하기 좋은", "조용한"** 같은 말랑한 검색이었습니다. 이건 네이버 태그에도 없고, 참/거짓으로 딱 떨어지지도 않습니다.

여기엔 **점수화**로 접근했습니다.

**1단계 — 미리 채점해 둡니다.** 모든 장소에 대해 LLM이 **188개 feature**(`date_spot`, `photo_zone_spot`, `quiet_space`, `panoramic_viewpoint`, `hanok_aesthetic` …)를 리뷰를 근거로 **0.5\~1.0 점수**로 채점해 저장합니다. 해당 없는 feature는 아예 안 매기고, 매긴 것만 남깁니다.

**2단계 — 검색어를 feature로 번역합니다.**

| 검색어에 이 말이 있으면  | 이 feature를 요구                             |
| -------------- | ----------------------------------------- |
| 인스타·인생샷·포토존·감성 | photo\_zone\_spot, instagrammable, unique |
| 데이트·소개팅        | date\_spot, romantic\_lighting            |
| 조용한·한적한        | quiet\_space                              |

**3단계 — 임계값으로 자릅니다.** `concepts.<feature> ≥ 0.6`. 여러 feature 중 하나만 넘으면 통과(OR), 검색어에 의도가 여러 개면 전부 만족해야 통과(AND).

즉 **"인스타 감성 카페"라는 말랑한 문장이, 뒤에서는 `photo_zone_spot ≥ 0.6`이라는 딱딱한 부등식으로 바뀝니다.** 결과:

> **인스타 카페 P@8: 29% → 100%**, 데이트 29% → 50%

10곳 중 3곳만 맞던 게 거의 전부 맞게 됐습니다. (이 188-feature를 어떻게 채점하고 관리하는지는 기술 6편에서 따로 다룹니다.)

## 축이 직교하면 조합이 공짜다

축으로 쪼갠 덕에 예상 못 한 이득이 하나 따라왔습니다. **조합 검색이 저절로 됩니다.**

"주차 되는 한옥 카페"를 처리할 때 별도 로직이 필요 없습니다. 세 축의 조건을 그냥 AND로 붙이면 끝입니다.  

```
업종 = 카페  AND  편의시설 ∋ 주차  AND  공간스타일 ∋ 한옥
```

이게 가능한 건 축들이 **직교(orthogonal)** 하기 때문입니다 — 편의시설 어휘(주차·발렛·단체·유아의자·와이파이)와 공간스타일 어휘(한옥·정원·루프탑·한강뷰)는 **단어가 하나도 겹치지 않습니다.** 겹치지 않으니 서로 간섭하지 않고, 간섭하지 않으니 조합이 안전합니다. 축을 나눌 때 "어휘가 안 겹치게" 나눈 게 나중에 조합 검색을 공짜로 만들어 준 셈입니다.

## 새 축을 추가하는 비용을 '빈 하나'로

품질 축은 파인다이닝·미슐랭·스페셜티 커피로 시작했지만, 운영하다 보면 계속 늘어납니다. 그런데 처음엔 축 하나 추가할 때마다 분류 코드·백필 스크립트·스케줄 등록·신규 장소 처리를 전부 손봐야 했습니다.

그래서 **레지스트리 패턴**으로 정리했습니다. 품질 분류기는 인터페이스 하나(`tierName` / 후보 조건 / 판정)를 구현한 **빈(bean) 하나**면 되고, 서비스가 등록된 분류기를 자동으로 수집합니다. **새 축 = 클래스 하나 추가**로 백필·일일 스케줄·신규 장소 자동 분류에 전부 자동 편입됩니다.

여기서 사소해 보이지만 중요한 장치가 하나 있습니다. **"평가했는데 아니었다"와 "아직 평가 안 했다"를 구분해 기록**합니다. 이 구분이 없으면 파인다이닝이 아닌 장소를 매일 밤 다시 LLM에 물어보게 됩니다. 6천 곳을 매일 재판정하는 비용은 농담이 아닙니다.

## 그런데 이 하드게이트를, 우리는 사흘 뒤에 풀었다

여기까지가 성공담입니다. 이제 반전입니다.

하드게이트를 켜고 정밀도는 확실히 올랐는데, 얼마 지나지 않아 이상한 제보가 들어왔습니다. **"카페 산"** 을 검색하면 분명히 산 전망이 좋은 카페인데 결과에 없다는 것이었습니다.

원인을 추적해 보니 그 카페는 **`마운틴뷰` 태그가 안 달려 있었습니다.** LLM 분류가 놓친 거죠. 그리고 하드게이트는 태그가 없으면 **정답이든 아니든 무조건 자릅니다.** 게이트가 제 일을 너무 충실히 한 겁니다.

이게 얼마나 큰 문제인지 재보기로 했습니다. 정답셋 19개 쿼리로 **"정답인데 결과에 안 나온 장소들이 대체 어느 단계에서 죽었는지"** 를 전수 귀인했습니다. 결과:

| 정답이 죽은 지점           | 비율      |
| ------------------- | ------- |
| 리랭크 창 밖이라 평가조차 못 받음 | **50%** |
| **태깅 하드게이트에 잘림**    | **31%** |
| 기타                  | 19%     |

**우리가 만든 게이트가 정답의 31%를 죽이고 있었습니다.**

여기서 **재현율(recall)** 이라는 반대편 지표가 등장합니다.

> **정밀도(precision)와 재현율(recall)**: 정밀도는 "보여준 것 중 맞는 비율", 재현율은 "맞는 것 중 보여준 비율"입니다. 아무것도 안 보여주면 정밀도는 100%지만 재현율은 0%입니다. 둘은 대체로 **서로를 잡아먹습니다.** 하드게이트는 정밀도를 사는 대신 재현율을 지불하는 거래였습니다.

그래서 게이트를 **소프트게이트로 바꿨습니다.**

- 태그를 통과한 후보는 **무조건 상위**에 둡니다 (하드게이트 시절의 정밀도를 그대로 유지).
- 태그가 없는 후보는 **자르지 않고 뒤에 남겨둡니다.**
- 뒤에 남은 후보는 넓어진 리랭크 창에서 **LLM이 근거를 직접 확인해 최종 판정**합니다.

즉 **"태그가 없다"를 사형이 아니라 후순위로 강등**한 겁니다. 태그 누락으로 억울하게 죽던 정답은 LLM이 리뷰 원문을 읽고 구제합니다. 측정 결과:

| 지표             | 하드게이트 | 소프트게이트             |
| -------------- | ----- | ------------------ |
| **Recall@10**  | 17.5% | **28.5%** (+11.0p) |
| Recall@20      | 35.9% | **45.2%**          |
| 후보 단계 재현율      | 62.9% | **87.5%**          |
| **정밀도 위반(오탐)** | 3/83  | **2/83** (악화 없음)   |

**재현율이 크게 오르는데 정밀도가 안 나빠졌습니다.** 통과자를 여전히 위에 두기 때문입니다. 태깅 하드게이트에 잘리던 정답도 21건 → 9건으로 줄었고, 남은 9건은 대부분 "검색 영역 밖"이라는 정당한 컷이었습니다.

### 무엇을 하드로 남기고 무엇을 풀었나

그렇다고 전부 푼 건 아닙니다. 기준은 하나였습니다 — **라벨 출처를 얼마나 믿을 수 있나.**

| 하드로 유지             | 소프트로 전환               |
| ------------------ | --------------------- |
| 업종 카테고리, 요리·메뉴 게이트 | 공간/뷰 스타일(venueStyles) |
| 편의시설(네이버 권위 태그)    | 추상 의도 점수(concepts)    |
| 숙박 제외, 지도 영역       |                       |

**네이버가 준 사실 정보는 하드로 남기고, LLM이 붙인 태그는 소프트로 풀었습니다.** 주차장이 있다는 태그가 틀릴 확률은 낮지만, "이 카페는 한옥이다"라는 LLM 판단이 누락될 확률은 꽤 높으니까요. 즉 **게이트의 강도를 그 출처의 신뢰도에 맞춘 것**입니다.

한 가지 예외도 뒀습니다. 임베딩을 안 쓰는 폴백 경로(어휘 검색·평점순)에는 **리랭커 검증이 없으므로 게이트를 다시 하드로 되돌립니다.** 뒤에서 걸러줄 사람이 없으면 앞에서 막아야 하니까요.

## 남은 한계

- **데이트는 29 → 50%에 그쳤습니다.** 식당의 `photo_zone_spot` 라벨이 전국에 **42건**뿐이라, 게이트를 걸면 정밀해지긴 하는데 **애초에 라벨된 후보가 부족합니다.** 필터는 있는 걸 골라낼 뿐, 없는 걸 만들어 주지는 않습니다.
- **소프트게이트는 병목을 옮겼을 뿐입니다.** 게이트 컷이 줄자 다음 병목이 드러났습니다 — 정답이 결과에 들어오긴 하는데 **10위 밖에 있는** 경우가 12건 → 32건으로 늘었습니다. 문제가 "못 불러온다"에서 "불러왔는데 순서가 나쁘다"로 이동한 겁니다. 좋은 이동이지만, 아직 끝은 아닙니다.
- 그리고 라벨 커버리지 자체를 올리는 일이 남았습니다. 그게 다음 편입니다.

## 이 글의 결론

- 임베딩의 '비슷함'은 **감자탕집과 한옥 카페를 구분하지 못합니다.** 이런 축은 정렬이 아니라 **필터로 걸러야** 합니다.
- 검색 조건을 **축으로 쪼개고, 축마다 가장 정확한 출처**를 씁니다. 네이버가 주는 건 네이버를, 안 주는 것만 LLM을 — **모든 걸 LLM에 맡기지 않는 게 핵심**입니다.
- 무거운 판단은 **검색할 때가 아니라 색인할 때 한 번.** 검색은 결정적 매칭만 합니다.
- 파인다이닝 **정밀도 0%** 가 알려준 건 "더 정교한 규칙이 필요하다"가 아니라 **"이 신호는 버려야 한다"** 였습니다. 텍스트를 버리고 LLM 검증 라벨만 쓰자 스페셜티·인스타 **P@8 29% → 100%**.
- 하드게이트는 **정밀도를 사고 재현율을 지불하는 거래**입니다. 실제로 정답의 **31%** 를 죽이고 있었고, 소프트게이트로 풀어 **Recall@10 17.5% → 28.5%** 를 정밀도 손실 없이 회수했습니다.
- 게이트의 강도는 **라벨 출처의 신뢰도에 맞춥니다.** 네이버 사실 정보는 하드, LLM 태깅은 소프트.

다음 글(기술 5)에서는 그 라벨 커버리지를 끌어올린 **문서 청크 임베딩** — 리뷰 한 문장에 묻힌 정답을 살리고, 그걸 '정렬'에 쓰려다 오히려 무너진 실패까지 — 를 봅니다.

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