Chat Prompt / Few-shot Prompt Template 예제 실습 (250813)

WonTerry·2025년 8월 13일

LLM

목록 보기
14/66

Chat Prompt Template (250813)

# 출처 : https://wikidocs.net/231328

# ChatPromptTemplate은 대화형 상황에서 여러 메시지 입력을 기반으로 단일 메시지 응답을 생성하는 데 사용됩니다. 
# 이는 대화형 모델이나 챗봇 개발에 주로 사용됩니다. 입력은 여러 메시지를 원소로 갖는 리스트로 구성되며, 
# 각 메시지는 역할(role)과 내용(content)으로 구성됩니다.


# MessagePromptTemplate 활용

from langchain_core.prompts import SystemMessagePromptTemplate,  HumanMessagePromptTemplate
from langchain_core.prompts import ChatPromptTemplate

chat_prompt = ChatPromptTemplate.from_messages(
    [
        SystemMessagePromptTemplate.from_template("이 시스템은 천문학 질문에 답변할 수 있습니다."),
        HumanMessagePromptTemplate.from_template("{user_input}"),
    ]
)

messages = chat_prompt.format_messages(user_input="태양계에서 가장 큰 행성은 무엇인가요?")
messages
[SystemMessage(content='이 시스템은 천문학 질문에 답변할 수 있습니다.', additional_kwargs={}, response_metadata={}),
 HumanMessage(content='태양계에서 가장 큰 행성은 무엇인가요?', additional_kwargs={}, response_metadata={})]
# 이렇게 생성된 메시지 리스트는 대화형 인터페이스나 언어 모델과의 상호작용을 위한 입력으로 사용될 수 있습니다. 
# 각 메시지는 role (메시지를 말하는 주체, 여기서는 system 또는 user)과 content (메시지의 내용) 속성을 포함합니다. 
# 이 구조는 시스템과 사용자 간의 대화 흐름을 명확하게 표현하며, 
# 언어 모델이 이를 기반으로 적절한 응답을 생성할 수 있도록 돕습니다.
# ollama 활용

# from langchain_community.chat_models import ChatOllama
from langchain_core.output_parsers import StrOutputParser

# model = ChatOllama(model = "llama3")  

from langchain_openai import ChatOpenAI
from langchain_core.callbacks.streaming_stdout import StreamingStdOutCallbackHandler

model = ChatOpenAI(
    base_url="http://localhost:11434/v1",   # url 정확히 입력할 것 : v1까지 입력하지 않을 경우 에러 (250813)
    api_key="lm-studio",
    model="lmstudio-community/Meta-Llama-3.1-8B-Instruct-GGUF",
    temperature=0.1,
    # streaming=False,

    streaming=True,
    callbacks=[StreamingStdOutCallbackHandler()], # 스트림 출력 콜백
)

# RAG Chain 연결
chain =  chat_prompt | model | StrOutputParser()

# Chain 실행
answer = chain.invoke({"user_input": "태양계에서 가장 큰 행성은 무엇인가요?"})

print("Query:", messages)
print("Answer:", answer)
태양계에서 가장 큰 행성은 목성입니다. 목성의 지구 대비 반지름은 약 11.2배로, 질량도 지구의 약 318배에 달합니다. 또한 목성은 태양계에서 가장 무거운 행성으로, 태양의 약 1/1000만 분의 1 정도의 질량을 가지고 있습니다.Query: [SystemMessage(content='이 시스템은 천문학 질문에 답변할 수 있습니다.', additional_kwargs={}, response_metadata={}), HumanMessage(content='태양계에서 가장 큰 행성은 무엇인가요?', additional_kwargs={}, response_metadata={})]
Answer: 태양계에서 가장 큰 행성은 목성입니다. 목성의 지구 대비 반지름은 약 11.2배로, 질량도 지구의 약 318배에 달합니다. 또한 목성은 태양계에서 가장 무거운 행성으로, 태양의 약 1/1000만 분의 1 정도의 질량을 가지고 있습니다.

Few-shot Prompt

# Few-shot 학습은 언어 모델에 몇 가지 예시를 제공하여 특정 작업을 수행하도록 유도하는 기법입니다.
# 이 방법은 모델의 성능을 크게 향상시킬 수 있습니다.

# Few-shot 예제를 포맷팅하기 위한 템플릿을 생성합니다.

from langchain_core.prompts import PromptTemplate

example_prompt = PromptTemplate.from_template("질문: {question}\n{answer}")

