1. RAG : Retrieval Augmented Generation
- 생성모델 + 검색 시스템 => 검색 기반 생성 모델
- | 나의 데이터를 가지고 직접 학습시킨다. | Modeling |
사전 학습된 LLM | 나의 데이터를 가지고 추가 학습시킨다. | Fine-tuning |
나의 데이터를 가지고 답변 시킨다. | RAG |
- LLM with RAG
① 사용자 질문을 받음
② 지식DB에서 답변에 필요한 문서 검색
③ 필요한 문서를 포함한 프롬프트 생성
④ LLM이 답변 생성하기
1) Vector DB : 대규모 텍스트 데이터 및 임베딩 벡터를 저장, 검색용
① 사용자 질문을 받음 | ② 지식DB에서 답변에 필요한 문서 검색 |
임베딩 : 벡터로 변환(질문 벡터) 토크나이저 + 임베딩 전처리를 통해 |
[질문 벡터]와 DB 내 저장된 [문서 벡터]와 유사도 계산 가장 유사도가 높은 문서 n개 찾기 |
(1) Vector DB 구축 절차 (Chroma DB)
① 텍스트 추출 Document Loader |
② 텍스트 분할 Text Splitter |
③ 텍스트 벡터화 Text Embedding |
④ Vector DB로 저장 Vector Store |
다양한 문서 (word, pdf, web page 등)로부터 텍스트 추출 | chunk 단위로 분할(문장,문단) Document 객체로 만들기 |
- | - |
(2) DB 구성
# 임베딩 모델 지정
embedding = OpenAIEmbedding(model='text-embedding-ada-002')
# DB 경로 지정
database = Chroma(persist_directory = path + 'db', # 임베딩 저장할 디렉토리 설정
embedding_function = embeddings)
(3) Insert 방법
① 단순 텍스트 입력(.add_texts()) : 각 단위 텍스트를 리스트 형태로 입력
input_list1 = ['test 데이터 입력1', 'test 데이터 입력2']
# 입력 시 인덱스 저장 (조회시 사용)
ind = database.add_texts(input_list1)
② 텍스트와 메타데이터 입력 (.add_documents()) : 각 단위 텍스트와 메타정보를 함께 입력
input_list2 = ['오늘 날씨는 매우 맑음.', '어제 주가는 큰 폭으로 상승했습니다.']
metadata = [{'category':'test'}, {'category':'test'}] # category라는 키로 'test' 값을 할당
# 각 문서의 텍스트(input_list2)와 해당 문서의 메타데이터(metadata) 결합하여 Document 객체 생성
doc2 = [Document(page_content = input_list2[i], metadata = metadata[i] for i in range(len(input_list2))]
# Chroma 데이터베이스에 추가
ind2 = database.add_document(doc2)
* database 내부 구성
① 단순 텍스트 입력(.add_texts()) | ② 텍스트와 메타데이터 입력 (.add_documents()) |
![]() |
![]() |
(4) 조회
# 전체 조회
database.get() # 전부 조회하는 방법이나, 실무에선 많이 쓰이진 않는다. (너무 방대하기 때문)
# 인덱스 조회
database.get(index)
# 조건 조회 : ChromaDB에서는 제공하지 않아, Dataframe으로 변환 후 사용 가능
data = database.get()
data = pd.DataFrame(data)
data.loc[data['metadatas']=={'category':'test'}]
2. 유사도
: Chroma DB를 이용하여 검색 시 계산되는 유사도 점수 (Similarity Score)
- Cosin Distance 이용 (1에 코사인 유사도를 뺀 값)
: Cosine Distance(a,b) = 1 - Cosine Similarity(a,b)
: Cosine Similarity (-1 ~ 1 범위) => Cosine Distance (0~2 범위)
: Cosine Distance가 0에 가까울 수록 유사도가 높다.
# .similarity_search_with_score()
# 문서 조회
query = '오늘 낮 기온은?' # 질문할 문장
k = 3 # 유사도 상위 k 개 문서 가져오기
# 데이터베이스에서 유사도가 높은 문서를 가져옴
result = database.similarity_search_with_score(query, k=k)
print(result)
for doc in result:
print(f'유사도 점수 : {round(doc[1], 5)}, 문서내용 : {doc[0].page_content}')
* 참고
.similarity_search_with_score(query, k=k)는 튜플 형태로 반환
(문서내용, 유사도점수)
=> doc[0] : 문서내용 , doc[1] : 유사도 점수
3. RAG 구성 함수
1) Retrieval QA : RAG용 QA chat 함수
- llm : 언어 모델
- retriver : RAG로 연결한 VectorDB (검색기)
- return_source_documents=True : 모델이 답변을 생성할 뿐만 아니라 그 답변에 사용된 출처 문서(document)도 함께 반환
chat = ChatOpenAI(model='gpt-3.5-turbo')
retriever = database2.as_retriever()
qa = RetrievalQA.from_llm(llm=chat, retriever=retriever, return_source_documents=True)
query='생성형 AI 도입 시 예상되는 보안 위협은 어떤 것들이 있어?'
result=qa(query)
print(result['result'])
2) Memory
- 이전 질문 답변을 Memory에 저장하고, 이를 Prompt에 포함시킨다.
# ConversationBufferMemory
from langchain.memory import ConversationBufferMemory
# 메모리 선언하기(초기화)
memory = ConversationBufferMemory(retrun_messages=True)
# 저장
memory.save_context({'input':'안녕하세요!'}.
'output':'안녕하세요! 어떻게 도와드릴까요?'})
memory.save_context({'input':'메일을 써야하는데 도와줘'}.
'output':'누구에게 보내는 어떤 메일인가요?}')
# 현재 담겨 있는 메모리 내용 전체 확인
memory.load_memory_variables({})
qa = RetrievalQA.from_llm(llm=chat, retriever=retriever, return_source_documents=True)
query = '생성형 AI 도입시 예상되는 보안 위협은 어떤 것들이 있어?'
result = qa(query)
memory = ConversationBufferMemory(return_messages=True)
memory.save_context({'input':query},
{'output':result['result']})
memory.load_memory_variables({})
3) Chain : 각 모듈 모두 연결해보기
- LLM, retriever, memory
- ConversationalRetrieverChain 함수
qa = ConversationalRetrievalChain.from_llm(llm=chat, retriever=retriever, memory=memory,
return_source_documents=True, output_key='answer')
# Chain 함수를 위한 memory 설정
memory = ConversationBufferMemory(memory_key='chat_history', input_key='question', output_key='answer',
return_messages=True)
4. 종합실습 : KT AIVLE SCHOOL FAQ 챗봇 만들기
1) 환경 준비
# 구글 드라이브 연결 (langchain 폴더 우성 생성하고, 제공받은 파일 다운로드 해놓기)
from google.colab import drive
drive.mount('/content/drive')
# 라이브러리
!pip install -r /content/drive/MyDrive/langchain/requirements.txt
import pandas as pd
import numpy as np
import os
import sqlite3
from datetime import datetime
import openai
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage, Document
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA, ConversationalRetrievalChain
from langchain.memory import ConversationBufferMemory
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
# OpenAI API Key 등록
def load_api_key(filepath):
with open(filepath, 'r') as file:
return file.readline().strip()
path = '/content/drive/MyDrive/langchain/'
# 텍스트 파일로 저장한 API 키 로드 및 환경변수 설정
openai.api_key = load_api_key(path + 'api_key.txt')
os.environ['OPENAI_API_KEY'] = openai.api_key
print(openai.api_key[:15])
2) Vector DB 만들기
data = pd.read_csv(path + 'aivleschool_qa.csv', encoding='UTF-8')
data = pd.DataFrame(data)
data.head()
# 벡터 데이터 베이스
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
database = Chroma(persist_directory = path + "./db3", # 경로 지정(구글 드라이브에서 db 폴더 생성)
embedding_function = embeddings) # 임베딩 벡터로 만들 모델 지정
# 데이터 입력
ids = database.get()
if ids['ids']:
database.delete(ids=ids['ids']) # 기존 입력 있으면 제거
# 질문 리스트로 변환
qa_list = data['QA'].tolist()
cat_list = [{'category':text} for text in data['구분'].tolist()]
# 각 행의 데이터를 Document 객체로 변환
documents = [Document(page_content=qa_list[i], metadata = cat_list[i]) for i in range(len(qa_list))]
database.add_documents(documents)
3) RAG+LLM 모델
# 모델 선언
chat = ChatOpenAI(model="gpt-3.5-turbo")
k=3
# 리트리버 선언
retriever = database.as_retriever(search_kwargs={"k":k}) # 검색 설정 인자 3개로 지정
# 대화 메모리 생성
memory = ConversationBufferMemory(memory_key="chat_history",
input_key="question",
output_key="answer",
return_messages=True)
# ConversationalRetrievalQA 체인 생성
qa = ConversationalRetrievalChain.from_llm(llm=chat, retriever=retriever, memory=memory,
return_source_documents=True, output_key='answer')
4) 모델 사용
# 질문
query1 = "취업상태에 에이블스쿨을 지원할 수 있나요?"
# 답변
result = qa(query1)
result['answer']
# 네, KT 에이블스쿨은 미취업자를 대상으로 하며, 교육 시작일 기준으로 재직자는 지원이 불가능합니다.
## 참고1. 토크나이저와 벡터 DB 청크의 차이점
'딥러닝' 카테고리의 다른 글
[딥러닝] UltraLytics : YOLO & Reboflow : Universe _ 20241107 (5) | 2024.11.07 |
---|---|
[딥러닝] Object Detection _ 20241107 (6) | 2024.11.07 |
[딥러닝] 언어 모델 활용 (1) LangChain _ 20241106 (1) | 2024.11.06 |
[딥러닝] 언어모델 이해 (3) Tokenizing & Embedding _ 20241105 (10) | 2024.11.05 |
[딥러닝] 언어모델 이해 (2) Transformer _ 20241105 (17) | 2024.11.05 |