본문 바로가기
Deep Learning

LlamaIndex를 활용한 PDF 기반 RAG 질의응답 시스템 구축

by ssury94 2025. 2. 12.
 
 
 

 

 

LlamaIndex는 문서를 효율적으로 검색하고 AI 모델과 연계하여 질의응답을 수행할 수 있는 강력한 프레임워크입니다.

이번 글에서는 LlamaIndex를 활용하여 PDF 문서에서 정보를 추출하고, 이를 기반으로 RAG(Retrieval-Augmented Generation) 방식의 질의응답 시스템을 구축하는 방법을 설명하겠습니다.

 

 

1. RAG 개념과 동작 방식

대형 언어 모델(LLM, 예: GPT-4, LLaMA-2)은 학습된 데이터만을 기반으로 답변을 생성합니다. 그러나 모델이 최신 정보를 포함하지 않을 경우 잘못된 정보(할루시네이션, Hallucination)가 발생할 수 있습니다.

RAG의 특징:

LLM이 외부 데이터베이스에서 관련 문서를 검색한 후 답변 생성
최신 정보를 반영할 수 있음 (고정된 모델 지식에 의존하지 않음)

문서 기반 사실에 입각한 응답 가능
법률, 의료, 금융 등 정확성이 중요한 분야에서 유용

 RAG의 동작 방식:

검색(Retrieval): 사용자의 질문을 벡터로 변환한 후, FAISS, Pinecone, ChromaDB 같은 벡터 데이터베이스에서 관련 문서를 검색
생성(Generation): 검색된 문서를 LLM에 입력하여, 문서 내용을 참고한 답변 생성

📌 한눈에 보는 RAG 프로세스
예제 질문: "2024년 최저임금은 얼마인가?"
✔ 벡터 검색 수행 → 관련 뉴스 기사, 공공 문서 검색
✔ 검색된 문서 제공 → "2024년 최저임금은 시간당 9,860원입니다."
✔ LLM이 답변 생성 → "2024년 대한민국 최저임금은 9,860원입니다."

 

 

 

2. LlamaIndex와 GPU의 관계

LLM은 복잡한 연산을 수행하기 때문에 일반적으로 GPU를 활용하지만, LlamaIndex는 주로 데이터 검색 및 인덱싱을 수행하므로 GPU 없이도 사용 가능합니다.

GPU가 필요한 경우: LLM이 직접 응답을 생성할 때
GPU가 필요 없는 경우: 문서 검색 및 인덱스 생성 과정 (LlamaIndex 활용)

즉, LlamaIndex를 사용하면 GPU 연산을 최소화하면서도 질의응답 시스템을 구축할 수 있습니다.

 

 

 

3. PDF에서 텍스트 추출하기

먼저, PDF 문서의 텍스트를 추출해야 합니다. 이를 위해 PyPDF2 라이브러리를 사용할 수 있습니다.

from PyPDF2 import PdfReader

def extract_text_from_pdf(pdf_file):
    reader = PdfReader(pdf_file)
    text = ""
    for page in reader.pages:
        text += page.extract_text()  # 각 페이지에서 텍스트 추출
    return text

위 함수는 PDF 파일을 입력받아 모든 페이지의 텍스트를 추출하여 반환합니다.

 

 

 

4. 한국어 지원이 우수한 LLM 설정

LlamaIndex에서 사용할 LLM을 설정합니다. 한국어 성능이 우수한 Mistral-7B 모델을 Hugging Face API를 통해 호출합니다.

from llama_index.llms import HuggingFaceInferenceAPI

llm = HuggingFaceInferenceAPI(
    model_name="mistralai/Mistral-7B-Instruct-v0.2",
    max_new_tokens=512,
    temperature=0,  # 0: 정확한 응답, 1: 창의적인 응답
    system_prompt="당신은 한국어로 대답하는 AI 어시스턴트입니다.",
    token='YOUR_API_KEY'  # 보안상 실제 키는 노출하지 말 것
)

API를 통해 호출하므로 GPU가 없어도 실행 가능
시스템 프롬프트를 설정하여 한국어 지원 최적화

 

 

 

5. LlamaIndex에서 임베딩 모델 설정

