왜 나는 벡터 검색 위에 LLM 파서를 추가했는가 (그리고 그것이 바꾼 점)

발행: (2026년 3월 9일 PM 08:27 GMT+9)
10 분 소요
원문: Dev.to

Source: Dev.to

위에 제공된 소스 링크 외에 번역할 텍스트가 포함되어 있지 않습니다. 번역을 원하는 본문을 알려주시면 한국어로 번역해 드리겠습니다.

벡터 검색만으로 충분하다고 생각했어요

저는 Queryra 를 만들었습니다 – WooCommerce와 Shopify용 AI‑search 플러그인입니다.
키워드 매칭을 의미론적 임베딩으로 대체했기 때문에 고객은 “something warm for winter” 와 같이 입력하고 바로 스웨터, 플리스 재킷, 담요 등을 찾을 수 있었습니다. 결과가 전혀 없는 검색은 드물게 발생했죠. 잘 작동했습니다… 누군가가 다음과 같이 검색할 때까지:

“wireless headphones under $80, not Beats”

벡터 검색은 무선 헤드폰을 반환했지만, 그 중 많은 제품이 $200이고 몇 개는 Beats였습니다. 가격 제한과 브랜드 제외 조건이 임베딩 모델에 전혀 반영되지 않았습니다.

그때 저는 깨달았습니다: 벡터 검색은 레이어 1에 불과합니다. 저는 레이어 2를 놓치고 있었던 것이죠.

순수 벡터 검색의 문제점

임베딩은 한 가지에 뛰어납니다: 의미적 유사성을 인코딩하는 것.

  • “Sneakers”(스니커즈)는 “trainers”(운동화)와 “running shoes”(러닝화)와 가깝게 위치합니다.
  • “Gift for dad”(아빠에게 줄 선물)는 정원 도구, 바베큐 세트, 시계 등을 찾아줍니다 – 쿼리에 해당 단어가 없어도 말이죠.

하지만 “laptop under $1000 for video editing, not Chromebook”(비디오 편집용 노트북, 가격 $1000 이하, Chromebook 제외) 와 같은 쿼리는 근본적으로 두 종류의 정보를 담고 있습니다:

유형설명
의미적 의도고객이 원하는 것 (비디오 작업을 위한 강력한 노트북)
구조적 제약결과를 필터링하는 방법 (가격 제한, 카테고리 제외)

임베딩은 의미적 의도를 잘 처리하지만 구조적 제약에 대한 메커니즘이 없습니다. “$1000 이하”를 벡터 공간의 방향으로 인코딩할 수 없으며, “Chromebook 제외”는 의미적 개념이 아니라 검색 시스템에 대한 지시이기 때문입니다. 모든 벡터 전용 구현은 이와 같은 사각지대를 가지고 있으며, 쿼리가 더 구체화될수록 문제는 심각해집니다.

가장 큰 피해자는 누구일까요? 바로 가장 높은 구매 의도를 가진 구매자들 – 즉, 지금 바로 구매를 결정하려는 사람들.

해결책: LLM 파서를 레이어 2로

벡터 검색보다 먼저 실행되는 쿼리 파서를 추가했습니다. 이 파서는 쿼리를 구조화된 구성 요소로 분해하는 역할을 합니다.

예시

{
  "semantic_query": "organic shampoo",
  "price_max": 25,
  "attribute_exclude": ["sulfates"],
  "sort_by": "rating"
}

각 구성 요소는 적절한 하위 시스템으로 전달됩니다:

구성 요소대상목적
semantic_query벡터 검색의미적으로 관련된 제품을 찾음
price_max데이터베이스 필터$25에서 강제 제한
attribute_exclude포스트‑필터황산염 함유 제품을 제거
sort_by결과 재정렬평점이 가장 높은 제품을 먼저 표시

벡터 레이어는 고객이 의미하는 바를 파악하고; 파서 레이어는 고객이 말한 바를 적용합니다.

우회 문제 (지연)

파서는 약 700–800 ms의 지연을 추가합니다. “blue t‑shirt”와 같은 간단한 쿼리의 경우, 임베딩만으로 충분히 처리되므로 이 오버헤드는 불필요합니다.

