
2단계 분류: 정규 표현식(Regex) 사전 필터 + 시맨틱 라우팅(Semantic Routing) — 의도 누락 방지
요약
정규 표현식(Regex)의 한계를 극복하기 위해 정확한 계층과 시맨틱 계층을 결합한 2단계 분류 시스템을 제안합니다. 임베딩과 검색을 활용한 시맨틱 라우팅을 통해 구어체 및 키워드가 없는 사용자 의도까지 정확하게 파악하는 방법을 다룹니다.
핵심 포인트
- 정규 표현식은 알려진 패턴에 강하지만 커버리지가 60~70%로 제한됨
- 2단계 분류를 통해 정확한 계층(Regex)과 퍼지 계층(Semantic)을 상호 보완
- 임베딩과 검색을 활용해 키워드가 없는 구어체 요청도 정확히 라우팅 가능
- 임계값 조정 및 마진 체크를 통해 엣지 케이스의 오라우팅 방지
고충 (The Pain): 지난 포스트에서는 씬 라우팅(scene routing)을 다루었습니다. 하지만 라우팅의 품질은 이를 뒷받침하는 분류(classification)의 품질에 달려 있습니다. 정규 표현식(Regex)만으로는 실제 요청의 약 60~70% 정도만 커버할 수 있으며, "XX에서 YY까지 비용이 얼마인지 물어봐 줘"와 같은 구어체 문장들은 놓치기 쉽습니다. 이러한 요청들을 어떻게 정확하게 라우팅할 수 있을까요?
학습 내용:
- 정규 표현식(Regex)에 한계가 있는 이유: 알려진 패턴은 일치시키지만, 알려지지 않은 표현은 일치시키지 못함
- 2단계 분류 (Two-layer classification): 정확한 계층(exact layer)이 하한선을 설정하고, 퍼지 계층(fuzzy layer)이 상한선을 높임
- 실전 시맨틱 계층 (Semantic layer):
all-MiniLM-L6-v2임베딩 (embeddings) + Chroma 검색 (retrieval) - 임계값(threshold) 조정 방법 (0.45 → 0.55) 및 마진 체크(margin check)가 엣지 케이스(edge-case)의 오라우팅을 방지하는 이유
- 키워드가 전혀 없는 요청인 "이 이메일을 sunny에게 전달해 줘"가 어떻게 올바른 씬(scene)에 도달하는지
1. 문제점: 정규 표현식(Regex)의 한계
초기 버전의 씬 라우팅은 정규 표현식(regular expressions)으로 사용자 의도를 판단했습니다:
import re
QUOTING_PATTERN = r'sea.*freight|air.*freight|quote|quotation|rate'
...
이는 일반적인 견적 관련 표현들을 처리했습니다: "What's the sea freight to Frankfurt?"는 일치하고, "DDP to CDG quote"도 일치합니다.
하지만 실제 운영 환경에 적용하자 수치는 다른 이야기를 했습니다: 정규 표현식(regex)의 커버리지는 약 60~70%에 불과했습니다.
실제 사용자의 다양한 표현들이 쏟아져 들어왔습니다 —
- "Ask what air freight from XX to YY costs"
- "HK to LAX, what price?"
- "How much for this shipment?"
— 이들은 매칭에 완전히 실패하거나 잘못된 씬(scene)과 매칭되었습니다.
더 까다로운 케이스는 '매칭(matching)'이 아니라 '이해(understanding)'가 필요한 것들이었습니다: "Forward this email to sunny" — 이메일 관련 키워드가 어디에도 없지만, 시맨틱(semantically)으로는 명백히 전달(forwarding) 의도입니다. 정규 표현식(Regex)은 이를 처리할 수 없습니다.
💡 핵심 통찰: 정규 표현식(regex)은 알려진 패턴에 강하고, 시맨틱(semantics)은 알려지지 않은 표현에 강합니다. 이 둘은 서로를 보완하는 것이지, 대체하는 것이 아닙니다.
2. 핵심 아이디어: 2단계 분류 (Two-Layer Classification)
해결책은 2단계 분류입니다. 첫 번째 계층은 정규 표현식 매칭(regex matching, 정확한 계층/exact layer)이고, 두 번째 계층은 시맨틱 매칭(semantic matching, 퍼지 계층/fuzzy layer)입니다.
**정확한 계층 (The exact layer)**은 "sea freight", "air freight", "quote", "quotation", "rate"와 같이 명확한 키워드가 포함된 표현을 처리합니다. 패턴이 안정적이고, 정규 표현식 (Regex)은 지연 시간 (latency)이 거의 제로에 가까워 매우 효율적입니다.
**퍼지 계층 (The fuzzy layer)**은 정확한 계층이 커버할 수 없는 모든 것을 처리합니다 — "ask how much XX to YY costs", "HK to LAX what price"와 같은 경우입니다. 고정된 키워드는 없지만, 의미론적 (semantics)으로는 명확하게 견적 (quoting)을 가리킵니다.
우선순위: 정확한 계층이 먼저 실행됩니다.