검색 성능을 높이기 위해 문장을 벡터로 변환하는 임베딩 모델을 설정합니다.

from llama_index.embeddings import HuggingFaceEmbedding

embed_model = HuggingFaceEmbedding(model_name="sentence-transformers/all-mpnet-base-v2")

📌 sentence-transformers/all-mpnet-base-v2 모델을 사용하여 문서 검색 성능 향상

 

 

#llm과 embed_model을 세팅
#(예측하는 인공지능, 토크나이징 모델)
Settings.llm=llm
Settings.embed_model=embed_model

 

 

from llama_index.node_parser import SentenceSplitter

# 문장 단위로 분할하며 청크 사이즈 조정
text_splitter = SentenceSplitter(
    chunk_size=512,
    chunk_overlap=50,
    separator="\n",
    paragraph_separator="\n\n",
)

# 문서 분할 적용
nodes = text_splitter.get_nodes_from_documents(documents)

청크(Chunk) 설정

  • 긴 문서를 처리할 때 텍스트를 부분으로 나누는 방법입니다. 예를 들어, PDF 문서를 페이지별로 나누거나, 문단 단위로 나눠서 각 청크를 독립적으로 처리할 수 있습니다.
  • 청크는 크기단위를 기준으로 나누며, 일반적으로 문서의 흐름을 깨지지 않게 나누는 것이 중요합니다.
  • 청크 사이즈가 작을수록 검색 정밀도가 높지만 문맥 유지가 어렵습니다.
  • 청크사이즈가 클수록 문맥은 풍부하지만 불필요한 정보가 포함될 수 있습니다.

오버랩(Overlap) 설정

  • 청크들 간의 연관성을 유지하기 위해 청크 간 겹치는 부분을 두는 방법입니다.
  • 이를 통해 청크들이 서로 연결되고, 검색된 문서들이 자연스럽게 이어지도록 만듭니다. 예를 들어, 하나의 청크에서 끝난 문장이 다음 청크에서 다시 나오는 방식입니다.
  • 오버랩을 통해 정보 손실을 줄이고, 문서 간의 연결성을 유지할 수 있습니다.

 

6. LlamaIndex 설정 및 문서 인덱싱

추출한 PDF 텍스트를 LlamaIndex에서 사용할 벡터 인덱스(Vector Index)로 변환합니다.

from llama_index import Document, VectorStoreIndex

# 1. PDF에서 텍스트 추출
pdf_text = extract_text_from_pdf("sample.pdf")

# 2. LlamaIndex가 처리할 수 있는 문서 객체 생성
documents = [Document(text=pdf_text)]

# 3. 문서로부터 벡터 인덱스 생성
index = VectorStoreIndex.from_documents(documents)

# 4. 인덱스 저장 (나중에도 사용 가능)
index.storage_context.persist(persist_dir='/content/drive/MyDrive/llamaindex/index_storage')

📌 한 번 생성한 인덱스를 저장하여 재사용 가능 → 검색 속도 최적화

 

 

 

7. 저장된 LlamaIndex 불러오기 및 질의응답 수행

저장된 인덱스를 불러와서 질의응답을 수행할 수 있습니다.

# 저장된 인덱스 불러오기
from llama_index.core import StorageContext, load_index_from_storage

storage_context = StorageContext.from_persist_dir('/content/drive/MyDrive/llamaindex/index_storage')
index = load_index_from_storage(storage_context)

# 쿼리 엔진 생성
query_engine = index.as_query_engine()

# 질문 목록
queries = [
    "사내근로복지기금의 회계관리는 어떻게 이루어지나요?",
    "컨설턴트는 공단 직원인가요?"
]

# 질의응답 수행
for query in queries:
    response = query_engine.query(query)
    print(f'Q: {query}')
    print(f'A: {response.response}\n')

 저장된 인덱스를 활용하여 빠르게 질의응답 수행 가능
 RAG 방식으로 문서를 검색하여 정확한 정보 제공 가능

 

 

9. 결론 🎯

 LlamaIndex를 활용하면 GPU 없이도 문서를 검색하고 처리 가능
 LLM API를 사용하여 모델 다운로드 없이도 실행 가능
 PDF 문서를 벡터 인덱스로 변환하여 검색 속도 최적화