AI

[AI] RAG์™€ LangChain์„ ํ™œ์šฉํ•œ Chatbot ๊ตฌํ˜„(2)

pseudocoder_ 2025. 2. 14. 19:47
728x90

๐Ÿ‘‰RAG์™€ LangChain์„ ํ™œ์šฉํ•œ Chatbot ๊ตฌํ˜„(1) ๊ฒŒ์‹œ๋ฌผ ๋ณด๋Ÿฌ๊ฐ€๊ธฐ

 

์ง€๋‚œ ๊ฒŒ์‹œ๋ฌผ์—์„œ RAG์˜ ๊ฐœ๋…, RAG๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์˜ ์žฅ์ , RAG ๊ตฌํ˜„์„ ์œ„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ langchain์˜ ํ™œ์šฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ณ  ์งˆ๋ฌธ์— ๊ฐ„๋‹จํ•˜๊ฒŒ ๋‹ต๋ณ€ํ•  ์ˆ˜ ์žˆ๋Š” RAG๋ฅผ ๊ตฌ์ถ•ํ•ด๋ณด์•˜๋‹ค.

 

์ง€๋‚œ ์‹œ๊ฐ„์— ๊ตฌ์ถ•ํ–ˆ๋˜ RAG๋ฅผ ์ข€ ๋” ๋ณด๊ฐ•ํ•˜์—ฌ ๋‹ต๋ณ€ ์‹ ๋ขฐ๋„์™€ ํ’ˆ์งˆ์„ ์ข€ ๋” ๋†’์—ฌ๋ณด์ž.

 

Chat history ์ถ”๊ฐ€ํ•˜๊ธฐ

RAG์—์„œ ๋Œ€ํ™” ๊ธฐ๋ก(chat history)๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ด์ „์˜ ๋ฌธ๋งฅ(context)๋ฅผ ํ† ๋Œ€๋กœ ๋” ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ์ผ๊ด€๋œ ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. chat history๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด ๋น„์Šทํ•œ ๋งฅ๋ฝ์˜ ์งˆ๋ฌธ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋‹ต๋ณ€์„ ์ œ๋Œ€๋กœ ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. 

"1๋ฃจ ์ฃผ์ž์™€ 2๋ฃจ ์ฃผ์ž๊ฐ€ ๋™์‹œ์— ๋ฒ ์ด์Šค๋ฅผ ํ›”์น˜๋Š” ๊ฒƒ์„ ๋ญ๋ผ๊ณ  ํ•˜๋‚˜์š”?"์™€ "๊ทธ๋Ÿผ ํ•œ ๋ช…์ด ํ•˜๋Š” ๊ฑด?"์€ ์‚ฌ๋žŒ์ด ๋ณด๊ธฐ์— ๋น„์Šทํ•œ ๋ฌธ๋งฅ์˜ ๋ฌธ์žฅ์ž„์— AI ๋ชจ๋ธ์—์„œ ์ด๋ฅผ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. chat history๋ฅผ ์ œ๊ณตํ•˜์—ฌ ์ด์ „์˜ ๋Œ€ํ™” ๊ธฐ๋ก์„ ์ฐธ๊ณ ํ•˜๋„๋ก ํ•˜์—ฌ AI์—๊ฒŒ ์ถ”๋ก  ๋Šฅ๋ ฅ์„ ๋ถ€์—ฌํ•˜๊ณ  ์ ์€ ์ •๋ณด๋กœ ์ •ํ™•ํ•œ ๋‹ต๋ณ€์„ ์ œ๊ณต๋ฐ›๊ณ  ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€ํ™” ๋˜ํ•œ ์ด์–ด๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋‹ค. 

 

๊ธฐ์กด์˜ RAG์— chat history๋ฅผ ์ ์šฉํ•ด๋ณด์ž. ๋จผ์ € ์ด์ „์˜ ๋Œ€ํ™” ๋‚ด์šฉ์„ chat history๋กœ ์ €์žฅํ•˜๋Š” ๊ฒƒ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ณด์ž. retriever๋Š” ์ด์ „์˜ retriever๋ฅผ ํ™œ์šฉํ•˜์—ฌ chat history๋ฅผ ํ† ๋Œ€๋กœ ๋ฌธ๋งฅ ํ๋ฆ„์„ ๊ณ„์† ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” history_aware_retriever๋ฅผ ์ƒ์„ฑํ•œ๋‹ค(create_history_aware_retriever๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ langchain 0.2v์˜ ๊ณต์‹๋ฌธ์„œ์—์„œ ์‚ฌ์šฉ๋ฒ• ํ™•์ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค). history_aware_retriever๋ฅผ ํ†ตํ•ด ์ฑ„ํŒ… ๊ธฐ๋ก์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๊ณ , ์ฑ„ํŒ… ๊ธฐ๋ก์€ key๊ฐ’์ธ session_id์™€ value ๊ฐ’์ธ ์ฑ„ํŒ…๊ธฐ๋ก(ChatMessageHistory)๋กœ ์ด๋ฃจ์–ด์ง„ ํ•ด์‹œ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ์˜ chat_storage๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

from langchain_core.prompts import MessagesPlaceholder
from langchain.chains import create_history_aware_retriever

chat_storage = {}

def get_llm():
    llm = ChatUpstage()
    return llm
    
# chat history๋ฅผ ๋ฐ˜์˜ํ•˜์—ฌ ์งˆ๋ฌธ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ์„ค์ •
def get_history_retriever():
    llm = get_llm()
    retriever = get_retriever()
    
    # chat history๋ฅผ ๋ฐ˜์˜ํ•˜์—ฌ ์งˆ๋ฌธ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ
    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."
    )
    
    # ์ฑ„ํŒ… ๊ธฐ๋ก์„ ๋ฐ˜์˜ํ•˜์—ฌ QA๋ฅผ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ
    contextualize_q_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", contextualize_q_system_prompt),
            MessagesPlaceholder("chat_history"), # ๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „๋‹ฌ
            ("human", "{input}")
        ]
    )
    
    history_aware_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)
    return history_aware_retriever

 

์ฑ„ํŒ… ๊ธฐ๋ก์„ ๋ฐ˜์˜ํ•˜๋Š” history_retriever๋ฅผ ๊ตฌํ˜„ํ–ˆ์œผ๋ฉด ์งˆ๋‹ต์„ ์œ„ํ•œ QA ์ฒด์ธ์„ ์ถ”๊ฐ€ํ•˜๊ณ  RAG ์ฒด์ธ์„ ์™„์„ฑํ•ด๋ณด์ž.

์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์€ ์ฑ„ํŒ… ๊ธฐ๋ก์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” history_retriever๊ฐ€ ์ถ”๊ฐ€ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— RAG ์ฒด์ธ ๋‚ด๋ถ€์—์„œ chat_storage์—์„œ ์ฑ„ํŒ… ๊ธฐ๋ก์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ์ €์žฅํ•˜๋Š” ๋กœ์ง ๋˜ํ•œ ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•œ๋‹ค. ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ๋‹ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์ด get_session_history(์„ธ์…˜์— ๋Œ€ํ•œ ์ฑ„ํŒ… ๊ธฐ๋ก์ด ์žˆ์œผ๋ฉด ๊ธฐ๋ก์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์—†์œผ๋ฉด ์ €์žฅ ํ›„ ๋ฐ˜ํ™˜)์ด๋‹ค.

 

chat history๋ฅผ ๋ฐ˜์˜ํ•˜๋Š” rag chain์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” RunnableWithMessageHistory ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

 

โœ…RunnableWithMessageHistory:

๋Œ€ํ™” ํžˆ์Šคํ† ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜์—ฌ Runnable ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” ํด๋ž˜์Šค. ๊ตฌํ˜„์„ ์œ„ํ•ด ์•„๋ž˜์˜ ์ด 5๊ฐœ์˜ ์ธ์ž๋ฅผ ํ™œ์šฉํ•œ๋‹ค.
1. runnable: ๋ฐ›์€ ์ธ์ž๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹คํ–‰ํ•  ์ฒด์ธ
2. get_session_history: ์„ธ์…˜ID ํ‚ค ๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” ์ฑ„ํŒ… ๊ธฐ๋ก ๋ฐ์ดํ„ฐ
3. input_messages_key: ์œ ์ €์˜ ์ž…๋ ฅ์ด ํฌํ•จ๋˜๋Š” ํ‚ค ๊ฐ’
4. history_messages_key: ์œ ์ €์˜ ์ฑ„ํŒ… ๊ธฐ๋ก์„ ์ €์žฅํ•  ํ‚ค ๊ฐ’
5. output_messages_key: ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ํ‚ค ๊ฐ’
# ์„ธ์…˜ ๊ธฐ๋ก์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜ ์„ค์ •
def get_session_history(session_id: str) -> BaseChatMessageHistory:
    # ์„ธ์…˜์ด ์—†์œผ๋ฉด ํ•ด๋‹น ์„ธ์…˜์— ๋Œ€ํ•œ ์ฑ„ํŒ…๊ธฐ๋ก ์ƒ์„ฑ
    if session_id not in chat_storage:
        chat_storage[session_id] = ChatMessageHistory()
    return chat_storage[session_id]

