본문 바로가기
AIML/RAG

[RAG] RAG 구조

by 기록 주인 2024. 11. 19.

llm이란?

: 많은 양의 학습데이터를 통해 학습이 된 머신

 

 

[llm의 문제점]

1. 내용을 뒷받침할 만한 출처가 없음. 그냥 떠오르는 답을 말한 것. 언제 어디서 누구에 의해 배웠는지로 돌아갈 출처가 업성 halluciation 문제가 생길 가능성이 높음

2. 특점 시점까지 학습이 완료된 모델을 사람들이 사용하기 떄문에, 최근에 업데이트된 내용에 대해서 모름. 

 

[Rag : retrieval- augmented generation]

-> 검색 증강 생성

-> llm에만 답변을 의존하는 것이 아닌, rag에 의해 추가된 지식 콘텐츠 저장소(인터넷, pdf자료)에서 가져옴. 


[RAG =  rietrival -> fusion -> generation]

1. Retrieval (정보 검색 단계)

 

  • 사용자의 질의(Query)를 받아 관련 문서나 정보를 외부 데이터베이스에서 검색.
  • 검색된 문서(Context)를 추출하고, 이를 생성 모델의 입력으로 전달.

- Retrieval 단계에서 사용자의 질의(Query)에 따라 검색된 관련 데이터나 문서를 가져오며, 이 데이터가 바로 **문맥(Context)**으로 활용된다.

- Retrieval로 검색된 문서 500단어에서, 일부 100단어를 선택하여 생성모델에게 전달 할 수 있다. 대부분의 llm 생성모델은 token limit을 가진다.(예, gpt3 4096 tokens **토큰한계는 입력토큰과 출력토큰을 합친값) 여기서 context가 너무 길면, 모델이 처리하지 못하여 중요한 정보를 잃을 수 있다.

- 토크나이저는 llm마다 다르며, 챗지피티는 subword tokenization을 사용한다. 단어보다 더 작은 단위로 쪼개어 의미를 해석한다. 이는 희소 단어와 같이 llm이 학습하지 않았을수도 있는 단어들에 대해서도 잘 분석하게끔 해준다.

 

1. 토크나이저 성능 분석

(1) 토크나이저 성능 비교 출처

 

(2) 한국어 토크나이저 성능 비교 출처

 

case1: Morphological Analyzer (형태소 분석기) -> Komoran

 

  • 언어 규칙 기반 분석:
    • 주로 한국어, 일본어와 같은 형태소 기반 언어에서 사용됨.
    • 언어의 문법 규칙(예: 어미, 접사 등)을 활용하여 단어를 분리.
  • 의미를 가지는 단위로 분리:
    • 단어를 구성하는 어근, 접두사, 접미사, 조사 등을 분리.
    • 예: "먹었습니다" → ["먹/VV", "었/EP", "습니다/EF"]
  • 품사 태깅:
    • 각 형태소에 품사 정보를 태그로 추가.
    • 품사를 통해 단어의 문법적 역할을 이해 가능.

-> komoran github

 

GitHub - shineware/KOMORAN: Korean Morphological Analyzer by shineware

Korean Morphological Analyzer by shineware. Contribute to shineware/KOMORAN development by creating an account on GitHub.

github.com

-> komoran blog 

 

✨komoran 사용해보기✨(코드분석🙆‍♂️)

komoran을 간단하게 사용해보자! 최대한 코드 한줄 한줄 분석해보았다. 코모란을 전체적으로 이해하는 데 도움이 될 것이다.

velog.io

 

 

 

case2: Subword Tokenizer -> KoELECTRA

 

  • 빈도 기반 분리:
    • 단어를 완전히 분리하지 않고, 자주 등장하는 하위 단어(부분 단어)를 통계적으로 결합.
    • 드문 단어는 여러 Subword로 분리.
  • 언어 규칙을 따르지 않음:
    • 형태소 분석처럼 언어학적 규칙을 사용하지 않음.
    • 단순히 문자 단위에서 빈도와 패턴에 따라 나눔.
  • 모델 학습에 특화:
    • 어휘(vocabulary) 크기를 줄이고, 모든 단어를 학습하지 않아도 처리 가능.

 

