프로그래밍/AI,ML

반쪽짜리 Contextual Retrieval로 RAG 강화 해보기

Lou Park 2025. 3. 26. 18:40

2024년 9월 20일, Anthropic은 Contextual Retrieval이라는 개념을 제시했다. Contextual Retrieval은 기존의 RAG의 검색 성공률을 향상시키기 위한 방법으로, Contextual Embeddings와 Contextual BM25의 두가지 하위 기술을 사용한다. Anthropic에 따르면 이 방법을 이용할 경우 실패한 검색 수를 49%까지 줄일 수 있으며, ReRanking과 함께 사용하면 67%까지 줄일 수 있다고한다.

 

최근에는 RAG에 이어 CAG(Cache-Augmented Generation)도 등장했다. CAG는 더 길어진 LLM의 Context Window를 충분히 활용하여, 검색 증강하려는 문서의 전체 내용이 Context Window에 들어갈 수 있는 정도의 사이즈인 경우 모든 문서를 Prompt에 올려버리는 방법이다. Retrieval이라는 단계가 필요없기 때문에 빠르고, 요즘에는 대부분 Prompt Caching을 지원하고 있기 때문에 비용에 대한 압박도 많이 줄었다. 그럼에도 불구하고 훨씬 더 많은 문서가 있는 경우에는 여전히 RAG를 사용해야하는 것이 일반적이다.

 

RAG에서는 긴 문서를 적당한 길이의 청크로 쪼개서 Embed한다. 그리고 문제는 여기에서 발생한다. 해당 청크가 전체 문서의 문맥을 모르기 때문에 올바른 정보를 가져오기 힘들다. 내가 Contextual Retrieval을 추가해보고자 했던 구체적인 케이스는 바로 “회의록”이다. 3월 6일에 유튜브 광고 마케팅에 대한 회의를 한 회의록이 있다고하자. 문서의 메타데이터로만 회의 날짜가 관리되기 때문에 “3월 6일 회의에 대해 찾아줘”라고 했을때 이 회의록을 찾을 수 없었다. 가령 회의록 서두에 “3월 6일 회의”라고 적혀있다고 하더라도 여러 청크로 쪼개지다보니 이 내용이 3월 6일 회의록의 일부라는 사실을 알기 어렵다. 결국에 이 문서는 “유튜브 광고 마케팅”으로만 검색할 수 있는 것이다.

 

original_chunk = "유튜브 광고 마케팅 캠페인 4월 26일~"

contextualized_chunk = "이 청크는 3월 26일 회의에서 발췌한 것입니다. 유튜브 광고 마케팅 캠페인 4월 26일~"

Contextual Retrieval을 사용한다면 이렇게 된다. 해당 청크에 대한 간단한 문맥을 제공하는 것이다.

 

<document> 
{{WHOLE_DOCUMENT}} 
</document> 
Here is the chunk we want to situate within the whole document 
<chunk> 
{{CHUNK_CONTENT}} 
</chunk> 
Please give a short succinct context to situate this chunk within the overall document for the purposes of improving search retrieval of the chunk. Answer only with the succinct context and nothing else.

Anthropic에서 Contextual Retrieval을 위해 사용한 프롬프트는 위 내용과 같으며, Claude-3.5-Haiku 모델을 사용했다고 한다. 

이게 전체적인 Contextual Retrieval 처리의 과정이고, 나는 여기서 Contextual Embedding만 우선적으로 적용해 보았다. Contextual Embedding은 문서를 청크로 나눈 뒤, 모든 청크에 대해서 이 프롬프트를 수행하면 된다. Batch Processing을 이용하면 많은 문서라도 짧은 시간안에 끝낼 수 있다. (Rate Limit은 고려해야한다)

 

 

Contextual Embedding 적용 전에는 거의 모든 회의록을 찾는 것이 불가능했다. 회의록 내용안에 회의하는 날짜가 기재되어있지는 않았기 때문이다.

 

Google Gemini-2.0-Flash로 Contextual Embedding을 진행했다. 회의록은 노션 문서로 관리되고 있었는데, 문서 전체와 노션 페이지의 프로퍼티를 모두 넣어서 언제 회의인지 파악할 수 있도록 했다. 위 사진은 3월 25일자 진행된 회의록 청크에 붙은 Context 정보다.

 

 

Context Embedding 이후 회의록을 (운이 좋다면…ㅋㅋㅋ) 검색할 수 있게 되었다. “운이 좋다면”이라는 조건이 들어간 이유는 지금 단순히 Similarity Search로만 문서를 가져오기 때문이다. “3월 25일 회의”로 검색해도 3월 14일이 걸린다던가, 3월 얘기가 많이 나오는 2월 회의록이 나온다던가 하는 이슈가 있다.

 

아직 이 문제를 어떻게 해결할지는 모르겠다. BM25를 도입하면 나아질까? 아직 관련한 개념에 대해서 이해못해서 공부를 선행해야하고...각 팀마다 메타 데이터 형식도 달라서 필터링을 넣는 방식을 쓰더라도 고민을 좀 해봐야할 것 같다.