# RAG ์ฒด์ธ์„ ์ƒ์„ฑ
def get_rag_chain():
    
    llm = get_llm()
    
    # ๋ชจ๋ธ์˜ ์—ญํ• ์„ ์ •์˜ํ•ด์ฃผ๊ธฐ ์œ„ํ•œ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ
    system_prompt = ("""
            ๋‹น์‹ ์€ ์ตœ๊ณ ์˜ KBO ๋ฆฌ๊ทธ ์•ผ๊ตฌ ๊ทœ์น™ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. 
            ์•„๋ž˜์˜ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์„ ํ•ด์ฃผ์„ธ์š”.
            ๋‹ต๋ณ€ ์‹œ์— ์ถœ์ฒ˜์— ๋Œ€ํ•ด์„œ๋„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ฐํ˜€์ฃผ์‹œ๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
            ๋‹ต๋ณ€์˜ ๊ธธ์ด๋Š” 2-3์ค„ ์ •๋„๋กœ ์ œํ•œํ•ด์ฃผ์„ธ์š”.
            \n\n
            ๋ฌธ์„œ: {context}
    """)
    
    # ์ฑ„ํŒ… ๊ธฐ๋ก ๋ฐ˜์˜ํ•˜์—ฌ QA๋ฅผ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ
    qa_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", system_prompt),
            MessagesPlaceholder("chat_history"), # ๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ(์ฑ„ํŒ… ๊ธฐ๋ก)๋ฅผ ์ „๋‹ฌ
            ("human", "{input}")
        ]
    )
    
    history_aware_retriever = get_history_retriever() # ๊ธฐ๋ก ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰์„ ์œ„ํ•œ retriever
    qa_chain = create_stuff_documents_chain(llm, qa_prompt) # ๋ชจ๋ธ์—๊ฒŒ ๊ฒ€์ƒ‰ํ•œ ๋ฌธ์„œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „๋‹ฌ
    rag_chain = create_retrieval_chain(history_aware_retriever, qa_chain) # RAG ์ฒด์ธ ์ƒ์„ฑ
    
    conversational_rag_chain = RunnableWithMessageHistory(
        rag_chain, # ์‹คํ–‰ํ•  RAG ์ฒด์ธ์ด๋‚˜ LLM ์ฒด์ธ
        get_session_history, # ์„ธ์…˜_ID ๊ธฐ๋ฐ˜์˜ ์ฑ„ํŒ… ๊ธฐ๋ก
        input_messages_key="input", # ์œ ์ €์˜ ์ž…๋ ฅ์ด ๋‹ด๊ธด ํ‚ค
        history_messages_key="chat_history", # ์ฑ„ํŒ… ๊ธฐ๋ก์„ ์ „๋‹ฌํ•  ํ‚ค
        output_messages_key="answer" # ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ํ‚ค
    ).pick("answer") # AI์˜ ์‘๋‹ต๋งŒ ์„ ํƒํ•ด์„œ ๋ฐ˜ํ™˜
    
    # ์ฑ„ํŒ… history๋ฅผ ํฌํ•จํ•œ retriever๋ฅผ ํ™œ์šฉํ•˜์—ฌ rag_chain ๋ฐ˜ํ™˜
    return conversational_rag_chain

์ดํ›„์— rag_chain์„ invokeํ•˜๊ณ  ์•ž์„œ ์ž‘์„ฑํ•œ ๋ชจ๋“  ์ฒด์ธ์„ ๋™์ž‘์‹œํ‚ค๊ธฐ ์œ„ํ•œ get_ai_responseํ•จ์ˆ˜๋ฅผ ์•„๋ž˜์™€ ์ž‘์„ฑํ•ด๋ณด์ž. ์•ž์„œ ์ž‘์„ฑํ•œ filter_chain, dictionary_chain, rag_chain์„ ์ฒด์ด๋‹ํ•ด์„œ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ํ•ด๋‹น ํŒŒ์ดํ”„๋ผ์ธ์„ invoke ํ•œ๋‹ค. ์ด ๋•Œ filter_chain์—์„œ ์ฟผ๋ฆฌ๋ฅผ "question" ํ‚ค ๊ฐ’์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— question์— ์‚ฌ์šฉ์ž ์งˆ๋ฌธ์„ ์ €์žฅํ•ด์„œ ๋„˜๊ฒจ์ฃผ๊ณ  conversational_rag_chain ๋™์ž‘์„ ์œ„ํ•ด์„œ๋Š” session_id๊ฐ€ ํ•„์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— config์˜ configurable ๊ฐ’์„ ํ†ตํ•ด session_id๋ฅผ ๋„˜๊ฒจ์ฃผ๋„๋ก ํ•˜์ž.

def get_ai_response():
    
    filter_chain = get_filter()
    dictionary_chain = get_dictionary_chain()
    rag_chain = get_rag_chain()
    
    baseball_chain = filter_chain | {"input": dictionary_chain} | rag_chain
    
    ai_response = baseball_chain.invoke(
        {"question": "์•ผ๊ตฌ์—์„œ ์ฃผ์ž ํ•œ๋ช…์ด ๋ฒ ์ด์Šค๋ฅผ ํ›”์น˜๋Š” ๊ฒƒ์„ ๋ญ๋ผ๊ณ  ํ•˜๋‚˜์š”?"},
        config={"configurable": {"session_id": "abc123"}}
    )
    
    return ai_response

์ง€๊ธˆ๊นŒ์ง€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ํ•˜๋‚˜์˜ .py ํŒŒ์ผ๋กœ ์˜ฎ๊ธฐ๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ์•„๋ž˜์˜ llm.py ํŒŒ์ผ์„ ์‹คํ–‰์‹œ์ผœ๋ณด์ž.

# llm.py

from langchain_upstage import ChatUpstage, UpstageEmbeddings
from langchain_pinecone import PineconeVectorStore
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain.chains import create_history_aware_retriever, create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory

chat_storage = {}

def get_llm():
    llm = ChatUpstage()
    return llm

# ์งˆ๋ฌธ์ด ์ฃผ์ œ์™€ ๊ด€๋ จ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ•„ํ„ฐ ์„ค์ •
def get_filter():
    llm = get_llm()
    
    filter_prompt = ChatPromptTemplate.from_template(f"""
        ์œ ์ €์˜ ์งˆ๋ฌธ์ด ์•ผ๊ตฌ์™€ ๊ด€๋ จ๋œ ์งˆ๋ฌธ์ธ์ง€ ํ™•์ธํ•˜๊ณ , ์•ผ๊ตฌ์™€ ๊ด€๋ จ๋œ ์งˆ๋ฌธ์ผ ๊ฒฝ์šฐ์—๋Š” "YES" ๋ผ๋Š” ๋‹ต๋ณ€์„, ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” "NO" ๋ผ๋Š” ๋‹ต๋ณ€์„ ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š”.
        ์งˆ๋ฌธ: {{question}}
                                                     """)
    
    filtering_chain = filter_prompt | llm | StrOutputParser()
    return filtering_chain
    
# ์‚ฌ์ „์„ ์ฐธ๊ณ ํ•˜์—ฌ ์œ ์ €์˜ ์งˆ๋ฌธ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ์„ค์ •
def get_dictionary_chain():
    
    llm = get_llm()
    
    dictionary = [
        "๋ฒ ์ด์Šค์— ์žˆ๋Š” ์„ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‘œํ˜„ -> ์ฃผ์ž",
        "ํƒ€์„์— ์žˆ๋Š” ์„ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‘œํ˜„ -> ํƒ€์ž",
        "๋งˆ์šด๋“œ ์œ„์—์„œ ๊ณต์„ ๋˜์ง€๋Š” ์„ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‘œํ˜„ -> ํˆฌ์ˆ˜",
        "๋ญ๋ผ๊ณ  ํ•˜๋‚˜์š”?, ๋ญ๋ผ๊ณ  ๋ถ€๋ฅด๋‚˜์š”(๋ฌด์—‡์ด๋ƒ๊ณ  ๋ฌผ์„ ๊ฒฝ์šฐ) -> ๋œปํ•˜๋Š” ์šฉ์–ด๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€์š”?"
    ]
    
    dictionary_prompt = ChatPromptTemplate.from_template(f"""
        ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์„ ํ™•์ธํ•˜๊ณ  ์‚ฌ์ „์„ ์ฐธ๊ณ ํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์„ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”.
        ๋งŒ์•ฝ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๊ณ  ํŒ๋‹จ๋˜๋ฉด ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์งˆ๋ฌธ์„ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š”.
        ์‚ฌ์ „: {dictionary}
        ์งˆ๋ฌธ: {{question}}
                                                         """)
    
    dictionary_chain = dictionary_prompt | llm | StrOutputParser()
    return dictionary_chain
    
# ๋ฌธ์„œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•œ retriever ์„ค์ •
def get_retriever():
    
    index_name = "baseball-rules-index"

    # ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒกํ„ฐํ™”ํ•  ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ ์„ค์ •
    embedding = UpstageEmbeddings(model="solar-embedding-1-large")
    database = PineconeVectorStore.from_existing_index(index_name=index_name, embedding=embedding)
    retriever = database.as_retriever(search_kwargs={"k": 4})
    return retriever
    