-> KoELECTRA tokenizer github

 

GitHub - monologg/KoELECTRA: Pretrained ELECTRA Model for Korean

Pretrained ELECTRA Model for Korean. Contribute to monologg/KoELECTRA development by creating an account on GitHub.

github.com

-> KoELECTRA tokenizer 설

 

[NLP] KoELECTRA/KcELECTRA : 한국어 ELECATRA 모델

KoElectra와 KcElectra는 ELECTRA의 한국어버전 language model 이다.ELECTRA에 대한 설명은 친절하고 아주 똑똑한 사람들이 정리한 ELECTRA 논문을 바탕으로 전 velog에 정리한 바 있다.ELECTRA는 간단히 말하면 기

velog.io

 

 

2. 토큰 제한에 관하여

(1) 입력(prompt)이 4096 tokens 이하인 경우

  • 입력 텍스트는 전부 토크나이저로 처리되며 모델에 전달.
  • 그러나 입력 길이가 길어질수록 출력 가능한 토큰 수는 줄어듭니다.
    • 예: 입력이 3500 토큰일 경우, 출력은 최대 596 토큰까지 생성 가능.

(2) 입력(prompt)이 4096 tokens를 초과하는 경우

  • 모델은 입력을 토크나이저 단계에서 처리하지 못하고 에러를 반환.
  • 입력 자체가 초과되면 잘리는 것이 아니라, 전체 입력이 모델에 전달되지 못함.

3. ChatGPT의 입력 처리 

  • OpenAI의 ChatGPT는 사용자 입력을 잘라서 자동으로 처리하지 않습니다.
  • 대신, 전체 입력(prompt)이 모델의 토큰 제한에 적합하지 않을 경우 에러를 반환.
  • 따라서 입력 텍스트가 제한을 초과하지 않도록 미리 전처리하거나 토큰 수를 계산해야 합니다.

4. 긴 입력에 대한 처리방법

(1) 입력 슬라이싱 (Manual Truncation)

긴 텍스트를 슬라이딩 윈도우 방식으로 나누어 처리.

**슬라이딩 윈도우: 지정된 고정 크기의 범위(윈도우)**로 텍스트를 나누고, 필요에 따라 다음 범위로 이동하며 데이터를 처리하는 방식

 

  • 긴 데이터를 **중첩(overlap)**을 포함한 작은 **연속적인 조각(chunks)**으로 나누는 기법입니다.
  • 각 조각은 연결된 문맥을 유지하며, 길이를 설정한 윈도우로 잘라냅니다.
  • 중복 처리로 인해 성능(시간 및 비용)이 비효율적일 수 있음.
  • 질문-응답(QA) 시스템: 긴 문서를 나누어 문맥을 유지하면서 질문에 답변.
  • 긴 문서 요약: 중첩된 텍스트 조각을 처리해 문맥을 유지한 요약 생성.

 

(2) Batch 처리

긴 입력을 여러 번 호출하여 나눠 처리하고, 결과를 병합.

 

  • 데이터를 **독립된 비연속적 덩어리(batch)**로 나누어 병렬 처리하는 방식입니다.
  • 각 배치(batch)는 다른 배치와 독립적으로 처리됩니다.

 

(3) 요약 모델 사용


2. Fusion (정보 융합 단계)

  • retrieval에서 가져온 컨텍스트와 사용자의 질의를 통합하여 생성 모델의 입력 형태로 구성.
  • 이 단계에서는 다음 작업이 수행된다:
    • 검색된 문서를 필터링하거나 랭킹을 조정.
    • 다수의 문서를 연결하여 최적의 컨텍스트를 생성.
    • 질의와 문맥(Context)을 함께 토큰화하여 언어 모델 입력으로 변환
