AI/LLM

[Semantic Search] 의미 기반 검색

jumemory 2025. 8. 4. 17:52

 

[LLM 컨셉] Semantic Search: 키워드를 넘어 '의도'를 검색하다

**의미 기반 검색(Semantic Search)**은 사용자의 검색어에 담긴 **의도(Intent)**와 문장의 **맥락(Context)**을 이해하여 가장 관련성이 높은 결과를 제공하는 기술입니다. "검색어가 무엇인가?"보다 "검색어를 던진 이유가 무엇인가?"에 집중하는 방식입니다.


1. 전통적 검색(Lexical Search) vs 의미 기반 검색

구분 키워드 검색 (Lexical) 의미 기반 검색 (Semantic)
작동 원리 문자열 일치 (TF-IDF, BM25) 벡터 공간 내 의미적 거리 측정
장점 고유 명사, 제품명 검색에 정확함 동의어, 문맥, 모호한 표현 처리에 강함
단점 오타나 유의어 처리에 취약함 계산 비용이 상대적으로 높음
비유 사전에서 똑같은 단어 찾기 대화의 맥락을 이해하는 비서

2. 의미 기반 검색의 핵심 기술

의미 기반 검색이 가능하려면 텍스트를 숫자로 바꾸고 거리를 재는 정교한 과정이 필요합니다.

① 텍스트 임베딩 (Text Embedding)

문장을 고차원 벡터로 변환할 때, 단순한 숫자가 아니라 문법적 구조와 의미적 특징이 담기도록 합니다.

  • 예: "은행에 가서 돈을 찾다"와 "강둑(Bank) 근처에서 놀다"에서 'Bank'라는 단어가 전혀 다른 위치에 배치되도록 문맥을 반영합니다.

② 유사도 측정 기법

벡터 공간에서 두 문장이 얼마나 가까운지 계산하는 수학적 방법입니다.

  • 코사인 유사도 (Cosine Similarity): 두 벡터 사이의 '각도'를 측정합니다. 문장의 길이에 상관없이 '방향성(의미)'이 얼마나 유사한지 판단할 때 가장 많이 쓰입니다.
  • L2 거리 (Euclidean Distance): 두 점 사이의 직선거리를 측정합니다. 데이터의 절대적인 크기가 중요할 때 사용합니다.

3. 검색 성능을 높이는 고도화 전략

실무에서는 단순히 벡터 검색만 하지 않고, 여러 기법을 섞어서 사용합니다.

  • 하이브리드 검색 (Hybrid Search): 키워드 기반의 BM25와 의미 기반의 벡터 검색을 결합합니다. 정확한 명칭(키워드)과 맥락(의미)을 모두 잡기 위한 가장 대중적인 전략입니다.
  • 리랭킹 (Re-ranking): 검색 엔진이 1차로 뽑아온 상위 결과물들을, 더 똑똑한 모델(Cross-Encoder 등)을 이용해 다시 한번 정밀하게 순위를 매기는 과정입니다. 속도와 정확도 사이의 균형을 맞추는 핵심 기술입니다.

4. 의미 기반 검색의 실전 활용 사례

  1. Q&A 봇: 사용자가 "환불 어떻게 해?"라고 물어도 "반품 절차", "결제 취소 방법" 문서를 찾아 답변합니다.
  2. 추천 시스템: 내가 읽은 기사와 '내용 면에서 유사한' 다른 기사를 추천합니다.
  3. 다국어 검색: 한국어로 검색해도 영문 문서 중에서 같은 의미를 지닌 내용을 찾아낼 수 있습니다. (Cross-lingual Embedding 활용)

5. [선생님의 심화 보충] Sparse Vector vs Dense Vector

  • Dense Vector (밀집 벡터): 우리가 지금까지 배운 임베딩입니다. 모든 차원에 숫자가 가득 차 있으며 문맥 파악에 유리합니다.
  • Sparse Vector (희소 벡터): 키워드 등장 횟수를 기록한 벡터입니다. 대부분이 0으로 채워져 있으며, 특정 단어를 정확히 찾는 데 유리합니다.
  • 현대적인 의미 기반 검색은 이 두 가지 벡터를 적절히 배합하여 완성됩니다.

✍️ 공부를 마치며

의미 기반 검색은 RAG가 단순히 아무 자료나 가져오는 게 아니라, 모델이 답변하기에 '가장 적절한 참고서'를 골라주는 필터 역할을 합니다. 이제 도구를 준비했으니, 이들을 하나로 엮어줄 프레임워크를 만날 차례입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