# chat history๋ฅผ ๋ฐ˜์˜ํ•˜์—ฌ ์งˆ๋ฌธ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ์„ค์ •
def get_history_retriever():
    llm = get_llm()
    retriever = get_retriever()
    
    # chat history๋ฅผ ๋ฐ˜์˜ํ•˜์—ฌ ์งˆ๋ฌธ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ
    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."
    )
    
    # ์ฑ„ํŒ… ๊ธฐ๋ก์„ ๋ฐ˜์˜ํ•˜์—ฌ QA๋ฅผ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ
    contextualize_q_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", contextualize_q_system_prompt),
            MessagesPlaceholder("chat_history"), # ๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „๋‹ฌ
            ("human", "{input}")
        ]
    )
    
    history_aware_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)
    return history_aware_retriever
    
# ์„ธ์…˜ ๊ธฐ๋ก์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜ ์„ค์ •
def get_session_history(session_id: str) -> BaseChatMessageHistory:
    # ์„ธ์…˜์ด ์—†์œผ๋ฉด ํ•ด๋‹น ์„ธ์…˜์— ๋Œ€ํ•œ ์ฑ„ํŒ…๊ธฐ๋ก ์ƒ์„ฑ
    if session_id not in chat_storage:
        chat_storage[session_id] = ChatMessageHistory()
    return chat_storage[session_id]
    
# RAG ์ฒด์ธ์„ ์ƒ์„ฑ
def get_rag_chain():
    
    llm = get_llm()
    
    # ๋ชจ๋ธ์˜ ์—ญํ• ์„ ์ •์˜ํ•ด์ฃผ๊ธฐ ์œ„ํ•œ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ
    system_prompt = ("""
            ๋‹น์‹ ์€ ์ตœ๊ณ ์˜ KBO ๋ฆฌ๊ทธ ์•ผ๊ตฌ ๊ทœ์น™ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. 
            ์•„๋ž˜์˜ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์„ ํ•ด์ฃผ์„ธ์š”.
            ๋‹ต๋ณ€ ์‹œ์— ์ถœ์ฒ˜์— ๋Œ€ํ•ด์„œ๋„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ฐํ˜€์ฃผ์‹œ๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
            ๋‹ต๋ณ€์˜ ๊ธธ์ด๋Š” 2-3์ค„ ์ •๋„๋กœ ์ œํ•œํ•ด์ฃผ์„ธ์š”.
            \n\n
            ๋ฌธ์„œ: {context}
    """)
    
    # ์ฑ„ํŒ… ๊ธฐ๋ก ๋ฐ˜์˜ํ•˜์—ฌ QA๋ฅผ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ
    qa_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", system_prompt),
            MessagesPlaceholder("chat_history"), # ๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ(์ฑ„ํŒ… ๊ธฐ๋ก)๋ฅผ ์ „๋‹ฌ
            ("human", "{input}")
        ]
    )
    
    history_aware_retriever = get_history_retriever() # ๊ธฐ๋ก ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰์„ ์œ„ํ•œ retriever
    qa_chain = create_stuff_documents_chain(llm, qa_prompt) # ๋ชจ๋ธ์—๊ฒŒ ๊ฒ€์ƒ‰ํ•œ ๋ฌธ์„œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „๋‹ฌ
    rag_chain = create_retrieval_chain(history_aware_retriever, qa_chain) # RAG ์ฒด์ธ ์ƒ์„ฑ
    
    conversational_rag_chain = RunnableWithMessageHistory(
        rag_chain, # ์‹คํ–‰ํ•  RAG ์ฒด์ธ์ด๋‚˜ LLM ์ฒด์ธ
        get_session_history, # ์„ธ์…˜_ID ๊ธฐ๋ฐ˜์˜ ์ฑ„ํŒ… ๊ธฐ๋ก
        input_messages_key="input", # ์œ ์ €์˜ ์ž…๋ ฅ์ด ๋‹ด๊ธด ํ‚ค
        history_messages_key="chat_history", # ์ฑ„ํŒ… ๊ธฐ๋ก์„ ์ „๋‹ฌํ•  ํ‚ค
        output_messages_key="answer" # ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ํ‚ค
    ).pick("answer")
    
    # ์ฑ„ํŒ… history๋ฅผ ํฌํ•จํ•œ retriever๋ฅผ ํ™œ์šฉํ•˜์—ฌ rag_chain ๋ฐ˜ํ™˜
    return conversational_rag_chain
    
def get_ai_response():
    
    filter_chain = get_filter()
    dictionary_chain = get_dictionary_chain()
    rag_chain = get_rag_chain()
    
    baseball_chain = filter_chain | {"input": dictionary_chain} | rag_chain
    
    ai_response = baseball_chain.invoke(
        {"question": "์•ผ๊ตฌ์—์„œ ์ฃผ์ž ํ•œ๋ช…์ด ๋ฒ ์ด์Šค๋ฅผ ํ›”์น˜๋Š” ๊ฒƒ์„ ๋ญ๋ผ๊ณ  ํ•˜๋‚˜์š”?"},
        config={"configurable": {"session_id": "abc123"}}
    )
    
    return ai_response

ai_response = get_ai_response()
print(ai_response)

๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค. ๊ธฐ์กด ํŒŒ์ดํ”„๋ผ์ธ์˜ ํ๋ฆ„์„ ์ •๋ฆฌํ•ด๋ณด์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€๋ฐ, dictionary_chain์˜ ๊ฒฐ๊ณผ๊ฐ’์ธ input์„ ๋ณด๋ฉด ์งˆ๋ฌธ์ด ์—†๊ฑฐ๋‚˜ ๋ช…ํ™•ํ•˜์ง€ ์•Š๋‹ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. filter chain์„ ํ†ตํ•ด ์ž…๋ ฅ๋œ query์˜ ๊ฒฐ๊ณผ๋ฌผ์ธ YES ๋‚˜ NO ๊ฐ€ dictionary chain์— ์ž…๋ ฅ๋œ๋‹ค. dictionary chain์—์„œ๋Š” "YES" ๋‚˜ "NO" ์ฟผ๋ฆฌ๋ฅผ dictionary๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์žฌ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๋‹น์—ฐํžˆ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๋”ฐ๋ผ์„œ "์งˆ๋ฌธ์ด ์—†๊ฑฐ๋‚˜ ์ž˜๋ชป๋œ ํ˜•์‹์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค...."์™€ ๊ฐ™์€ ๋‹ต๋ณ€์„ ์ถœ๋ ฅํ•˜๊ณ  ์ด ๋‹ต๋ณ€์„ rag chain์— ๋„˜๊ฒจ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰ filter_chain์—์„œ dictionary_chain์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ธฐ๋Š” ๊ณผ์ •์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

์‚ฌ์‹ค ์ƒ๊ฐํ•ด๋ณด๋ฉด chat history๋ฅผ ํ™œ์šฉํ•˜๋Š” ์‹œ์ ์—์„œ filter chain์€ ํ•„์š”๊ฐ€ ์—†๊ณ  ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์— ์˜คํžˆ๋ ค ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

 

1๏ธโƒฃ์ฒซ ๋ฒˆ์งธ ์งˆ๋ฌธ: "์•ผ๊ตฌ์—์„œ ์ฃผ์ž ํ•œ๋ช…์ด ๋„๋ฃจํ•˜๋Š” ๊ฒƒ์„ ๋ญ๋ผ๊ณ  ํ•ด?"

2๏ธโƒฃ๋‘ ๋ฒˆ์งธ ์งˆ๋ฌธ: "๊ทธ๋Ÿผ 2๋ช…์ด ํ•˜๋Š”๊ฑด?"

 

๋‘ ์งˆ๋ฌธ์ด ์„œ๋กœ ๊ฐ™์€ ๋ฌธ๋งฅ์˜ ์งˆ๋ฌธ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  filter chain(๊ฐ€์žฅ ๋จผ์ € ๋™์ž‘ํ•˜๋Š” ์ฒด์ธ, history retriever๋ณด๋‹ค ๋จผ์ € ๋™์ž‘ํ•œ๋‹ค)์—์„œ ๋‘ ๋ฒˆ์งธ ์งˆ๋ฌธ์„ ์•ผ๊ตฌ ๊ทœ์น™๊ณผ ์—ฐ๊ด€์„ฑ์ด ์—†๋Š” ์งˆ๋ฌธ์œผ๋กœ ํŒ๋‹จํ•˜๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ filter chain์„ ์ œ๊ฑฐํ•˜๊ณ  ํ•ด๋‹น ๊ธฐ๋Šฅ์„ rag chain์— ์œ„์ž„ํ•˜๋Š” ๊ฒƒ๋„ ๋‚˜์˜์ง€ ์•Š์€ ์„ ํƒ์ด๋‹ค. filter chain์„ ์‚ญ์ œํ•˜๊ณ  rag chain์—์„œ ํ•„ํ„ฐ๋ง์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ˆ˜์ •ํ•˜์ž.

