Gemini 프롬프트 설계 전략 정리

cjkangme·2025년 12월 2일

TIL

목록 보기
43/43
post-thumbnail

개요

최근 AI 어플리케이션을 다루면서 프롬프트 엔지니어링의 중요성을 많이 체감하고 있는데요.
특정 상황에서의 팁이나 유용한 문구들은 많이 봤지만, 핵심 원칙 등 기본적인 프롬프트 엔지니어링 원칙에 대한 지식이 부족해서 각 모델 프로바이더들이 제공하는 공식문서를 읽고 정리하고자 합니다.

이번 내용은 최근 Gemini-3-pro를 발표한 구글의 공식문서입니다.

공식문서: 프롬프트 설계 전략

LLM 프롬프트 설계 전략

시스템 프롬프트는 모델의 답변을 결정하는 가장 중요한 부분입니다.
하지만 시스템 프롬프트 하나에서 모델의 응답 원칙, 응답에 대한 전반적인 가이드, 요청 및 출력 예시등이 함께 섞여서 제공되기 때문에 잘 구조화되지 않으면 모델이 의도치 않게 시스템 프롬프트를 해석할수도 있습니다. 이를 방지하기 위해 어느 부분이 무엇에 해당하는지 명확히 표시해주어야 합니다.

Prefix

모델에 이 문장이 어떤 가이드에 해당하는지 명시하기 위한 방법으로 prefix가 있습니다.

Classify the text as one of the following categories.
- large
- small
Text: Rhino
The answer is: large
Text: Mouse
The answer is: small
Text: Snail
The answer is: small
Text: Elephant
The answer is:

위 예시에서는 입력에 대한 prefix로 Text: 를 사용했고, 출력에 대한 prefix로 The answer is: 를 사용했습니다.

이렇게 prefix를 사용했다면, 일관성을 유지하기 위해 실제 user message에도 Text: prefix를 추가하는 것을 잊지 말아야 합니다. 또, 모델이 높은 확률로 The answer is: 로 응답을 시작할 것이기 때문에 유저에게 보여서 안된다면 해당부분을 제거하는 처리가 별도로 필요합니다.

Few shot

Few shot은 원하는 응답을 유도하기 위해 올바른 정답 예시를 모델에 제공하는 방법입니다.
제공하는 예시의 수에 따라 one shot, two shot..이 되는데 통틀어서 그냥 few shot이라 합니다.

Few shot은 프롬프트에서 명시적으로 설명하기 애매한 부분이나 암시적인 의도를 모델이 해석하는데 도움이 됩니다. 때문에 모든 것을 일일히 설명하기 어렵다면 few shot을 몇 개 제공하는 것이 효과적일 수 있습니다.

예시

  • 질문
Below are some examples showing a question, explanation, and answer format:

Question: Why is the sky blue?
Explanation1: The sky appears blue because of Rayleigh scattering, which causes
shorter blue wavelengths of light to be scattered more easily than longer red
wavelengths, making the sky look blue.
Explanation2: Due to Rayleigh scattering effect.
Answer: Explanation2

Question: What is the cause of earthquakes?
Explanation1: Sudden release of energy in the Earth's crust.
Explanation2: Earthquakes happen when tectonic plates suddenly slip or break
apart, causing a release of energy that creates seismic waves that can shake the
ground and cause damage.
Answer: Explanation1

Now, Answer the following question given the example formats above:

Question: How is snow formed?
Explanation1: Snow is formed when water vapor in the air freezes into ice
crystals in the atmosphere, which can combine and grow into snowflakes as they
fall through the atmosphere and accumulate on the ground.
Explanation2: Water vapor freezes into ice crystals forming snow.
Answer:
  • 응답
Answer: Explanation2

위 예시에서 시스템 프롬프트에서는 명시적으로 가이드를 제공하지 않았지만, 모델이 짧은 쪽을 선택하는 예시를 제공했습니다. 이를 통해 모델에게 짧게 요약된 문장을 선택하라는 가이드를 암시적으로 제공했고, 새 질문에도 모델이 짧은 쪽인 Explanation2를 선택하게 했습니다.

Few shot은 어떻게 전달할까?

few shot을 모델에 전달하기 위한 방법은 크게 두 가지가 있습니다.

1. 시스템 프롬프트에 포함하기

