일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 스파르타코딩
- 티스토리챌린지
- SQL
- 프로그래머스
- 미세먼지
- 파이썬 완벽 가이드
- 웹 스크랩핑
- harkerrank
- 파이썬 머신러닝 완벽가이드
- R
- 파이썬 머신러닝 완벽 가이드
- 중회귀모형
- 프로젝트
- hackerrank
- 텍스트 분석
- 내일배움
- TiL
- 파이썬 철저입문
- 파이썬 철저 입문
- 스파르타 코딩
- MySQL
- wil
- 실전 데이터 분석 프로젝트
- 내일배움카드
- 회귀분석
- 내일배움캠프
- 스파르타
- Cluster
- 파이썬
- 오블완
- Today
- Total
OkBublewrap
LLM - RAG(2) 본문
환경 설정
!pip install -U google-generativeai
-U: --upgrade 축약
- 이미 설치 되어 있으면, 최신 버젼으로 업그레이드
- 설치된 패키지가 없으면 일반적인 설치와 동일하게 동작
google-generativeai: Gemini 생성형 API 라이브러리
예시)
import google.generativeai as genai
genai.configure(api_key="YOUR_API_KEY")
model = genai.GenerativeModel('gemini-pro')
response = model.generate_content("질문 또는 프롬프트")
print(response.text)
사용가능한 모델 목록
# 사용가능한 모델 목록
models_nm = genai.list_models()
for model_nm in models_nm:
print(model_nm.name)
사용법 예제
%%time
# 질문 입력
response = model.generate_content("LLM에 대해 3줄 이내로 설명해줘.")
# 출력
print(response.text)
LLM은 대량의 텍스트 데이터를 학습하여 인간과 유사한 텍스트를 생성하고 다양한 자연어 처리 작업을 수행하는 인공지능 모델입니다. 질문 답변, 번역, 요약, 텍스트 생성 등 다양한 분야에 활용됩니다. 쉽게 말해, 글쓰기와 언어 이해에 특화된 똑똑한 컴퓨터 프로그램입니다.
CPU times: user 33.7 ms, sys: 5.26 ms, total: 38.9 ms Wall time: 2.83 s
LangChain으로 RAG 구현
%%capture
!pip install -U transformers accelerate trl bitsandbytes pyarrow
!pip install langchain langchain_core pymupdf sentence_transformers faiss-gpu pypdf tabula-py
!pip install -U langchain-community
!pip install PyMuPDF
!pip install faiss-cpu
- transformers:
Hugging Face에서 제공하는 자연어처리(NLP) 및 생성형 AI 모델 사용 라이브러리입니다. (ChatGPT, BERT, GPT-2/3/4 등 다양한 모델 지원) - accelerate:
Hugging Face의 딥러닝 모델 학습 및 추론 속도를 GPU 등으로 빠르게 높여주는 유틸리티 라이브러리입니다. - trl (Transformers Reinforcement Learning):
Hugging Face의 생성형 모델을 강화학습으로 미세조정(RLHF, PPO 등)할 때 사용하는 라이브러리입니다. - bitsandbytes:
GPU 메모리를 효율적으로 관리하며, 모델을 양자화(quantization)하여 GPU 메모리 사용량을 최적화하는데 사용하는 라이브러리입니다. (특히 대형 언어모델 최적화에 많이 사용) - pyarrow:
대용량 데이터 처리에 특화된 Apache Arrow의 Python 인터페이스로, pandas, 대용량 csv, parquet 데이터 등을 빠르게 읽고 처리할 때 사용됩니다. - langchain & langchain_core:
여러 생성형 AI 모델을 쉽게 연결해 복잡한 AI 응용 프로그램을 만들 수 있게 해주는 라이브러리입니다. 다양한 AI모델 연결(예: GPT, Gemini 등) 및 벡터스토어 활용 등에 사용됩니다. - PyMuPDF (pymupdf):
PDF 문서의 내용을 빠르게 읽고 추출하는 라이브러리입니다. PDF 문서를 텍스트화하거나 이미지 추출 시 사용합니다. - sentence_transformers:
문장/텍스트를 벡터(embedding) 형태로 변환하여 의미 기반 유사성 비교, 벡터 검색 등을 가능하게 해주는 라이브러리입니다. - faiss-gpu:
Facebook에서 만든 GPU 기반의 벡터 검색 라이브러리로, 텍스트 임베딩 기반 유사성 검색을 아주 빠르게 할 수 있습니다. - pypdf:
PDF 문서의 텍스트나 메타정보를 읽고 처리하는 간단한 라이브러리입니다. 주로 PDF 내용을 추출하거나 페이지별로 처리할 때 사용합니다. - tabula-py:
PDF에서 표(table)를 추출해 pandas 데이터프레임으로 변환할 때 사용됩니다. - langchain-community:
LangChain 라이브러리에서 다양한 외부 라이브러리, 데이터 소스, API와 연결할 수 있게 하는 커뮤니티 확장 라이브러리입니다. 다양한 데이터 소스와의 통합 및 커뮤니티 제공 도구를 제공합니다 - CPU 기반의 벡터검색 라이브러리인 FAISS를 설치합니다.
- 앞서 GPU 기반인 faiss-gpu를 설치한 경우, GPU가 없는 환경에서 백업용으로 CPU 기반 검색을 사용할 수 있게 합니다. (단, 이미 GPU 버전 설치 후라면 보통 CPU 버전은 별도로 설치하지 않아도 됩니다.)
PDF 제목
test = pd.read_csv('llm_data/test.csv')
print(test.Source.unique())
1️⃣ 문서 LOAD
재정정보 AI 검색 알고리즘 경진대회 - DACON
분석시각화 대회 코드 공유 게시물은 내용 확인 후 좋아요(투표) 가능합니다.
dacon.io
from langchain.schema import Document
from langchain.document_loaders import PyPDFLoader, PyMuPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
import fitz
def extract_text_and_tables_from_pdf(pdf_path):
doc = fitz.open(pdf_path)
all_content = []
for page_num in range(len(doc)):
page = doc.load_page(page_num)
# 텍스트 추출
text = page.get_text("text")
if text:
all_content.append(("text", text))
return all_content
# 텍스트와 표 데이터를 결합하여 하나의 Document 객체로 생성
def create_combined_document(pdf_path, metadata=None):
content_data = extract_text_and_tables_from_pdf(pdf_path)
combined_content = ""
for content_type, content in content_data:
if content_type == "text":
combined_content += content + "\n"
elif content_type == "table":
combined_content += "\n[TABLE]\n" + content + "\n[TABLE]\n"
if metadata is None:
metadata = {}
# Langchain Document 객체 생성
document = Document(page_content=combined_content, metadata=metadata)
return document
file_nm = '보건복지부_노인장기요양보험 사업운영'
pdf_path = f"llm_data/test_source/{file_nm}.pdf"
metadata = {"source": pdf_path.split('/')[-1]}
langchain_document = create_combined_document(pdf_path, metadata)
len(langchain_document.page_content)
총 4029 page_countent로 출력이 됨
- 1 -\n사 업 명\n(74) 노인장기요양보험 사업운영 (2231-303)\n
생각보다 잘 분리 하는 것 같다.앞 -1은 페이지로 나오고, 테이블은 \n[TABLE]\n + content + \n[TABLE]\n으로사업명 부분 사업운영 부분으로 제대로 나눠졌다.
2️⃣ 문서 Split
def text_splitter(document, length_f, chunk_size, chunk_overlap) :
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
separators=['\n\n', '\n[TABLE]\n', '-', '. \n', '\n'],
length_function=length_f
)
chunks = text_splitter.split_text(document.page_content)
print(f'chunk 수 : {len(chunks)}')
chunk_documents = [Document(page_content=chunk, metadata=langchain_document.metadata) for chunk in chunks]
return chunk_documents
# chunk가 커서 문제일 수 있음
documents = text_splitter(langchain_document, len, 200, 100)
# chunk 수 : 36
매개변수 | 설명 |
document | 분리하고자 하는 전체 텍스트를 가진 Document 객체 (page_content, metadata 등의 속성을 가지고 있음) |
length_f | 각 chunk의 길이를 계산하는 함수(일반적으로 토큰 수 계산함수나, 단순히 글자 수 계산 함수) |
chunk_size | 하나의 chunk로 나누고자 하는 길이 제한 (보통 글자 수 또는 토큰 수 기준) |
chunk_overlap | chunk 간에 겹치는 길이 (앞뒤로 문맥을 유지하기 위해 사용하는 오버랩 길이) |
3️⃣ 문서 임베딩 & VectorDB 생성
from langchain.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
def process_pdfs_from_dataframe(path, chunks, base_directory):
"""딕셔너리에 pdf명을 키로해서 DB, retriever 저장"""
embedding_model = 'BAAI/bge-m3' #'beomi/kcbert-base''BAAI/bge-m3' # large 모델 변경 실험
model_kwargs = {'device':'cuda'}
encode_kwargs = {'normalize_embeddings': False}
embeddings = HuggingFaceEmbeddings(
model_name=embedding_model,
model_kwargs=model_kwargs,
encode_kwargs=encode_kwargs
)
full_path = os.path.normpath(os.path.join(base_directory, path.lstrip('./'))) if not os.path.isabs(path) else path
pdf_title = os.path.splitext(os.path.basename(full_path))[0]
print(f"Processing {pdf_title}...")
# 벡터 DB 생성
db = FAISS.from_documents(chunks, embeddings)
# Retriever 생성
retriever = db.as_retriever(search_type="mmr", search_kwargs={'k': 2, 'fetch_k': 10})
return retriever
retriever = process_pdfs_from_dataframe(pdf_path, documents, base_directory='llm_data/test_source/')
4️⃣ Query와 관련 문서 추출하기
query ="장기요양보험가입자 및 피부양자의 자격취득과 관련하여 어떤 법률을 준용해야 하는가?"
docs = retriever.get_relevant_documents(query, consider_metadata=True)
print('질문 :', query)
print()
print('문서 1 : ', docs[0].page_content, '\n')
print()
print('문서 2 : ', docs[1].page_content, '\n')
질문 : 장기요양보험가입자 및 피부양자의 자격취득과 관련하여 어떤 법률을 준용해야 하는가?
문서 1 : 6조, 제8조부터 제11조까지, 제69조제1항부터 제3항까지, 제76조부터 제86조까지 및 제110조는 장기요양보험가입자·피부양자의 자격취득·상실, 장기요양보험료 등의 납부·징수 및 결손처분 등에 관하여 이를 준용한다. 이 경우 "보험료"는 "장기요양보험료"로, "건강보험"은 "장기요양보험"으로, "가입자"는 "장기요양보험가입자"로 본다.
문서 2 :
- (’18.12월) 장기요양기관 지정갱신제 법적 근거 마련(’25. 시행)
- (’19.6월) 장기요양요원의 권익 보호 등을 위해 장기요양요원지원센터 설치
- (’21.12월) 요양시설 CCTV 설치 의무화 법 개정(’23.6월 시행)
- (’22.10월) 요양보호사 인력배치기준 개선(요양보호사 1명당 시설수급자 2.5명→2.3명)
# Gemini 만 사용한 추론 -- 생각보다 잘 대답한다?
response = model.generate_content(query)
# 출력
print(response.text)
장기요양보험 가입자 및 피부양자의 자격 취득과 관련하여 준용해야 하는 법률은 **「노인장기요양보험법」** 입니다.
구체적으로는 다음과 같습니다.
* **가입자 자격:** 「국민건강보험법」에 따른 건강보험 가입자는 자동적으로 장기요양보험 가입자가 됩니다. 따라서, 장기요양보험 가입자 자격 취득은 「국민건강보험법」 상의 건강보험 가입자 자격 취득 규정을 준용합니다. (노인장기요양보험법 제5조, 제6조)
* **피부양자 자격:** 마찬가지로, 「국민건강보험법」에 따른 건강보험 피부양자는 장기요양보험 피부양자가 됩니다. 따라서, 장기요양보험 피부양자 자격 취득은 「국민건강보험법」 상의 건강보험 피부양자 자격 취득 규정을 준용합니다. (노인장기요양보험법 제7조) 즉, 장기요양보험은 건강보험과 연계되어 운영되므로, 가입자 및 피부양자 자격 취득과 관련해서는
**「노인장기요양보험법」이 「국민건강보험법」의 관련 규정을 준용**하는 구조입니다. 따라서, 장기요양보험 가입자 및 피부양자 자격에 대한 구체적인 내용을 확인하려면, 「노인장기요양보험법」 뿐만 아니라 「국민건강보험법」의 가입자/피부양자 관련 조항을 함께 살펴봐야 합니다.
5️⃣ Inference
def format_documents_for_prompt(retrieved_docs):
"""
검색된 문서를 Gemini 프롬프트 형식으로 변환
"""
formatted_docs = "\n\n".join([f"📄 **출처:** {doc.metadata['source']}\n📌 {doc.page_content}" for doc in retrieved_docs])
return f"""아래 문서를 참고하여 질문에 답변하세요.
🔹 **검색된 문서:**
{formatted_docs}
---
**📢 질문:**
"""
def ask_gemini(query, retrieved_docs):
"""
검색된 문서를 활용하여 Google Gemini 모델에 질문을 전달
"""
# 문서를 프롬프트로 변환
context = format_documents_for_prompt(retrieved_docs)
prompt = context + query # 사용자 질문 추가
response = model.generate_content(prompt)
return response.text
%%time
# 실행
rag_response = ask_gemini(query, docs)
print(rag_response)
6️⃣ langchain chain 사용해보기
from langchain_google_genai import ChatGoogleGenerativeAI
# Google Gemini 모델 설정
llm = ChatGoogleGenerativeAI(
model="gemini-1.5-pro",
google_api_key=api_data['api_key']
)
from langchain.chains import RetrievalQA
# RetrievalQAChain 설정
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=retriever, # 설정한 Retriever 사용
return_source_documents=True # 검색된 문서도 함께 반환
)
# 체인 실행
result = qa_chain(query)
# 출력
print("📢 답변:", result["result"])
print("📄 참조된 문서:")
for doc in result["source_documents"]:
print(f"📌 출처: {doc.metadata['source']}\n내용: {doc.page_content}\n")
📢 답변: 제시된 법률 조항에 따르면, 장기요양보험가입자 및 피부양자의 자격 취득과 관련하여 국민건강보험법 제6조, 제8조부터 제11조까지를 준용합니다. 이 경우 "가입자"는 "장기요양보험가입자"로 봐야 합니다.
📄 참조된 문서:
📌 출처: 보건복지부_노인장기요양보험 사업운영.pdf 내용: 6조, 제8조부터 제11조까지, 제69조제1항부터 제3항까지, 제76조부터 제86조까지 및 제110조는 장기요양보험가입자·피부양자의 자격취득·상실, 장기요양보험료 등의 납부·징수 및 결손처분 등에 관하여 이를 준용한다. 이 경우 "보험료"는 "장기요양보험료"로, "건강보험"은 "장기요양보험"으로, "가입자"는 "장기요양보험가입자"로 본다.
📌 출처: 보건복지부_노인장기요양보험 사업운영.pdf 내용: - (’18.12월) 장기요양기관 지정갱신제 법적 근거 마련(’25. 시행) - (’19.6월) 장기요양요원의 권익 보호 등을 위해 장기요양요원지원센터 설치 - (’21.12월) 요양시설 CCTV 설치 의무화 법 개정(’23.6월 시행) - (’22.10월) 요양보호사 인력배치기준 개선(요양보호사 1명당 시설수급자 2.5명→2.3명)
'Python > 학습용' 카테고리의 다른 글
추천시스템 (3): 협업필터링 실습 (0) | 2025.03.21 |
---|---|
추천시스템 (2): 협업필터링 (0) | 2025.03.21 |
LLM - RAG(1) (0) | 2025.03.20 |
연관 규칙 (2): Apriori 알고리즘 (0) | 2025.03.08 |
연관 규칙 (1): 이론, 평가척도 설명 (0) | 2025.03.07 |