# RAG ์ฒด์ธ์„ ์ƒ์„ฑ
def get_rag_chain():
    
    llm = get_llm()
    
    # ๋ชจ๋ธ์˜ ์—ญํ• ์„ ์ •์˜ํ•ด์ฃผ๊ธฐ ์œ„ํ•œ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ
    system_prompt = ("""
            ๋‹น์‹ ์€ ์ตœ๊ณ ์˜ KBO ๋ฆฌ๊ทธ ์•ผ๊ตฌ ๊ทœ์น™ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. 
            ์•„๋ž˜์˜ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์„ ํ•ด์ฃผ์„ธ์š”.
            
            ๋จ„์•ฝ์— ์•ผ๊ตฌ ๊ทœ์น™๊ณผ ๊ด€๋ จ์ด ์—†๋‹ค๋ฉด "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."๋ผ๊ณ  ๋‹ต๋ณ€ํ•ด์ฃผ์„ธ์š”.
            ๋งŒ์•ฝ์— ๋‹ต๋ณ€ํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ๋ชจ๋ฅธ๋‹ค๊ณ  ๋‹ต๋ณ€ํ•ด์ฃผ์„ธ์š”.
            
            ๋‹ต๋ณ€ ์‹œ์— ์ถœ์ฒ˜์— ๋Œ€ํ•ด์„œ๋„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ฐํ˜€์ฃผ์‹œ๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
            ๋‹ต๋ณ€์˜ ๊ธธ์ด๋Š” 2-3์ค„ ์ •๋„๋กœ ์ œํ•œํ•ด์ฃผ์„ธ์š”.
            \n\n
            ๋ฌธ์„œ: {context}
    """)
    
    # ์ฑ„ํŒ… ๊ธฐ๋ก ๋ฐ˜์˜ํ•˜์—ฌ QA๋ฅผ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ
    qa_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", system_prompt),
            MessagesPlaceholder("chat_history"), # ๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ(์ฑ„ํŒ… ๊ธฐ๋ก)๋ฅผ ์ „๋‹ฌ
            ("human", "{input}")
        ]
    )
    
    history_aware_retriever = get_history_retriever() # ๊ธฐ๋ก ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰์„ ์œ„ํ•œ retriever
    qa_chain = create_stuff_documents_chain(llm, qa_prompt) # ๋ชจ๋ธ์—๊ฒŒ ๊ฒ€์ƒ‰ํ•œ ๋ฌธ์„œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „๋‹ฌ
    rag_chain = create_retrieval_chain(history_aware_retriever, qa_chain) # RAG ์ฒด์ธ ์ƒ์„ฑ
    
    conversational_rag_chain = RunnableWithMessageHistory(
        rag_chain, # ์‹คํ–‰ํ•  RAG ์ฒด์ธ์ด๋‚˜ LLM ์ฒด์ธ
        get_session_history, # ์„ธ์…˜_ID ๊ธฐ๋ฐ˜์˜ ์ฑ„ํŒ… ๊ธฐ๋ก
        input_messages_key="input", # ์œ ์ €์˜ ์ž…๋ ฅ์ด ๋‹ด๊ธด ํ‚ค
        history_messages_key="chat_history", # ์ฑ„ํŒ… ๊ธฐ๋ก์„ ์ „๋‹ฌํ•  ํ‚ค
        output_messages_key="answer" # ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ํ‚ค
    ).pick("answer")
    
    # ์ฑ„ํŒ… history๋ฅผ ํฌํ•จํ•œ retriever๋ฅผ ํ™œ์šฉํ•˜์—ฌ rag_chain ๋ฐ˜ํ™˜
    return conversational_rag_chain
    
def get_ai_response():
    
    dictionary_chain = get_dictionary_chain()
    rag_chain = get_rag_chain()
    
    baseball_chain = {"input": dictionary_chain} | rag_chain
    
    ai_response = baseball_chain.invoke(
        {"question": "์•ผ๊ตฌ์—์„œ ์ฃผ์ž ํ•œ๋ช…์ด ๋ฒ ์ด์Šค๋ฅผ ํ›”์น˜๋Š” ๊ฒƒ์„ ๋ญ๋ผ๊ณ  ํ•˜๋‚˜์š”?"},
        config={"configurable": {"session_id": "abc123"}}
    )
    
    return ai_response

๋‘ ์งˆ๋ฌธ์— ๋Œ€ํ•ด ๋‹ต๋ณ€์„ ์ž˜ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿšจ์—ฌ๋Ÿฌ ๋ฒˆ ํ•ด๋ณด๋‹ˆ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋Š”๋ฐ, ์ฒซ ๋ฒˆ์งธ ์งˆ๋ฌธ์—์„œ๋Š” ์ œ๋Œ€๋กœ ๋‹ต๋ณ€์„ ํ•˜์ง€๋งŒ ์ด์ „ ์ฑ„ํŒ… ๊ธฐ๋ก์„ ํ† ๋Œ€๋กœ ๋ฌธ๋งฅ์„ ์œ ์ถ”ํ•ด์„œ ๋‹ต๋ณ€์„ ํ•ด์•ผ ํ•˜๋Š” "๊ทธ๋Ÿผ ๋‘ ๋ช…์ด ๋™์‹œ์— ํ•˜๋Š” ๊ฑด ๋ญ๋ผ๊ณ  ํ•ด?" ๊ฐ™์€ ์งˆ๋ฌธ์—๋Š” ์—‰๋šฑํ•œ ๋‹ต๋ณ€์„ ํ•˜๊ฑฐ๋‚˜ ์ œ๋Œ€๋กœ ๋‹ตํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์ข…์ข… ์žˆ๋‹ค.

์ •๋‹ต์€ ๋”๋ธ”์Šคํ‹ธ์ธ๋ฐ ์—‰๋šฑํ•œ ๋‹ต๋ณ€์„ ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š” ์ด์œ ๋Š” dictionary chain์—์„œ "๋‘ ๋ช…์ด ๋™์‹œ์— ํ•˜๋Š”๊ฑด ๋ญ๋ผ๊ณ  ํ•ด?"์™€ ๊ฐ™์€ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๊ฐ•์„ ํ•œ๋‹ต์‹œ๊ณ  ํ”„๋กฌํ”„ํŠธ๋ฅผ ํ†ตํ•ด ๋ณ€๊ฒฝ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฟผ๋ฆฌ๊ฐ€ ๋ชจํ˜ธํ•˜๋”๋ผ๋„ dictionary chain ์ดํ›„์˜ history retriever์—์„œ chat history๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋ฌธ๋งฅ ํŒŒ์•…์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— dictionary chain์—์„œ ์•ฝ๊ฐ„์˜ ์šฉ์–ด ์ˆ˜์ •์„ ํ†ตํ•ด ์ฟผ๋ฆฌ๋ฅผ ๋ณด๊ฐ•ํ•˜๋˜ ์•„์˜ˆ ๋ชจํ˜ธํ•œ ์งˆ๋ฌธ์— ๋Œ€ํ•ด์„œ๋Š” ์ˆ˜์ •์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•ด์•ผํ•œ๋‹ค. 

 

๋ชจํ˜ธํ•œ ์งˆ๋ฌธ์— ๋Œ€ํ•ด์„œ๋Š” ๋ฌธ๋งฅ ํŒŒ์•…์„ ํ†ตํ•ด ์ฟผ๋ฆฌ ์ˆ˜์ •์„ ํ•˜๋„๋ก dictionary chain์˜ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์กฐ๊ธˆ ์ˆ˜์ •ํ•ด๋ณด์ž.

# ์‚ฌ์ „์„ ์ฐธ๊ณ ํ•˜์—ฌ ์œ ์ €์˜ ์งˆ๋ฌธ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ์„ค์ •
def get_dictionary_chain():
    
    llm = get_llm()
    
    dictionary = [
        "๋ฒ ์ด์Šค์— ์žˆ๋Š” ์„ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‘œํ˜„ -> ์ฃผ์ž",
        "ํƒ€์„์— ์žˆ๋Š” ์„ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‘œํ˜„ -> ํƒ€์ž",
        "๋งˆ์šด๋“œ ์œ„์—์„œ ๊ณต์„ ๋˜์ง€๋Š” ์„ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‘œํ˜„ -> ํˆฌ์ˆ˜"
    ]
    
    dictionary_prompt = ChatPromptTemplate.from_template(f"""
        ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์„ ํ™•์ธํ•˜๊ณ  ์‚ฌ์ „์„ ์ฐธ๊ณ ํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์„ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”.
        ๋งŒ์•ฝ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๊ณ  ํŒ๋‹จ๋˜๋ฉด ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์งˆ๋ฌธ์„ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š”.
        ์งˆ๋ฌธ์ด๋‚˜ ์ฃผ์–ด๊ฐ€ ๋ชจํ˜ธํ•  ๊ฒฝ์šฐ history retriever์—์„œ history chat์„ ์ฐธ๊ณ ํ•˜์—ฌ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋„๋ก ์งˆ๋ฌธ์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š”.
        ์‚ฌ์ „: {dictionary}
        ์งˆ๋ฌธ: {{question}}
                                                         """)
    
    dictionary_chain = dictionary_prompt | llm | StrOutputParser()
    return dictionary_chain

๊ฒฐ๊ณผ๊ฐ€ ์ž˜ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.


Few-shot ์ถ”๊ฐ€ํ•˜๊ธฐ