1️⃣ itemgetter (operator 모듈)

✅ 개념

  • 리스트, 튜플, 딕셔너리 등에서 특정 위치(index)나 키(key)의 값을 빠르게 꺼낼 수 있게 해주는 함수
  • lambda x: x[1] 같은 역할을 더 빠르고 간결하게 구현

✅ 사용법

from operator import itemgetter

my_list = ['a', 'b', 'c', 'd']
get_index_1 = itemgetter(1)
print(get_index_1(my_list))  # 👉 'b'

my_dict = {'name': 'Alice', 'age': 30}
get_age = itemgetter('age')
print(get_age(my_dict))  # 👉 30

📝 추가 설명

  • 여러 개의 인덱스나 키도 동시에 가져올 수 있음
aget_name_age = itemgetter('name', 'age')
print(get_name_age(my_dict))  # 👉 ('Alice', 30)
  • 데이터 정렬 시 자주 사용 (예: sorted(data, key=itemgetter(1)))

2️⃣ re 모듈과 정규표현식

✅ 개념

  • 문자열에서 특정 패턴을 검색·추출·치환할 때 사용
  • 전화번호, 이메일 등 패턴이 있는 데이터를 찾는 데 유용

✅ 사용 예시

import re

text = "안녕하세요! 제 번호는 010-9999-4567 입니다."
match = re.search(r"(\d{3}-\d{4}-\d{4})", text)

if match:
    phone_number = match.group(1)
    print(phone_number)  # 👉 010-9999-4567

🔑 핵심 패턴

  • \d → 숫자
  • {3} → 3자리 반복
  • () → 그룹핑 (group(1)로 접근)

3️⃣ 바다코끼리 연산자 (:=)

✅ 개념

  • 할당 표현식: if, while 등에서 변수를 선언하면서 동시에 조건식에 활용 가능
  • Python 3.8부터 지원

✅ 사용 예시

import re

text = "안녕하세요! 제 번호는 010-9999-4567 입니다."
if match := re.search(r"(\d{3}-\d{4}-\d{4})", text):
    phone_number = match.group(1)
    print(phone_number)

🔹 위 코드는 match = re.search(...) + if match: 를 한 줄로 줄인 것.


4️⃣ LangChain 주요 개념

① ChatPromptTemplate

  • 대화형 프롬프트를 만들 때 사용
  • 역할(Role)과 메시지를 지정
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "사용자 입력한 요리의 레시피를 생각하세요"),
    ("human", "{dish}")
])

② ChatOpenAI

  • OpenAI의 챗 모델을 LangChain에서 불러올 때 사용
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model='gpt-4o-mini', temperature=0)

🔑 오타 주의: temerature → temperature


③ StrOutputParser

  • 모델의 응답을 문자열로 변환해주는 파서
from langchain_core.output_parsers import StrOutputParser

parser = StrOutputParser()

④ 체인 연결 (| 연산자)

  • 프롬프트 → 모델 → 출력 파서를 하나의 체인으로 연결
 
chain = prompt | model | StrOutputParser()
chain.invoke({'dish': '라면'})  # 단일 요청

⑤ 스트리밍(stream)과 배치(batch)

  • 스트리밍: 모델이 생성하는 응답을 실시간으로 출력
for chunk in chain.stream({'dish': '마라탕'}):
    print(chunk, end="")
  • 배치: 여러 개의 요청을 한 번에 처리
output = chain.batch([{'dish':'라면'}, {'dish':'떡볶이'}])

📝 전체 요약 표

개념설명예시
itemgetter 리스트/딕셔너리 값 추출 itemgetter(1)(my_list)
re.search 문자열에서 패턴 검색 re.search(r"\d{3}", text)
:= (바다코끼리) 변수 할당 + 조건식 if match := re.search(...):
ChatPromptTemplate 프롬프트 메시지 구성 from_messages([...])
ChatOpenAI OpenAI 모델 사용 ChatOpenAI(model='gpt-4o-mini')
StrOutputParser 응답을 문자열로 변환 StrOutputParser()
chain.stream 실시간 응답 출력 for chunk in chain.stream(...):
chain.batch 여러 요청 처리 chain.batch([...])

 

랭스미스 모니터링?

 

깃 이그노어?

 

 

 

