이번에는 LangChain 프롬프트 Library에서 사용할 만한 프롬프트를 가져온 후 다듬어서 LangChain의 품질을 높이는 작업을 해보겠다.
- API KEY (model : OPEN AI, Langchain : Langchain)
import os
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("OPEN_API_KEY")
langchain_api_key = os.getenv("LANGCHAIN_API_KEY")
os.environ["LANGCHAIN_API_KEY"] = langchain_api_key
prompt = hub.pull("rlm/rag-answer-hallucination")
prompt_text = prompt.messages[0].prompt.template
# # 프롬프트 데이터를 문자열로 변환
# prompt_text = str(prompt)
output_dir = "Prompts"
output_path = os.path.join(output_dir, "prompt_rlm_rag-answer-hallucination.txt")
# 프롬프트 데이터를 파일에 저장
with open(output_path, "w", encoding="utf-8") as file:
file.write(prompt_text)
print(f"Prompt saved to {output_path}")
ex.
You are an expert AI on a question and answer task.
Use the "Following Context" when answering the question. If you don't know the answer, reply to the "Following Text" in the header and answer to the best of your knowledge, or if you do know the answer, answer without the "Following Text". If a question is asked in Korean, translate it to English and always answer in Korean.
Following Text: "주어진 정보에서 답변을 찾지는 못했지만, 제가 아는 선에서 답을 말씀드려볼게요! **틀릴 수도 있으니 교차검증은 필수입니다!**"
Following Context: {context}
Question: {question}
Helpful Answer:
- 저장한 Prompt read
output_dir = "Prompts"
output_path = os.path.join(output_dir, "prompt1.txt")
promt_txt = ""
# 프롬프트 데이터를 파일에 저장
with open(output_path, "r", encoding="utf-8") as file:
promt_txt = file.read()
promt_txt
- 프롬프트 템플릿 정의
- 앞서 받아온 프롬프트가 요구하는 inputs 가 Context와 Question이기 때문에 아래와 같이 명시
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
# 프롬프트 템플릿 정의
contextual_prompt = ChatPromptTemplate.from_messages([
("system", promt_txt),
("user", "Context: {context}\\n\\nQuestion: {question}")
])
- PDF 파일 업로드
from langchain.document_loaders import PyPDFLoader
# PDF 파일 로드. 파일의 경로 입력
loader = PyPDFLoader("../초거대 언어모델 연구 동향.pdf")
# 페이지 별 문서 로드
docs = loader.load()
- 청크 생성
from langchain.text_splitter import RecursiveCharacterTextSplitter
recursive_text_splitter = RecursiveCharacterTextSplitter(
chunk_size=100,
chunk_overlap=10,
length_function=len,
is_separator_regex=False,
)
splits = recursive_text_splitter.split_documents(docs)
- 임베딩 모델 초기화
from langchain_openai import OpenAIEmbeddings
# OpenAI 임베딩 모델 초기화
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002", api_key=api_key)
- 비슷한 맥락을 찾아주는 FAISS 생성 및 vectorstore 생성
import faiss
from langchain_community.vectorstores import FAISS
vectorstore = FAISS.from_documents(documents=splits, embedding=embeddings)
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 5})
- 맥락 기반하여 프롬프트 명령에 맞는 출력값 생성
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
# 모델 초기화
model = ChatOpenAI(model="gpt-4o-mini", api_key=api_key)
class DebugPassThrough(RunnablePassthrough):
def invoke(self, *args, **kwargs):
output = super().invoke(*args, **kwargs)
print("Debug Output:", output)
return output
# 문서 리스트를 텍스트로 변환하는 단계 추가
class ContextToText(RunnablePassthrough):
def invoke(self, inputs, config=None, **kwargs): # config 인수 추가
# context의 각 문서를 문자열로 결합
# context_text = "\n".join([doc.page_content for doc in docs])
context_text = "\n".join([doc.page_content for doc in inputs["context"]])
# return 값들을 디버그를 해줌
return {"context": context_text, "question" : inputs["question"]}
# RAG 체인에서 각 단계마다 DebugPassThrough 추가
rag_chain_debug = {
"context": retriever, # 컨텍스트를 가져오는 retriever # 사용자 질문이 그대로 전달되는지 확인하는 passthrough
# 어디서 질문을 찾는지 디버그를 하기 위해
"question": DebugPassThrough()
} | DebugPassThrough() | ContextToText()| contextual_prompt | model
- 동작
while True:
query = input("어떤 질문을 하시겠어요? : ")
if query == "exit":
break
# inputs 구성
response = rag_chain_debug.invoke(query)
print("Final Response:")
print(response.content)
기본 OpenAI에게 "최신 정보"를 물어보면 (질문 : 2024년 3분기 벤처 투자의 몇 %가 인공지능 투자했어??)
아래와 같은 답변을 내놓는다.
죄송합니다, 저는 실시간 업데이트가 되지 않는 인공지능이기 때문에 2024년 3분기의 벤처 투자 비율에 대한 정보를 제공하지 못합니다. 최신 정보는 신뢰할 수 있는 뉴스 출판물이나 산업 보고서를 찾아보시는 것이 가장 좋습니다.
그렇지만 같은 질문을 RAG를 거친 AI에게 물어보면
2024년 3분기 벤처 자금의 31%가 AI 스타트업에 투자되었습니다.
이처럼 해당하는 자료를 찾아 자료에 근거하는 답변을 내놓음을 확인할 수 있다.
LangcChain의 gpt 모델과 openai의 gpt 모델은 동일하며 API 호출 시에 비용차이도 존재하지 않는다고 함
- 단, 메시지 체계에서 차이를 보임
- LangChain의 메시지 체계 : SystemMessage, HumanMessage, AIMessage
- OpenAI의 메시지 체계 : messages, role(system, user, assistant), content
Raw 하게 받아온 프롬프트 (문맥에 맞는 질문을 생성해달라는 요청)
You are an AI assistant tasked with generating question and answer pairs for the given context using the given format. Only answer in the format with no other text. You should create the following number of question/answer pairs: {number_of_pairs}. Return the question/answer pairs as a Python List. Each dict in the list should have the full context provided, a relevant question to the context and an answer to the question.
Format:
{data_format}
Context:
{context}
수정한 프롬프트
- 수정 내용 : 명확하게 논문 주제를 밝힘
- 쓸모없는 질문이라 판별되는 저자에 관한, 연도에 관한 질문을 제외해달라는 요청을 추가
You are an AI assistant tasked with generating question and answer pairs based on the given context, strictly following the given format. Create exactly {number_of_pairs} question/answer pairs.
Each output should be a Python list containing dictionaries, each with a "context" key holding the full context, a relevant "question" related to the context, and an accurate "answer" to the question.
Important: Exclude any questions about author names, contributors, or publication date/year. Focus only on information specifically related to LLMs, their capabilities, applications, research findings, methodologies, and limitations.
Format:
{data_format}
Context:
{context}
To be continued...