์ฝ”๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ๋Œ๋ ค๋ณด๋ฉด ๋‹ต๋ณ€์ด ์ผ๊ด€์ ์ด์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค("๋”๋ธ” ์Šคํ‹ธ", ~~ํ•˜๋Š” ๊ฒƒ์„ "๋”๋ธ”์Šคํ‹ธ"์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค... ๋“ฑ). ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ๋„ ์ผ๊ด€์ ์ธ ํ˜•ํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋‹ต๋ณ€์„ ๋ณด๋Š” ๊ฒƒ์ด ํŽธํ•˜๋‹ˆ Few-shot์„ ์ถ”๊ฐ€ํ•ด๋ณด์ž(shot์ด ์—†๋Š” ๊ฒƒ์„ Zero-shot, ํ•˜๋‚˜์ธ ๊ฒƒ์„ One-shot, Single-shot์œผ๋กœ ๋ถ€๋ฅด๊ธฐ๋„ ํ•œ๋‹ค).

 

Few-shot์ด๋ž€ ์‰ฝ๊ฒŒ ๋งํ•ด ์˜ˆ์‹œ ์งˆ๋ฌธ๊ณผ ๋‹ต๋ณ€์„ ์ฃผ๊ณ  ์ด๋Ÿฐ ์‹์œผ๋กœ ๋‹ต๋ณ€ํ•˜๋ฉด ๋ผ! ๋ผ๊ณ  ๋ชจ๋ธ์—๊ฒŒ ๋ฏธ๋ฆฌ ๊ฐ€๋ฅด์น˜๋Š” ๊ฒƒ์ด๋‹ค. ๋ชจ๋ธ์ด ์ƒˆ๋กœ์šด ์งˆ๋ฌธ์„ ๋ฐ›์„ ๋•Œ ๋ฏธ๋ฆฌ ํ•™์Šตํ•œ ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜๋„๋ก ํ•˜๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.

๋А๋‚€ ๋ฐ”๋กœ๋Š” ์•„๋ž˜์˜ ์žฅ์ ์ด ์žˆ๋‹ค.

 

1. hallucination(ํ™˜๊ฐ) ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์„ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ๋‹ค. ์ฃผ์ œ๋ฅผ ๋ฒ—์–ด๋‚˜๋Š” ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ต๋ณ€ํ•˜์ง€ ์•Š๋„๋ก ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ํ•™์Šต์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

2. ๋‹ต๋ณ€ ์–‘์‹์„ ํ†ต์ผ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ๋‹ต๋ณ€ ์–‘์‹์— ๋งž์ถฐ ์ผ๊ด€๋œ ๋‹ต๋ณ€ ํ˜•์‹์„ ์œ ์ €์—๊ฒŒ ์ œ๊ณตํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

3. ๊ทธ ๋ฐ–์˜ ์ž์ž˜ํ•œ ๋ชจ๋ธ์˜ ์˜ค์ž‘๋™ ๋ฐฉ์ง€(๋ฌธ๋งฅ ํŒŒ์•… ์˜ค๋ฅ˜ ๋“ฑ)์™€ ๋” ์ •ํ™•ํ•œ ๋‹ต๋ณ€ ์ƒ์„ฑ

 

์ด์ „์— ์ง„ํ–‰ํ–ˆ๋˜ ํ”„๋กœ์ ํŠธ Cquis์—์„œ๋„ OPENAI ๋ชจ๋ธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž‘์„ฑํ–ˆ์—ˆ๋Š”๋ฐ ๊ทธ ๋•Œ๋Š” Few-shot์˜ ๊ฐœ๋…๋„ ์ž˜ ๋ชจ๋ฅด๋Š” ์ฑ„๋กœ ๋‚˜๋ฆ„๋Œ€๋กœ hallucination์„ ์žก๊ฒ ๋‹ค๊ณ  ๋…ธ๋ ฅํ–ˆ์—ˆ๋‹ค. 

๋‹ต๋ณ€ ์–‘์‹ ์ผ๊ด€์„ฑ์„ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ์˜ ์ผ๋ถ€
์ฃผ์ œ์™€ ๋ฌด๊ด€ํ•œ ์ฟผ๋ฆฌ์˜ ์˜ˆ์‹œ๋ฅผ ๋ฏธ๋ฆฌ ํ•™์Šต์‹œ์ผฐ๋‹ค.

few shot์€ ์ตœ์ข… qa_prompt์—์„œ ์ฐธ๊ณ ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ChatPromptTemplate.from_messages์˜ ์ธ์ž๋กœ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ํ”„๋กฌํ”„ํŠธ ์‹คํ–‰ ์‹œ์— ์ถ”๊ฐ€ํ•œ few shot ๊ด€๋ จ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•œ๋‹ค. example_prompt๋ฅผ ํ†ตํ•ด ๋ฏธ๋ฆฌ ๋Œ€ํ™” ํ˜•์‹์˜ ํ‹€์„ ์ œ๊ณตํ•ด์ฃผ๊ณ  answer_examples๋ฅผ ํ†ตํ•ด ์งˆ๋‹ต ์˜ˆ์‹œ๋ฅผ ๋ฏธ๋ฆฌ ํ•™์Šต์‹œํ‚จ๋‹ค.

# RAG ์ฒด์ธ์„ ์ƒ์„ฑ
def get_rag_chain():
    
    llm = get_llm()
    
    # few-shot์„ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ ์„ค์ •
    example_prompt = ChatPromptTemplate.from_messages(
        [
            ("human", "{input}"),
            ("ai", "{answer}")
        ]
    )
    
    # few-shot์„ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ ์„ค์ •
    few_shot_prompt = FewShotChatMessagePromptTemplate(
        example_prompt=example_prompt,
        examples=answer_examples
    )
    
    # ๋ชจ๋ธ์˜ ์—ญํ• ์„ ์ •์˜ํ•ด์ฃผ๊ธฐ ์œ„ํ•œ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ
    system_prompt = ("""
            ๋‹น์‹ ์€ ์ตœ๊ณ ์˜ KBO ๋ฆฌ๊ทธ ์•ผ๊ตฌ ๊ทœ์น™ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. 
            ์•„๋ž˜์˜ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์„ ํ•ด์ฃผ์„ธ์š”.
            
            ๋จ„์•ฝ์— ์•ผ๊ตฌ ๊ทœ์น™๊ณผ ๊ด€๋ จ์ด ์—†๋‹ค๋ฉด "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."๋ผ๊ณ  ๋‹ต๋ณ€ํ•ด์ฃผ์„ธ์š”.
            ๋งŒ์•ฝ์— ๋‹ต๋ณ€ํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ๋ชจ๋ฅธ๋‹ค๊ณ  ๋‹ต๋ณ€ํ•ด์ฃผ์„ธ์š”.
            
            ๋‹ต๋ณ€ ์‹œ์— ์ถœ์ฒ˜์— ๋Œ€ํ•ด์„œ๋„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ฐํ˜€์ฃผ์‹œ๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
            ๋‹ต๋ณ€์˜ ๊ธธ์ด๋Š” 2-3์ค„ ์ •๋„๋กœ ์ œํ•œํ•ด์ฃผ์„ธ์š”.
            \n\n
            ๋ฌธ์„œ: {context}
    """)
    
    # ์ฑ„ํŒ… ๊ธฐ๋ก ๋ฐ˜์˜ํ•˜์—ฌ QA๋ฅผ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ
    qa_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", system_prompt),
            few_shot_prompt, # few-shot์„ ์ฐธ๊ณ ํ•˜๋„๋ก ์ „๋‹ฌ
            MessagesPlaceholder("chat_history"), # ๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ(์ฑ„ํŒ… ๊ธฐ๋ก)๋ฅผ ์ „๋‹ฌ
            ("human", "{input}")
        ]
    )
    
    history_aware_retriever = get_history_retriever() # ๊ธฐ๋ก ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰์„ ์œ„ํ•œ retriever
    qa_chain = create_stuff_documents_chain(llm, qa_prompt) # ๋ชจ๋ธ์—๊ฒŒ ๊ฒ€์ƒ‰ํ•œ ๋ฌธ์„œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „๋‹ฌ
    rag_chain = create_retrieval_chain(history_aware_retriever, qa_chain) # RAG ์ฒด์ธ ์ƒ์„ฑ
    
    conversational_rag_chain = RunnableWithMessageHistory(
        rag_chain, # ์‹คํ–‰ํ•  RAG ์ฒด์ธ์ด๋‚˜ LLM ์ฒด์ธ
        get_session_history, # ์„ธ์…˜_ID ๊ธฐ๋ฐ˜์˜ ์ฑ„ํŒ… ๊ธฐ๋ก
        input_messages_key="input", # ์œ ์ €์˜ ์ž…๋ ฅ์ด ๋‹ด๊ธด ํ‚ค
        history_messages_key="chat_history", # ์ฑ„ํŒ… ๊ธฐ๋ก์„ ์ „๋‹ฌํ•  ํ‚ค
        output_messages_key="answer" # ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ํ‚ค
    ).pick("answer")
    
    # ์ฑ„ํŒ… history๋ฅผ ํฌํ•จํ•œ retriever๋ฅผ ํ™œ์šฉํ•˜์—ฌ rag_chain ๋ฐ˜ํ™˜
    return conversational_rag_chain

