RAG(Retrieval-Augmented Generation)

|

1. What is RAG?

RAG(Retrieval-Augmented Generation)은 LLM 기반 QA시스템에서 LLM의 hallucination 문제를 완화하고 정보를 효율적이고 정확하게 반환하기 위한 방법론이다.
RAG은 Indexing-Retrieval-Generation 단계를 통해 사용자로부터 입력된 질문에 대해 답을 반환한다.

1) Indexing

  • 문서(PDF, docx 등)를 chunk로 분절

        Transformer 계열의 모델은 고정된 입력 길이를 input으로 받는다. 모델의 context window가 커도 문서 전체를 입력으로 넣는 것보다 질문과 의미 유사도가 높은 몇몇 chunk만 입력으로 넣는 것이 정확한 답변을 생성하는 데에 도움이 된다. Chunking 단계에서는 각 chunk들이 의미를 잃지 않는 선에서 일정한 크기로 분절되는 것이 중요하다. 예를 들어 하나의 문장이 chunk size에 걸려 두 부분으로 나뉘어서는 안 된다. 문장이나 단락 단위로 chunk를 나누는 것이 좋다. chunk size는 사용중인 embedding 모델에 따라 결정하는 것이 좋다. Sentence-Transformer의 경우 max token size가 512이고, OpenAI ada-002는 8191이다.

  • 분절된 chunk를 vector로 encode(indexing)

    embedding model 선정도 매우 중요하다. MTEB Leaderboard를 통해 적절한 Embedding Model을 선정할 수 있다.

  • vector DB에 적재

2) Retrieval

  • 입력된 질문과 의미 유사도가 높은 Top k의 chunk를 찾는다.
  • Indexing 단계에서 사용된 embedding model과 동일한 모델을 사용하여 사용자 질문을 encoding해야 한다.

3) Generation

  • 입력된 질문과 retrieved chunk를 LLM에 함께 입력하여 답변을 생성한다.

    아래와 같이 user_message(사용자 질문)과 context(retrieval 결과)를 함께 LLM에 입력하며, context를 참고하여 user_message에 대한 답변을 생성하라는 prompt를 포함시켜 LLM에 입력한다.

     prompt=f"""
     <|im_start|>system
     You are a helpful assistant chatbot. 
     Write a response that appropriately completes the request, referring to given Context.
     When generating responses, it is crucial to adhere to the following conditions.
     - Do not generate new question. You must respond only to the given question.
     - You should never repeat the same sentence.
     - Do not repeat the questions in your response. 
     - You must answer in Korean Language. Do not use any other languages except Korean.
     Here is context to help:
     context: {context}<|im_end|>
     <|im_start|>user
     {user_message}<|im_end|>
     <|im_start|>assistant
     """  
    

2. Naive RAG

    Naive RAG(standard RAG)은 가장 기본적인 RAG이다.

Illustrated by the author


2.1 Naive RAG의 문제점

    Naive RAG의 각 단계마다 문제점들이 존재한다.

1) Query

        사용자의 질문이 명확하지 않은 경우, similarity search 과정에서 오류가 발생할 수 있다.

2) Indexing

        2.1) Parsing: PDF와 같은 비정형 문서 내 이미지 및 표에 담긴 유용한 정보에 대한 추출이 불완전하다.

        2.2) Chunking: 파일 특성을 고려하지 않고 일률적인 크기로 chunking함으로써 의미상 포함되어야 할 정보가 고정된 size 문제로 잘려 각 chunk에 불완전한 정보가 담겨있을 가능성이 있다.

        2.3) Indexing: vector db의 indexing 구조가 파일 유형마다 최적화되어 있지 않아 retreival 과정에 부정적인 영향을 미칠 수 있다.

        2.4) Embedding Model: 임베딩 모델의 semantic representation 성능이 좋지 않을 경우 retreival 과정에 부정적인 영향을 미칠 수 있다.

3) Retrieval

        3.1) 검색된 chunk들과 질문의 관련성이 낮을 가능성이 있다.

        3.2) 여러 검색 알고리즘을 종합적으로 사용할 수 없어 검색 기능이 제한적이다.

        3.3) 검색된 chunk들에 유사한 정보가 중첩되는 경우, LLM이 생성 시 참고할 정보가 제한적이다.

4) Generation

        1) 생성모델 특성 상 동일한 질문에 대해 일관적이지 않은 답변이 생성될 수 있다.

        2) 생성 모델의 성능에 따라 새로운 답변을 생성하지 않고 검색된 chunk에 과도하게 의존하는 경우도 있다. 이 경우 chunk를 그대로 반환하기도 한다.

        3) LLM의 문제점을 완화하기 위해 RAG을 적용했지만 여전히 부정확하거나 관련 없는 답변을 생성할 가능성이 있다.

