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 문서를 벡터 인덱스로 변환하여 검색 속도 최적화