라우팅 바로가기

import re

def should_parse(query: str) -> bool:
    # Price signals
    if re.search(r'under \$|below \$|\$\d+|budget|cheap|premium', query, re.I):
        return True
    # Exclusion signals
    if re.search(r'\bnot\b|\bwithout\b|\bno\b|\bexclude\b', query, re.I):
        return True
    # Sorting signals
    if re.search(r'best rated|top rated|newest|cheapest|most popular', query, re.I):
        return True
    # Brand signals (capitalized words that aren't at sentence start)
    if re.search(r'(?<!^)(?<!\. )[A-Z][a-z]+(?:\s[A-Z][a-z]+)*', query):
        return True

    return False   # Simple query — go straight to vector search

간단한 쿼리는 파서를 완전히 건너뜁니다. 복잡한 쿼리는 전체 의도 추출을 수행합니다. 라우팅은 사용자에게 보이지 않으며, 사용자는 더 나은 결과만 받게 됩니다.

변경 사항

쿼리이전 (벡터만)이후 (벡터 + 파서)
“$80 이하 헤드폰”모든 헤드폰$80 이하 헤드폰만
“BrandX 제외”BrandX 포함BrandX 제외
“최고 평점 커피 메이커”무작위 순서평점 순으로 정렬
“유기농, 황산염 무첨가”모든 유기농 샴푸황산염‑무첨가 필터링

각 표의 첫 번째 행은 동일합니다 – 간단한 의미론적 쿼리는 동일하게 작동합니다. 다른 모든 행은 파서가 메우는 차이를 보여줍니다.

예상치 못한 한 가지 이점: 오타 + 제약조건

I expected the parser to help with structured queries, but it also solved a secondary problem: typos combined with constraints.

  • Vector search 자체만으로도 오타를 잘 처리한다 – “moisturiser”가 “moisturizer”를 찾는다.
  • “moisturiser under $20 without pareban”(오타가 난 parabens)은 임베딩 유사도가 오타가 난 용어에서 떨어져서 제외 조건이 깨졌다.

The LLM parser handles both in one pass: it corrects the typo, extracts the price constraint, and identifies the exclusion. This combined robustness was a pleasant surprise.

트레이드‑오프

파서는 복잡한 쿼리에서 LLM API 호출을 수행하기 때문에 비용이 발생합니다. 저는 gpt‑4.1‑nano를 사용합니다(gpt‑4o‑mini와 동일한 품질이며, 이 사용 사례에서는 약 33 % 저렴합니다). 우회 로직을 적용하면 전체 쿼리 중 일부만 파서를 통과하지만, 비용은 트래픽에 따라 여전히 증가합니다.

  • 셀프‑호스팅 옵션: API 호출을 로컬 모델로 교체합니다(예: Ollama + Mistral 7B는 의도 추출에 꽤 잘 작동합니다).
  • SaaS 제품: LLM 사용량을 가격에 반영합니다.

다음 단계

파서는 현재 다음을 추출합니다:

  • 가격 범위
  • 브랜드 언급
  • 속성 필터 및 제외
  • 정렬 선호도
  • 기본 부정

다음 항목: 다중 의도 쿼리.
예시: “사무실용 제품과 체육관용 제품” – 두 개의 별도 의미 검색 결과를 병합합니다. 벡터 검색만으로는 의도를 분리할 수 없지만 파서는 가능합니다.

전자상거래 검색을 구축하면서 같은 문제에 직면한다면—첫 두 개의 의미 있는 단어 이후를 무시하는 벡터 결과—이 2단계 접근 방식은 추가 복잡성을 감수할 가치가 있습니다.

여기에서 매장 소유자를 위한 더 길고 비기술적인 버전을 작성했습니다: Why Vector Search Alone Isn’t Enough for Ecommerce Stores

질문에 기꺼이 답변해 드립니다!

Queryra는 WooCommerce와 Shopify용 AI 검색입니다. queryra.com

0 조회
Back to Blog

관련 글

더 보기 »