계층 1은 결정론적 (deterministic)이고, 계층 2는 시맨틱 (semantic)이며, 폴백 (fallback)은 어떤 것도 누락되지 않음을 보장합니다.
3. 구현 (Implementation)
3.1 시맨틱 계층 (Semantic Layer): 임베딩 벡터 (Embedding Vectors) + Chroma
퍼지 계층의 기초는 텍스트 임베딩 (text embeddings)입니다. 우리는 텍스트를 384차원 벡터 공간 (vector space)으로 매핑하는 경량 Sentence-BERT 모델인 all-MiniLM-L6-v2를 사용합니다.
from sentence_transformers import SentenceTransformer
import chromadb
...
3.2 매칭 로직 (Matching Logic)
def semantic_match(text):
# 사용자 요청 인코딩 (Encode the user request)
query_vec = model.encode(text)
...
3.3 튜닝 (Tuning): 0.45에서 0.55로
임계값 (threshold)은 근거 없이 정해진 것이 아니라, 체계적인 튜닝 과정을 통해 도출되었습니다:
| 임계값 (Threshold) | 커버리지 (Coverage) | 오분류 (Misclassification) | 문제점 (Problem) |
|---|---|---|---|
| 0.45 | ~90% | ~15% | 커버리지는 훌륭하지만 오판함 — "check the flight status"가 견적으로 라우팅됨 |
| ... |

0.55 + 마진(margin) 0.1이 승리합니다: 몇 번의 놓침을 허용하는 것이 잘못된 라우팅을 허용하는 것보다 낫습니다 — 잘못된 장면(scene)은 잘못된 도구를 의미하기 때문입니다.
저는 0.55를 선택했습니다. 일부 경계에 있는 표현들을 "놓치는" 것(이들은 일반적인 장면(general scene)으로 폴백(fallback)됩니다)은 허용할 수 있지만, "오판하는" 것(요청을 잘못된 장면으로 잘못 라우팅하는 것)은 허용할 수 없기 때문입니다.
추가적인 검증 단계가 하나 더 추가되었습니다: 마진(margin). 단순히 가장 높은 유사도(top similarity)가 임계값(threshold)을 넘는 것만으로는 부족합니다. 가장 높은 유사도와 두 번째로 높은 유사도 사이의 간격(gap) 또한 마진(0.1)을 넘어야 합니다. 이는 모호한 경계 근처에서의 오판을 더욱 억제합니다.
def semantic_match_with_margin(text):
results = collection.query(query_embeddings=[model.encode(text)], n_results=2)
...
3.4 장면 프로토타입 설계 (Scene Prototype Design)
프로토타입의 품질이 매칭 품질을 직접적으로 결정합니다. 세 가지 원칙은 다음과 같습니다:
- 장면당 최소 5개의 프로토타입을 구성하여 일반적인 변형들을 포괄해야 합니다. 견적(quoting) 장면에는 해상 운송 견적(sea-freight quotes), 항공 운송 견적(air-freight quotes), DDP 견적, DAP 견적, 복합 운송 견적(multimodal quotes) 등이 포함됩니다. 모든 프로토타입은 실제 사용자 표현(과거 대화에서 수집됨)입니다.
- 장면 간의 프로토타입은 구별 가능해야 합니다. 두 장면의 프로토타입이 의미론적으로 너무 가까우면 매칭 품질이 저하됩니다.
- 프로토타입은 주기적으로 갱신해야 합니다. 사용자의 표현 방식이 변함에 따라 오래된 프로토타입은 커버리지(coverage)를 잃게 됩니다. 매달 폴백 장면(fallback scene)에서 매칭되지 않은 표현들을 수집하고, 새로운 프로토타입이 필요한지 평가해야 합니다.
✅ 검증(Verification): 2단계 분류를 배포한 후, 분류 정확도가 80%에서 ~100%에 가깝게 향상되었습니다. "forward this email to sunny"와 같이 키워드가 없는 요청도 이제 이메일 장면(email scene)으로 안정적으로 도달합니다.
🩸 함정(Pitfall): 처음에는 정규 표현식(regex)만 사용했습니다. 커버리지는 60~70%였고, 구어체 요청들이 대량으로 폴백 장면(fallback scene)에 쏟아졌습니다. 시맨틱 레이어(semantic layer)를 추가하면서 커버리지가 극적으로 상승했지만, 임계값이 0.45일 때는 오판이 매우 심각했습니다. 0.55 임계값과 0.1 마진을 찾아내기까지 일주일 내내 튜닝(tuning)을 거쳐야 했습니다.
💼 가치(Value): 모든 요청이 적절한 도구 세트(toolset)를 갖춘 올바른 장면으로 라우팅됩니다. 그 어떤 요청도 그물망을 빠져나가지 않습니다.
▸ 인지적 전환 (Cognitive shift): 정확한 매칭 (exact)과 퍼지 매칭 (fuzzy)은 이분법적인 선택 사항이 아닙니다. 정규 표현식 (Regex)은 _결정론 (determinism)_을 제공하고, 시맨틱 (semantics)은 _커버리지 (coverage)_를 제공합니다. 오직 이 둘의 결합만이 높은 정밀도 (precision) 및 높은 재현율 (recall)을 보장합니다.

