테마
프롬프트 템플릿과 메시지
LLM에게 질문을 전달하는 3가지 방법과, 프롬프트를 유연하게 구성하는 템플릿을 배웁니다
학습 목표
- LLM invoke의 3가지 입력 타입을 이해한다
- PromptTemplate으로 동적 프롬프트를 만든다
- BaseMessage 계층 구조(System, Human, AI, Tool)를 이해한다
- 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?" |
| AIMessage | LLM이 생성한 응답 | "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이 가장 권장되는 이유:
- Placeholder 주입 가능
- LCEL 파이프라인에 연결 가능 (뒤에서 배울
|연산자) - 역할 분리 (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"핵심 정리
invoke는 string, PromptValue, List[BaseMessage] 3가지만 받음- PromptTemplate: 중괄호
{변수}로 Placeholder를 정의하고 invoke로 값을 대입 - BaseMessage 4종: SystemMessage, HumanMessage, AIMessage, ToolMessage
- Few-shot: 예제를 메시지 이력으로 제공하여 답변 형식을 유도 (예제가 많을수록 정확)
- ChatPromptTemplate: 튜플 방식으로 역할별 메시지를 정의하며, LCEL 연계까지 가능하므로 가장 권장