์•„๋ž˜์™€ ๊ฐ™์€ ์งˆ๋‹ต ์˜ˆ์‹œ ๋ฌธ์„œ๋ฅผ ๋”ฐ๋กœ ์ž‘์„ฑํ•ด์„œ llm.py์— import ์‹œ์ผฐ๋‹ค.

# fewshot_doc.py

answer_examples = [
    {
        "input": "์ฃผ์ž๊ฐ€ ๋‘ ๋ช…์ด ๋™์‹œ์— ๋„๋ฃจํ•˜๋Š” ๊ฒƒ์„ ๋ญ๋ผ๊ณ  ํ•ด?",
        "answer": "์ฃผ์ž ๋‘ ๋ช…์ด ๋™์‹œ์— ๋„๋ฃจํ•˜๋Š” ๊ฒƒ์€ '๋”๋ธ” ์Šคํ‹ธ'์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค!\n\n"
                  "๋”๋ธ” ์Šคํ‹ธ(Double Steal)์€ ๋‘ ๋ช… ์ด์ƒ์˜ ์ฃผ์ž๊ฐ€ ๋™์‹œ์— ๋‹ค์Œ ๋ฒ ์ด์Šค๋กœ ๋„๋ฃจํ•˜๋Š” ์ „๋žต์  ํ”Œ๋ ˆ์ด์ž…๋‹ˆ๋‹ค. "
                  "ํŠนํžˆ, ์ˆ˜๋น„ ํŒ€์ด ํ•œ ์ฃผ์ž์—๊ฒŒ ์ง‘์ค‘ํ•  ๋•Œ ๋‹ค๋ฅธ ์ฃผ์ž๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ง„๋ฃจํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง€๋Š” ์ „์ˆ ์ž…๋‹ˆ๋‹ค.\n"
                  "[์ถœ์ฒ˜: KBO ๊ทœ์น™ ๋ฌธ์„œ]"
    },
    {
        "input": "ํˆฌ์ˆ˜๊ฐ€ ๋ฐ˜์น™ ๋™์ž‘์„ ํ•˜๋ฉด ๋ญ๋ผ๊ณ  ํ•ด?",
        "answer": "ํˆฌ์ˆ˜๊ฐ€ ๋ฐ˜์น™ ๋™์ž‘์„ ํ•˜๋ฉด '๋ณดํฌ'๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค!\n\n"
                  "๋ณดํฌ(Balk)๋Š” ํˆฌ์ˆ˜๊ฐ€ ์ฃผ์ž๊ฐ€ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ ๊ทœ์น™์— ์–ด๊ธ‹๋‚˜๋Š” ๋ถˆ๋ฒ• ๋™์ž‘์„ ํ–ˆ์„ ๋•Œ ์„ ์–ธ๋ฉ๋‹ˆ๋‹ค. "
                  "๋ณดํฌ๊ฐ€ ์„ ์–ธ๋˜๋ฉด ๋ชจ๋“  ์ฃผ์ž๋Š” ํ•œ ๋ฒ ์ด์Šค์”ฉ ์ง„๋ฃจํ•˜๊ฒŒ ๋˜๋ฉฐ, ์ด๋Š” ํˆฌ์ˆ˜์˜ ํŽ˜์ดํฌ ๋™์ž‘ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ๊ทœ์ •์ž…๋‹ˆ๋‹ค.\n"
                  "[์ถœ์ฒ˜: KBO ๊ทœ์น™ ๋ฌธ์„œ]"
    },
    {
        "input": "๊ฒฝ๊ธฐ ์ค‘ ํƒ€์ž๊ฐ€ ์‚ผ์ง„์„ ๋‹นํ–ˆ์ง€๋งŒ 1๋ฃจ๋กœ ๋‹ฌ๋ฆด ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์€?",
        "answer": "ํƒ€์ž๊ฐ€ ์‚ผ์ง„์„ ๋‹นํ–ˆ์ง€๋งŒ 1๋ฃจ๋กœ ๋‹ฌ๋ฆด ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์€ '๋‚ซ์•„์›ƒ ์‚ผ์ง„'์ž…๋‹ˆ๋‹ค!\n\n"
                  "๋‚ซ์•„์›ƒ ์‚ผ์ง„(Dropped Third Strike)์€ ์ŠคํŠธ๋ผ์ดํฌ ์•„์›ƒ์ด ์„ ์–ธ๋˜์—ˆ์ง€๋งŒ ํฌ์ˆ˜๊ฐ€ ๊ณต์„ ๋†“์ณ์„œ ์žก์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. "
                  "์ด๋•Œ, 1๋ฃจ์— ์ฃผ์ž๊ฐ€ ์—†๊ฑฐ๋‚˜ 2์•„์›ƒ ์ƒํ™ฉ์ด๋ผ๋ฉด ํƒ€์ž๋Š” 1๋ฃจ๋กœ ๋‹ฌ๋ ค ์ถœ๋ฃจ๋ฅผ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n"
                  "[์ถœ์ฒ˜: KBO ๊ทœ์น™ ๋ฌธ์„œ]"
    },
    {
        "input": "์ฃผ์ž๊ฐ€ 1๋ฃจ์™€ 2๋ฃจ ์‚ฌ์ด์—์„œ ํƒœ๊ทธ ์•„์›ƒ๋˜์ง€ ์•Š์œผ๋ ค๊ณ  ์™”๋‹ค ๊ฐ”๋‹ค ํ•˜๋Š” ๊ฒƒ์€?",
        "answer": "์ฃผ์ž๊ฐ€ 1๋ฃจ์™€ 2๋ฃจ ์‚ฌ์ด์—์„œ ํƒœ๊ทธ ์•„์›ƒ๋˜์ง€ ์•Š์œผ๋ ค๊ณ  ์™”๋‹ค ๊ฐ”๋‹ค ํ•˜๋Š” ๊ฒƒ์€ '๋Ÿฐ๋‹ค์šด'์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค!\n\n"
                  "๋Ÿฐ๋‹ค์šด(Rundown)์€ ์ฃผ์ž๊ฐ€ ์•ผ์ˆ˜๋“ค์˜ ์†ก๊ตฌ ํ”Œ๋ ˆ์ด ์‚ฌ์ด์—์„œ ์•„์›ƒ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ขŒ์šฐ๋กœ ์›€์ง์ด๋ฉฐ ๋„๋ง๊ฐ€๋Š” ์ƒํ™ฉ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. "
                  "์ˆ˜๋น„ํŒ€์€ ์ฃผ์ž๋ฅผ ํ˜‘๋ ฅํ•˜์—ฌ ๋น ๋ฅด๊ฒŒ ํƒœ๊ทธ ์•„์›ƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋ฉฐ, ์ด๋ฅผ '๋Ÿฐ๋‹ค์šด ํ”Œ๋ ˆ์ด'๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค.\n"
                  "[์ถœ์ฒ˜: KBO ๊ทœ์น™ ๋ฌธ์„œ]"
    },
    # ๋‹ต๋ณ€ํ•  ์ˆ˜ ์—†๋Š” ์งˆ๋ฌธ ์˜ˆ์‹œ
    {
        "input": "์˜ค๋Š˜ KBO ๋ฆฌ๊ทธ ๊ฒฝ๊ธฐ ๊ฒฐ๊ณผ ์•Œ๋ ค์ค˜.",
        "answer": "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
    },
    {
        "input": "2024๋…„ KBO ๋ฆฌ๊ทธ์—์„œ ๊ฐ€์žฅ ๋งŽ์€ ํ™ˆ๋Ÿฐ์„ ์นœ ์„ ์ˆ˜๋Š” ๋ˆ„๊ตฌ์•ผ?",
        "answer": "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
    },
    {
        "input": "KBO ๋ฆฌ๊ทธ์—์„œ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ํŒ€์€ ์–ด๋””์•ผ?",
        "answer": "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
    },
    {
        "input": "์•ผ๊ตฌ์žฅ์—์„œ ๊ฐ€์žฅ ๋ง›์žˆ๋Š” ์Œ์‹ ์ถ”์ฒœํ•ด์ค˜.",
        "answer": "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
    }
]

few shot ์ ์šฉ ํ›„์— ๋‹ต๋ณ€์„ ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์•„๋ž˜์˜ ์งˆ๋ฌธ set์„ ์‹คํ–‰์‹œ์ผฐ๋‹ค. chat history๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋™์ž‘ํ•˜๋„๋ก ์ผ๋ถ€๋Ÿฌ ๋‘ ๋ฒˆ์งธ ์งˆ๋ฌธ์€ ๋งฅ๋ฝ์„ ์œ ์ถ”ํ•ด์•ผ ๋‹ต๋ณ€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž‘์„ฑํ–ˆ๋‹ค.

 

Question Set 1.

1๏ธโƒฃ์ฃผ์ž๊ฐ€ ๋ฒ ์ด์Šค๋ฅผ ํ›”์น˜๋Š” ๊ฒƒ์„ ๋ญ๋ผ๊ณ  ํ•ด?