모든 요청은 정확히 하나의 장면 (scene)으로 종료됩니다 — 고아 요청도, 추측도 없습니다.
4. 장점과 단점
✅ 장점
- 매우 높은 커버리지 (coverage) — 정규 표현식이 매칭하지 못하는 것을 시맨틱 레이어 (semantic layer)가 잡아냅니다.
- 키워드가 없는 표현도 매칭됩니다 (예: "forward this email to sunny")
- 정규 표현식과 시맨틱은 대체 관계가 아닌 상호 보완 관계입니다 — 정확한 레이어 (exact layer)가 기반을 다지면, 퍼지 레이어 (fuzzy layer)가 범위를 확장합니다.
- Chroma 벡터 검색 (vector retrieval)은 매우 빠르며 (<10 ms), 사용자에게는 보이지 않을 정도로 신속합니다.
- 프로토타입 (prototypes) 확장이 용이합니다 — 새로운 표현을 처리하기 위해 새로운 프로토타입만 추가하면 됩니다.
⚠️ 단점
- 시맨틱 매칭은 임베딩 (embedding) 품질에 의존합니다 — 모델 버전이 변경되면 안정성이 흔들릴 수 있습니다.
- 초기 로딩 속도가 느립니다 — 모델 다운로드와 Chroma 인덱스 구축에 약 30초가 소요됩니다.
- 오판 위험 — 시맨틱적으로 인접한 장면들 (예: 항공편 상태 vs 항공 화물 견적) 사이의 경계가 모호해질 수 있습니다.
- 임계값 (threshold) 튜닝은 경험에 의존합니다 — 아직 자동화된 튜닝 메커니즘이 없습니다.
- 콜드 스타트 (Cold-start) 문제 — 새로운 장면이 안정적으로 매칭되려면 누적된 프로토타입이 필요합니다.
5. 현재 당신의 위치
이 글을 읽고 있는 당신은 더 이상 "벽처럼 쌓인 정규 표현식을 작성하며 모든 표현을 커버하기를 기도하는" 비관론자가 아닙니다. 당신은 모든 요청이 제 자리를 찾을 수 있도록 2단계 분류 (two-layer classification)를 사용하는 시스템 설계자가 되어가고 있습니다.
자연어 처리 (NLP)에서 인간 표현의 끝없는 변주에 직면했을 때, 우리에게 필요한 것은 더 이상 "하나의 정확한 일치를 찾는 것"이 아니라 "가장 가능성 높은 범위 내에서 가장 정확한 판단을 내리는 것"입니다. 그것이 바로 퍼지 매칭 (fuzzy matching)의 기술입니다.
다음 포스트: 라우팅(routing)과 분류(classification)가 준비되었습니다 — 하지만 복잡한 작업은 어떻게 할까요? 하나의 보고서에는 견적 요청, 결제 독촉, 그리고 재무 항목이 포함될 수 있습니다 — 단일 시나리오(single scene)로는 이를 모두 담을 수 없습니다. 복합 파이프라인 컨테이너(composite pipeline container)는 보고서를 하나의 파이프라인으로 변환합니다.
저자 소개: Wu Ji (无记) — 에이전트 엔지니어링 (Agent engineering), 루프 엔지니어링 (Loop Engineering), 그리고 디지털 전환 (digital transformation)에 집중하는 AI 및 디지털화 실무자입니다. 실용적이고 직접 따라 할 수 있는 튜토리얼을 제공합니다 — 그대로 따라 하기만 하면 바로 작동합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기