Home / Advanced RAG 기법 / Advanced RAG 사전 검색
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건이면 넓히고, 섞였으면 분해 — 문제마다 다른 쪼개기

Step-back

상위 개념 추상화

  • "트라토리아 벨라 런치 파스타 가격" → "이탈리안 메뉴 가격 정책"
  • 핵심 의도를 유지한 채 검색 범위 확대
  • 너무 구체적인 질문의 0건 문제 해결

언제 — 검색 결과가 0건에 가까울 때

Sub-Query

독립 주제 분해

  • "예약 바꾸면서 인원 추가 돼?" → 독립 질문 2개
  • 하위 질문별로 검색 → 결과 합산 → LLM 전달
  • Multi-Query와 다름 — 표현 변형이 아니라 주제 분리

언제 — 질문에 독립 주제가 2개 이상 섞였을 때

takeaway

셋 다 프롬프트 지시문의 차이일 뿐입니다 — "다른 관점으로" · "상위 개념으로" · "독립 질문으로" 분해 방향만 바꿉니다.

PART 3 · 사전 검색

RAG Fusion — 분해의 완성

여러 쿼리의 결과를 단순 합집합이 아니라 순위 융합으로 — 공통 상위 문서가 진짜 관련 문서

takeaway

질문을 관점 쿼리로 분해(Multi-Query)한 뒤, 점수가 아니라 순위로 융합합니다 — 하이브리드 검색도 같은 융합기 RRF를 씁니다.

기법을 쌓는 것이 아니라, 병목을 진단하고 처방하세요.

인덱싱 → 사후 → 사전 순으로 — 평가 루프로 효과를 확인하며 한 번에 하나씩