2๏ธโƒฃ๊ทธ๋Ÿผ ์ฃผ์ž ๋‘ ๋ช…์ด ๋™์‹œ์— ํ•˜๋Š” ๊ฑด ๋ญ๋ผ๊ณ  ํ•ด?

 

Question Set 2.

1๏ธโƒฃ์ธํ•„๋“œ ํ”Œ๋ผ์ด์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด์ค˜.

2๏ธโƒฃํ•ด๋‹น ์ƒํ™ฉ์—์„œ ์ฃผ์ž๋Š” ์–ด๋–ป๊ฒŒ ํ–‰๋™ํ•˜๋Š”์ง€ ์„ค๋ช…ํ•ด์ค˜.

๋‹ต๋ณ€์ด ์ž˜ ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค(llm.py, fewshot_doc.py)

# llm.py

from langchain_upstage import ChatUpstage, UpstageEmbeddings
from langchain_pinecone import PineconeVectorStore
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder, FewShotChatMessagePromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain.chains import create_history_aware_retriever, create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
from fewshot_doc import answer_examples

chat_storage = {}

def get_llm():
    llm = ChatUpstage()
    return llm
    
# ์‚ฌ์ „์„ ์ฐธ๊ณ ํ•˜์—ฌ ์œ ์ €์˜ ์งˆ๋ฌธ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ์„ค์ •
def get_dictionary_chain():
    
    llm = get_llm()
    
    dictionary = [
        "๋ฒ ์ด์Šค์— ์žˆ๋Š” ์„ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‘œํ˜„ -> ์ฃผ์ž",
        "ํƒ€์„์— ์žˆ๋Š” ์„ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‘œํ˜„ -> ํƒ€์ž",
        "๋งˆ์šด๋“œ ์œ„์—์„œ ๊ณต์„ ๋˜์ง€๋Š” ์„ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ‘œํ˜„ -> ํˆฌ์ˆ˜"
    ]
    
    dictionary_prompt = ChatPromptTemplate.from_template(f"""
        ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์„ ํ™•์ธํ•˜๊ณ  ์‚ฌ์ „์„ ์ฐธ๊ณ ํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์„ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”.
        ๋งŒ์•ฝ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๊ณ  ํŒ๋‹จ๋˜๋ฉด ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์งˆ๋ฌธ์„ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š”.
        ์งˆ๋ฌธ์ด๋‚˜ ์ฃผ์–ด๊ฐ€ ๋ชจํ˜ธํ•  ๊ฒฝ์šฐ history retriever์—์„œ history chat์„ ์ฐธ๊ณ ํ•˜์—ฌ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋„๋ก ์งˆ๋ฌธ์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š”.
        ์‚ฌ์ „: {dictionary}
        ์งˆ๋ฌธ: {{question}}
                                                         """)
    
    dictionary_chain = dictionary_prompt | llm | StrOutputParser()
    return dictionary_chain
    
# ๋ฌธ์„œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•œ retriever ์„ค์ •
def get_retriever():
    
    index_name = "baseball-rules-index"

    # ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒกํ„ฐํ™”ํ•  ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ ์„ค์ •
    embedding = UpstageEmbeddings(model="solar-embedding-1-large")
    database = PineconeVectorStore.from_existing_index(index_name=index_name, embedding=embedding)
    retriever = database.as_retriever(search_kwargs={"k": 4})
    return retriever
    
# chat history๋ฅผ ๋ฐ˜์˜ํ•˜์—ฌ ์งˆ๋ฌธ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ์„ค์ •
def get_history_retriever():
    llm = get_llm()
    retriever = get_retriever()
    
    # chat history๋ฅผ ๋ฐ˜์˜ํ•˜์—ฌ ์งˆ๋ฌธ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ
    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."
    )
    
    # ์ฑ„ํŒ… ๊ธฐ๋ก์„ ๋ฐ˜์˜ํ•˜์—ฌ QA๋ฅผ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ
    contextualize_q_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", contextualize_q_system_prompt),
            MessagesPlaceholder("chat_history"), # ๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „๋‹ฌ
            ("human", "{input}")
        ]
    )
    
    history_aware_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)
    return history_aware_retriever
    
# ์„ธ์…˜ ๊ธฐ๋ก์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜ ์„ค์ •
def get_session_history(session_id: str) -> BaseChatMessageHistory:
    # ์„ธ์…˜์ด ์—†์œผ๋ฉด ํ•ด๋‹น ์„ธ์…˜์— ๋Œ€ํ•œ ์ฑ„ํŒ…๊ธฐ๋ก ์ƒ์„ฑ
    if session_id not in chat_storage:
        chat_storage[session_id] = ChatMessageHistory()
    return chat_storage[session_id]
    
# RAG ์ฒด์ธ์„ ์ƒ์„ฑ
def get_rag_chain():
    
    llm = get_llm()
    
    # few-shot์„ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ ์„ค์ •
    example_prompt = ChatPromptTemplate.from_messages(
        [
            ("human", "{input}"),
            ("ai", "{answer}")
        ]
    )
    
    # few-shot์„ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ ์„ค์ •
    few_shot_prompt = FewShotChatMessagePromptTemplate(
        example_prompt=example_prompt,
        examples=answer_examples
    )
    
    # ๋ชจ๋ธ์˜ ์—ญํ• ์„ ์ •์˜ํ•ด์ฃผ๊ธฐ ์œ„ํ•œ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ
    system_prompt = ("""
            ๋‹น์‹ ์€ ์ตœ๊ณ ์˜ KBO ๋ฆฌ๊ทธ ์•ผ๊ตฌ ๊ทœ์น™ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. 
            ์•„๋ž˜์˜ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์„ ํ•ด์ฃผ์„ธ์š”.
            
            ๋จ„์•ฝ์— ์•ผ๊ตฌ ๊ทœ์น™๊ณผ ๊ด€๋ จ์ด ์—†๋‹ค๋ฉด "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."๋ผ๊ณ  ๋‹ต๋ณ€ํ•ด์ฃผ์„ธ์š”.
            ๋งŒ์•ฝ์— ๋‹ต๋ณ€ํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ๋ชจ๋ฅธ๋‹ค๊ณ  ๋‹ต๋ณ€ํ•ด์ฃผ์„ธ์š”.
            
            ๋‹ต๋ณ€ ์‹œ์— ์ถœ์ฒ˜์— ๋Œ€ํ•ด์„œ๋„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ฐํ˜€์ฃผ์‹œ๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
            ๋‹ต๋ณ€์˜ ๊ธธ์ด๋Š” 2-3์ค„ ์ •๋„๋กœ ์ œํ•œํ•ด์ฃผ์„ธ์š”.
            \n\n
            ๋ฌธ์„œ: {context}
    """)
    
    # ์ฑ„ํŒ… ๊ธฐ๋ก ๋ฐ˜์˜ํ•˜์—ฌ QA๋ฅผ ์œ„ํ•œ ํ”„๋กฌํ”„ํŠธ
    qa_prompt = ChatPromptTemplate.from_messages(
        [
            ("system", system_prompt),
            few_shot_prompt, # few-shot์„ ์ฐธ๊ณ ํ•˜๋„๋ก ์ „๋‹ฌ
            MessagesPlaceholder("chat_history"), # ๋ฉ”์‹œ์ง€ ๋ฆฌ์ŠคํŠธ(์ฑ„ํŒ… ๊ธฐ๋ก)๋ฅผ ์ „๋‹ฌ
            ("human", "{input}")
        ]
    )
    
    history_aware_retriever = get_history_retriever() # ๊ธฐ๋ก ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰์„ ์œ„ํ•œ retriever
    qa_chain = create_stuff_documents_chain(llm, qa_prompt) # ๋ชจ๋ธ์—๊ฒŒ ๊ฒ€์ƒ‰ํ•œ ๋ฌธ์„œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ „๋‹ฌ
    rag_chain = create_retrieval_chain(history_aware_retriever, qa_chain) # RAG ์ฒด์ธ ์ƒ์„ฑ
    
    conversational_rag_chain = RunnableWithMessageHistory(
        rag_chain, # ์‹คํ–‰ํ•  RAG ์ฒด์ธ์ด๋‚˜ LLM ์ฒด์ธ
        get_session_history, # ์„ธ์…˜_ID ๊ธฐ๋ฐ˜์˜ ์ฑ„ํŒ… ๊ธฐ๋ก
        input_messages_key="input", # ์œ ์ €์˜ ์ž…๋ ฅ์ด ๋‹ด๊ธด ํ‚ค
        history_messages_key="chat_history", # ์ฑ„ํŒ… ๊ธฐ๋ก์„ ์ „๋‹ฌํ•  ํ‚ค
        output_messages_key="answer" # ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ํ‚ค
    ).pick("answer")
    
    # ์ฑ„ํŒ… history๋ฅผ ํฌํ•จํ•œ retriever๋ฅผ ํ™œ์šฉํ•˜์—ฌ rag_chain ๋ฐ˜ํ™˜
    return conversational_rag_chain
    
def get_ai_response1():
    
    dictionary_chain = get_dictionary_chain()
    rag_chain = get_rag_chain()
    
    baseball_chain = {"input": dictionary_chain} | rag_chain
    
    ai_response = baseball_chain.invoke(
        {"question": "์ธํ•„๋“œ ํ”Œ๋ผ์ด์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด์ค˜."},
        config={"configurable": {"session_id": "abc123"}}
    )
    
    return ai_response