postgresql 원래는 RBMS, 확장팩 설치하묜 벡터디비로 서용 가능
FAISS 페이스북에서 만든거
크로마 기본
레그를 사용하면 이용한 벡터 디비 3종류

 

 

🧠 오늘 학습한 내용 정리


1️⃣ Python 기본 개념

  • itemgetter: 리스트/딕셔너리에서 특정 인덱스나 키로 값을 빠르게 꺼낼 때 사용
  • re 모듈: 정규 표현식으로 패턴 매칭 (전화번호 추출)
  • 바다코끼리 연산자 (:=): 할당과 조건 검사를 한 번에 처리

2️⃣ LangChain 기본 체인 만들기

  • ChatPromptTemplate: 프롬프트(모델에게 지시문) 작성
  • ChatOpenAI: OpenAI 모델을 LangChain에서 사용
  • StrOutputParser: 모델 응답을 문자열로 변환
  • 체인 연결: prompt | model | parser
  • 사용법:
    • invoke → 단일 요청
    • stream → 실시간 스트리밍
    • batch → 여러 요청 한 번에 처리

3️⃣ 환경 변수와 LangSmith 연결

  • .env 파일로 API 키, 프로젝트 설정
  • load_dotenv()로 Python에서 불러오기
  • LangSmith(smith.langchain.com)를 통해 체인 실행 로그 추적 가능

4️⃣ 체인 고급 기능

  • Chain of Thought (CoT):
    • 모델이 단계별로 생각 → 결론만 추출하는 체인
  • RunnableLambda:
    • 체인 결과를 후처리 (예: 답변을 대문자로 변환)
  • RunnableParallel:
    • 여러 체인을 동시에 실행 (낙관주의 vs 비관주의 체인)
  • 결과 합치기:
    • 여러 의견 → 종합 프롬프트 → 최종 답변 생성

5️⃣ 리트리버 & Tavily 검색

  • Tavily API로 실시간 웹 검색 리트리버 사용
  • TAVILY_API_KEY를 .env에 저장 후 활용
  • 체인에서:
  • python
    코드 복사
    {'context': retriever, 'question': RunnablePassthrough()} | prompt | model

6️⃣ Git 문서 로딩 + Chroma 벡터 DB

  • GitLoader: GitHub 리포지토리에서 문서 불러오기
  • 텍스트 분할: RecursiveCharacterTextSplitter
  • 임베딩 생성: OpenAIEmbeddings
  • DB 저장: Chroma.from_documents()
  • RAG 체인: 리트리버로 관련 문서 검색 → 모델 답변

7️⃣ HyDE (Hypothetical Document Embeddings)

  • 질문만으로 검색 → 정확도가 떨어질 수 있음
  • 모델이 먼저 "가짜 문서"를 만들어서 검색에 활용
  • 코드:
  • python
    코드 복사
    hypothetical_prompt → hypothetical_chain | retriever
  • RAG 성능 향상

8️⃣ Multi-query RAG

  • Pydantic 모델(QueryGenerationOutput)로 3개 이상의 검색 쿼리 자동 생성
  • 여러 쿼리를 병렬로 검색 → 결과 합침
  • multi_query_rag_chain으로 다양한 검색 관점 확보

9️⃣ PostgreSQL 설치

  • postgresql-common 설치
  • APT 리포지토리 등록 과정에서 Signed-By 충돌 문제 해결
  • 올바른 설치 순서:
  • bash
    코드 복사
    sudo apt install -y postgresql-common sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh sudo apt update sudo apt -y install postgresql
  • 충돌 시 /etc/apt/sources.list.d/pgdg.list 중복 키 제거

✅ 오늘 배운 핵심 포인트

  • LangChain 체인 조합(|), 후처리(RunnableLambda), 병렬 실행(RunnableParallel)
  • 리트리버 기반 RAG 검색 + HyDE, Multi-query 개선
  • Git → 벡터 DB → RAG 구현
  • PostgreSQL 설치 문제와 해결 방법

 

질문받고 라우터를 통해서 어디로 검색할지 판단하고 질문에 응답함   

'AI > LLM' 카테고리의 다른 글

[LangGraph] 에이전트의 설계도  (0) 2025.08.06
[LangChain] AI 파이프라인 구축  (0) 2025.08.05
[Vector DB] 지식의 저장소  (3) 2025.08.01
[RAG 기초] 환각 현상의 구세주  (0) 2025.07.31
[PEFT 2] 양자화 튜닝 QLoRA  (3) 2025.07.30