3. Advanced RAG

    Advanced RAG은 Naive RAG의 문제점을 완화하기 위해 Indexing 과정 혹은 Retrieval 앞뒤에 검색 정확도를 높이기 위한 과정이 추가된 RAG이다. 아래 그림에서 파란색 부분이 이에 해당한다.

Illustrated by the author


3.1 Enhancing Parsing Techniques

Illustrated by the author


    RAG은 문서를 검색한 후 검색된 문서를 기반으로 답변을 반환하는 구조로 작동되기 때문에 비정형 데이터로부터 정보를 정확히 추출하는 것이 중요하다. RAG을 위한 비정형 데이터의 종류는 매우 다양하지만 그 중 PDF parsing이 매우 까다롭다. PDF parsing 방법은 크게 세 가지이다.

    1) Rule-base parsing

        pypdf, pdfplumber와 같은 규칙 기반 parser를 사용하는 방법이다. 이와 같은 라이브러리는 정해진 규칙에 따라 pdf에서 텍스트를 추출하기 때문에 다양한 형식의 PDF를 다루기에는 범용성이 떨어지는 문제가 있다.

    2) deep learning model base parsing

        object detection과 OCR 기술을 결합한 deep learning 모델을 기반으로 PDF에서 정보를 추출하는 방법이다. object detection을 통해 문서의 레이아웃을 식별하거나 표 내부 구조를 파악하여 정보를 보다 정확하게 추출할 수 있다. 하지만 모델을 사용하는 만큼 pasing에 소요되는 시간이 rule-base보다 길다는 것이 단점이다.

    3) multimodal large model base parsing

        multimodal LLM을 사용하여 PDF를 parsing하는 방법이다.

3.2 Pre-Retrieval(Query transformations)

https://finddme.github.io/llm%20/%20multimodal/2024/03/03/rag_query/

Illustrated by the author


    Pre-Retrieval 단계에서는 Retrieval 시 질문과 관련있는 chunk를 더 잘 검색하기 위해 Query를 조작한다.

    1) Query reformulation

        사용자의 의도와 더 가깝게 질문을 재작성하는 방법.

    2) Query expansion

        동의어나 관련 표현들을 통해 질문을 확장함으로써 관련있는 chunk 검색을 돕는 방법

    3) HyDE(Hypothetical Document Embeddings)

        HyDE는 LLM에 사용자의 질문을 입력하여 가상 응답 및 문서를 생성하도록 한 후 생성된 가상 응답/문서와 chunk 사이의 유사도를 통해 검색을 수행하는 방법이다.

    4) Query normalization

        철자 수정, 용어 차이 완화, 특수문자 및 공백 제거 불용어 제거 등 query 정규화 방법

    5) Multi/Sub query transformation

        LLM을 통해 복잡한 query를 여러 개의 단순한 query로 생성하거나, query를 다양한 버전으로 생성하는 방법.

        예를 들어 “John과 Mike 중 이번 중간 평가 평균 점수를 알려줘”

        -> sub query 1) John의 중간 평가 평균 점수를 알려줘.

         sub query 2) Mike의 중간 평가 평균 점수를 알려줘.

        하지만 이 방법은 두 sub query에 대해 검색된 chunk가 상이하여 서로 다른 문서로부터 답을 찾을 가능성이 있다는 문제가 있다.

    6) Rewrite-Retrieve-Read          Query Rewriting for Retrieval-Augmented Large Language Models 논문에서 제안된 방법으로, 사용자의 질문이 LLM 검색에 최적화되지 않은 경우가 많아 LLM을 통해 질문을 재 작성하는 방법을 소개한다.

    7) Step-Back Prompting

        prompting을 통해 LLM이 질문의 핵심을 파악하도록하는 것이다. 질문이 너무 구체적인 경우, LLM은 특정 세부 사항에 꽂혀서 제대로된 답을 하지 못한다. 예를 들어 “2023년 4월부터 2024 5월까지 나온 LLM 관련 논문은 몇 개야?”라는 질문은 너무 세세하게 명시된 기간으로 인해 LLM이 적절한 답을 반환하지 못할 가능성이 높다. 이 예시의 경우, “LLM 관련 논문 수를 연도별로 알려줘”라는 query로 묻는 것이 더 효과적이다.

         Step-Back Prompting은 두 단계를 통해 진행된다.

        1. 추상화 : LLM이 query에 대한 high-level concept 혹은 기본 개념에 관한 광범위한 질문을 만들도록 prompting한다.

        2. 추론 : 추상화된 질문에 대한 답을 추론한다. 이를 abstract reasoning이라고 부른다.

3.3 Query Routing