def fuse_query_and_context(query: str, contexts: List[str], top_k: int = 3) -> str:
    """
    질의(Query)와 검색된 문맥(Contexts)을 결합하여 생성 모델 입력을 생성.
    - 가장 관련성 높은 Top-K 문맥만 포함.
    
    Args:
    - query (str): 사용자 질의.
    - contexts (List[str]): 검색된 문맥 리스트.
    - top_k (int): 통합할 상위 문맥 개수.

    Returns:
    - fused_input (str): 질의와 통합된 문맥 문자열.
    """
    # Step 1: 상위 K개의 문맥 선택
    selected_contexts = contexts[:top_k]
    
    # Step 2: 질의와 문맥을 통합
    fused_input = f"[Query]: {query}\n[Context]: " + " ".join(selected_contexts)
    
    return fused_input

# 예제 데이터
query = "What is the capital of France?"
contexts = [
    "Paris is the capital and most populous city of France.",
    "France is a country in Western Europe known for its culture and history.",
    "Paris is a global center for art, fashion, and culture."
]

 


3. Generation (응답 생성 단계)  through  llm

  • Retrieval 단계에서 가져온 문맥 정보와 사용자 질의를 바탕으로 최종 결과를 생성.
  • 이 단계는 RAG의 핵심이며, 생성 모델이 작동하는 방식은 다음과 같다:
    • Input: [Query + Retrieved Context]
    • Output: 자연어 형태의 답변.
!pip install openai

import openai

# OpenAI API 키 설정
openai.api_key = "your_api_key_here"  # 여기에 API 키를 입력하세요.

# 쿼리(Query)와 컨텍스트(Context) 정의
query = "What is the capital of France?"
context = """
France is a country located in Western Europe. 
Its capital city is Paris, which is known for its art, fashion, and culture.
"""

# 입력을 ChatGPT에 전달하기 위해 쿼리와 컨텍스트 결합
prompt = f"Context: {context}\n\nQuery: {query}\n\nAnswer:"

# ChatGPT API 호출
response = openai.Completion.create(
    engine="text-davinci-003",  # 또는 사용 중인 GPT-4 엔진 설정 ("gpt-4")
    prompt=prompt,
    max_tokens=100,  # 출력 길이 제한
    temperature=0.7  # 응답의 창의성 조정
)

# 결과 출력
print("ChatGPT Response:")
print(response.choices[0].text.strip())

 


4. Post-processing (후처리 단계)

  • 생성된 응답을 사용자가 이해하기 쉽게 정제하는 과정.
  • 주요 작업:
    • 불필요한 내용 제거: Retrieval된 문맥과 관련 없는 생성 내용을 필터링.
    • 형식화: 사용자가 요청한 답변 형식으로 정리.
    • 정보 검증: 생성된 답변이 정확한지 검토 (Optional).
def post_process_text(generated_text, max_length=50):
    """
    Post-processing 작업을 수행하여 생성된 텍스트를 정제.
    - 불필요한 텍스트 제거
    - 형식 정리
    - 요약 (옵션)
    """
    # Step 1: 특수 문자 및 공백 제거
    clean_text = re.sub(r'\s+', ' ', generated_text.strip())  # 여러 공백 제거
    clean_text = re.sub(r'[^\w\s.,!?]', '', clean_text)       # 특수 문자 제거

    # Step 2: 중복 문장 제거
    sentences = list(dict.fromkeys(clean_text.split('. ')))  # 문장 중복 제거
    clean_text = '. '.join(sentences)

    # Step 3: 요약 (긴 답변일 경우만 수행)
    if len(clean_text.split()) > max_length:
        summarized = summarizer(clean_text, max_length=max_length, min_length=10, do_sample=False)
        return summarized[0]['summary_text']

    return clean_text

'AIML > RAG' 카테고리의 다른 글

[RAG] 24.11.23  (0) 2024.11.23