examples = [
    {
        "question": "지구의 대기 중 가장 많은 비율을 차지하는 기체는 무엇인가요?",
        "answer": "지구 대기의 약 78%를 차지하는 질소입니다."
    },
    {
        "question": "광합성에 필요한 주요 요소들은 무엇인가요?",
        "answer": "광합성에 필요한 주요 요소는 빛, 이산화탄소, 물입니다."
    },
    {
        "question": "피타고라스 정리를 설명해주세요.",
        "answer": "피타고라스 정리는 직각삼각형에서 빗변의 제곱이 다른 두 변의 제곱의 합과 같다는 것입니다."
    },
    {
        "question": "지구의 자전 주기는 얼마인가요?",
        "answer": "지구의 자전 주기는 약 24시간(정확히는 23시간 56분 4초)입니다."
    },
    {
        "question": "DNA의 기본 구조를 간단히 설명해주세요.",
        "answer": "DNA는 두 개의 폴리뉴클레오티드 사슬이 이중 나선 구조를 이루고 있습니다."
    },
    {
        "question": "원주율(π)의 정의는 무엇인가요?",
        "answer": "원주율(π)은 원의 지름에 대한 원의 둘레의 비율입니다."
    }
]
from langchain_core.prompts import FewShotPromptTemplate

# FewShotPromptTemplate을 생성합니다.
prompt = FewShotPromptTemplate(
    examples=examples,              # 사용할 예제들
    example_prompt=example_prompt,  # 예제 포맷팅에 사용할 템플릿
    suffix="질문: {input}",          # 예제 뒤에 추가될 접미사
    input_variables=["input"],      # 입력 변수 지정
)

# 새로운 질문에 대한 프롬프트를 생성하고 출력합니다.
print(prompt.invoke({"input": "태양계에서 가장 큰 행성은 무엇인가요?"}).to_string())
질문: 지구의 대기 중 가장 많은 비율을 차지하는 기체는 무엇인가요?
지구 대기의 약 78%를 차지하는 질소입니다.

질문: 광합성에 필요한 주요 요소들은 무엇인가요?
광합성에 필요한 주요 요소는 빛, 이산화탄소, 물입니다.

질문: 피타고라스 정리를 설명해주세요.
피타고라스 정리는 직각삼각형에서 빗변의 제곱이 다른 두 변의 제곱의 합과 같다는 것입니다.

질문: 지구의 자전 주기는 얼마인가요?
지구의 자전 주기는 약 24시간(정확히는 23시간 56분 4초)입니다.

질문: DNA의 기본 구조를 간단히 설명해주세요.
DNA는 두 개의 폴리뉴클레오티드 사슬이 이중 나선 구조를 이루고 있습니다.

질문: 원주율(π)의 정의는 무엇인가요?
원주율(π)은 원의 지름에 대한 원의 둘레의 비율입니다.

질문: 태양계에서 가장 큰 행성은 무엇인가요?
# Chain 실행

chain =  prompt | model | StrOutputParser()

answer = chain.invoke({"input": "태양계에서 가장 큰 행성은 무엇인가요?"})

print("Query:", messages)
print("Answer:", answer)
1.  지구 대기의 약 78%를 차지하는 기체는 질소입니다.
2.  광합성에 필요한 주요 요소는 빛, 이산화탄소, 물입니다.
3.  피타고라스 정리는 직각삼각형에서 빗변의 제곱이 다른 두 변의 제곱의 합과 같다는 것입니다. (a² + b² = c²)
4.  지구의 자전 주기는 약 24시간(정확히는 23시간 56분 4초)입니다.
5.  DNA의 기본 구조를 간단히 설명하면 두 개의 폴리뉴클레오티드 사슬이 이중 나선 구조를 이루고 있습니다.
6.  원주율(π)의 정의는 원의 지름에 대한 원의 둘레의 비율입니다.
7.  태양계에서 가장 큰 행성은 목성입니다.Query: [SystemMessage(content='이 시스템은 천문학 질문에 답변할 수 있습니다.', additional_kwargs={}, response_metadata={}), HumanMessage(content='태양계에서 가장 큰 행성은 무엇인가요?', additional_kwargs={}, response_metadata={})]
Answer: 1.  지구 대기의 약 78%를 차지하는 기체는 질소입니다.
2.  광합성에 필요한 주요 요소는 빛, 이산화탄소, 물입니다.
3.  피타고라스 정리는 직각삼각형에서 빗변의 제곱이 다른 두 변의 제곱의 합과 같다는 것입니다. (a² + b² = c²)
4.  지구의 자전 주기는 약 24시간(정확히는 23시간 56분 4초)입니다.
5.  DNA의 기본 구조를 간단히 설명하면 두 개의 폴리뉴클레오티드 사슬이 이중 나선 구조를 이루고 있습니다.
6.  원주율(π)의 정의는 원의 지름에 대한 원의 둘레의 비율입니다.
7.  태양계에서 가장 큰 행성은 목성입니다.
# 리소스 모니터링 : 코드 실행시 GPU를 100% 사용한다. (250813)
# 동일한 질문에 대해 Few-Shot을 이용한 경우,
# 부연 설명없이 간단하게 한 줄로 "목성"이라고 답한다. 응답의 차이 발견 (250813)

# 굳이 Few-Shot 예제를 보여주는 이유는 무엇인가?

의미적 유사성 분석으로 가장 관련성이 높은 예제를 선택하는 방법

from langchain_chroma import Chroma
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
# from langchain_openai import OpenAIEmbeddings   # API Key가 없으므로 (250813)