https://finddme.github.io/llm%20/%20multimodal/2024/03/03/rag_query/

Query를 LLM에 효과적으로 입력하기 위해 Query부터 LLM 입력까지의 경로를 지정하는 것이다. 즉, 입력된 Query에 따라 가장 적합한 분기를 타도록 하는 것이다.

3.4 Enhanced indexing strategy

Illustrated by the author


    1) Hierarchical index retrieval

        검색 데이터(문서)가 많은 경우, 검색 효율을 높이기 위해 문서 요약 index와 문서 chunk index 단계를 만들어 우선 요약을 통해 관련 문서를 filtering한 후 해당하는 문서 chunk 중 질문과 의미 유사도가 높은 chunk들을 뽑는 방법이다.

    2) Hypothetical Questions

        LLM을 통해 각 chunk들에 대한 질문을 생성하여 이와 같은 가상 질문을 embedding하여 chunk와 함께 vector DB에 저장하는 것이다. 이와 같은 방법은 질문과 가상 질문 간의 의미적 유사도가 질문과 chunk 사이의 유사도보다 높기 때문에 검색 품질을 향상시킬 수 있다.

    3) Context enrichment

        Context enrichment는 검색된 chunk에 대해 추가적으로 context를 강화하는 방법이. Context enrichment에는 크게 두 가지 방식이 있다.

        3.1) Sentence Window Retrieval

            chunk를 문장 단위로 만들어 embedding한 후 query와 문장 사이의 유사도를 검색한 후 해당 문장의 전 후 k개 문장으로 context window를 확장하여 LLM에 입력하는 방법.

        3.2) Auto-merging Retriever (Parent Document Retriever)

            우선 작은 size의 chunk를 검색한 후 검색된 상위 k개의 chunk 중 n개 이상의 조각이 동일한 상위 node(larger chunk)와 연결된 경우 해당 node를 LLM이 참고할 context로 입력한다.

3.5 Optimizing Embedding Model

Illustrated by the author


    retrieval 수행 시 가장 관련성 높은 chunk를 추출하는 것이 중요하다. 일반적으로 retrieval은 query와 indexing된 chunk들 간의 벡터 검색을 통해 산출된 의미 유사도를 기반으로 수행된다. 이에 따라 embedding model이 문장 의미 정보를 잘 표현하는 것이 중요하다. Embedding model을 강화하는 방법으로 아래 두 가지가 잘 알려져 있다.

    1) Fine-tuning embedding model

        Embedding model을 domain-specific context에 맞게 fine-tuning하는 방법이다.

    2) Dynamic Embedding

        각 단어에 하나의 벡터만 사용하는 static embedding(정적 임베딩)과 달리 model이 context에 맞게 vector를 embedding하는 방법으로, OpenAI의 embeddings-ada-02가 대표적인 동적 임베딩 모델이다.

3.6 Retrieval

https://finddme.github.io/llm%20/%20multimodal/2024/03/04/similar_search/

    1) Fusion retrieval or hybrid search

        Fusion retrieval 혹은 hybrid search는 Query와 chunk에 대한 의미 유사도, 키워드 매칭을 모두 고려하기 위해 tf-idf 혹은 BM25와 같은 keyword-based old school search와 최근에 많이 사용되는 semantic/vectore search 를 결합하는 방법이다.

        이 방법론에서 중요한 것은 두 검색 결과를 적절히 결합하는 것이다. 검색 결과 결합에는 일반적으로 Reciprocal Rank Fusion algorithm이 사용된다.

3.7 Post-Retrieval

Illustrated by the author


    Post-Retrieval 단계에서는 검색된 문서들을 정제하여 답변 생성 품질을 향상시키기 위한 처리들을 한다.

    1) Re-Ranking

        검색 결과에 대해 유사도 점수 등을 기준으로 chunk를 정렬하여 query와 관련성 높은 문서를 강조하기 위한 처리이다. Re-Ranking model은 query와 context를 input으로 받아 유사도를 측정한다.

    2) Prompt compression

        관련 없는 context는 제거하고 중요한 context는 강조하여 전체 prompt 길이를 줄인다. 이 과정을 통해 LLM을 중요한 정보만 입력 받아 정확한 답변을 생성할 가능성이 높아지고, LLM의 입력이 줄어들어 추론 속도가 감소할 수 있다.

    3) Filtering

        키워드나 metadata를 기반으로 검색된 chunk를 filtering하는 단계로, 관련 없는 문서가 검색되었을 때 해당 문서를 제거하기 위한 과정이다.

    4) Decomposition

        multi-query과 같이 query를 여러 버전으로 생성 혹은 분리한 후 각 qeury들에 대한 관련 문서를 검색하여 LLM을 통해 각각의 답을 생성하여 각 qa set을 최종적으로 LLM에 입력하는 방법이다.

        이 방법론에서 중요한 것은 두 검색 결과를 적절히 결합하는 것이다. 검색 결과 결합에는 일반적으로 Reciprocal Rank Fusion algorithm이 사용된다.

