같은 모델이라도 어떻게 묻느냐에 따라 답의 품질이 크게 달라진다. 이 편에서는 실무에서 가장 많이 쓰는 프롬프트 기법 네 가지 — PromptTemplate, 역할 부여, Zero-shot, Few-shot — 를 Spring AI 코드로 익힌다.
이 편에서 만드는 것
/prompt/template · /prompt/role · /prompt/zero-shot · /prompt/few-shot 네 개의 엔드포인트.
1. PromptTemplate — 틀에 값 채우기
프롬프트에 {변수}를 두고 실행 시점에 값을 채운다. 사용자 입력을 안전하게 끼워 넣고, 프롬프트를 재사용할 수 있다.
public String promptTemplate(String city, String days) {
PromptTemplate template = new PromptTemplate("""
너는 여행 가이드야.
{city}를 {days}일 동안 여행하는 일정을 하루 한 줄로 추천해줘.
""");
Prompt prompt = template.create(Map.of("city", city, "days", days)); // 변수 바인딩
return chatClient.prompt(prompt).call().content();
}curl -G "http://localhost:8080/prompt/template" \
--data-urlencode "city=교토" --data-urlencode "days=2"
# 1일차: 기온 거리와 청수사 … 2일차: 아라시야마 대나무 숲과 금각사 …문자열 연결과의 차이
"...." + city + "...." 로 직접 이어 붙여도 되지만, PromptTemplate은 변수를 명시적으로 분리해 재사용·테스트·다국어화가 쉽다. 프롬프트를 외부 파일(.st)로 빼내 관리할 수도 있다.
2. 역할 부여(Role) — 말투와 관점 고정
system 메시지로 모델에 역할을 입히면 답의 어조·전문성·관점이 일관되게 유지된다.
public String role(String question) {
return chatClient.prompt()
.system("너는 30년 경력의 한식 셰프야. 항상 요리사 관점에서 친근한 반말로 답해.")
.user(question)
.call()
.content();
}curl -G "http://localhost:8080/prompt/role" \
--data-urlencode "question=김치찌개 맛있게 끓이는 비법 하나만"
# 익은 김치를 써! 그래야 깊은 맛이 나거든 … (셰프 말투)flowchart LR
S["system: '너는 한식 셰프야'"] --> LLM
U["user: '김치찌개 비법?'"] --> LLM
LLM --> A["셰프 관점의 반말 답변"]3. Zero-shot — 예시 없이 바로 지시
예시를 주지 않고 작업만 지시하는 방식. 분류·요약처럼 모델이 이미 잘 아는 일에 적합하다.
public String zeroShot(String review) {
return chatClient.prompt()
.user("""
다음 리뷰의 감정을 긍정/부정/중립 중 하나로만 답해.
리뷰: %s
""".formatted(review))
.call()
.content();
}curl -G "http://localhost:8080/prompt/zero-shot" \
--data-urlencode "review=배송도 빠르고 품질도 최고예요"
# 긍정출력 형식을 좁혀라
"긍정/부정/중립 중 하나로만"처럼 답의 형태를 못 박으면 후처리가 쉬워진다. 더 엄격하게 Java 객체로 받고 싶다면 구조화 출력 편을 보라.
4. Few-shot — 예시 몇 개로 형식 학습
원하는 입출력 예시를 몇 개 보여 주면, 모델이 그 패턴을 따라 한다. 출력 형식이 까다롭거나 도메인 특수 규칙이 있을 때 강력하다.
public String fewShot(String order) {
return chatClient.prompt()
.user("""
주문 문장에서 메뉴와 수량을 JSON으로 뽑아줘.
예시1) "아메리카노 두 잔 주세요" -> {"menu":"아메리카노","qty":2}
예시2) "라떼 한 잔이요" -> {"menu":"라떼","qty":1}
주문: %s
""".formatted(order))
.call()
.content();
}curl -G "http://localhost:8080/prompt/few-shot" \
--data-urlencode "order=카푸치노 세 잔 포장해주세요"
# {"menu":"카푸치노","qty":3}기법 한눈에 보기
기법 | 핵심 | 적합한 작업 |
|---|---|---|
PromptTemplate |
| 입력이 바뀌는 재사용 프롬프트 |
역할 부여 | system으로 관점·말투 고정 | 챗봇 페르소나, 도메인 전문가 |
Zero-shot | 예시 없이 지시 | 분류·요약 등 일반 작업 |
Few-shot | 예시로 패턴 학습 | 특수 출력 형식·도메인 규칙 |
더 복잡한 기법들
Chain-of-Thought(단계적 추론), Self-Consistency(여러 추론 경로 비교) 같은 고급 기법도 있으나, 실무에서는 위 네 가지의 조합으로 대부분 해결된다. 출력을 코드로 안정적으로 받는 것이 더 중요하므로 다음 편으로 이어진다.
➡️ 다음 편: 구조화 출력