Amazon Bedrock, LangChain과 사용하기
2. Amazon Bedrock API, LangChain 사용해보기
6. 간단한 검색증강(RAG : Retrieval Augmented Generation) 구현
7. 간단한 챗봇 구현 (Conversation Memory)
8. 챗봇 구현 (RAG + Conversation Memory)
이전에 챗봇에 RAG패턴을 적용하여 조금더 강력한 챗봇을 개발해보고자 합니다. ConversationBufferWindowMemory 를 사용하여 메모리를 구현하고 ConversationalRetrievalChain 을 사용하여 체이닝을 통한 RAG 챗봇을 구성하도록 하겠습니다.
아키텍쳐의 Flow에 대해 간략히 소개하도록 하겠습니다.
- 과거 상호작용에 대한 내용이 메모리 개체에서 추적됩니다.
- 사용자가 새로운 메세지를 입력합니다.
- 채팅기록이 메모리에서 검색되어 새 메세지 앞에 추가됩니다.
- Titan Embedding을 사용하여 질문이 벡터로 변환됩니다. 변환된 벡터는 다음 벡터 디비에서 가장 가까운 벡터를 찾습니다.
- 결합된 히스토리, 날리지, 새로운 메세지가 LLM으로 전송됩니다.
- 모델의 리스폰스가 사용자에게 출력됩니다.
라이브러리 (lib.py)
이번에는 Conversation Memory와 RAG모두 사용할것이므로 관련 라이브러리를 모두 임포트하겠습니다.
from langchain.memory import ConversationBufferWindowMemory
from langchain.llms.bedrock import Bedrock
from langchain.chains import ConversationalRetrievalChain
from langchain.embeddings import BedrockEmbeddings
from langchain.indexes import VectorstoreIndexCreator
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import PyPDFLoader
LangChain 클라이언트를 생성하는 함수를 구현합니다.
def get_llm():
model_kwargs = { #AI21
"maxTokens": 1024,
"temperature": 0,
"topP": 0.5,
"stopSequences": ["Human:"],
"countPenalty": {"scale": 0 },
"presencePenalty": {"scale": 0 },
"frequencyPenalty": {"scale": 0 }
}
llm = Bedrock(
region_name='us-east-1',
endpoint_url="https://bedrock-runtime.us-east-1.amazonaws.com",
model_id="ai21.j2-ultra-v1",
model_kwargs=model_kwargs)
return llm
인메모리 벡터디비(FAISS)를 생성하는 함수를 구현합니다.
def get_index():
embeddings = BedrockEmbeddings(
region_name='us-east-1',
endpoint_url="https://bedrock-runtime.us-east-1.amazonaws.com",
)
pdf_path = "/Users/hyeonminkim/Desktop/Bedrock/basicrag/2022-Shareholder-Letter.pdf"
loader = PyPDFLoader(file_path=pdf_path)
text_splitter = RecursiveCharacterTextSplitter(
separators=["\n\n", "\n", ".", " "],
chunk_size=1000,
chunk_overlap=100
)
index_creator = VectorstoreIndexCreator(
vectorstore_cls=FAISS,
embedding=embeddings,
text_splitter=text_splitter,
)
index_from_loader = index_creator.from_loaders([loader])
return index_from_loader
LangChain 메모리 개체를 초기화하는 함수를 구현합니다.
def get_memory():
memory = ConversationBufferWindowMemory(memory_key="chat_history", return_messages=True)
return memory
Bedrock을 호출하는 함수를 구현합니다.
def get_rag_chat_response(input_text, memory, index):
llm = get_llm()
conversation_with_retrieval = ConversationalRetrievalChain.from_llm(llm, index.vectorstore.as_retriever(), memory=memory)
chat_response = conversation_with_retrieval({"question": input_text})
return chat_response['answer']
전체적인 코드는 다음과 같습니다.
from langchain.memory import ConversationBufferWindowMemory
from langchain.llms.bedrock import Bedrock
from langchain.chains import ConversationalRetrievalChain
from langchain.embeddings import BedrockEmbeddings
from langchain.indexes import VectorstoreIndexCreator
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import PyPDFLoader
def get_llm():
model_kwargs = { #AI21
"maxTokens": 1024,
"temperature": 0,
"topP": 0.5,
"stopSequences": ["Human:"],
"countPenalty": {"scale": 0 },
"presencePenalty": {"scale": 0 },
"frequencyPenalty": {"scale": 0 }
}
llm = Bedrock(
region_name='us-east-1',
endpoint_url="https://bedrock-runtime.us-east-1.amazonaws.com",
model_id="ai21.j2-ultra-v1",
model_kwargs=model_kwargs)
return llm
def get_index():
embeddings = BedrockEmbeddings(
region_name='us-east-1',
endpoint_url="https://bedrock-runtime.us-east-1.amazonaws.com",
)
pdf_path = "/Users/hyeonminkim/Desktop/Bedrock/basicrag/2022-Shareholder-Letter.pdf"
loader = PyPDFLoader(file_path=pdf_path)
text_splitter = RecursiveCharacterTextSplitter(
separators=["\n\n", "\n", ".", " "],
chunk_size=1000,
chunk_overlap=100
)
index_creator = VectorstoreIndexCreator(
vectorstore_cls=FAISS,
embedding=embeddings,
text_splitter=text_splitter,
)
index_from_loader = index_creator.from_loaders([loader])
return index_from_loader
def get_memory():
memory = ConversationBufferWindowMemory(memory_key="chat_history", return_messages=True)
return memory
def get_rag_chat_response(input_text, memory, index):
llm = get_llm()
conversation_with_retrieval = ConversationalRetrievalChain.from_llm(llm, index.vectorstore.as_retriever(), memory=memory)
chat_response = conversation_with_retrieval({"question": input_text})
return chat_response['answer']
Streamlit Application (front.py)
라이브러리를 임포트한 후 페이지를 구성합니다.
import streamlit as st
import lib as glib
st.set_page_config(page_title="RAG Chatbot")
st.title("RAG Chatbot")
세션 캐시에 LangChain 메모리와 UI채팅기록, 벡터 인덱스를 추가합니다.
if 'memory' not in st.session_state:
st.session_state.memory = glib.get_memory()
if 'chat_history' not in st.session_state:
st.session_state.chat_history = []
if 'vector_index' not in st.session_state:
with st.spinner("Indexing document..."):
st.session_state.vector_index = glib.get_index()
이전 채팅 메세지를 렌더링하기 위한 for 루프와 입력 요소를 추가합니다.
input_text = st.chat_input("Chat with your bot here")
if input_text:
with st.chat_message("user"):
st.markdown(input_text)
st.session_state.chat_history.append({"role":"user", "text":input_text})
chat_response = glib.get_rag_chat_response(input_text=input_text, memory=st.session_state.memory, index=st.session_state.vector_index,)
with st.chat_message("assistant"):
st.markdown(chat_response)
st.session_state.chat_history.append({"role":"assistant", "text":chat_response})
전체적인 코드는 다음과 같습니다.
import streamlit as st
import lib as glib
st.set_page_config(page_title="RAG Chatbot")
st.title("RAG Chatbot")
if 'memory' not in st.session_state:
st.session_state.memory = glib.get_memory()
if 'chat_history' not in st.session_state:
st.session_state.chat_history = []
if 'vector_index' not in st.session_state:
with st.spinner("Indexing document..."):
st.session_state.vector_index = glib.get_index()
for message in st.session_state.chat_history:
with st.chat_message(message["role"]):
st.markdown(message["text"])
input_text = st.chat_input("Chat with your bot here")
if input_text:
with st.chat_message("user"):
st.markdown(input_text)
st.session_state.chat_history.append({"role":"user", "text":input_text})
chat_response = glib.get_rag_chat_response(input_text=input_text, memory=st.session_state.memory, index=st.session_state.vector_index,)
with st.chat_message("assistant"):
st.markdown(chat_response)
st.session_state.chat_history.append({"role":"assistant", "text":chat_response})
결과 확인
첨부된 PDF내용을 기반으로 이전대화내용을 포함한 내용을 출력함을 확인 할 수 있습니다.
'Bedrock' 카테고리의 다른 글
Amazon Bedrock, LangChain과 사용하기 - 7. 간단한 챗봇 구현 (Conversation Memory) (0) | 2023.10.18 |
---|---|
Amazon Bedrock, LangChain과 사용하기 - 6. 간단한 검색증강(RAG : Retrieval Augmented Generation) 구현 (0) | 2023.10.18 |
Amazon Bedrock, LangChain과 사용하기 - 5. Streamlit, 텍스트/이미지 생성 (0) | 2023.10.18 |
Amazon Bedrock, LangChain과 사용하기 - 4. 스트리밍 API, 벡터 임베딩 (0) | 2023.10.18 |
Amazon Bedrock, LangChain과 사용하기 - 3. 추론 매개변수 (0) | 2023.10.18 |