Skip to content

프롬프트 템플릿과 메시지

LLM에게 질문을 전달하는 3가지 방법과, 프롬프트를 유연하게 구성하는 템플릿을 배웁니다

학습 목표

  1. LLM invoke의 3가지 입력 타입을 이해한다
  2. PromptTemplate으로 동적 프롬프트를 만든다
  3. BaseMessage 계층 구조(System, Human, AI, Tool)를 이해한다
  4. ChatPromptTemplate과 Few-shot 기법을 활용한다

1. invoke 입력 타입

LLM의 invoke 메서드는 3가지 타입만 받아들입니다:

다른 타입(숫자, 딕셔너리 등)을 넣으면 에러가 발생합니다:

python
llm.invoke(0)  # TypeError!
# invoke할 때 PromptValue, string, BaseMessage의 list만 가능

2. PromptTemplate

2.1 기본 개념

PromptTemplate은 프롬프트 안에 **Placeholder(자리표시자)**를 넣어 동적으로 값을 대입하는 도구입니다.

웹 개발에서 <input placeholder="이메일을 입력하세요"> 처럼, 중괄호 {country}가 Placeholder 역할을 합니다.

2.2 코드 예시

python
from langchain_core.prompts import PromptTemplate

# 템플릿 정의 (중괄호가 Placeholder)
prompt = PromptTemplate(
    template="What is the capital of {country}?",
    input_variables=["country"]
)

# invoke로 값 대입 → PromptValue 생성
prompt_value = prompt.invoke({"country": "France"})
print(prompt_value)
# StringPromptValue(text='What is the capital of France?')

2.3 PromptTemplate + LLM 연결

PromptTemplate의 결과(PromptValue)를 LLM에 바로 전달할 수 있습니다:

python
from langchain_ollama import ChatOllama
from langchain_core.prompts import PromptTemplate

llm = ChatOllama(model="llama3.2:1b")

prompt = PromptTemplate(
    template="What is the capital of {country}?",
    input_variables=["country"]
)

# PromptTemplate invoke → PromptValue → LLM invoke
prompt_value = prompt.invoke({"country": "France"})
response = llm.invoke(prompt_value)
print(response.content)  # "The capital of France is Paris."

3. BaseMessage 계층 구조

LangChain에서 메시지는 대화 참여자의 역할을 구분합니다. 모든 메시지는 BaseMessage를 상속합니다.

3.1 각 메시지의 역할

메시지역할예시
SystemMessage애플리케이션의 목적, 페르소나 지정"You are a helpful assistant"
HumanMessage사용자가 보내는 질문이나 명령"What is the capital of France?"
AIMessageLLM이 생성한 응답"The capital of France is Paris."
ToolMessage외부 도구(API 등)의 실행 결과날씨 API 응답, 검색 결과 등

3.2 메시지 리스트로 호출

메시지 리스트는 반드시 리스트로 감싸야 합니다:

python
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage

# 단일 메시지도 리스트로 감싸야 함
response = llm.invoke([HumanMessage(content="What is the capital of France?")])

# 여러 메시지 조합
messages = [
    SystemMessage(content="You are a helpful assistant."),
    HumanMessage(content="What is the capital of France?")
]
response = llm.invoke(messages)

주의: 마지막 메시지가 HumanMessage여야 LLM이 답변을 생성합니다. AIMessage로 끝나면 답변할 질문이 없는 것입니다.


4. Few-shot 학습

4.1 Few-shot이란?

Few-shot은 LLM에게 예제를 제공하여 원하는 형식으로 답변하도록 유도하는 기법입니다. 예제가 많을수록 정확도가 올라갑니다.

OpenAI 논문에 따르면:

  • Zero-shot (예제 0개): 정확도 10% 미만
  • One-shot (예제 1개): 정확도 약 50%
  • Few-shot (예제 여러 개): 정확도 크게 향상

4.2 메시지 리스트로 Few-shot 구현

python
messages = [
    SystemMessage(content="You are a helpful assistant."),
    # Few-shot 예제 (대화 이력처럼 구성)
    HumanMessage(content="What is the capital of South Korea?"),
    AIMessage(content="Seoul"),
    HumanMessage(content="What is the capital of Japan?"),
    AIMessage(content="Tokyo"),
    # 실제 질문
    HumanMessage(content="What is the capital of France?")
]

response = llm.invoke(messages)
print(response.content)  # "Paris"

핵심은 마치 대화 이력이 있던 것처럼 LLM을 속이는 것입니다. AI가 이전에 이런 형식으로 대답했다고 알려주면, 같은 형식을 따릅니다.


5. ChatPromptTemplate

5.1 메시지 리스트의 한계

메시지 리스트로 직접 구성하면 Placeholder 주입이 안 됩니다:

python
# 이렇게 하면 {country}가 대입되지 않음!
messages = [
    SystemMessage(content="You are a helpful assistant."),
    HumanMessage(content="What is the capital of {country}?")
]

5.2 ChatPromptTemplate 사용법

ChatPromptTemplate튜플 형식으로 메시지를 정의하고, Placeholder를 정상적으로 주입합니다:

python
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("human", "What is the capital of {country}?")
])

# invoke로 Placeholder 주입
prompt_value = prompt.invoke({"country": "France"})
print(prompt_value.messages)
# [SystemMessage(content='You are a helpful assistant.'),
#  HumanMessage(content='What is the capital of France?')]

5.3 PromptTemplate vs ChatPromptTemplate

ChatPromptTemplate이 가장 권장되는 이유:

  1. Placeholder 주입 가능
  2. LCEL 파이프라인에 연결 가능 (뒤에서 배울 | 연산자)
  3. 역할 분리 (System, Human, AI)가 명확

5.4 ChatPromptTemplate + LLM 호출

python
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate

llm = ChatOllama(model="llama3.2:1b")

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("human", "What is the capital of {country}?")
])

# PromptTemplate invoke → LLM invoke
prompt_value = prompt.invoke({"country": "France"})
response = llm.invoke(prompt_value)
print(response.content)  # "Paris"

핵심 정리

  • invokestring, PromptValue, List[BaseMessage] 3가지만 받음
  • PromptTemplate: 중괄호 {변수}로 Placeholder를 정의하고 invoke로 값을 대입
  • BaseMessage 4종: SystemMessage, HumanMessage, AIMessage, ToolMessage
  • Few-shot: 예제를 메시지 이력으로 제공하여 답변 형식을 유도 (예제가 많을수록 정확)
  • ChatPromptTemplate: 튜플 방식으로 역할별 메시지를 정의하며, LCEL 연계까지 가능하므로 가장 권장