def get_ai_response2():
    
    dictionary_chain = get_dictionary_chain()
    rag_chain = get_rag_chain()
    
    baseball_chain = {"input": dictionary_chain} | rag_chain
    
    ai_response = baseball_chain.invoke(
        {"question": "ํ•ด๋‹น ์ƒํ™ฉ์—์„œ ์ฃผ์ž๋Š” ์–ด๋–ป๊ฒŒ ํ–‰๋™ํ•˜๋Š”์ง€ ์„ค๋ช…ํ•ด์ค˜."},
        config={"configurable": {"session_id": "abc123"}}
    )
    
    return ai_response

ai_response = get_ai_response1()
print(f"ai_response1:\n {ai_response}\n")
ai_response = get_ai_response2()
print(f"ai_response2:\n {ai_response}\n")
# fewshot_doc.py

answer_examples = [
    {
        "input": "์ฃผ์ž๊ฐ€ ๋‘ ๋ช…์ด ๋™์‹œ์— ๋„๋ฃจํ•˜๋Š” ๊ฒƒ์„ ๋ญ๋ผ๊ณ  ํ•ด?",
        "answer": "์ฃผ์ž ๋‘ ๋ช…์ด ๋™์‹œ์— ๋„๋ฃจํ•˜๋Š” ๊ฒƒ์€ '๋”๋ธ” ์Šคํ‹ธ'์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค!\n\n"
                  "๋”๋ธ” ์Šคํ‹ธ(Double Steal)์€ ๋‘ ๋ช… ์ด์ƒ์˜ ์ฃผ์ž๊ฐ€ ๋™์‹œ์— ๋‹ค์Œ ๋ฒ ์ด์Šค๋กœ ๋„๋ฃจํ•˜๋Š” ์ „๋žต์  ํ”Œ๋ ˆ์ด์ž…๋‹ˆ๋‹ค. "
                  "ํŠนํžˆ, ์ˆ˜๋น„ ํŒ€์ด ํ•œ ์ฃผ์ž์—๊ฒŒ ์ง‘์ค‘ํ•  ๋•Œ ๋‹ค๋ฅธ ์ฃผ์ž๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ง„๋ฃจํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง€๋Š” ์ „์ˆ ์ž…๋‹ˆ๋‹ค.\n"
                  "[์ถœ์ฒ˜: KBO ๊ทœ์น™ ๋ฌธ์„œ]"
    },
    {
        "input": "ํˆฌ์ˆ˜๊ฐ€ ๋ฐ˜์น™ ๋™์ž‘์„ ํ•˜๋ฉด ๋ญ๋ผ๊ณ  ํ•ด?",
        "answer": "ํˆฌ์ˆ˜๊ฐ€ ๋ฐ˜์น™ ๋™์ž‘์„ ํ•˜๋ฉด '๋ณดํฌ'๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค!\n\n"
                  "๋ณดํฌ(Balk)๋Š” ํˆฌ์ˆ˜๊ฐ€ ์ฃผ์ž๊ฐ€ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ ๊ทœ์น™์— ์–ด๊ธ‹๋‚˜๋Š” ๋ถˆ๋ฒ• ๋™์ž‘์„ ํ–ˆ์„ ๋•Œ ์„ ์–ธ๋ฉ๋‹ˆ๋‹ค. "
                  "๋ณดํฌ๊ฐ€ ์„ ์–ธ๋˜๋ฉด ๋ชจ๋“  ์ฃผ์ž๋Š” ํ•œ ๋ฒ ์ด์Šค์”ฉ ์ง„๋ฃจํ•˜๊ฒŒ ๋˜๋ฉฐ, ์ด๋Š” ํˆฌ์ˆ˜์˜ ํŽ˜์ดํฌ ๋™์ž‘ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ๊ทœ์ •์ž…๋‹ˆ๋‹ค.\n"
                  "[์ถœ์ฒ˜: KBO ๊ทœ์น™ ๋ฌธ์„œ]"
    },
    {
        "input": "๊ฒฝ๊ธฐ ์ค‘ ํƒ€์ž๊ฐ€ ์‚ผ์ง„์„ ๋‹นํ–ˆ์ง€๋งŒ 1๋ฃจ๋กœ ๋‹ฌ๋ฆด ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์€?",
        "answer": "ํƒ€์ž๊ฐ€ ์‚ผ์ง„์„ ๋‹นํ–ˆ์ง€๋งŒ 1๋ฃจ๋กœ ๋‹ฌ๋ฆด ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์€ '๋‚ซ์•„์›ƒ ์‚ผ์ง„'์ž…๋‹ˆ๋‹ค!\n\n"
                  "๋‚ซ์•„์›ƒ ์‚ผ์ง„(Dropped Third Strike)์€ ์ŠคํŠธ๋ผ์ดํฌ ์•„์›ƒ์ด ์„ ์–ธ๋˜์—ˆ์ง€๋งŒ ํฌ์ˆ˜๊ฐ€ ๊ณต์„ ๋†“์ณ์„œ ์žก์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. "
                  "์ด๋•Œ, 1๋ฃจ์— ์ฃผ์ž๊ฐ€ ์—†๊ฑฐ๋‚˜ 2์•„์›ƒ ์ƒํ™ฉ์ด๋ผ๋ฉด ํƒ€์ž๋Š” 1๋ฃจ๋กœ ๋‹ฌ๋ ค ์ถœ๋ฃจ๋ฅผ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n"
                  "[์ถœ์ฒ˜: KBO ๊ทœ์น™ ๋ฌธ์„œ]"
    },
    {
        "input": "์ฃผ์ž๊ฐ€ 1๋ฃจ์™€ 2๋ฃจ ์‚ฌ์ด์—์„œ ํƒœ๊ทธ ์•„์›ƒ๋˜์ง€ ์•Š์œผ๋ ค๊ณ  ์™”๋‹ค ๊ฐ”๋‹ค ํ•˜๋Š” ๊ฒƒ์€?",
        "answer": "์ฃผ์ž๊ฐ€ 1๋ฃจ์™€ 2๋ฃจ ์‚ฌ์ด์—์„œ ํƒœ๊ทธ ์•„์›ƒ๋˜์ง€ ์•Š์œผ๋ ค๊ณ  ์™”๋‹ค ๊ฐ”๋‹ค ํ•˜๋Š” ๊ฒƒ์€ '๋Ÿฐ๋‹ค์šด'์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค!\n\n"
                  "๋Ÿฐ๋‹ค์šด(Rundown)์€ ์ฃผ์ž๊ฐ€ ์•ผ์ˆ˜๋“ค์˜ ์†ก๊ตฌ ํ”Œ๋ ˆ์ด ์‚ฌ์ด์—์„œ ์•„์›ƒ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ขŒ์šฐ๋กœ ์›€์ง์ด๋ฉฐ ๋„๋ง๊ฐ€๋Š” ์ƒํ™ฉ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. "
                  "์ˆ˜๋น„ํŒ€์€ ์ฃผ์ž๋ฅผ ํ˜‘๋ ฅํ•˜์—ฌ ๋น ๋ฅด๊ฒŒ ํƒœ๊ทธ ์•„์›ƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋ฉฐ, ์ด๋ฅผ '๋Ÿฐ๋‹ค์šด ํ”Œ๋ ˆ์ด'๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค.\n"
                  "[์ถœ์ฒ˜: KBO ๊ทœ์น™ ๋ฌธ์„œ]"
    },
    # ๋‹ต๋ณ€ํ•  ์ˆ˜ ์—†๋Š” ์งˆ๋ฌธ ์˜ˆ์‹œ
    {
        "input": "์˜ค๋Š˜ KBO ๋ฆฌ๊ทธ ๊ฒฝ๊ธฐ ๊ฒฐ๊ณผ ์•Œ๋ ค์ค˜.",
        "answer": "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
    },
    {
        "input": "2024๋…„ KBO ๋ฆฌ๊ทธ์—์„œ ๊ฐ€์žฅ ๋งŽ์€ ํ™ˆ๋Ÿฐ์„ ์นœ ์„ ์ˆ˜๋Š” ๋ˆ„๊ตฌ์•ผ?",
        "answer": "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
    },
    {
        "input": "KBO ๋ฆฌ๊ทธ์—์„œ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ํŒ€์€ ์–ด๋””์•ผ?",
        "answer": "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
    },
    {
        "input": "์•ผ๊ตฌ์žฅ์—์„œ ๊ฐ€์žฅ ๋ง›์žˆ๋Š” ์Œ์‹ ์ถ”์ฒœํ•ด์ค˜.",
        "answer": "๐Ÿšซ์•ผ๊ตฌ ๊ทœ์น™์— ๋Œ€ํ•œ ์งˆ๋ฌธ๋งŒ ๋‹ต๋ณ€์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
    }
]

References

https://python.langchain.com/v0.2/docs/how_to/qa_chat_history_how_to/#chains

https://python.langchain.com/v0.2/docs/how_to/few_shot_examples_chat/#create-prompt-template

728x90