logo

RAG 구현의 어려움과 해결 방법 - TeddyNote 세미나

2024-03-05Updated 2026-03-094 min read·
#rag
#llm
#langchain
#teddynote
#seminar
#challenges
#optimization

RAG 시스템 구현 시 마주하는 실전 문제와 해결 방안 세미나 정리

Summary

TeddyLee의 RAG 구현 난제와 해결책을 다룬 세미나 내용이다. RAG가 실무에서 어려운 이유(문서 품질, 청크 크기, 검색 정확도, 환각 문제), 최적화 전략(하이브리드 검색, Reranking, 프롬프트 튜닝), 평가 방법론, 그리고 langchain-kr 라이브러리를 활용한 실전 구현 사례를 포함한다.

TeddyLee님의 langchain-kr 깃허브: https://github.com/teddylee777/langchain-kr

목차

  1. 지난 1년간 (2023) 6개 기업의 10여개 프로젝트에서 얻은 RAG 경험담
  2. 마주한 도전들
  3. 실패 사례, 극복 시도
  4. Vector Store, Prompt Engineering, LLM Fine-tuninggi

용어정리

RAG: Retrieval Augmented Generation

RAG 프로세스

자체 정의한 RAG 프로세스 과정

1. 전처리 작업

  1. Load Document: 처리할 문서를 시스템에 불러옵
  2. Chunk(Split): 문서를 더 작고 관리하기 쉬운 조각으로 나눈다(llm은 한번에 읽을 수 있는 단어는 few thousands 이기 때문)
  3. Embedding: 이 조각들을 내용의 본질을 포착하는 숫자 표현으로 변환
  4. Store: 임베딩들을 데이터베이스에 저장

https://i.imgur.com/yUgGrWZ.png

2. 서비스 단계에서 이뤄지는 작업

  • llm 서비스 구동중인 상태에서 이뤄지는 작업
  1. 유저 질문을 받아 Embedding 처리
  2. Retrieve(발췌)
    • 실시간으로 이루어짐
  3. 프롬프트 엔지니어링후 LLM에 전달
  4. output

https://i.imgur.com/6nPNirw.png

문서 전처리

모듈

  1. Document Loader: 문서 로드
    • Langchain에서 150가지 loader 지원
  2. Text Splitter: 분할 전략
    • 10 가지 알고리즘 지원
  3. Embedding: 임베딩
    • Langchain + HuggingFace
  4. Vector Store: Vector DB
    • Semantic Search를 위해 RAG에서는 주로 VectorDB사용
    • LangChain에서 80가지 지원
  5. Retrievers: Vector DB 검색기
    • 50가지 지원

강의 목적: 위 내용을 조합하여 3억개 이상의 조합 발생 → 모든 상황 테스트 불가능 → pipeline 구성시 참고용 경험 공유

Document Loader(PDF)

  • Excel/SCV, PDF을 주로 취급
  • 보안에 유리한 PDF 형식의 문서가 많았음

LangChain의 강점: 통합된 Interface를 제공해 여러 모듈들을 바꿔가며 테스트해보기 용이함

Document Loader 선택시 고려사항

  • 텍스트를 원형 그대로 가져오는지
    • 한글, 특수문자
  • 메타데이터(metadata)의 종류
    • page_content
    • 페이지번호(page)
    • 표, 차트, 문서의 coordinates(좌표), 속성(Title, Table, Image, Text)
  • 속도

속도 vs 다양한 메타데이터 제공여부가 관건이 될것 같다

Retriever

Multi-Query Retriever

  • LLM 사용해 사용자 입력 쿼리 -> 여러 관점에서의 여러 쿼리 생성(Prompt Tuning 프로세스 자동화 효과)

  • 각 쿼리에 대해 관련 문서 집합을 검색하고 모든 쿼리에서 고유한 유니온을 사용하여 잠재적으로 관련성이 높은 문서 집합을 가져옴

  • 키워드 기반 검색 시 의미를 잘 포착하지 못하는 문제를 해결함

    ex) 질문: "Page Rank에 대해 알려줘" Multi-Query Retriever 결과:

    1. Page Rank 알고리즘의 작동 원리는 무엇인가요?
    2. Page Rank를 사용하는 이유와 그 효과에 대해 설명해주세요
    3. 구글의 Page Rank 기술에 대한 상세한 정보를 제공해줄 수 있나요?

