프로젝트 개발 일지/AI
[LLM with RAG] History
ballbig
2024. 9. 26. 17:07
728x90
create_history_aware_retriever 활용하기
https://python.langchain.com/v0.2/docs/how_to/qa_chat_history_how_to/#chains
How to add chat history | 🦜️🔗 LangChain
In many Q&A applications we want to allow the user to have a back-and-forth conversation, meaning the application needs some sort of "memory" of past questions and answers, and some logic for incorporating those into its current thinking.
python.langchain.com
- LangChain에서는 create_history_aware_retriever input 생성자를 제공하여 대화의 맥락에 맞게 LLM의 답변이 올 수 있도록 지원한다.
- create_history_aware_retriever입력으로 다음을 요구한다.
- LLM => GPT 모델 사용함
- Retriever => pinecone을 사용하여 가져옴
- Prompt => 수정✅
[수정 전 코드]
더보기
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import OpenAIEmbeddings
from langchain_pinecone import PineconeVectorStore
from langchain_community.document_loaders import Docx2txtLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
from langchain import hub
from pinecone import Pinecone
from dotenv import load_dotenv
import getpass
import os
# .env 파일에서 환경 변수를 로드
load_dotenv()
# PINECONE API 키 설정
if not os.getenv("PINECONE_API_KEY"):
os.environ["PINECONE_API_KEY"] = getpass.getpass("Enter your Pinecone API key: ")
pinecone_api_key = os.environ.get("PINECONE_API_KEY")
# LangSmith API 키 설정
if not os.getenv("LANGSMITH_API_KEY"):
os.environ["LANGSMITH_API_KEY"] = getpass.getpass("Enter your LangSmith API key: ")
langsmith_api_key = os.environ.get("LANGSMITH_API_KEY")
def get_retriever(question, k=4):
index_name = "chatbot-index"
embedding = OpenAIEmbeddings(model='text-embedding-3-large')
database = PineconeVectorStore.from_existing_index(index_name=index_name, embedding=embedding)
retriever = database.as_retriever(search_kwargs={'k': k})
relevant_docs = retriever.invoke(question)
# 검색된 문서 출력
for doc in relevant_docs:
print(doc.page_content)
return retriever
# llm 모델 반환
def get_llm(model='gpt-4o'):
llm = ChatOpenAI(model=model)
return llm
# keyword 사전을 이용한 query 수정
def get_question(query):
dictionary = ["사람을 나타내는 표현 -> 거주자", "Trabean -> bean"]
prompt = ChatPromptTemplate.from_template(f"""
사용자의 질문을 보고, 우리의 사전을 참고해서 사용자의 질문을 변경해주세요.
만약 변경할 필요가 없다고 판단된다면, 사용자의 질문을 변경하지 않아도 됩니다.
그런 경우에는 질문만 리턴해주세요
사전: {dictionary}
질문: {{question}}
""")
llm = get_llm()
dictionary_chain = prompt | llm | StrOutputParser()
question = dictionary_chain.invoke({"question": query, "dictionary": dictionary})
return question
# 질문에 대한 LLM 답변 반환
def get_ai_message(query):
prompt = hub.pull("rlm/rag-prompt") # 알맞은 프롬프트 생성 모델 불러오기
llm = get_llm()
question = get_question(query)
retriever = get_retriever(question, 4)
qa_chain = RetrievalQA.from_chain_type( # RetrievalQA 객체 생성
llm, # llm 모델
retriever=retriever,
chain_type_kwargs={"prompt": prompt}
)
answer = qa_chain.invoke({"query": question})
return answer
print(get_ai_message("Trabean 환전 기능에 대해 알고 싶어"))
Prompt 수정
- 기존에 사용한 프롬프트 생성 모델이 생성한 prompt
prompt = hub.pull("rlm/rag-prompt") # 알맞은 프롬프트 생성 모델 불러오기
- input_variables=['context', 'question'] input_types={} partial_variables={} metadata={'lc_hub_owner': 'rlm', 'lc_hub_repo': 'rag-prompt', 'lc_hub_commit_hash': '50442af133e61576e74536c6556cefe1fac147cad032f4377b60c436e6cdcb6e'} messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['context', 'question'], input_types={}, partial_variables={}, template="You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.\nQuestion: {question} \nContext: {context} \nAnswer:"), additional_kwargs={})]
- "chat_history" 입력 키를 사용하여 프롬프트에 메시지 목록을 전달하기
# langChain에서 제공하는 history prompt
contextualize_q_system_prompt = (
"Given a chat history and the latest user question "
"which might reference context in the chat history, "
"formulate a standalone question which can be understood "
"without the chat history. Do NOT answer the question, "
"just reformulate it if needed and otherwise return it as is."
)
contextualize_q_prompt = ChatPromptTemplate.from_messages(
[
("system", contextualize_q_system_prompt),
MessagesPlaceholder("chat_history"),
("human", "{input}"),
]
)