RAG의 검색 품질은 청크의 품질에서 시작되지만, 그 다음으로 중요한 것은 질문 자체의 품질이다.
사용자는 자신이 원하는 정보를 항상 정확하게 표현하지 못한다. "그거 알려줘"처럼 모호한 질문, 여러 개념이 뒤섞인 복잡한 질문, 혹은 검색 대상 문서와 어휘가 전혀 다른 질문을 던지기도 한다. 이런 질문을 그대로 벡터 검색에 넣으면, 관련성 높은 문서를 놓치거나 엉뚱한 결과를 가져오게 된다.
Query Enhancement(쿼리 강화) 는 사용자의 원본 질문을 검색에 더 적합한 형태로 변환하여 이 문제를 해결한다. 질문 자체를 바꾸는 것만으로도 검색 결과가 극적으로 달라질 수 있다.
왜 원본 질문 그대로는 부족한가?
벡터 검색은 질문 벡터와 문서 벡터 사이의 의미적 유사도를 기반으로 작동한다. 그런데 사용자의 질문과 실제 문서는 서로 다른 "언어"를 사용하는 경우가 많다.
예를 들어, 사용자가 "LLM이 헛소리하는 거 어떻게 막아?"라고 물었다고 하자. 벡터 저장소에는 "Hallucination 완화를 위한 Grounding 기법"이라는 제목의 문서가 있다. 의미는 같지만, 표현의 간극이 크다. 단순한 벡터 유사도 검색만으로는 이 간극을 메우기 어렵다.
Query Enhancement의 핵심 아이디어는 단순하다. "검색 엔진이 이해하기 쉬운 형태로 질문을 다시 써주자."
이 아이디어를 구현하는 방식은 크게 두 갈래로 나뉜다. 질문 자체를 변환하는 방식(Query Transformation)과, 질문 대신 가상 문서를 생성하여 검색하는 방식(HyDE, HyPE)이다.
Query Transformation: 질문을 다듬고 확장하기
Query Transformation(쿼리 변환) 은 원본 질문을 여러 변형된 형태로 확장하여, 단일 질문만으로는 놓칠 수 있는 관련 문서를 찾아내는 기법이다. 사용자가 다소 모호하게 질문하더라도 시스템이 의도를 파악하여 관련성 높은 문서를 더 폭넓게 검색할 수 있다.
대표적인 세 가지 전략을 살펴보자.
쿼리 재작성 (Query Rewriting)
가장 직관적인 방법이다. 모호하거나 불완전한 질문을 LLM이 더 구체적이고 명확한 형태로 다시 작성한다.
예를 들어 다음과 같은 변환이 일어난다.
| 원본 질문 | 재작성된 질문 |
|---|---|
| "RAG 성능 올리려면?" | "RAG 파이프라인의 검색 정확도를 향상시키는 기법에는 어떤 것이 있는가?" |
| "트랜스포머가 뭐야?" | "Transformer 아키텍처의 핵심 구조와 작동 원리는 무엇인가?" |
모호한 표현이 제거되고, 검색 키워드가 풍부해지면서 벡터 검색의 적중률이 올라간다. 대화형 RAG에서 특히 유용한데, 이전 대화 맥락을 반영하여 "그거"나 "아까 그것" 같은 지시어를 구체적인 용어로 치환할 수 있기 때문이다.
스텝백 프롬프팅 (Step-back Prompting)
Step-back Prompting은 세부적인 질문을 한 단계 일반화(추상화) 하여 더 넓은 배경 지식을 먼저 확보하는 전략이다.
구체적인 질문에 바로 답하려 하면 관련 문서를 놓칠 수 있다. 한 발 물러서서 상위 개념을 먼저 검색하면, 구체적인 답변에 필요한 맥락까지 함께 가져올 수 있다.
| 원본 질문 | Step-back 질문 |
|---|---|
| "GPT-4의 컨텍스트 윈도우는 몇 토큰인가?" | "대규모 언어 모델의 컨텍스트 윈도우란 무엇이며, 모델별로 어떻게 다른가?" |
| "FAISS에서 IVF 인덱스를 쓰면 왜 빨라지나?" | "벡터 데이터베이스의 근사 최근접 이웃 검색(ANN) 알고리즘에는 어떤 종류가 있는가?" |
세부 질문의 답이 상위 개념을 설명하는 문서 안에 포함되어 있는 경우가 많기 때문에, 이 전략이 효과적이다. 좁은 범위의 검색으로는 찾지 못했을 배경 정보를 확보할 수 있다.
하위 쿼리 분해 (Sub-query Decomposition)
복잡한 질문은 하나의 검색으로 답하기 어렵다. Sub-query Decomposition은 복잡한 질문을 여러 개의 단순한 하위 질문으로 분해하여, 각 측면을 빠짐없이 검색하는 전략이다.
예를 들어, "RAG와 파인튜닝의 차이점은 무엇이고, 각각 언제 사용하는 것이 적합한가?"라는 질문은 다음과 같이 분해할 수 있다.
- "RAG의 정의와 작동 방식은?"
- "파인튜닝의 정의와 작동 방식은?"
- "RAG와 파인튜닝의 비용 및 성능 비교는?"
- "RAG가 적합한 사용 사례는?"
- "파인튜닝이 적합한 사용 사례는?"
각 하위 질문으로 독립적으로 검색을 수행한 뒤, 검색된 문서들을 종합하여 최종 답변을 생성한다. 복합적인 질문에서 특정 측면이 누락되는 것을 방지할 수 있다.
HyDE: 가상의 답변으로 검색하기
지금까지 살펴본 기법들은 모두 질문을 변형하는 방식이었다. 여기서 발상을 완전히 뒤집는 기법이 등장한다.
HyDE(Hypothetical Document Embedding) 는 질문을 변형하는 대신, 질문에 대한 가상의 답변 문서를 먼저 생성하고, 그 문서의 임베딩으로 검색하는 기법이다.
HyDE의 핵심 가정: "질문과 문서"보다 "답변과 문서" 가 벡터 공간에서 더 가깝다.
작동 원리
일반적인 RAG에서는 "질문 벡터 ~ 문서 벡터"의 유사도를 비교한다. 하지만 질문과 문서는 형태가 다르다. 질문은 의문문이고, 문서는 서술문이다. 이 형태적 차이가 벡터 공간에서의 거리를 벌려놓는다.
HyDE는 이 문제를 다음과 같이 해결한다.
- 사용자가 질문을 입력한다.
- LLM이 이 질문에 대한 가상의 완벽한 답변(Hypothetical Document) 을 생성한다. 이 답변은 실제 사실에 기반하지 않아도 된다.
- 생성된 가상 답변을 벡터로 변환한다.
- 이 벡터로 벡터 DB에서 실제 문서를 검색한다.
가상 답변은 서술문이기 때문에 벡터 저장소에 있는 실제 문서와 형태가 유사하다. 같은 서술문끼리 비교하므로 의미적 매칭이 훨씬 정확해진다.
예시
사용자 질문이 "Transformer에서 Positional Encoding은 왜 필요한가?"라고 하자.
LLM이 생성하는 가상 답변은 대략 이런 형태다.
"Transformer는 순환 구조가 없기 때문에 단어의 순서 정보를 자체적으로 파악할 수 없다.
Positional Encoding은 각 단어의 위치 정보를 임베딩에 더하여 모델이 순서를
인식하도록 돕는다. 사인과 코사인 함수를 사용한 고정 위치 인코딩이 대표적이다."
이 가상 답변은 실제 사실 여부와 무관하게, "Positional Encoding을 설명하는 문서"와 형태적으로 매우 유사하다. 원래 의문문 형태의 질문보다 실제 문서에 훨씬 가까운 벡터를 만들어내는 것이다.
장점과 한계
장점은 명확하다. 복잡하고 추상적인 질문에 대해 검색의 방향성을 잡아주어 검색 정확도를 크게 향상시킨다. 특히 질문과 문서의 어휘 간극이 큰 경우에 효과적이다.
한계도 있다. LLM이 가상 답변을 생성하는 추가 호출이 필요하므로 응답 지연(Latency)이 증가한다. 또한 LLM이 질문의 의도를 잘못 파악하여 엉뚱한 가상 답변을 생성하면, 검색 방향 자체가 틀어질 수 있다.
HyPE: 질문으로 질문을 찾는다
HyPE(Hypothetical Prompt Embedding) 는 HyDE와 유사한 철학을 공유하지만, 접근 방향이 정반대다. HyDE가 검색 시점에 가상 답변을 생성한다면, HyPE는 인덱싱 시점에 가상 질문을 미리 생성해둔다.
HyPE의 핵심 아이디어: 문서를 저장할 때, "이 문서에 대해 사용자가 물어볼 법한 질문"을 미리 만들어두자.
작동 원리
HyPE의 과정은 다음과 같다.
- 인덱싱 단계: 각 문서 청크에 대해 LLM이 "이 문서를 찾기 위해 사용자가 던질 법한 질문" 여러 개를 생성한다.
- 벡터 저장: 원본 문서 대신(또는 함께), 이 가상 질문들의 벡터를 벡터 DB에 저장한다. 각 가상 질문 벡터는 원본 문서 청크와 매핑되어 있다.
- 검색 단계: 사용자가 실제 질문을 입력하면, 이 질문 벡터와 가장 유사한 가상 질문 벡터를 찾는다. 즉, 질문과 질문을 비교한다.
- 문서 반환: 가장 유사한 가상 질문을 찾았다면, 그 질문과 연결된 원본 문서 청크를 최종적으로 가져와 답변 생성에 사용한다.
핵심은 벡터 공간에서의 비교 대상이 달라진다는 점이다. 일반 RAG가 "질문 vs 문서"를 비교하고, HyDE가 "가상 답변 vs 문서"를 비교한다면, HyPE는 "질문 vs 질문" 을 비교한다. 질문끼리 비교하므로 형태적 불일치 문제가 원천적으로 사라진다.
장점
HyPE의 장점은 세 가지로 요약된다.
- 쿼리 시간 단축: LLM 호출이 인덱싱 단계에서 미리 이루어지므로, 실제 검색 시에는 순수한 벡터 유사도 비교만 수행한다. HyDE처럼 검색할 때마다 LLM을 호출할 필요가 없어 응답 속도가 빠르다.
- 검색 정확도 향상: 질문과 질문을 비교하므로, 형태적으로 동일한 유형의 텍스트 간 유사도 계산이 이루어져 매칭 정확도가 높아진다.
- 다각적 검색: 하나의 문서 청크에 대해 여러 개의 가상 질문(Multi-Vector)이 생성되므로, 사용자가 어떤 방식으로 질문하더라도 해당 문서 청크를 찾아낼 확률이 높아진다. "Positional Encoding이란?", "Transformer가 순서를 어떻게 아는가?", "위치 인코딩의 역할은?" 등 다양한 표현이 모두 같은 문서를 가리키게 된다.
한계
인덱싱 시 모든 청크에 대해 LLM을 호출해야 하므로 초기 인덱싱 비용이 크다. 문서가 자주 업데이트되는 환경에서는 가상 질문도 재생성해야 하므로 유지 비용이 발생한다. 또한, LLM이 예측하지 못한 질문 패턴에는 여전히 취약할 수 있다.
HyDE vs HyPE: 어떤 것을 선택할까?
두 기법은 같은 문제(질문-문서 간 형태 불일치)를 해결하지만, 비용을 언제 지불하느냐가 다르다.
| HyDE | HyPE | |
|---|---|---|
| LLM 호출 시점 | 검색 시 (매 질문마다) | 인덱싱 시 (사전 준비) |
| 검색 시 비교 대상 | 가상 답변 vs 실제 문서 | 실제 질문 vs 가상 질문 |
| 검색 지연(Latency) | 높음 (LLM 호출 포함) | 낮음 (벡터 비교만) |
| 인덱싱 비용 | 낮음 | 높음 (모든 청크에 대해 질문 생성) |
| 문서 업데이트 대응 | 유연함 | 재인덱싱 필요 |
| 적합한 상황 | 문서가 자주 바뀌는 환경 | 문서가 안정적이고 응답 속도가 중요한 환경 |
실시간 응답이 중요하고 문서 변경이 적은 서비스라면 HyPE가 유리하다. 반대로 문서가 자주 갱신되거나 인덱싱 비용을 줄이고 싶다면 HyDE가 더 적합하다. 물론 두 기법을 다른 최적화 전략(Query Rewriting, Reranking 등)과 조합하여 사용할 수도 있다.
정리
RAG의 검색 품질을 높이는 가장 직접적인 방법은 질문을 더 좋은 형태로 바꾸는 것이다. 이 글에서 다룬 기법들을 요약하면 다음과 같다.
- Query Rewriting: 모호한 질문을 구체적이고 명확하게 재작성하여 검색 적중률을 높인다.
- Step-back Prompting: 세부 질문을 일반화하여 넓은 배경 지식을 먼저 확보한다.
- Sub-query Decomposition: 복잡한 질문을 단순한 하위 질문들로 분해하여 빠짐없이 검색한다.
- HyDE: 질문에 대한 가상 답변을 생성하고, 그 임베딩으로 문서를 검색한다. "답변 vs 문서" 비교로 형태 불일치를 해소한다.
- HyPE: 인덱싱 시 각 문서에 대한 가상 질문을 미리 생성하여, "질문 vs 질문" 비교로 검색한다. 검색 시 LLM 호출이 불필요하여 빠르다.
이 기법들은 서로 배타적이지 않다. Query Rewriting으로 질문을 다듬은 뒤, HyDE로 검색하는 식의 조합도 가능하다. 중요한 것은 각 기법의 비용-성능 트레이드오프를 이해하고, 자신의 시스템 요구사항에 맞는 전략을 선택하는 것이다.