인공지능 모델이 특정 맥락에서 유용하게 사용되기 위해서는 배경 지식에 대한 접근이 필요합니다. 예를 들어, 고객 지원 챗봇은 해당 비즈니스에 대한 지식이 필요하며, 법률 분석 봇은 방대한 과거 사례에 대한 정보를 알아야 합니다.
개발자들은 일반적으로 **RAG(Retrieval-Augmented Generation)**를 사용하여 AI 모델의 지식을 향상시킵니다. RAG는 지식 베이스에서 관련 정보를 검색하여 사용자의 프롬프트에 추가함으로써 모델의 응답을 크게 개선하는 방법입니다. 그러나 전통적인 RAG 솔루션은 정보를 인코딩할 때 맥락을 제거하는 경향이 있어, 시스템이 지식 베이스에서 관련 정보를 검색하지 못하는 경우가 종종 발생합니다.
이 글에서는 RAG의 검색 단계를 획기적으로 개선하는 방법을 소개합니다. 이 방법은 **컨텍스추얼 리트리벌(Contextual Retrieval)**이라고 불리며, 두 가지 하위 기술인 **컨텍스추얼 임베딩(Contextual Embeddings)**과 컨텍스추얼 BM25를 사용합니다. 이 방법은 검색 실패율을 49%까지 감소시키며, 재랭킹과 결합하면 67%까지 감소시킬 수 있습니다. 이는 검색 정확도의 상당한 향상을 나타내며, 이는 다운스트림 작업의 성능 향상으로 직접 연결됩니다.
인공지능 모델이 특정 상황에서 유용하려면 배경 지식에 대한 접근이 필수적입니다. 예를 들어, 고객 지원 챗봇은 해당 기업의 정보를, 법률 분석 봇은 다양한 과거 사례를 알아야 합니다.
개발자들은 일반적으로 **RAG(Retrieval-Augmented Generation)**를 사용하여 AI 모델의 지식을 확장합니다. 이는 지식 베이스에서 관련 정보를 검색하여 프롬프트에 추가함으로써 모델의 응답을 개선하는 방법입니다. 그러나 기존 RAG는 정보를 인코딩할 때 맥락을 제거하여, 필요한 정보를 제대로 검색하지 못하는 문제가 있습니다.
더 긴 프롬프트를 사용하는 것에 대한 주의사항
때로는 가장 간단한 해결책이 최선일 수 있습니다. 지식 베이스가 20만 토큰(약 500페이지 분량)보다 작다면, RAG나 유사한 방법 없이 지식 베이스 전체를 모델에게 제공하는 것으로 충분합니다.
몇 주 전, Claude를 위한 **프롬프트 캐싱(prompt caching)**을 출시하여 이 접근 방식을 더욱 빠르고 비용 효율적으로 만들었습니다. 개발자들은 이제 API 호출 간에 자주 사용되는 프롬프트를 캐싱하여 지연 시간을 2배 이상 줄이고 비용을 최대 90%까지 절감할 수 있습니다. 그러나 지식 베이스가 커질수록 더 확장 가능한 솔루션이 필요합니다. 바로 이때 컨텍스추얼 리트리벌이 필요합니다.
인공지능 모델이 특정 상황에서 유용하려면 배경 지식에 대한 접근이 필수적입니다. 예를 들어, 고객 지원 챗봇은 해당 기업의 정보를, 법률 분석 봇은 다양한 과거 사례를 알아야 합니다.
개발자들은 일반적으로 **RAG(Retrieval-Augmented Generation)**를 사용하여 AI 모델의 지식을 확장합니다. 이는 지식 베이스에서 관련 정보를 검색하여 프롬프트에 추가함으로써 모델의 응답을 개선하는 방법입니다. 그러나 기존 RAG는 정보를 인코딩할 때 맥락을 제거하여, 필요한 정보를 제대로 검색하지 못하는 문제가 있습니다.
RAG 개요: 더 큰 지식 베이스로의 확장
컨텍스트 윈도우에 맞지 않는 큰 지식 베이스의 경우, RAG가 일반적인 해결책입니다. RAG는 다음과 같은 전처리 단계를 거쳐 지식 베이스를 활용합니다:
- 지식 베이스(문서 "코퍼스")를 수백 토큰 이하의 작은 텍스트 청크로 분할합니다.
- 임베딩 모델을 사용하여 이러한 청크를 의미를 인코딩하는 벡터 임베딩으로 변환합니다.
- 이러한 임베딩을 벡터 데이터베이스에 저장하여 의미 유사성을 기반으로 검색할 수 있도록 합니다.
실행 시, 사용자가 모델에 질의를 입력하면, 벡터 데이터베이스를 사용하여 질의와 의미적으로 유사한 관련 청크를 찾습니다. 그런 다음 가장 관련성 높은 청크를 생성 모델에 보내는 프롬프트에 추가합니다.
임베딩 모델은 의미적 관계를 캡처하는 데 뛰어나지만, 중요한 정확한 매치를 놓칠 수 있습니다. 다행히도 이러한 상황에서 도움을 줄 수 있는 오래된 기술이 있습니다. **BM25(Best Matching 25)**는 정확한 단어나 구절 매치를 찾기 위해 어휘 매칭을 사용하는 랭킹 함수입니다. 특히 고유 식별자나 기술 용어를 포함하는 질의에 효과적입니다.
BM25는 TF-IDF(역문헌빈도)를 기반으로 작동합니다. TF-IDF는 단어가 전체 문서 컬렉션에서 얼마나 중요한지를 측정합니다. BM25는 문서 길이를 고려하고 용어 빈도에 포화 함수를 적용하여 일반적인 단어가 결과를 지배하지 않도록 개선합니다.
임베딩 모델이 놓치는 부분에서 BM25가 어떻게 성공할 수 있는지 예를 들어보겠습니다: 사용자가 기술 지원 데이터베이스에서 "오류 코드 TS-999"를 질의한다고 가정해봅시다. 임베딩 모델은 일반적인 오류 코드에 대한 내용을 찾을 수 있지만, 정확한 "TS-999" 매치를 놓칠 수 있습니다. BM25는 이 특정 텍스트 문자열을 찾아 관련 문서를 식별합니다.
RAG 솔루션은 임베딩과 BM25 기술을 결합하여 보다 정확하게 가장 관련성 높은 청크를 검색할 수 있습니다:
- 지식 베이스를 작은 청크로 분할합니다.
- 이러한 청크에 대해 TF-IDF 인코딩과 의미 임베딩을 생성합니다.
- 정확한 매치를 기반으로 BM25를 사용하여 상위 청크를 찾습니다.
- 의미적 유사성을 기반으로 임베딩을 사용하여 상위 청크를 찾습니다.
- (3)과 (4)의 결과를 랭크 퓨전 기법을 사용하여 결합하고 중복을 제거합니다.
- 상위 K개의 청크를 프롬프트에 추가하여 응답을 생성합니다.
BM25와 임베딩 모델을 모두 활용함으로써, 전통적인 RAG 시스템은 정확한 용어 매칭과 광범위한 의미 이해의 균형을 맞춰 더 포괄적이고 정확한 결과를 제공할 수 있습니다.
전통적인 RAG 시스템은 임베딩과 BM25를 사용하여 정보를 검색합니다. TF-IDF는 단어 중요도를 측정하고 BM25의 기반이 됩니다.
이 접근 방식은 단일 프롬프트에 담을 수 있는 것보다 훨씬 더 큰 지식 베이스로 비용 효율적으로 확장할 수 있습니다. 그러나 이러한 전통적인 RAG 시스템에는 맥락을 종종 파괴한다는 중요한 한계가 있습니다.
전통적인 RAG의 맥락 문제
전통적인 RAG에서, 문서는 효율적인 검색을 위해 일반적으로 더 작은 청크로 분할됩니다. 이 접근 방식은 많은 응용 분야에서 잘 작동하지만, 개별 청크에 충분한 맥락이 부족한 경우 문제가 발생할 수 있습니다.
예를 들어, 재무 정보(예: 미국 SEC 제출 문서) 컬렉션이 지식 베이스에 포함되어 있고, 다음과 같은 질문을 받았다고 가정해봅시다: "ACME Corp의 2023년 2분기 매출 성장률은 얼마였나요?"
관련 청크에는 "회사의 매출은 전 분기 대비 3% 성장했다."라는 텍스트가 포함될 수 있습니다. 그러나 이 청크 자체로는 어떤 회사를 지칭하는지 또는 관련 시간 기간을 명시하지 않기 때문에 올바른 정보를 검색하거나 효과적으로 사용할 수 없습니다.
컨텍스추얼 리트리벌 소개
컨텍스추얼 리트리벌은 각 청크에 청크별 설명 맥락을 추가하여 이 문제를 해결합니다. 이는 임베딩하기 전에 각 청크에 해당 청크의 맥락 정보를 앞에 추가하는 방식으로 이루어집니다.
SEC 제출 문서 예시로 돌아가 봅시다. 청크가 어떻게 변환되는지 보겠습니다:
- 원본 청크: "회사의 매출은 전 분기 대비 3% 성장했다."
- 맥락화된 청크: "이 청크는 ACME Corp의 2023년 2분기 실적에 대한 SEC 파일링에서 발췌한 것입니다; 전 분기의 매출은 3억 1,400만 달러였습니다. 회사의 매출은 전 분기 대비 3% 성장했다."
다른 문맥을 활용하여 검색을 개선하기 위한 다른 접근 방식들도 제안된 바 있습니다. 예를 들어, 청크에 일반적인 문서 요약을 추가하거나, 가설적 문서 임베딩, 요약 기반 인덱싱 등이 있습니다. 그러나 실험 결과, 이러한 방법들은 제한된 개선만을 보였습니다.
컨텍스추얼 리트리벌 구현하기
물론 수천 또는 수백만 개의 청크를 수동으로 주석 처리하는 것은 너무 많은 작업입니다. 컨텍스추얼 리트리벌을 구현하기 위해 Claude를 사용합니다. 모델에게 전체 문서의 맥락을 사용하여 청크를 설명하는 간결한 청크별 맥락을 제공하도록 지시하는 프롬프트를 작성했습니다. 다음과 같은 Claude 3 Haiku 프롬프트를 사용하여 각 청크에 대한 맥락을 생성했습니다
<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.
결과로 나온 맥락 텍스트는 보통 50~100 토큰이며, 임베딩하기 전에 청크의 앞에 추가됩니다. BM25 인덱스를 생성할 때도 동일하게 적용됩니다.
실제 전처리 흐름은 다음과 같습니다.
컨텍스추얼 리트리벌은 검색 정확도를 개선하는 전처리 기법입니다.
프롬프트 캐싱을 통한 컨텍스추얼 리트리벌 비용 절감
컨텍스추얼 리트리벌은 Claude의 특별한 프롬프트 캐싱 기능 덕분에 저렴한 비용으로 가능해집니다. 프롬프트 캐싱을 사용하면 각 청크에 대해 참조 문서를 매번 전달할 필요가 없습니다. 문서를 한 번 캐시에 로드하고 이전에 캐시된 콘텐츠를 참조하면 됩니다. 800토큰 청크, 8,000토큰 문서, 50토큰 맥락 지시사항, 청크당 100토큰의 맥락을 가정하면, 청크를 맥락화하는 데 드는 일회성 비용은 백만 문서 토큰당 $1.02입니다.
방법론
다양한 지식 도메인(코드베이스, 소설, ArXiv 논문, 과학 논문), 임베딩 모델, 검색 전략, 평가 메트릭을 통해 실험을 수행했습니다. 각 도메인에 사용한 질문과 답변의 예시는 부록 II에 포함되어 있습니다.
아래 그래프는 모든 지식 도메인에서 최고 성능의 임베딩 구성(Gemini Text 004)을 사용하고 상위 20개 청크를 검색했을 때의 평균 성능을 보여줍니다. 1 - recall@20을 평가 메트릭으로 사용했으며, 이는 관련 문서 중 상위 20개 청크 내에서 검색되지 못한 비율을 측정합니다. 전체 결과는 부록에서 확인할 수 있으며, 컨텍스추얼 리트리벌은 평가한 모든 임베딩 소스 조합에서 성능을 향상시켰습니다.
성능 개선
실험 결과:
- 컨텍스추얼 임베딩은 상위 20개 청크의 검색 실패율을 35% 감소시켰습니다(5.7% → 3.7%).
- 컨텍스추얼 임베딩과 컨텍스추얼 BM25를 결합하면 검색 실패율이 49% 감소했습니다(5.7% → 2.9%).
컨텍스추얼 임베딩과 컨텍스추얼 BM25를 결합하면 상위 20개 청크의 검색 실패율이 49% 감소합니다.
구현 고려사항
컨텍스추얼 리트리벌을 구현할 때 몇 가지 고려해야 할 사항이 있습니다:
- 청크 경계: 문서를 청크로 분할하는 방법을 고려하세요. 청크 크기, 청크 경계, 청크 중첩의 선택이 검색 성능에 영향을 줄 수 있습니다1.
- 임베딩 모델: 컨텍스추얼 리트리벌은 테스트한 모든 임베딩 모델에서 성능을 향상시키지만, 일부 모델은 다른 모델보다 더 큰 이점을 얻을 수 있습니다. Gemini와 Voyage 임베딩이 특히 효과적이라는 것을 발견했습니다.
- 맞춤형 컨텍스추얼라이저 프롬프트: 제공한 일반적인 프롬프트도 잘 작동하지만, 특정 도메인이나 사용 사례에 맞춘 프롬프트로 더 나은 결과를 얻을 수 있습니다(예: 지식 베이스의 다른 문서에만 정의된 주요 용어의 용어집 포함).
- 청크 수: 컨텍스트 윈도우에 더 많은 청크를 추가하면 관련 정보를 포함할 가능성이 높아집니다. 그러나 너무 많은 정보는 모델에 혼란을 줄 수 있으므로 한계가 있습니다. 5개, 10개, 20개의 청크를 전달하여 테스트했으며, 20개를 사용하는 것이 가장 성능이 좋았습니다(비교는 부록에서 확인). 그러나 여러분의 사용 사례에 맞게 실험해보는 것이 좋습니다.
- 항상 평가를 수행하세요: 응답 생성은 컨텍스추얼화된 청크를 전달하고 무엇이 맥락이고 무엇이 청크인지 구분함으로써 개선될 수 있습니다.
재랭킹으로 성능을 더욱 향상시키기
마지막 단계에서, 컨텍스추얼 리트리벌을 다른 기술과 결합하여 더욱 성능 개선을 이끌어낼 수 있습니다. 전통적인 RAG에서는 AI 시스템이 지식 베이스를 검색하여 잠재적으로 관련 있는 정보 청크를 찾아냅니다. 큰 지식 베이스의 경우, 이 초기 검색은 수백 개의 청크를 반환하며, 그 관련성과 중요성은 다양합니다.
**재랭킹(reranking)**은 모델에 전달되는 청크의 수를 줄여 가장 관련성 높은 청크만 전달하기 위한 일반적인 필터링 기술입니다. 재랭킹은 더 나은 응답을 제공하며, 모델이 처리하는 정보가 줄어들기 때문에 비용과 지연 시간을 줄여줍니다. 주요 단계는 다음과 같습니다:
- 초기 검색을 수행하여 잠재적으로 관련성 높은 상위 청크를 얻습니다(상위 150개를 사용했습니다).
- 사용자의 질의와 함께 상위 N개의 청크를 재랭킹 모델에 전달합니다.
- 재랭킹 모델을 사용하여 각 청크에 질의에 대한 관련성과 중요성에 기반한 점수를 부여하고, 상위 K개의 청크를 선택합니다(상위 20개를 사용했습니다).
- 최종적으로 선택된 상위 K개의 청크를 모델에 컨텍스트로 전달하여 최종 결과를 생성합니다.
컨텍스추얼 리트리벌과 재랭킹을 결합하여 검색 정확도를 극대화합니다.
성능 개선
시장에는 여러 재랭킹 모델이 있습니다. Cohere의 재랭커를 사용하여 테스트를 진행했습니다. Voyage도 재랭커를 제공하지만, 테스트할 시간이 없었습니다. 실험 결과, 다양한 도메인에서 재랭킹 단계를 추가하면 검색이 더욱 최적화되었습니다.
구체적으로, 재랭킹된 컨텍스추얼 임베딩과 컨텍스추얼 BM25는 상위 20개 청크의 검색 실패율을 67% 감소시켰습니다(5.7% → 1.9%).
재랭킹된 컨텍스추얼 임베딩과 컨텍스추얼 BM25는 상위 20개 청크의 검색 실패율을 67% 감소시킵니다.
비용 및 지연 시간 고려사항
재랭킹을 사용할 때 중요한 고려사항은 특히 많은 수의 청크를 재랭킹할 때 비용과 지연 시간에 미치는 영향입니다. 재랭킹은 실행 시간에 추가 단계이므로, 청크를 병렬로 점수화하더라도 약간의 지연 시간이 발생합니다. 더 나은 성능을 위해 더 많은 청크를 재랭킹하는 것과 지연 시간과 비용을 줄이기 위해 더 적은 청크를 재랭킹하는 것 사이에는 타협이 있습니다. 여러분의 특정 사용 사례에 맞게 다양한 설정으로 실험하여 적절한 균형을 찾는 것이 좋습니다.
위에서 설명한 모든 기술(임베딩 모델, BM25 사용, 컨텍스추얼 리트리벌 사용, 재랭킹 사용, 검색되는 상위 K개의 결과 수)을 다양한 데이터셋 유형에 걸쳐 조합하여 많은 테스트를 수행했습니다. 발견을 요약하면 다음과 같습니다:
- 임베딩 + BM25는 임베딩만 사용하는 것보다 더 낫습니다.
- Voyage와 Gemini는 테스트한 임베딩 중 가장 우수했습니다.
- 상위 20개 청크를 모델에 전달하는 것이 상위 10개나 5개를 전달하는 것보다 효과적이었습니다.
- 청크에 맥락을 추가하면 검색 정확도가 크게 향상되었습니다.
- 재랭킹은 재랭킹을 사용하지 않는 것보다 낫습니다.
- 이 모든 이점은 누적됩니다: 성능 개선을 극대화하기 위해, 컨텍스추얼 임베딩(Voyage 또는 Gemini)을 컨텍스추얼 BM25와 결합하고, 재랭킹 단계를 추가하며, 프롬프트에 20개의 청크를 추가할 수 있습니다.
참고
'인공지능' 카테고리의 다른 글
GPT Canvas: 창의적 협업을 위한 혁신적 도구 (1) | 2024.10.07 |
---|---|
검색 정확도를 높이는 비결: Reranker의 역할과 도입 효과 (0) | 2024.10.04 |
출처까지 알려주는 혁신적 AI 검색 엔진, Perplexity AI의 모든 것 (0) | 2024.09.30 |
LangGraph로 쉽게 구현하는 RAG 파이프라인: LLM 정확도를 높이는 비결 (0) | 2024.09.27 |
LangChain에서 효율적인 검색을 위한 다중 Retriever전략 (0) | 2024.09.26 |