4. Self-RAG

일반적인 RAG은 입력된 모든 query에 대해 vector DB에 저장된 전체 문서와 유사도를 구하여 관련 chunk를 찾아 답을 생성하는 방식으로 작동된다. Self-RAG의 경우, 아래 그림과 같이 익숙한 주제에 대해서는 LLM이 바로 답변하도록 하고, 그렇지 않은 주제에 대해서는 RAG을 수행하는 방식으로 작동된다.

Pinecone(https://www.pinecone.io/learn/advanced-rag-techniques/)


reward 모델을 align하는 것처럼 reflection token을 예측하는 model을 학습시켜 익숙한 주제인지 아닌지 분류한다. 해당 모델의 데이터는 특정 도메인에 대해 fine-tuning된 모델이든 아니면 그냥 사전학습모델이든 frozen LLM 모델이 반환하는 답변과 질문을 openai gpt-4에 입력하여 답변이 질문과 관련있는지, 어느정도 관련이 있는지, 얼마나 supported한지, retreival이 필요해 보이는지 등의 label을 수집한다. 자세한 데이터 수집 방법은 https://github.com/AkariAsai/self-rag/tree/main/data_creation/critic/gpt4_reward 여기에서 확인 가능하다.

위 과정을 통해 수집된 데이터로 reflection token 예측 모델을 학습시켜 RAG에 사용한다.

5. Corrective RAG (CRAG)

CRAG은 일반적인 RAG과 동일하게 입력된 모든 query에 대해 vector DB에 저장된 전체 문서와 유사도를 구하여 관련 chunk를 찾는다. chunk를 찾은 이후 답을 생성하기 전, 검색된 정보가 올바른지, 아닌지 혹은 애매한지 분류하고 분류 유형에 따라 답 생성 방식을 달리한다. Correct, Incorrect, Ambiguout 분류 모델은 T5-large를 학습시킨 모델을 사용한다.

Pinecone(https://www.pinecone.io/learn/advanced-rag-techniques/)


각 분류 결과에 따른 답 생성 방식은 다음과 같다:

1) Correct: 검색된 문서에 query가 요구하는 정보가 포함되어 있기 때문에 해당 문서에 대한 filtering 작업만 거치고 RAG을 수행한다. filtering은 문서를 보다 작은 단위로 자르고 다시 Retrieval evaluate model(T5-large based)로 분류 한 후 0.5보다 낮은 부분은 제거, 나머지는 사용하는 방식으로 수행된다.

2) Incorrect: 검색된 문서에 query가 요구하는 정보가 없기 때문에 Web 검ㅅ개을 통해 관련 문서를 가져온다.

3) Ambiguout: 검색된 문서에 query가 요구하는 정보가 충분하지 않은 경우로, “Incorrect”의 경우와 마찬가지로 추가 정보도 찾고 “Correct”에서 수행한 filtering 작업을 거친 후 RAG을 수행한다.

6. Handling Chat history

Chat Engine에서 이전 대화 내용을 반영하여 답변을 반환한는 것은 중요한 과제이다. LLM이 이전 대화를 참조할 수 있도록 chat history와 현재 query를 적절하게 LLM에 입력하여 사용자가 chatbot이 자신과의 대화를 기억하는 것처럼 보이게 해야 한다. chat history를 다루는 방법은 크게 두 가지가 있다.

6.1. Chat Engine Context

가장 간단하게 chat history를 다루는 방법이다. retrieval 결과+query와 함께 chat history를 LLM에 입력하는 방식이다.

Illustrated by the author


6.2. Chat Engine condense plus context

chat history와 query를 LLM에 입력하여 새로운 query를 생성한 후 RAG을 수행하는 방법이다.

Illustrated by the author


Reference

Retrieval-Augmented Generation for Large Language Models: A Survey

https://medium.com/@vipra_singh/building-llm-applications-advanced-rag-part-10-ec0fe735aeb1#979b

https://pub.towardsai.net/advanced-rag-techniques-an-illustrated-overview-04d193d8fec6

https://ai.plainenglish.io/advanced-rag-part-01-problems-of-naive-rag-7e5f8ebb68d5

https://www.pinecone.io/learn/advanced-rag-techniques/

SELF-RAG: LEARNING TO RETRIEVE, GENERATE, AND CRITIQUE THROUGH SELF-REFLECTION

https://github.com/AkariAsai/self-rag/tree/main