Ensemble Retriever

배경

  • Semantic Search의 문제점
    • 유사 의미를 가지는 문서의 검색에서는 유리
    • BUT : 특정 키워드가 반드시 포함되어야 하는 검색시 유사 단어가 포함된 문서가 검색될 수 있음 ex) "비타민A 영양제 추천해줘" -> "비타민C가 풍부한 영양제는 00 영양제", "비타민D가 부족하다면 이 영양제를 추천합니다"

'비타민' 때문에 유사성 발생 -> Semantic Search

위와 같은 경우 키워드 기반 검색을 사용하는 Sparse Retriever이 유리함 -> 여러 Retriever을 ensemble하자

장점:

  • 여러 Retriever을 ensemble하여 사용(Sparse Retriever + Dense Retriever의 ensemble)
  • 서로 다른 알고리즘의 강점 활용 -> 단일 Retriever 대비 성능 향상
  • ensemble하는 retriever간 weight 조절도 가능

Sparse Retriever: BM25Retriever, Dense Retriever: faiss_vectorstore.as_retriver() 사용한 예시

#initialize the bm25 retriever and faiss retriever
bm25_retriever = BM25Retriever from_texts(doc_list)
bm25_retriever.k = 2
 
embedding = OpenAIEmbeddings()
faiss_vectorstore = FAISS.from_texts(doc_list, embedding)
faiss_retriever = faiss_vectorstorem.as_retriver(search_kwargs={"k"::2})
 
# initialize the ensemble retriever
ensemble_retriever = EnsembleRetriever(
									   retrievers = [bm25_retriver, faiss_retriever], weights=[0.5, 0.5]
)
 

Long Context Reorder

  • https://arxiv.org/abs/2307.03172
  • 모델 아키텍처와 관계없이 검색된 문서를 10개 이상 포함시 상당한 성능 저하 발생
  • 긴 context 중간 정보 access해야 하는 경우, 제공된 문서를 무시하는 경향이 발생

https://i.imgur.com/5qHk0B7.png

  • 정렬 방식 : 중요도 기준 내림차순 정렬 -> 매우중요 - 덜 중요 - 중요
  • 중요한 문서 검색 결과를 상위로 재조종하여 중요한 정보를 답변에 포함하도록 유도
# 문서 재정렬:
# 관련성이 낮은 문서는 목록의 가운데에 배치
# 시작/끝에 관련성 높은 요소 배치
reordering = LongContextReorder()
reordered_docs = reordering.transform_documents(docs)
 
  • Multi-Vector Retriever: 여러 VectorStore의 Retriever ensemble
  • ContextualCOmpressor: 긴 길이의 문서 검색 결과 압축
  • LLMChainFilter: 문서의 검색 결과 필터링

Prompt Engineering

  • 양식에 맞춘 출력 형식이 중요한 경우(사업기획서, 보고서)
    • FewShotPromptTemplate 활용
  • LangSmith Hub에 업로드 되어 있는 완성형 Prompt을 Pull하여 사용하기
  • 별도의 .yaml 파일로 프롬프트 version관리

Chain of Density(문서요약 프롬프트)

배경

  • 요약에 포함할 정보의 "적절한" 양을 선택하는 것은 어려운 작업
  • 좋은 요약은 정보의 밀도가 높고, Entity 중심이어야 함

해결 방안

  • Chain of Density 프롬프트를 사용하여 점점 더 밀도가 높은 요약을 요청
  • 이전 Missing Entities를 추가 및 갱신하여 요약할때마다 Denser Summary 출력

방식

  1. Sparse한 요약 생성
  2. 이전의 Sparse 요약에 Missing Entity 발견
  3. Missing Entity를 추가한 Denser Summary 생성
  4. 1~3번을 5회 반복
Comments