첫 번째 방법은 앞서 본 예시처럼 시스템 프롬프트에 예시를 포함하는 것입니다.
가장 단순한 방법이고, 시스템 프롬프트를 캐싱하면 모델 호출 비용이 저렴해진다는 장점도 있습니다.
특히 최신 대규모 LLM 모델들은 시스템 프롬프트 이해도가 뛰어나기 때문에 이것만으로 충분한 경우가 많습니다.

다만 주의해야 할 부분은 XML 문법이나 마크다운 헤더(###) 등으로 few shot이라는 것을 명확히 전달해야 한다는 것입니다.
XML 포맷으로 구분한다면 다음과 같이 작성할 수 있습니다.

<examples> 
	<example> 
		<input>이 영화 정말 최악이야.</input> 
		<output>Negative</output> 
	</example> 
	<example> 
		<input>배우들 연기가 좋았어.</input> 
		<output>Positive</output> 
	</example> 
</examples>

2. Fake history 만들기

두 번째 방법은 user-assitant 질의응답 쌍을 멀티턴 대화 형식으로 few shot 예시에 활용하는 방법입니다.

[ 
	{"role": "system", "content": "너는 감성 분석기야."}, 
	{"role": "user", "content": "이 영화 정말 최악이야."}, // Shot 1 입력 
	{"role": "assistant", "content": "Negative"}, // Shot 1 출력 
	{"role": "user", "content": "배우들 연기가 좋았어."}, // Shot 2 입력 
	{"role": "assistant", "content": "Positive"}, // Shot 2 출력 
	{"role": "user", "content": "지금 입력할 실제 데이터"} // 실제 질문 ]
]

위와 같은 방식으로 마치 이전에 모델에 질의응답이 오갔던 것 처럼 가짜 히스토리를 만들어 전달하는 방식입니다.
이 경우 모델이 few shot 패턴을 따르도록 확실히 강제할 수 있다는 장점이 있습니다. 다만 프롬프트 캐싱을 적용하기 어렵고, 일반적으로 메세지 한 턴에는 많은 special token이 덕지덕지 붙기 때문에 전체적으로 추론 비용이 비싸질 수 있습니다.

+ a (최대한 많은 few shot 활용하기)

few shot의 단점은 예시를 무한정 넣을 수 없다는 것입니다.
대부분의 에이전트는 상당히 복잡한 문제를 푸는 것을 목표로하기 때문에 예시 몇개로 모든 경우를 설명하는 것은 어렵죠.

이런 문제를 해결하기 위해 우선 few shot을 최대한 많이 만들어두고, RAG를 도입해서 유저 질문에 가장 적합한 few shot k개를 선별해서 사용하는 방법도 있습니다.
다만 RAG를 구축하고, 유저 질문과 유사한 case를 정확히 검색되게하기 위해 추가 LLM 단계가 붙어야 하는 등.. 많은 복잡도를 필요로하기 때문에 정말 필요할 때 도입하는게 좋을 것 같네요

few shot 사용 시 주의 사항

  • 적절한 개수로 사용하기. 너무 많은 예시를 사용하면 모델의 전체적인 성능이 저하되거나, 특정 case에 과적화될 수 있음
  • 모델이 따라야할 정답 패턴을 예시로 사용하기. 하면 안되는 것을 설명하면 덜 효과적이라고 한다.
  • 일관된 형식 사용하기 (XML 태그, 공백, 줄바꿈 문자 등)

Context

개인적으로 사람들이 LLM 사용 시 흔히 갖는 오해는, 대충 물어봐도 의도를 알아서 파악해서 구글 검색이나 사전처럼 정확한 답변을 해줄 것이라 기대한다는 점입니다.
적어도 제가 아는 고전적인 LLM 학습 방법으로 학습된 모델은 그렇지 않을 가능성이 높습니다. 모델은 대충 물어본 질문에 대해서는 일반적으로 아주 평균적인 (번지르르하지만 실제 도움은 안되는..) 대답을 할 것입니다.

예시

공식 문서에서 제공하는 예시에서도 이러한 점을 잘 보여줍니다.

  • 질문
What should I do to fix my disconnected wifi? The light on my Google
Wifi router is yellow and blinking slowly.
  • 답변
A yellow blinking light on your Google Wifi router usually indicates a problem
with the internet connection. Here are some steps to troubleshoot and fix the
issue:
1. Restart your router and modem:
- Unplug your modem from the power outlet and wait for 30 seconds.
- Plug your modem back in and wait for it to fully boot up.
- Unplug your Google Wifi router and wait for 30 seconds.
- Plug your Google Wifi router back in and wait for it to fully boot up.
.....

유저는 Wifi router is yellow and blinking slowly라는 현상을 제공했지만, 모델은 그냥 고장났을 때 흔하게 사용하는 대처 방법 정도만 설명했습니다.

모델이 사용자가 제시한 라우터 문제에 대한 정확한 지식을 갖고 사용자에게 응답을 제공하기 위해서는 모델에게 직접 지식을 주입해야 합니다.

Answer the question using the text below. Respond with only the text provided.
Question: What should I do to fix my disconnected wifi? The light on my Google Wifi router is yellow and blinking slowly.

Text:
Color: Slowly pulsing yellow
What it means: There is a network error.
What to do:
Check that the Ethernet cable is connected to both your router and your modem and both devices are turned on. You might need to unplug and plug in each device again.

Color: Fast blinking yellow
What it means: You are holding down the reset button and are factory resetting this device.
What to do:
If you keep holding down the reset button, after about 12 seconds, the light will turn solid yellow. Once it is solid yellow, let go of the factory reset button.

Color: Solid yellow
What it means: Router is factory resetting.
What to do:
This can take up to 10 minutes. When it's done, the device will reset itself and start pulsing white, letting you know it's ready for setup.

Color: Solid red
What it means: Something is wrong.
What to do:
Critical failure. Factory reset the router. If the light stays red, contact Wifi customer support.

이렇게 Wifi router의 불빛 색과, 상태를 명시하는 Context를 추가해주면 모델이 해당 context를 참고해서 좋은품질의 대답을 생성할 것입니다.

Context 주입하기 (Context Grounding)

Context를 제공하는 방법은 검색 API, DB 조회(Text2SQL 등으로 쿼리 생성), RAG 등의 기능을 Tool로 제공하여 모델이 선택해서 사용하게 하거나, 무조건 사용한 다음 모델에 주입하는 방식이 있습니다.

또 Context를 가져오는 것 뿐만 아니라 LLM에 자연스럽게 주입하는 것도 중요합니다.
이를 Context Grouding이라고 합니다.

1. User message에 주입하기

가장 범용적인 방법은 user message에 주입하는 것입니다. 이 방법은 어떤 대화에서 어떤 context를 사용했는지 기록하기 용이하다는 장점이 있습니다.
하지만 잘못 주입하면 모델이 엉뚱한 소리를 하게될수도 있습니다.

가령 오늘 삼성전자 어때? 라는 질문에 대해 삼성전자에 대한 웹 검색 결과를 Context로 추가하고자 할 때 다음과 같이 그냥 합쳐버릴 수 있습니다.

2024년 5월 20일 기준 삼성전자 종가는 78,000원입니다. 최근 반도체 업황 개선 기대감으로 주가가 상승세입니다. 오늘 삼성전자 어때?

이러면 모델 입장에서는 사용자가 정보를 물어본 것인지, 자신에게 정보를 준 것인지 헷갈릴 것입니다.
그래서 제공 해주신 정보에 따르면~~ 이라는 유저 입장에서는 황당하게 들릴 수 있는 응답을 잘 못 말할 가능성이 높습니다.

다음의 <context>를 바탕으로 사용자의 질문에 답변해. <context>에 없는 내용은 지어내지 마.

<context> 
[문서1] 2024년 5월 20일 기준 삼성전자 종가는 78,000원입니다. 
[문서2] 최근 반도체 업황 개선 기대감으로 주가가 상승세입니다. 
</context> 

질문: 오늘 삼성전자 주가 흐름 어때?

이렇게 context를 잘 파싱해서 전달하면 모델은 context가 참고자료라는 것을 이해하고 사용자에 질문에 대해서만 잘 대답해 줄 것입니다.

2. Tool message에 주입하기


openai, claude의 경우 위와 같이 Tool의 실행결과, 즉 검색 결과와 같은 context를 담을 수 있는 role을 별도로 제공해줍니다.

User message에 담는다면 우리가 수동으로 관리하는 셈이지만, Tool message에 담는다면 해당 모델에 최적화 된 방법으로 context 주입이 된다는 것을 기대할 수 있습니다. 무엇보다 가장 쉽구요.

다만, SDK마다 제공 여부, 문법이 다르기 때문에 범용적으로 사용하기 어렵다는 단점이 있습니다.

프롬프트 세분화(문제를 작게 쪼개기)

풀어야 하는 문제가 복잡하다면, 하나의 프롬프트에 모든 설명을 담기보다는 여러개의 LLM Call로 쪼개고 각각의 Call마다 더 단순한 시스템 프롬프트를 작성하는 것이 더 효과적일 수 있습니다.

이렇게 문제를 작게 쪼개면 복잡성을 관리하기 쉬워지고, 특정 문제에 대한 프롬프트 수정이 다른 부분에도 영향을 줄 것을 걱정할 필요 없이 해당 문제에만 집중할 수 있습니다.

세분화된 각각의 LLM Call을 바탕으로 최종 출력을 만들기 위해서는, 각 LLM Call을 적절히 엮어주어야 합니다. 이것도 여러가지 방법이 있습니다.

1. 프롬프트 체이닝


문제 해결 순서에 따라 순차적으로 LLM Call을 하는 방식입니다. 이전 단계의 output이 다음 단계의 input이 됩니다.

흔히 우리가 생각하는 문제 해결 절차를 그대로 구현하는 장점이 있지만, 순차적으로 진행하기 때문에 단계가 많아질수록 오래 걸린다는 단점이 있습니다.

2. 병렬 실행 및 집계


세분화된 문제가 서로 연관이 없는 문제라면 한 번에 병렬적으로 실행할 수 있습니다.
이 경우 일반적으로 각 LLM이 생성한 응답을 정리해서 최종 응답을 만드는 모델이 추가로 붙습니다.

병렬 실행이기 때문에 훨씬 효율적이지만, 각 모델 사이의 연관성이 사라지기 때문에 병렬 처리해도 되는지는 신중히 판단해야 합니다.

실험과 개선 반복하기 하기 (노가다 하기)

위 방법들은 좋은 시스템 프롬프트를 만들기 위한 원칙들이지만, 결국 내가 해결해야 하는 문제에 대해 만족스러운 답변을 얻으려면 실험 -> 평가 -> 개선을 반복해야 합니다.

Gemini3용 가이드

지금까지의 가이드는 모델에 상관없이 전반적으로 적용하면 좋은 가이드였고, 지금부터는 Gemini3에 특히 적합한 가이드들입니다.

핵심 프롬프팅 원칙

  • 명확하고 직접적으로 표현하기: 간접적인 표현이나 불필요하게 설득적인 표현을 사용하지 마세요
  • 일관된 구조 사용: XML 태그, 마크다운 제목 등 명확한 separator를 사용해 프롬프트의 각 부분을 구별하세요.
  • 파라미터 정의: 모호한 용어나 파라미터가 프롬프트에 사용된다면 명시적으로 설명하세요.
  • 출력 스타일 가이드 정의: Gemini3는 기본적으로 효율적으로 간결한 답을 출력합니다. 대화체 스타일이나 자세한 설명이 필요하다면 프롬프트에 명시하세요.
  • 멀티모달 입력 처리: Gemini3는 텍스트 외에 이미지, 오디오, 비디오 등을 입력받을 수 있으므로, 이를 일관적으로 적절히 처리해주어야 모델이 참조할 수 있습니다.
  • 중요한 안내에 대해서 우선순위 지정하기: 필수 제약조건, 페르소나, 출력 형식 등 중요한 안내는 명확히 명시하고, 시스템 프롬프트나 유저 메세지의 가장 앞에 배치하세요.
  • 긴 컨텍스트는 가장 앞에 두기: 긴 컨텍스트를 user message로 제공할 때는 컨텍스트를 먼저 제공하고, 구체적인 질문, 요청사항은 프롬프트의 가장 마지막에 배치하세요
  • 컨텍스트 구분하기: 각 컨텍스트 블록이 큰 경우 명확한 전환문구를 사용해서 질문과 연결하세요. (위의 정보를 바탕으로...)

일관된 구조 예시

  • XML
<role>
You are a helpful assistant.
</role>

<constraints>
1. Be objective.
2. Cite sources.
</constraints>

<context>
[Insert User Input Here - The model knows this is data, not instructions]
</context>

<task>
[Insert the specific user request here]
</task>
  • 마크다운
# Identity
You are a senior solution architect.

# Constraints
- No external libraries allowed.
- Python 3.11+ syntax only.

# Output format
Return a single code block.

템플릿

공식문서에서 앞서 안내된 핵심 프롬프팅 원칙을 포함한 시스템 프롬프트 템플릿을 제공하고 있습니다.

0개의 댓글