# 문장을 임베딩으로 변환하고 벡터 저장소에 저장

# numpy 1.X 버전으로 다운그레이드 필요함 (250813)
# Python 3.11을 지원하는 가장 낮은 NumPy 버전은 NumPy 1.23.0입니다.  --> 버전 충돌 문제
# pip install numpy==1.26.2  (최종 설치, 250813)

from langchain.embeddings import HuggingFaceEmbeddings

embeddings_model = HuggingFaceEmbeddings(
    model_name='sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2',    # 다국어 모델
    # model_name='jhgan/ko-sroberta-multitask',  # 한국어 모델 - 에러 발생 (250603)
    # model_name = 'BAAI/bge-m3',                # 에러 발생 (250603)
    model_kwargs={'device':'cpu'},
    encode_kwargs={'normalize_embeddings':True},
)

# SemanticSimilarityExampleSelector를 초기화합니다.
example_selector = SemanticSimilarityExampleSelector.from_examples(
    examples,            # 사용할 예제들 - 위에서 미리 정의해둔 예제들
    embeddings_model,     # 임베딩 모델 (허깅 페이스, 250813)
    #OpenAIEmbeddings(),  # 임베딩 모델
    Chroma,              # 벡터 저장소
    k=1,                 # 선택할 예제 수
)

# 새로운 질문에 대해 가장 유사한 예제를 선택합니다.
question = "태양계에서 가장 큰 행성은 무엇인가요?"
selected_examples = example_selector.select_examples({"question": question})
print(f"입력과 가장 유사한 예제: {question}")

for example in selected_examples:
    print("\n")
    for k, v in example.items():
        print(f"{k}: {v}")
입력과 가장 유사한 예제: 태양계에서 가장 큰 행성은 무엇인가요?


question: 지구의 대기 중 가장 많은 비율을 차지하는 기체는 무엇인가요?
answer: 지구 대기의 약 78%를 차지하는 질소입니다.
# 문제점 : 내용의 유사도이며, 경우에 따라서 질문 또는 답변의 구조적 유사도가 필요할 수 있다. (250813)
# FewShotPromptTemplate을 생성합니다.
prompt = FewShotPromptTemplate(
    examples=selected_examples,       # 사용할 예제들 - 유사도 분석에서 선택된 1개의 예제
    example_prompt=example_prompt,  # 예제 포맷팅에 사용할 템플릿
    suffix="질문: {input}",          # 예제 뒤에 추가될 접미사
    input_variables=["input"],      # 입력 변수 지정
)

# 새로운 질문에 대한 프롬프트를 생성하고 출력합니다.
print(prompt.invoke({"input": "태양계에서 가장 큰 행성은 무엇인가요?"}).to_string())

질문: 지구의 대기 중 가장 많은 비율을 차지하는 기체는 무엇인가요?
지구 대기의 약 78%를 차지하는 질소입니다.

질문: 태양계에서 가장 큰 행성은 무엇인가요?
# Chain 실행

chain =  prompt | model | StrOutputParser()

answer = chain.invoke({"input": "태양계에서 가장 큰 행성은 무엇인가요?"})

print("Query:", messages)
print("Answer:", answer)
질문에 대한 답변:

1. 지구의 대기 중 가장 많은 비율을 차지하는 기체는 질소입니다. 지구 대기의 약 78%를 차지합니다.
2. 태양계에서 가장 큰 행성은 목성입니다. 목성은 태양계의 외곽에 위치한 가스 거대행성으로, 지구보다 약 12배 더 무겁고, 반경이 약 11배 더 크습니다.Query: [SystemMessage(content='이 시스템은 천문학 질문에 답변할 수 있습니다.', additional_kwargs={}, response_metadata={}), HumanMessage(content='태양계에서 가장 큰 행성은 무엇인가요?', additional_kwargs={}, response_metadata={})]
Answer: 질문에 대한 답변:

1. 지구의 대기 중 가장 많은 비율을 차지하는 기체는 질소입니다. 지구 대기의 약 78%를 차지합니다.
2. 태양계에서 가장 큰 행성은 목성입니다. 목성은 태양계의 외곽에 위치한 가스 거대행성으로, 지구보다 약 12배 더 무겁고, 반경이 약 11배 더 크습니다.
# 유사도 분석에 의해 선택된 질문과 답안지의 경우, 구체적인 숫치를 답변에 제시하였다.
# 따라서 태양계에서 가장 큰 행성에 대한 답변을 단순히 "목성"이라고 단답형으로 제시하지 않고,
# 지구 보다 "12배" 무겁고, 반경이 "11배" 크다는 구체적인 수치를 추가로 제시하여 답변을 길게 작성하였다. (250813)
profile
Hello, I'm Terry! 👋 Enjoy every moment of your life! 🌱 My current interests are Signal processing, Machine learning, Python, Database, LLM & RAG, MCP & ADK, Multi-Agents, Physical AI, ROS2...

0개의 댓글