Gemma를 위한 프롬프트 엔지니어링 (Prompt Engineering) 모범 사례
요약
Gemma 모델의 성능을 극대화하기 위한 프롬프트 엔지니어링 모범 사례를 다룹니다. 채팅 템플릿의 올바른 사용법, 명확한 구조화, 퓨샷 예시 활용 및 온도 설정 등 실무적인 가이드를 제공합니다.
핵심 포인트
- Gemma 전용 채팅 템플릿(<start_of_turn>)을 정확히 준수해야 함
- 시스템 역할 대신 첫 번째 사용자 턴에 지침을 포함해야 함
- 구분자(##, <tag>)를 사용하여 지시 사항과 데이터를 명확히 분리
- JSON 등 특정 형식이 필요한 경우 퓨샷(Few-shot) 예시를 활용할 것
- 토크나이저의 채팅 템플릿 헬퍼를 사용하여 형식 오류 방지
Gemma로부터 양질의 출력을 얻는 것은 영리한 기술의 문제가 아닙니다. 이는 모델의 정확한 채팅 템플릿 (Chat Template)을 맞추고, 지침을 명확하게 구조화하며, 함수 호출 (Function-calling) 및 추론 (Reasoning) 기능에 추가적인 가드레일 (Guardrails)이 필요한 지점을 파악하는 것에 관한 것입니다. 이 가이드는 실제로 실질적인 변화를 만들어내는 실용적인 프롬프팅 패턴을 다룹니다.
먼저 Gemma의 채팅 템플릿 (Chat Template)을 이해하세요
Gemma 모델은 Llama 모델에서 사용하는 [INST]/[/INST] 형식 대신 <start_of_turn> 및 <end_of_turn> 토큰을 턴 구분자로 사용합니다. 다른 모델 제품군의 형식을 혼합하는 것이 출력 품질 저하의 가장 흔한 원인입니다.
<start_of_turn>user
{system instructions + user message}<end_of_turn>
<start_of_turn>model
몇 가지 타협할 수 없는 규칙:
- Gemma의 채팅 템플릿에는 전용
system역할 (Role)이 없습니다. 시스템 수준의 지침은 별도의 역할로 보내는 대신 첫 번째 사용자 턴 (User turn)에 직접 추가되어야 합니다. - BOS 토큰
<bos>는apply_chat_template에 의해 자동으로 추가됩니다. 수동으로 추가하지 마세요. 그렇지 않으면 형식이 잘못된 프롬프트가 생성됩니다. - 함수 호출 (Function calling)을 사용할 때는
tools인자가 포함된apply_chat_template를 사용하여 스키마 (Schema)를 자동으로 주입되도록 하세요. 도구 JSON을 사용자 메시지에 직접 직렬화하면 모델이 학습한 형식이 깨집니다. - 원시 문자열을 직접 구축하기보다 항상 토크나이저 (Tokenizer)의 채팅 템플릿 헬퍼를 사용하세요. 작은 형식 오류 (추가 공백, 누락된 토큰)는 출력 품질을 눈에 띄게 저하시킵니다.
모든 프롬프트를 명확하게 구조화하세요
Gemma는 길고 구조화되지 않은 지침 문단보다 명시적인 구조를 가진 프롬프트에 가장 잘 반응합니다.
Task: 다음 트랜잭션 로그를 3개의 불렛 포인트로 요약하세요.
Input: {log text}
Output:
## 또는 사용자 정의 태그(<context>, <instruction>)와 같은 구분자(delimiters)를 사용하여 프롬프트의 서로 다른 부분을 시각적으로 분리하세요. 이는 모델이 어떤 텍스트가 지시 사항(instruction)이고 어떤 것이 처리할 데이터인지 오독할 가능성을 크게 줄여줍니다. 실제 지시 사항은 간결하게 유지하세요. 장황하고 반복적인 서문(preambles)은 짧고 직접적인 요청보다 결과가 좋지 않은 경향이 있습니다.
형식 제어를 위한 퓨샷 예시 (Few-Shot Examples) 사용
정확한 필드 이름을 가진 JSON, 특정 어조, 또는 고정된 구조와 같이 특정한 출력 형태가 필요한 경우, 형식을 말로만 설명하는 것보다 1~5개의 예시를 보여주는 것이 훨씬 더 안정적으로 작동합니다.
| 패턴 | 설명 | 예시 |
|---|---|---|
| 제로샷 (Zero-shot) | 예시 없는 직접적인 지시 | "송장 총액을 JSON으로 추출하세요: {amount: number}" |
| ... |
한 개발자는 명시적인 스키마 정의(schema definition)를 잘 구성된 단 하나의 예시와 결합하는 것만으로 JSON 전용 출력 정확도를 약 65%에서 95% 이상으로 높였다고 보고했습니다. 이는 모델 출력을 프로그래밍 방식으로 파싱하는 백엔드 통합(backend integrations) 작업에서 적은 투자로 큰 효과를 얻을 수 있는 방법입니다.
작업에 따른 온도 (Temperature) 설정
온도(Temperature)는 구조화된 작업(structured tasks)과 창의적인 작업(creative tasks)에 대한 Gemma의 신뢰성에 매우 큰 영향을 미칩니다.
- 개체 추출 (entity extraction), 번역, 분류, 또는 백엔드 로직에 직접 입력되는 작업과 같이 결정론적인(deterministic) 작업에는 0.1-0.2를 사용하세요.
- 일반적인 대화 또는 균형 잡힌 추론 작업에는 0.7-1.0을 사용하세요.
- 브레인스토밍이나 콘텐츠 초안 작성과 같이 가변성(variability)이 바람직한 창의적 생성 작업에만 1.2-2.0을 사용하세요.
- 조정해야 할 특별한 이유가 없다면 다른 샘플링 파라미터(top-p, top-k)는 기본값으로 두세요. 여러 파라미터를 한꺼번에 과도하게 조정하면 출력 품질의 디버깅이 훨씬 어려워집니다.
함수 호출 (Function Calling) 및 에이전트 (Agents)를 위한 프롬프트 엔지니어링
Gemma의 도구 호출 (Tool-calling)은 도구 설명과 시스템 지침 (System instructions)이 정밀할 때만 안정적으로 작동합니다. 모호한 설명은 에이전트가 도구를 무시하거나 불필요하게 호출하게 만드는 가장 큰 원인입니다.
- 상세하고 구체적인 도구 설명을 작성하세요 — 모델은 어떤 도구를 언제 호출할지 결정하기 위해 전적으로 이 설명에 의존합니다.
- JSON 스키마 (JSON schemas)에서
required필드를 사용하여 모델이 중요한 파라미터 (Parameters)를 누락하는 것을 방지하세요. - 호출당 사용 가능한 도구의 수를 5~10개로 제한하세요; 옵션이 너무 많으면 도구 선택 시 눈에 띄게 혼란을 줍니다.
- 올바른 인자 (Argument) 형식을 안내하기 위해 파라미터 설명에 예시 값을 포함하세요 (예: "도시 이름, 예: 'Lagos', 'London'").
- 모델이 도구를 무시하고 자신의 지식으로 직접 답변한다면, "계좌 잔액이나 거래 데이터를 절대 추측하지 마세요 — 항상 제공된 도구를 사용하세요"와 같은 명시적인 지침을 추가하세요.
- 모델이 도구를 불필요하게 호출한다면, "사용자가 명시적으로 잔액 확인을 요청할 때만 사용하세요"와 같이 범위를 제한하는 조건으로 설명을 강화하세요.
- 무한 도구 호출 루프를 방지하기 위해 에이전트 루프 (Agent loop)에
max_steps제한을 설정하세요. - 구조화된 에러 정보를 반환하여 도구 에러를 유연하게 처리하세요. 이를 통해 모델이 조용히 실패하는 대신 재시도하거나 사용자에게 실패 원인을 설명할 수 있습니다.
계좌 조회나 청구서 결제를 처리하는 핀테크 (Fintech) 에이전트의 경우, 이러한 가드레일 (Guardrails)은 일반적인 프롬프트 문구보다 더 중요합니다. 잘 설명된 도구 스키마는 프롬프트 자체의 그 어떤 설득력 있는 문구보다 더 큰 역할을 합니다.
복잡한 다단계 로직 분해 (Break Down Complex Multi-Step Logic)
단일 프롬프트가 조건부 다단계 추론("먼저 X를 수행하고, 결과가 A이면 M을 수행하고, 그렇지 않으면 N을 수행한 뒤 Y를 수행하세요")을 요구하는 경우, Gemma는 모든 분기 로직을 한 번에 실행하도록 요청하는 것보다 코드에서 체인(Chain)으로 연결된 별도의 호출로 분리했을 때 더 안정적으로 작동합니다. 각각의 개별 호출은 하나의 명확하고 제한된 작업에 집중하도록 유지하세요.
출력을 짧고 의도적으로 유지하기 (Keep Output Short and Deliberate)
추론 속도(Inference speed)는 출력 길이에 크게 좌우되므로, 불필요한 장황함을 줄이는 것은 품질과 성능 측면 모두에서 이점이 있습니다.
- 작업을 충족하는 가장 짧은 출력을 명시적으로 요청하세요. 그런 다음 모델이 모든 것을 완벽하게 형식화하도록 의존하기보다는 코드 내에서 가벼운 후처리(post-processing)를 수행하세요.
- 온디바이스(on-device) 또는 저지연(low-latency) 사용 사례(E2B/E4B)의 경우, 생성되는 모든 추가 토큰이 응답 시간에 직접적으로 더해지기 때문에 이 점이 더욱 중요합니다.
- 동일한 호출에서 긴 설명과 구조화된 답변을 모두 요청하는 것을 피하세요. 구조화된 답변만 요청하고, 디버깅을 위해 추론 과정이 필요한 경우 별도로 기록(log)하세요.
Python 예제: 엔드투엔드(End-to-End) 함수 호출 (Function Calling)
다음은 transformers 라이브러리와 tools 스키마를 사용하는 apply_chat_template을 이용한 최소한의 작동 패턴입니다. 이는 위에서 설명한 수동 직렬화(manual-serialization)의 함정을 피하는 것과 동일한 접근 방식입니다.
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch, json
...
이 예제가 실제로 보여주는 몇 가지 사항은 다음과 같습니다:
- 도구의
description은 모델이 언제 이를 호출해야 하는지 명시적으로 범위를 지정하며, 이는 위에서 언급한 "설명을 구체화하라"는 지침을 직접적으로 적용한 것입니다. required: ["account_id"]는 모델이 유효한 인자 없이 함수를 호출하는 것을 방지합니다.- Temperature는
0.1로 설정되어 있으며, 이는 백엔드 로직으로 전달되는 모든 작업에 대한 결정론적 작업(deterministic-task) 지침과 일치합니다. - 응답은
try/except를 사용하여 방어적으로 파싱됩니다. 프로덕션 에이전트 루프(agent loops)는 모델이 구조화된 호출 대신 일반 텍스트로 응답하는 경우를 항상 처리해야 하기 때문입니다.
전체 에이전트 루프를 구현하려면 이를 max_steps 카운터가 있는 while 루프로 감싸고, 함수의 반환 값을 tool 역할의 턴으로 메시지 기록에 다시 입력한 후 generate를 다시 호출하세요.
피해야 할 일반적인 프롬프팅 실수
- Gemma의 네이티브
<start_of_turn>템플릿 대신 다른 모델 제품군의 프롬프트 형식([INST], ChatML)을 혼합하여 사용함 apply_chat_template을 사용하는 대신 BOS 토큰을 수동으로 삽입하거나 도구 스키마 (tool schemas)를 직접 직렬화함- 모호한 도구 설명을 작성하고 신뢰할 수 있는 함수 호출 (function-calling) 결정을 기대함
- 매우 다른 작업들(데이터 추출 vs 창의적 글쓰기)에 대해 단일한 온도 (temperature) 설정을 사용함
- 집중된 호출을 체이닝 (chaining)하는 대신 하나의 프롬프트에서 다단계 조건부 로직을 요구함
- 백엔드 파싱을 위해 엄격한 출력 형식(JSON 등)이 필요한 경우 퓨샷 (few-shot) 예시를 생략함
이러한 기본 사항들 — 올바른 채팅 템플릿 (chat template), 명확한 구조, 작업에 적합한 온도 (temperature), 그리고 정밀한 도구 설명 — 을 제대로 갖추는 것만으로도, 더 깊은 미세 조정 (fine-tuning)이 필요하기 전에 발생하는 "Gemma가 지침을 따르지 않는다"는 불만 사항의 대부분을 해결할 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기