Part 1에서 이미지와 PDF를 Vector Store에 저장하는 방법을 배웠다면, 이번에는 저장된 Document를 실제 질문과 비교해서 검색하는 방법을 학습했다.
이번 프로젝트에서 핵심적으로 사용한 것은 다음과 같다.
VectorStoresimilaritySearch()SearchRequesttopKsimilarityThresholdQuestionAnswerAdvisor를 활용한 검색즉, 단순히 데이터를 Vector Store에 저장하는 것에서 끝나는 것이 아니라 사용자의 질문과 의미적으로 가까운 Document를 찾아오는 과정을 구현했다.
이미지 RAG에서는 다음과 같이 VectorStore에서 검색을 수행한다.
SearchRequest request = SearchRequest.builder()
.query(query)
.topK(3)
.similarityThreshold(0.5)
.build();
List<Document> results =
imageVectorStore.similaritySearch(request);
여기서 핵심은 similaritySearch()다.
사용자가 검색어를 입력하면 해당 검색어를 기반으로 Vector Store에서 유사한 Document를 찾아온다.
사용자 검색어
↓
Vector Store 검색
↓
유사도가 높은 Document
↓
List<Document>
이번 프로젝트에서는 단순히 문자열만 전달하는 것이 아니라 SearchRequest를 사용해서 검색 조건을 지정했다.
SearchRequest request = SearchRequest.builder()
.query(query)
.topK(3)
.similarityThreshold(0.5)
.build();
각 옵션의 의미는 다음과 같다.
| 설정 | 의미 |
|---|---|
query() | 검색할 질문 또는 검색어 |
topK(3) | 최대 3개의 검색 결과를 가져옴 |
similarityThreshold(0.5) | 유사도가 0.5 이상인 결과만 사용 |
따라서 이 코드는
검색어와 유사도가 충분히 높은 Document 중 최대 3개를 가져온다.
라고 이해할 수 있다.
topK()는 검색 결과의 최대 개수를 결정한다.
이번 프로젝트의 이미지 검색에서는 다음과 같이 설정되어 있다.
.topK(3)
따라서 검색 결과가 아무리 많더라도 최대 3개의 Document만 가져온다.
검색 결과
├─ Document 1
├─ Document 2
├─ Document 3
├─ Document 4
└─ Document 5
↓ topK(3)
최종 결과
├─ Document 1
├─ Document 2
└─ Document 3
여기서 중요한 것은 topK가 반드시 3개를 반환한다는 의미는 아니라는 것이다.
similarityThreshold 조건까지 적용되기 때문에 조건을 만족하는 Document가 2개라면 2개만 반환될 수 있다.
다음 설정은 검색 결과의 최소 유사도 기준이다.
.similarityThreshold(0.5)
검색된 Document의 유사도가 너무 낮다면 결과에서 제외한다.
개념적으로 보면 다음과 같다.
검색 결과
Document A → 0.91
Document B → 0.76
Document C → 0.61
Document D → 0.42
Document E → 0.31
similarityThreshold = 0.5
↓
Document A → 포함
Document B → 포함
Document C → 포함
Document D → 제외
Document E → 제외
따라서 topK와 similarityThreshold는 서로 다른 역할을 한다.
similarityThreshold
→ "얼마나 비슷해야 검색 결과로 인정할 것인가?"
topK
→ "인정된 결과를 최대 몇 개 가져올 것인가?"
이미지 RAG에서는 검색된 Document를 그대로 사용하는 것이 아니라 ImageRagSearchResult로 표현한다.
실제 DTO는 다음과 같다.
public record ImageRagSearchResult(
String caption,
String publicUrl
) {
}
여기에는 두 가지 정보가 들어간다.
caption: 이미지에 대해 생성된 설명publicUrl: Supabase Storage에 저장된 이미지 URL즉, 이미지 검색 결과는 단순히 "비슷한 벡터가 발견됐다"에서 끝나는 것이 아니라 검색된 이미지의 설명과 실제 이미지를 확인할 수 있는 정보로 구성된다.
PDF RAG에서는 검색 결과를 직접 다루는 방식 외에 QuestionAnswerAdvisor를 이용해서 RAG 검색과 답변 생성을 연결한다.
업로드된 PDF의 Chunk가 Vector Store에 저장되어 있기 때문에 사용자의 질문이 들어오면 관련 Document를 검색하고 이를 질문에 활용할 수 있다.
PDF RAG에서 사용하는 검색 조건 역시 다음과 같이 SearchRequest를 기반으로 구성되어 있다.
SearchRequest.builder()
.topK(3)
.similarityThreshold(0.5)
.build()
여기서 중요한 점은 검색 결과를 LLM에게 그냥 전부 전달하는 것이 아니라 검색 조건을 통해 관련성이 높은 Document를 선별한다는 것이다.
이번 프로젝트에서 Vector Search를 구현하면서 가장 중요하게 이해한 것은 다음 두 가지다.
.topK(3)
얼마나 많은 Document를 가져올지 결정한다.
.similarityThreshold(0.5)
어느 정도 이상 유사한 Document만 검색 결과로 사용할지 결정한다.
둘을 함께 사용하면 다음과 같은 형태가 된다.
검색어
│
▼
Vector Search
│
┌────────┴────────┐
│ │
유사도 기준 확인 결과 개수 제한
│ │
threshold = 0.5 topK = 3
│ │
└────────┬────────┘
▼
검색 결과
이번 프로젝트에서는 이미지와 PDF가 모두 Vector Search를 사용하지만, 검색 결과를 활용하는 방식에는 차이가 있다.
| 구분 | Image RAG | PDF RAG |
|---|---|---|
| 저장 대상 | 이미지 설명 caption | PDF에서 추출한 Chunk |
| 검색 | imageVectorStore.similaritySearch() | QuestionAnswerAdvisor와 Vector Store |
| 검색 조건 | SearchRequest | SearchRequest |
topK | 3 | 3 |
similarityThreshold | 0.5 | 0.5 |
| 검색 결과 활용 | caption, publicUrl | 질문에 필요한 문서 Context |
즉, 검색 자체의 핵심 원리는 동일하고 검색된 Document를 어떻게 활용하는지가 다르다.
Vector Search는 단순히
similaritySearch(query)
한 줄로 끝나는 기능처럼 보이지만 실제로는 검색 결과를 어떻게 제한할 것인지 결정하는 것이 중요하다.
이번 프로젝트에서는
SearchRequest.builder()
.query(query)
.topK(3)
.similarityThreshold(0.5)
.build();
처럼 검색 조건을 명시적으로 구성했다.
이를 통해
검색어
↓
유사도 비교
↓
threshold 기준으로 필터링
↓
topK만큼 결과 선택
↓
RAG에서 활용
이라는 검색 과정을 이해할 수 있었다.
이번 Part 2에서 가장 중요하게 배운 것은 Vector Store에 문서를 저장하는 것과 저장된 문서를 검색해서 활용하는 것은 별도의 과정이라는 점이다.
Part 1에서는
이미지 → Document → Vector Store
PDF → Document → Chunk → Vector Store
처럼 데이터를 적재하는 과정을 다뤘다면,
Part 2에서는
질문
↓
SearchRequest
↓
Vector Search
↓
관련 Document 검색
↓
RAG에서 활용
하는 과정을 다룬다.
특히 SearchRequest를 이용해
.topK(3)
.similarityThreshold(0.5)
와 같이 검색 범위를 조절할 수 있다는 점이 중요했다.
이번 프로젝트를 통해 RAG는 단순히 AI에게 질문을 전달하는 방식이 아니라, 질문과 관련된 데이터를 먼저 검색하고 그 결과를 AI가 활용하도록 만드는 구조라는 것을 코드로 이해할 수 있었다.
특히 이미지 RAG에서는 검색된 Document에서 caption과 publicUrl을 활용하고, PDF RAG에서는 검색된 문서를 질문에 활용한다는 차이를 확인하면서 같은 Vector Search를 서로 다른 형태의 데이터에 적용할 수 있다는 점을 배웠다.
또한 topK와 similarityThreshold를 직접 설정하면서 RAG에서 무엇을 검색할 것인지뿐만 아니라 검색 결과를 어디까지 허용할 것인지도 중요하다는 것을 알게 되었다.