2단계 출시: 임베딩 기반 라우팅(Embedding-Based Routing)에 대해 내가 잘못 알고 있었던 5가지
요약
임베딩 기반 라우팅 시스템을 구축하며 겪은 시행착오를 다룹니다. 정확도 지표의 기준 설정 오류와 카테고리 간 혼동이 실제 시스템 성능에 미치는 영향에 대한 통찰을 제공합니다.
핵심 포인트
- 정확도 측정 시 Groq의 과거 결정과 비교하는 것의 한계 인지
- 라우팅의 목표는 객관적 정답이 아닌 기존 시스템과의 일관성 유지
- 동일한 티어로 라우팅되는 카테고리 간의 혼동은 실제 비용에 영향 없음
- 임베딩 기반 k-NN 방식의 효율적인 모델 라우팅 구현
_AI가 스스로의 뇌를 선택하도록 가르치기의 후속 글입니다.
지난 포스트에서 저는 한 가지 계획을 세우며 마무리했습니다. Groq LLM 분류기를 로컬 multilingual-e5-large 임베딩(embeddings)으로 교체하는 것이었습니다. 유사한 과거 메시지를 찾아 카테고리에 투표하고, API 호출을 건너뛰는 방식입니다. 간단하죠.
실제로 이를 출시하게 만든 것은 Groq의 서비스 중단이었습니다.
2026-05-22, Groq가 2시간 동안 다운되었습니다. 503 요청이 조용히 중간 티어(medium tier)로 폴백(fallback)되었습니다. 사용자에게 에러가 나타나지는 않았지만, 아무도 자신이 받아야 했던 모델을 받지 못했습니다. 이는 문제가 발생하기 전까지는 괜찮아 보이는 종류의 "회복탄력성(resilience)"입니다.
그래서 저는 2단계를 출시했습니다. 제가 잘못 알고 있었던 부분들을 소개합니다.
잘못된 점 #1: 정확도 지표가 정답(correctness)에 관한 것이라고 생각했다
저는 임베딩 풀(embedding pool)에 대해 하나를 빼고 검증하는 교차 검증(leave-one-out cross-validation)을 사용하여 "티어 정확도(tier accuracy)"를 측정했습니다. 결과는 **83.2%**였습니다. 괜찮은 수치입니다. 하지만 저는 계속 스스로에게 물었습니다. 83.2%의 정확도는 어떤 정답(ground truth)에 대비한 것인가?
답은 다음과 같습니다: Groq의 과거 결정에 대비한 것입니다.
풀(pool)은 Groq에 의해 라벨링(labeled)됩니다. k-NN(k-최근접 이웃)은 해당 라벨들로부터 Groq의 카테고리 경계를 학습합니다. 제가 정확도를 측정할 때, 저는 "k-NN이 Groq와 얼마나 자주 일치하는가?"를 측정하는 것이지, "라우팅이 객관적으로 얼마나 정확한가?"를 측정하는 것이 아닙니다.
사실 이것이 측정해야 할 올바른 대상입니다. 2단계의 목표는 Groq를 로컬의 빠르고 효율적인 무언가로 교체하는 것이기 때문입니다. 품질 기준은 "Groq보다 나은 것"이 아니라 "Groq와 구별할 수 없는 것"입니다. 하지만 저는 제가 실제로 무엇을 측정하고 있는지 이해하기 전까지, 왜 83%라는 수치가 좋으면서도 동시에 무의미하게 느껴지는지에 대해 일주일 동안 혼란스러워했습니다.
잘못된 점 #2: analysis와 research_lookup 사이의 혼동이 문제라고 생각했다
analysis 카테고리의 정확도는 59%였습니다. 끔찍해 보이는 수치입니다. 임베딩이 analysis 프롬프트에 대해 research_lookup을 계속 예측하거나, 그 반대의 경우가 발생했습니다.
저는 이 문제를 해결하기 위해 이틀을 보냈습니다. 더 많은 합성 데이터(synthetic data)를 생성하고, 풀(pool)을 조정하고, 검증을 다시 실행했습니다. 수치는 거의 변하지 않았습니다.
그러다 티어 맵(tier map)을 살펴보았습니다:
CATEGORY_TIER_MAP = {
"analysis": "medium",
"research_lookup": "medium", # 동일한 목적지
...
두 카테고리 모두 **medium 티어 (medium tier)**로 라우팅됩니다. 임베딩 (embedding)은 이 둘을 구분할 수 없으며, 구분할 필요도 없습니다. 이는 두 도로가 모두 같은 도시로 향할 때, 두 길을 구분하지 못하는 것과 같습니다.
실제로 비용을 발생시키는 혼동은 coding이 strong 대신 medium으로 전송될 때입니다. 이는 요청의 3%에서 발생합니다. analysis/research_lookup의 혼동은요? 라우팅에 미치는 영향이 제로(0)입니다.
교훈: 카테고리 정확도 (category accuracy)가 아니라 티어 정확도 (tier accuracy)를 측정하세요. 이 둘은 서로 다른 것이며, 시스템의 실제 작업에 중요한 것은 오직 하나뿐입니다.
잘못된 점 #3: 합성 데이터 (synthetic data)만으로 충분하다고 생각했다
k-NN을 수행하려면 풀 (pool)에 레이블이 지정된 예시가 필요합니다. 저의 첫 번째 본능은 템플릿을 사용하여 카테고리당 60개의 합성 프롬프트 (synthetic prompts)를 생성해 풀을 빠르게 채우는 것이었습니다.
저는 실제로 이렇게 했습니다. 실제 임베딩 공간 (embedding space)을 확인하기 전까지는 괜찮아 보였습니다. 약간의 변형을 준 60개의 템플릿은 아마도 15개 정도의 뚜렷한 의미론적 클러스터 (semantic clusters)만을 생성할 뿐입니다. 나머지는 거의 중복된 것들(near-duplicates)입니다. 즉, 명사만 다를 뿐 문구는 동일한 것입니다. 거의 중복된 데이터로 가득 찬 k-NN 풀은 일반화 (generalizing)하는 대신 암기 (memorizing)를 해버립니다.
실제로 효과가 있었던 것은 실제 사용자 메시지였습니다. 저는 실제 채팅 세션 기록에서 342개의 프롬프트를 필터링했습니다. 이는 실제 사용자들이 다양한 언어로, 다양한 길이로, 실제 작업을 수행하며 진정으로 질문했던 것들입니다. 이 데이터는 합성 템플릿이 흉내 낼 수 없는 다양성을 가지고 있습니다.
데이터가 부족한 카테고리를 위해 (명시적인 다양성 제약 조건—다른 언어, 다른 길이, 다른 도메인—을 적용한 claude-haiku 사용) LLM 생성 프롬프트를 혼합한 후, 풀은 1,309개의 항목에 도달했고 티어 정확도가 유의미해졌습니다.
거의 중복된 임베딩 (Near-duplicate embeddings)이 풀 품질의 진짜 적입니다. 잘못된 레이블이 아닙니다.
잘못된 점 #4: 30%의 "잘못 레이블링된" 합성 프롬프트가 노이즈라고 생각했다
코딩 프롬프트를 생성하여 레이블링을 위해 Groq에 실행했을 때, 30%가 analysis로 반환되었습니다. 저의 첫 반응은 'Groq가 틀렸다. 이것들은 명백히 코딩 프롬프트이므로 내가 레이블을 덮어써야(override) 한다'는 것이었습니다.
하지만 저는 그렇게 하지 않았고, 그것이 옳았습니다.
그 "잘못 레이블링된" 프롬프트들이 실제로 무엇이었는지 보십시오: "이 알고리즘의 시간 복잡도(time complexity)를 설명해줘", "재귀(recursion)와 반복(iteration)의 차이점은 무엇인가", "이 이진 탐색(binary search) 방식에 대해 검토해줘". 이것들은 무언가를 설명하는 것(analysis)과 코드를 다루는 것(coding) 사이의 경계선에 바로 걸쳐 있습니다.
Groq는 일관되게 이것들을 analysis라고 부릅니다. 따라서 임베딩 풀(embedding pool)은 Groq의 경계를 정확하게 학습하게 되며, 이는 실제 라이브 시스템이 사용하는 경계이기도 합니다. 레이블이 틀린 것이 아니었습니다. 경계가 어디에 있어야 하는지에 대한 저의 직관이 틀렸던 것입니다.
만약 레이블 소스(label source)가 일관된 의견을 가지고 있다면, 당신의 본능보다 그것을 신뢰하십시오.
잘못된 점 #5: 불일치가 대칭적(symmetric)일 것이라고 생각했다
임베딩 k-NN이 티어(tier)에 대해 Groq와 의견이 일치하지 않는 17%의 요청 중에서:
Upgrade (k-NN -> 더 강력한 모델): 10.0%
Downgrade (k-NN -> 더 약한 모델): 6.8%
저는 대략 50/50일 것이라고 예상했습니다. 하지만 대신, 시스템은 불확실할 때 자연스럽게 더 강력한 모델 쪽으로 기울어집니다. 저는 이것을 설계(engineer)하지 않았습니다. 이것은 데이터로부터 나타납니다. casual 및 simple_lookup 프롬프트에 대한 임베딩 공간(embedding space)은 매우 조밀하고 깨끗하기 때문에, 저가형 티어(cheap-tier) 예측은 확신이 있습니다. 반면 strong 티어 주변의 경계는 더 모호하기 때문에, k-NN이 그곳에서 불확실할 때는 더 강력한 이웃(neighbors) 쪽으로 끌어당기는 경향이 있습니다.
라우팅 시스템(routing system)에게 이러한 비대칭성(asymmetry)은 바람직합니다. 필요 이상의 강력한 모델을 사용하는 것은 비용이 많이 들지만 조용히 넘어갑니다. 반면 필요보다 약한 모델을 사용하는 것은 비용은 저렴하지만 사용자에게 잠재적으로 드러날 수 있습니다.
1개월 후의 수치 현황
실제 트래픽 분포 (메시징 봇):
cheap tier ████████████████████████ 84.9% (일상적인 대화)
strong tier ███ 8.9% (코딩, 추론)
...
이 수치들을 살펴보기 전에 한 가지 중요한 주의 사항이 있습니다: crab-bot은 메시징 봇으로 작동하며, 주요 사용 사례는 일상적인 대화, 빠른 검색, 그리고 가끔 발생하는 기술적 질문입니다. 84.9%의 저가형 티어 (cheap-tier) 트래픽은 그러한 사용 패턴을 직접적으로 반영한 결과입니다. 만약 개발자 도구, 고객 지원 봇, 또는 연구 보조를 위해 라우팅을 수행한다면, 여러분의 분포는 매우 다르게 나타날 것입니다. 코딩 비중이 높은 워크로드(workload)는 저가형과 강력형(strong)의 비중을 뒤바꿀 수 있으며, 그에 따라 비용 절감 곡선도 변화할 것입니다.
이 분포를 기반으로 한 대략적인 비용 추정치:
공식은 간단합니다:
routing_cost = sum(tier_pct x cost_per_request_for_tier)
savings = (always_medium_cost - routing_cost) / always_medium_cost
저가형(cheap)이 중간형(medium)의 약 1/15이고, 강력형(strong)이 중간형의 약 3배라는 일반적인 가격 비율을 적용하면:
routing_cost = (84.9% x 1/15) + (6.3% x 1) + (8.9% x 3)
= 0.057 + 0.063 + 0.267
= 0.387 -> 항상 중간형을 사용할 때 비용의 약 39%
이 특정 트래픽 패턴에서는 항상 중간형을 사용하는 것보다 대략 61% 더 저렴합니다.
여러분의 절감액을 추정하려면, 여러분의 티어 분포와 모델의 실제 토큰당 가격을 대입해 보세요:
| 시나리오 | cheap% | medium% | strong% | 항상-중간형 대비 예상 절감액 |
|---|---|---|---|---|
| 채팅 봇 (본 사례) | 85% | 6% | 9% | ~61% |
| ... |
절감 효과는 실재하지만, 이는 거의 전적으로 트래픽 중 실제 저가형 티어에 해당하는 비중이 얼마나 되는지에 의해 결정됩니다.
| 1단계 (모든 요청에 Groq 사용) | 2단계 (k-NN 로컬) | |
|---|---|---|
| 분류 지연 시간 (Categorization latency) | ~380ms | <20ms |
| ... | ||
| *이 트래픽 분포를 기준으로 합니다. 실제 결과는 상황에 따라 다를 수 있습니다. |
다음 단계
analysis/research_lookup 분석 결과는 자연스러운 결론에 도달합니다: 이 둘을 하나의 카테고리로 병합하는 것입니다. 둘 다 중간형 티어로 전달되며, 임베딩 공간 (embedding space)에서 이들을 분리할 수 없고, 7개 카테고리 분류 체계는 이득 없이 혼란만 야기하는 인위적인 경계선을 만들고 있습니다.
현재 풀(pool)에서 병합을 시뮬레이션한 결과: 카테고리 정확도(category accuracy)는 78.6%에서 82.1%로, 중간 계층 라우팅 정확도(medium-tier routing accuracy)는 79.9%에서 82.4%로 상승했습니다. 분류 체계(taxonomy)는 모델의 기하학적 구조(geometry)와 일치해야 하며, 그 반대가 되어서는 안 됩니다.
이것이 3단계입니다. 제품이 출시되면 상세 내용을 작성하겠습니다.
여러분이 구축하고 있는 작업에 이 내용이 도움이 된다면, 댓글을 통해 구현 세부 사항을 기꺼이 공유하겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기