Skip to main content

Query Rewriting + HyDE

쿼리 재작성(Query Rewriting)과 HyDE(Hypothetical Document Embeddings)는 단일 쿼리를 변환하여 검색 품질을 높이는 기법입니다.

Query Rewriting (쿼리 재작성)

LLM을 사용하여 원본 질문을 검색에 최적화된 쿼리로 변환합니다.

왜 필요한가?

사용자 질문은 종종 구어체이거나, 약어를 포함하거나, 핵심 키워드가 부족합니다.

기본 구현

from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = init_chat_model("gpt-4o-mini", temperature=0)

rewrite_prompt = ChatPromptTemplate.from_messages([
    ("system", """당신은 검색 쿼리 최적화 전문가입니다.
사용자의 질문을 벡터 데이터베이스 검색에 최적화된 쿼리로 변환하세요.

규칙:
- 모호한 표현을 구체적으로 변환
- 약어를 풀어서 작성
- 핵심 키워드를 포함
- 한 문장으로 작성"""),
    ("human", "원본 질문: {question}\n\n최적화된 검색 쿼리:"),
])

rewrite_chain = rewrite_prompt | llm | StrOutputParser()
optimized = rewrite_chain.invoke({"question": "RAG 좀 알려줘"})
# → "RAG(Retrieval-Augmented Generation)의 정의, 핵심 구성 요소, 동작 원리"

고급 프롬프트 설계

도메인에 따라 프롬프트를 커스터마이즈할 수 있습니다.
# 기술 문서용 쿼리 재작성
tech_rewrite_prompt = ChatPromptTemplate.from_messages([
    ("system", """당신은 기술 문서 검색 쿼리 최적화 전문가입니다.

규칙:
1. 약어를 풀어서 작성 (예: RAG → Retrieval-Augmented Generation)
2. 기술 용어를 정확히 사용
3. 동의어를 포함하여 검색 범위 확대
4. 구체적인 기술 키워드를 추가

예시:
- "LLM 환각" → "대규모 언어 모델(LLM)의 환각(hallucination) 문제 원인과 해결 방법"
- "벡터DB 비교" → "벡터 데이터베이스(Chroma, Qdrant, Milvus, Weaviate) 성능 비교와 특징"
"""),
    ("human", "원본 질문: {question}\n\n최적화된 검색 쿼리:"),
])

Retriever와 통합

from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma(collection_name="docs", embedding_function=embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})

# 쿼리 재작성 → 검색 파이프라인
def rewrite_and_retrieve(question: str):
    optimized_query = rewrite_chain.invoke({"question": question})
    results = retriever.invoke(optimized_query)
    return results

results = rewrite_and_retrieve("RAG 좀 알려줘")

HyDE (Hypothetical Document Embeddings)

LLM이 질문에 대한 가상의 답변을 먼저 생성한 뒤, 그 답변의 임베딩으로 검색합니다.

핵심 아이디어

질문의 임베딩보다 답변의 임베딩이 실제 문서와 더 유사합니다.

구현

from langchain.chat_models import init_chat_model
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = init_chat_model("gpt-4o-mini", temperature=0)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma(collection_name="docs", embedding_function=embeddings)

# 1. 가상 답변 생성
hyde_prompt = ChatPromptTemplate.from_messages([
    ("system", """질문에 대한 답변을 작성하세요.
정확하지 않아도 됩니다. 관련 키워드와 개념을 최대한 포함하세요.
답변은 실제 기술 문서처럼 작성하세요."""),
    ("human", "{question}"),
])

hyde_chain = hyde_prompt | llm | StrOutputParser()

# 2. 가상 답변으로 검색
def hyde_retrieve(question: str, k: int = 4):
    hypothetical_answer = hyde_chain.invoke({"question": question})
    results = vectorstore.similarity_search(hypothetical_answer, k=k)
    return results

results = hyde_retrieve("RAPTOR는 어떻게 동작하나요?")

HyDE가 효과적인 경우

시나리오효과이유
질문이 매우 짧을 때높음가상 답변이 풍부한 키워드를 생성
질문과 문서 스타일이 다를 때매우 높음스타일 갭을 해소
전문 용어가 포함된 질문높음관련 용어를 확장
사실 확인 질문낮음잘못된 가상 답변이 검색을 왜곡
HyDE는 LLM이 생성한 가상 답변으로 검색하므로, 답변에 환각(hallucination)이 포함될 수 있습니다. 이 경우 실제 관련 문서가 아닌 환각 내용과 유사한 문서가 검색될 수 있습니다. 사실 확인(fact-checking)이 중요한 경우에는 Query Rewriting이 더 안전합니다.

Query Rewriting vs HyDE 비교

항목Query RewritingHyDE
변환 대상질문 → 최적화된 질문질문 → 가상 답변
LLM 호출1회1회
환각 위험낮음있음 (가상 답변이 잘못될 수 있음)
키워드 확장보통높음
적합한 경우모호하거나 짧은 질문질문-문서 스타일 차이
안전성더 안전환각 가능성 존재
안전한 기본 선택은 Query Rewriting입니다. 검색 품질이 부족하고, 특히 질문과 문서 간 스타일 차이가 큰 경우에 HyDE를 시도해보세요. 두 기법을 순차적으로 적용하는 것도 가능합니다.

참고 논문

논문학회/연도링크
Precise Zero-Shot Dense Retrieval without Relevance Labels (Gao et al.)ACL 2023arXiv 2212.10496
Query Rewriting for Retrieval-Augmented Large Language Models (Ma et al.)EMNLP 2023arXiv 2305.14283