Note
Advanced RAG 사전 검색
Query Rewriting, HyDE, Multi-Query, RAG Fusion
⏱ 40분
52 / 189
Advanced RAG 사전 검색
Query Rewriting, HyDE, Multi-Query, RAG Fusion
검색이 엉뚱할 때 쓰는 처방전
실패 유형 진단과 파이프라인 단계별 처방 — 검색 품질을 끌어올리는 기법 체계
🔄
사전 검색
Query Rewriting · HyDE · Multi-Query · RAG Fusion
PART 3 · 사전 검색
사전 검색
사용자 질문을 그대로 검색하지 않음 — LLM이 쿼리를 변환한 뒤 검색
🔄
검색 전에 쿼리를 고친다
이름은 많지만 구현은 하나 — 프롬프트 템플릿과 LLM 호출입니다. 지시문만 바꾸면 다른 기법이 됩니다
- Query Rewriting — 구어체를 검색어로
- HyDE — 가상 답변으로 검색
- Multi-Query 가족 — 관점 분해·추상화·주제 분해
- RAG Fusion — 여러 결과를 RRF로 융합
takeaway
매 쿼리마다 LLM 호출이 추가되는 단계입니다 — 효과는 크지만 비용도 커서, 인덱싱·사후 검색을 먼저 시도한 뒤 적용합니다.
PART 3 · 사전 검색
Query Rewriting
"해약하면 돈 내야 해?" → "예약 취소 수수료 정책" — 가장 값싸고 확실한 첫 처방
핵심 포인트
- REWRITE_PROMPT
- 지시문이 곧 기법 — 구어체→공식 용어, 대명사→구체 명사
- str(result)
- AgentResult에서 텍스트를 꺼내는 정본 — message는 dict입니다.
- chat_history
- 최근 3턴을 함께 주면 "그거 얼마야?" 같은 대명사 해소
- @tool
- Agentic RAG 모듈의 에이전트에 그대로 장착 가능한 형태
코드
python
from strands import Agent, tool
from strands.models import BedrockModel
model = BedrockModel(model_id="us.anthropic.claude-sonnet-4-6")
REWRITE_PROMPT = """사용자 질문을 검색에 최적화된 쿼리로 변환하세요.
- 구어체를 공식 용어로, 대명사를 구체적 명사로
- 검색 키워드만 출력 (설명 없이)"""
# 재작성 에이전트를 도구로 — 출력 텍스트는 str(result)로 추출
@tool
def rewrite_query(query: str) -> str:
"""사용자 질문을 검색 최적 쿼리로 변환합니다."""
rewriter = Agent(model=model, system_prompt=REWRITE_PROMPT)
return str(rewriter(query))
# "해약하면 돈 내야 해?" → "예약 취소 수수료 정책"
PART 3 · 사전 검색
HyDE — 가상 답변으로 검색
HyDE(Hypothetical Document Embeddings) — 문서를 닮은 가상 답변을 만들어, 질문 대신 그 임베딩으로 검색
핵심 포인트
- 형식 갭 해소
- 짧은 질문 ↔ 긴 문서 — 답변 임베딩이 문서와 더 가깝습니다.
- LLM 2회
- 가상 답변 생성 + 최종 응답 — 레이턴시 비용을 감수하는 기법
- 적합
- FAQ 스타일 문서, 전문 용어 문서를 일반 사용자가 검색할 때
- 역효과
- 수치·날짜·최신 데이터 질문 — 가상 답변이 환각 노이즈가 됩니다.
코드
python
import boto3
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
# 1단계 — 가상 답변 생성 (정확할 필요 없음, 형식만 문서와 닮으면 됨)
def hypothetical_answer(query: str) -> str:
response = bedrock.converse(
modelId="us.anthropic.claude-sonnet-4-6",
messages=[{"role": "user", "content": [
{"text": f"다음 질문에 상세히 답변하세요 (부정확해도 됩니다): {query}"}]}],
inferenceConfig={"maxTokens": 200, "temperature": 0},
)
return response["output"]["message"]["content"][0]["text"]
# 2단계 — 질문 대신 가상 답변의 임베딩으로 벡터 검색
docs = vector_search(embed(hypothetical_answer("이탈리안 코스 가격?")))
PART 3 · 사전 검색
질문을 쪼개는 세 가지 방법
모호하면 관점을 늘리고, 0건이면 넓히고, 섞였으면 분해 — 문제마다 다른 쪼개기
Multi-Query 추천
관점 분해
- 1개 질문 → 3~5개 다른 관점의 쿼리
- 각각 검색 후 합집합 — 재현율 극대화
- 병렬 검색(asyncio)으로 레이턴시 방어
언제 — 질문이 모호해 어떤 관점인지 불확실할 때
Step-back
상위 개념 추상화
- "트라토리아 벨라 런치 파스타 가격" → "이탈리안 메뉴 가격 정책"
- 핵심 의도를 유지한 채 검색 범위 확대
- 너무 구체적인 질문의 0건 문제 해결
언제 — 검색 결과가 0건에 가까울 때
Sub-Query
독립 주제 분해
- "예약 바꾸면서 인원 추가 돼?" → 독립 질문 2개
- 하위 질문별로 검색 → 결과 합산 → LLM 전달
- Multi-Query와 다름 — 표현 변형이 아니라 주제 분리
언제 — 질문에 독립 주제가 2개 이상 섞였을 때
takeaway
셋 다 프롬프트 지시문의 차이일 뿐입니다 — "다른 관점으로" · "상위 개념으로" · "독립 질문으로" 분해 방향만 바꿉니다.
PART 3 · 사전 검색
RAG Fusion — 분해의 완성
여러 쿼리의 결과를 단순 합집합이 아니라 순위 융합으로 — 공통 상위 문서가 진짜 관련 문서
takeaway
질문을 관점 쿼리로 분해(Multi-Query)한 뒤, 점수가 아니라 순위로 융합합니다 — 하이브리드 검색도 같은 융합기 RRF를 씁니다.
기법을 쌓는 것이 아니라, 병목을 진단하고 처방하세요.
인덱싱 → 사후 → 사전 순으로 — 평가 루프로 효과를 확인하며 한 번에 하나씩