아래 내용은 번역한 내용이며, 해당 원서는 아래에 올렸습니다.
프롬프트 엔지니어링
저자: Lee Boonstra
감사의 말
검토자 및 기여자
Michael Sherman, Yuan Cao, Erick Armbrust, Anant Nawalgaria, Antonio Gulli, Simone Cammel
큐레이터 및 편집자
Antonio Gulli, Anant Nawalgaria, Grace Mollison
기술 문서 작성자
Joey Haymaker
디자이너
Michael Lanning
목차
- 서론
- 프롬프트 엔지니어링
- LLM 출력 구성
- 출력 길이
- 샘플링 제어
- 온도
- Top-K 및 Top-P
- 통합하기
- 프롬프트 기술
- 일반 프롬프트 / 제로샷
- 원샷 및 퓨샷
- 시스템, 문맥 및 역할 프롬프트
- 시스템 프롬프트
- 역할 프롬프트
- 문맥 프롬프트
- Step-back 프롬프트
- Chain of Thought (CoT)
- 자기 일관성(Self-consistency)
- Tree of Thoughts (ToT)
- ReAct (이성적 사고 & 행동)
- 자동 프롬프트 엔지니어링
- 코드 프롬프트
- 코드 작성을 위한 프롬프트
- 코드 설명 프롬프트
- 코드 번역 프롬프트
- 코드 디버깅 및 리뷰 프롬프트
- 멀티모달 프롬프트란?
베스트 프랙티스
- 예시 제공
- 단순함으로 설계하기
- 출력에 대해 구체적으로 작성하기
- 제약 조건보다 지시문 사용하기
- 최대 토큰 길이 제어하기
- 프롬프트에 변수 사용하기
- 입력 형식 및 작문 스타일 실험하기
- 퓨샷 분류 작업에서는 클래스 순서를 섞기
- 모델 업데이트에 적응하기
- 출력 형식 실험하기
- 다른 프롬프트 엔지니어들과 함께 실험하기
- CoT 베스트 프랙티스
- 다양한 프롬프트 시도 문서화하기
요약
엔드노트
"데이터 과학자나 머신러닝 엔지니어가 될 필요는 없습니다. 누구나 프롬프트를 작성할 수 있습니다."
서론
대규모 언어 모델(LLM)의 입력과 출력을 생각할 때, 텍스트 프롬프트(때로는 이미지 프롬프트와 같은 다른 형태와 함께 제공되기도 함)는 모델이 특정 출력을 예측하기 위해 사용하는 입력입니다. 데이터 과학자나 머신러닝 엔지니어일 필요는 없습니다. 누구나 프롬프트를 작성할 수 있습니다. 그러나 가장 효과적인 프롬프트를 작성하는 것은 복잡할 수 있습니다.
프롬프트의 많은 요소들이 그 효과성에 영향을 미칩니다: 사용하는 모델, 모델의 학습 데이터, 모델 구성, 단어 선택, 스타일과 톤, 구조, 그리고 문맥 모두 중요합니다. 따라서 프롬프트 엔지니어링은 반복적인 과정입니다. 부적절한 프롬프트는 모호하고 부정확한 응답으로 이어질 수 있으며, 모델이 의미 있는 출력을 제공하는 능력을 저해할 수 있습니다.
Gemini 챗봇과 대화할 때 여러분은 기본적으로 프롬프트를 작성하고 있는 것입니다. 하지만 이 백서에서는 Vertex AI 내에서 Gemini 모델을 사용하거나 API를 통해 직접 프롬프트를 작성하는 방법에 초점을 맞춥니다. 이렇게 직접 프롬프트를 작성하면 온도(temperature)와 같은 구성 요소에 접근할 수 있기 때문입니다.
이 백서는 프롬프트 엔지니어링을 자세히 다룹니다. 프롬프트 작성을 시작하는 데 도움이 될 다양한 프롬프트 기술을 살펴보고, 프롬프트 전문가가 되기 위한 팁과 모범 사례도 공유합니다. 또한 프롬프트를 작성할 때 마주칠 수 있는 몇 가지 과제도 다룰 것입니다.
LLM은 이 과정을 계속 반복하도록 운영되며, 이전에 예측된 토큰을 순차적 텍스트의 끝에 추가하여 다음 토큰을 예측합니다. 다음 토큰의 예측은 이전 토큰에 있는 내용과 모델이 학습 중에 본 것들 간의 관계에 기반합니다.
프롬프트를 작성할 때, 여러분은 LLM이 올바른 토큰 시퀀스를 예측하도록 설정하려는 것입니다.
프롬프트 엔지니어링은 LLM이 정확한 출력을 생성하도록 안내하는 고품질 프롬프트를 설계하는 과정입니다.
이 과정에는 최적의 프롬프트를 찾기 위한 실험, 프롬프트 길이 최적화, 과업과의 관련성 측면에서 프롬프트의 작성 스타일과 구조를 평가하는 작업이 포함됩니다.
자연어 처리(NLP)와 LLM의 문맥에서 프롬프트는 모델에 제공되어 응답 또는 예측을 생성하도록 하는 입력입니다.
이러한 프롬프트는 다음과 같은 다양한 이해 및 생성 과업을 달성하는 데 사용될 수 있습니다:
텍스트 요약, 정보 추출, 질문 및 응답, 텍스트 분류, 언어 또는 코드 번역, 코드 생성, 코드 문서화 또는 추론 등입니다.
간단하고 효과적인 프롬프트 예제가 포함된 Google의 프롬프트 가이드를 참고해도 좋습니다【주2,3】.
프롬프트 엔지니어링을 할 때는 모델을 선택하는 것부터 시작합니다. 사용 중인 모델이 Gemini, GPT, Claude, 또는 Gemma나 LLaMA 같은 오픈소스 모델이든 상관없이 프롬프트는 특정 모델에 맞게 최적화되어야 할 수도 있습니다.
프롬프트 외에도, LLM의 다양한 구성 요소들을 실험적으로 조정해야 할 수 있습니다.
LLM 출력 구성
모델을 선택한 후에는 그 모델의 구성을 이해하고 설정해야 합니다. 대부분의 LLM은 출력 결과를 제어하는 다양한 구성 옵션을 제공합니다.
효과적인 프롬프트 엔지니어링은 과업에 맞게 이러한 설정들을 최적으로 조정하는 것을 요구합니다.
출력 길이 (Output length)
중요한 구성 설정 중 하나는 응답에서 생성할 토큰 수입니다.
더 많은 토큰을 생성하는 것은 LLM의 더 많은 계산을 요구하며, 이는 더 높은 에너지 소비, 느린 응답 시간, 더 높은 비용으로 이어질 수 있습니다.
LLM의 출력 길이를 줄인다고 해서 LLM이 더 간결하거나 스타일상 정리된 출력을 생성하는 것은 아닙니다.
단지 정해진 토큰 수에 도달하면 예측을 멈출 뿐입니다.
짧은 출력이 필요한 경우, 프롬프트 자체도 이에 맞게 설계되어야 할 수 있습니다.
출력 길이 제한은 특히 ReAct와 같은 일부 LLM 프롬프트 기술에서 중요합니다. 이 경우 모델이 원하는 응답 이후에도 불필요한 토큰을 계속 출력할 수 있기 때문입니다.
샘플링 제어 (Sampling controls)
LLM은 단일 토큰을 "정확히" 예측하는 것이 아니라, 다음 토큰이 될 수 있는 후보에 대한 확률 분포를 예측합니다.
LLM의 어휘 내 각 토큰은 어떤 확률을 부여받으며, 그 확률을 기반으로 샘플링하여 다음에 생성될 토큰을 결정합니다.
Temperature, Top-K, Top-P는 예측된 토큰 확률을 처리하여 단일 출력 토큰을 선택하는 데 가장 흔히 사용되는 구성 설정입니다.
온도 (Temperature)
온도 설정은 토큰 선택에서 무작위성의 정도를 제어합니다.
낮은 온도는 더 결정적인(deterministic) 응답이 필요한 프롬프트에 적합하며,
높은 온도는 더 다양하거나 예측 불가능한 결과를 유도할 수 있습니다.
온도 0은 **탐욕적 디코딩(greedy decoding)**이라 불리며, 가장 높은 확률을 가진 토큰을 항상 선택합니다.
(단, 두 개 이상의 토큰이 동일한 확률을 가질 경우, 타이브레이크 방식에 따라 결과가 달라질 수 있음)
온도가 최대에 가까워질수록, 모든 토큰이 거의 동일한 확률을 가지게 되어 출력이 훨씬 더 무작위적이 됩니다.
가장 높은 확률을 가진 토큰이 두 개 이상일 경우, 타이브레이크(tiebreaking) 구현 방식에 따라 온도 0 설정에서도 항상 같은 출력이 나오지 않을 수도 있습니다.
온도가 최대치에 가까워지면 출력은 더욱 무작위성이 커지고, 온도가 매우 높아지면 모든 토큰이 동등하게 다음 예측 토큰이 될 가능성을 갖게 됩니다.
Gemini의 온도 제어는 머신러닝에서 사용되는 소프트맥스(softmax) 함수와 유사하게 이해할 수 있습니다. 낮은 온도 설정은 낮은 softmax 온도(T)와 비슷하게 작동하며, 확신을 가지고 하나의 선호 토큰을 강조합니다. 반면, 높은 Gemini 온도 설정은 높은 softmax 온도처럼 작동하여 선택된 설정 주변의 넓은 범위의 토큰을 수용 가능하게 만듭니다.
이러한 불확실성 증가는 정확한 온도가 필요하지 않은 창의적인 출력 실험과 같은 상황에 적합합니다.
Top-K 및 Top-P
Top-K와 Top-P(nucleus sampling이라고도 불림)는, LLM이 예측한 다음 토큰 후보를 가장 높은 확률을 가진 일부 토큰들로 제한하는 샘플링 설정입니다.
온도 설정과 마찬가지로, 이들 샘플링 설정은 출력되는 텍스트의 무작위성과 다양성을 제어합니다.
- Top-K 샘플링: 모델이 예측한 확률 분포 중 상위 K개의 가장 가능성 높은 토큰을 선택합니다.
- Top-K 값이 클수록 모델 출력은 더 창의적이고 다양해지며,
- Top-K 값이 작을수록 출력은 더 제한적이고 사실 기반이 됩니다.
- Top-K가 1이면, 이는 **탐욕적 디코딩(greedy decoding)**과 같습니다.
- Top-P 샘플링: 누적 확률이 특정 값 P를 넘지 않는 상위 토큰들만 선택합니다.
- P 값은 0(탐욕적 디코딩)부터 1(어휘 전체)까지 가능합니다.
Top-K와 Top-P 중 어떤 것을 사용할지는 두 가지 방법 모두 실험해보고 원하는 결과를 잘 생성하는 쪽을 선택하는 것이 가장 좋습니다.
두 설정을 함께 사용하는 것도 가능합니다.
또 하나 중요한 구성 설정은, 앞서 언급했듯이 응답에서 생성할 토큰 수입니다.
토큰을 더 많이 생성할수록 LLM이 더 많은 계산을 수행해야 하며, 더 높은 에너지 소비, 느린 응답 시간, 더 높은 비용이 발생할 수 있습니다.
모든 설정을 조합해서 이해하기
Top-K, Top-P, 온도, 출력 토큰 수를 어떻게 조합할지는 적용 사례와 원하는 결과에 따라 다릅니다.
이 설정들은 서로 영향을 주며 상호작용하기 때문에, 사용하는 모델이 이 샘플링 설정들을 어떻게 조합하는지도 반드시 이해해야 합니다.
예를 들어 Vertex AI Studio처럼 온도, Top-K, Top-P가 모두 사용 가능한 환경에서는,
Top-K와 Top-P 조건을 모두 만족하는 토큰들이 다음 예측 토큰 후보가 되고, 이후 온도가 적용되어 이들 중 하나가 선택됩니다.
Top-K 또는 Top-P 중 하나만 설정 가능할 경우, 해당 조건만 적용되어 무작위 샘플링이 이뤄집니다.
온도 설정이 없을 경우, Top-K 및/또는 Top-P 조건을 만족하는 토큰 중에서 무작위로 하나가 선택됩니다.
다음은 극단적인 샘플링 설정값이 어떻게 다른 설정을 무력화하는지에 대한 예입니다:
- 온도를 0으로 설정하면, Top-K와 Top-P는 무의미해집니다. 가장 확률이 높은 토큰 하나만 선택됩니다.
- 온도를 매우 높게(예: 1 이상, 심지어 10 이상) 설정하면, 온도 설정 자체가 의미 없어지고 Top-K/P 조건에 따라 샘플링됩니다.
- Top-K를 1로 설정하면, 온도와 Top-P 설정은 의미가 없어집니다. 단 하나의 토큰만 선택되기 때문입니다.
- Top-K를 매우 크게 설정하면(모델 어휘 크기만큼), 거의 모든 토큰이 후보가 되어 필터링 효과가 사라집니다.
- Top-P를 0이나 매우 작은 값으로 설정하면, 가장 확률 높은 토큰 하나만 선택되고, 다른 설정은 무의미해집니다.
- Top-P를 1로 설정하면, 확률이 0이 아닌 모든 토큰이 포함되어 필터링이 사라집니다.
초기 권장 설정 예시:
- 일반적인 창의적이지만 과도하지 않은 결과 →
온도: 0.2, Top-P: 0.95, Top-K: 30 - 더 창의적인 결과가 필요할 경우 →
온도: 0.9, Top-P: 0.99, Top-K: 40 - 덜 창의적이고 일관된 결과가 필요할 경우 →
온도: 0.1, Top-P: 0.9, Top-K: 20 - 정답이 하나뿐인 경우 (예: 수학 문제 답) →
온도: 0
주의: 온도, Top-K, Top-P, 출력 토큰 수의 자유도가 커질수록, LLM은 덜 관련된 텍스트를 생성할 가능성이 높아집니다.
Top-K 및/또는 Top-P 조건을 만족한 모든 토큰이 다음 예측 토큰 후보가 되고, 이 중 하나가 무작위로 샘플링됩니다.
- Top-K를 1로 설정하면, 온도와 Top-P는 무의미해집니다. Top-K 조건을 만족하는 단 하나의 토큰만 선택되고, 그 토큰이 예측 결과가 됩니다.
- Top-K를 매우 크게 설정하면 (예: LLM 어휘 전체 크기 수준), 확률이 0이 아닌 모든 토큰이 조건을 만족하게 되며, 선택이 제거되지 않습니다.
- Top-P를 0(또는 매우 작은 값) 으로 설정하면, 대부분의 LLM 샘플링 구현은 가장 높은 확률의 토큰만 Top-P 조건을 만족하는 것으로 간주하므로, 온도와 Top-K는 무의미해집니다.
- Top-P를 1로 설정하면, 확률이 0이 아닌 모든 토큰이 조건을 만족하게 되어, 필터링이 사라집니다.
일반적인 시작 지점 추천 설정:
- 온도: 0.2, Top-P: 0.95, Top-K: 30 → 일관성이 있으면서 적당히 창의적인 결과
- 온도: 0.9, Top-P: 0.99, Top-K: 40 → 특히 창의적인 결과
- 온도: 0.1, Top-P: 0.9, Top-K: 20 → 창의성을 줄인 결과
- 항상 정답이 하나인 과업(예: 수학 문제) → 온도: 0
주의: 온도, Top-K, Top-P, 출력 토큰 수의 자유도를 높이면, LLM이 관련성 낮은 텍스트를 생성할 가능성도 높아집니다.
프롬프트 기술 (Prompting Techniques)
LLM은 지시를 따르도록 튜닝되어 있고, 대량의 데이터를 기반으로 학습되어 프롬프트를 이해하고 응답을 생성할 수 있습니다.
하지만 LLM은 완벽하지 않으며, 프롬프트가 명확할수록 LLM이 다음 텍스트를 예측하는 데 더 유리합니다.
또한 LLM이 어떻게 학습되었는지와 작동 방식에 기반한 특정 기술을 사용하면 원하는 결과를 더 잘 얻을 수 있습니다.
이제 프롬프트 엔지니어링이 무엇이며 무엇이 필요한지 이해했으니,
가장 중요한 프롬프트 기법들 중 몇 가지 예시를 살펴보겠습니다.
일반 프롬프트 / 제로샷 (General Prompting / Zero-shot)
제로샷(Zero-shot) 프롬프트는 가장 단순한 형태의 프롬프트입니다.
단순히 과업에 대한 설명과 LLM이 시작할 수 있는 텍스트만 제공합니다.
이 입력은 질문, 이야기의 시작, 지시 등 무엇이든 될 수 있습니다.
‘제로샷’이라는 이름은 "예시 없음" 을 의미합니다.
우리는 Vertex AI의 언어용 Vertex AI Studio를 사용하여 프롬프트를 실험해볼 수 있습니다【주6】.
표 1에서는 영화 리뷰를 분류하는 제로샷 프롬프트 예시를 볼 수 있습니다.
아래의 표 형식은 프롬프트를 문서화하는 데 매우 좋은 방식입니다.
프롬프트는 코드베이스에 들어가기 전까지 여러 번의 반복을 거치게 되므로,
프롬프트 엔지니어링 작업을 체계적이고 구조적으로 기록하는 것이 매우 중요합니다.
이 표 형식, 프롬프트 엔지니어링 작업 추적의 중요성, 프롬프트 개발 프로세스에 대한 내용은
이 장의 뒷부분 [모범 사례] > "다양한 프롬프트 시도 문서화하기" 절에서 더 자세히 설명됩니다.
이 예시에서는 창의성이 필요 없기 때문에, 모델의 온도는 낮게 설정되어야 하며,
Gemini-pro의 기본 Top-K 및 Top-P 설정을 사용하여 이들을 효과적으로 비활성화합니다.
(위에서 설명한 LLM 출력 구성 참조)
생성된 출력에서 주의 깊게 봐야 할 점은, disturbing 과 masterpiece 라는 단어가 같은 문장에서 사용되어
예측을 더 복잡하게 만들 수 있다는 것입니다.
이번 부분은 원샷/퓨샷 프롬프트 기법과 시스템/문맥/역할 프롬프트의 개요를 설명하는 내용입니다.:
표 1. 제로샷 프롬프트 예시
제로샷이 효과적이지 않을 경우, 프롬프트 내에 데모나 예시를 제공할 수 있습니다.
이것이 바로 "원샷(one-shot)"과 "퓨샷(few-shot)" 프롬프트로 이어집니다.
원샷 & 퓨샷 (One-shot & Few-shot)
AI 모델을 위한 프롬프트를 생성할 때, 예시(example) 를 제공하는 것은 매우 도움이 됩니다.
이러한 예시는 모델이 당신이 요구하는 바를 이해하는 데 도움이 됩니다.
특히, 출력 구조나 패턴을 특정 방향으로 유도하고 싶을 때 예시는 매우 유용합니다.
- 원샷 프롬프트는 단 하나의 예시만 제공합니다. 이름 그대로 "한 번(one-shot)"의 예시입니다.
이 방식의 핵심은 모델에게 참고할 수 있는 예시를 제공함으로써, 과업을 모방하여 보다 잘 수행할 수 있도록 돕는 것입니다. - 퓨샷 프롬프트는 여러 개의 예시를 제공합니다.
이 접근 방식은 모델에게 따라야 할 패턴을 보여줍니다.
원샷과 비슷한 아이디어지만, 여러 개의 예시를 제공함으로써, 모델이 그 패턴을 따를 확률이 높아집니다.
퓨샷 프롬프트에서 필요한 예시의 수는 다음과 같은 요소에 따라 달라집니다:
- 과업의 복잡도
- 예시의 품질
- 사용하는 생성형 AI(GenAI) 모델의 능력
일반적인 경험칙으로는, 퓨샷 프롬프트에는 최소 3~5개의 예시를 사용하는 것이 좋습니다.
그러나 과제가 더 복잡할수록 예시를 더 많이 사용할 수도 있으며, 반대로 모델의 입력 길이 제한으로 인해 더 적은 수를 사용해야 할 수도 있습니다.
표 2는 퓨샷 프롬프트의 예시를 보여줍니다.
앞서와 동일한 Gemini-pro 모델 설정을 사용하되, 더 긴 응답을 수용하기 위해 토큰 제한을 증가시켜야 합니다.
표 2. 퓨샷 프롬프트의 예시
프롬프트에 사용할 예시를 선택할 때는, 반드시 해당 과업과 관련 있는 예시를 사용하세요.
예시는 다양하고, 높은 품질이며, 잘 작성된 문장이어야 합니다.
작은 실수 하나만으로도 모델이 혼란스러워져 원하지 않는 결과가 나올 수 있습니다.
다양한 입력에 대해 견고한 출력을 생성하려면, 예시 중에 에지 케이스(edge cases) 를 포함하는 것이 중요합니다.
에지 케이스란 비정상적이거나 예외적인 입력이지만, 모델이 문제 없이 처리할 수 있어야 하는 입력을 말합니다.
시스템, 문맥, 역할 프롬프트 (System, Contextual, and Role Prompting)
시스템 프롬프트, 문맥 프롬프트, 역할 프롬프트는 모두 LLM이 텍스트를 생성하는 방식을 안내하는 기술이지만, 집중하는 측면이 다릅니다.
- 시스템 프롬프트(System prompting):
LLM에 대해 전체적인 맥락과 목적을 설정합니다.
예를 들어 언어 번역, 리뷰 분류와 같은 작업을 명시함으로써 모델이 수행할 "큰 그림(big picture)"을 정의합니다. - 문맥 프롬프트(Contextual prompting):
현재 대화나 과업과 관련된 구체적인 세부 정보나 배경 정보를 제공합니다.
이것은 모델이 요청의 뉘앙스를 이해하고, 그에 맞는 응답을 조정하는 데 도움을 줍니다. - 역할 프롬프트(Role prompting):
LLM에게 특정한 인격이나 역할을 부여합니다.
예를 들어, "너는 여행 가이드야", "너는 유치원 선생님이야"처럼 일관된 스타일과 지식을 가진 응답을 생성하도록 합니다.
이 세 가지 프롬프트 유형 사이에는 상당한 중첩이 있을 수 있습니다.
예를 들어, 시스템에 역할을 부여하는 프롬프트는 동시에 문맥 정보를 포함할 수도 있습니다.
그러나 각 프롬프트는 약간씩 다른 주 목적(primary purpose) 을 가지고 있습니다:
- 시스템 프롬프트: 모델의 기본 능력과 전반적인 목적을 정의합니다.
- 문맥 프롬프트: 현재 과업 또는 입력에 특화된 정보를 제공합니다. 이 정보는 동적입니다.
- 역할 프롬프트: 모델의 출력 스타일과 목소리를 설정하며, 전문성이나 개성을 추가합니다.
다음은 시스템 프롬프트, 역할 프롬프트, 문맥 프롬프트 각각의 구체적인 예시를 포함한 설명입니다.
- 역할 프롬프트(Role prompt):
모델의 출력 스타일과 목소리를 정의합니다.
이는 응답에 특정성과 개성을 더하는 계층을 추가합니다.
시스템, 문맥, 역할 프롬프트를 구분하는 것은
명확한 의도를 가진 프롬프트를 설계하기 위한 체계를 제공하며,
프롬프트 간 유연한 조합을 가능하게 하고,
각 프롬프트 유형이 언어 모델 출력에 어떻게 영향을 주는지 분석하기 쉽게 만들어 줍니다.
이제 이 세 가지 프롬프트 유형 각각을 자세히 살펴보겠습니다.
시스템 프롬프트 (System Prompting)
표 3에는 시스템 프롬프트 예시가 들어 있습니다. 여기서는 출력 방식에 대해 추가 정보를 명확하게 지정하고 있습니다.
저는 더 높은 창의성 수준을 얻기 위해 온도를 높이고,
출력 토큰 수 제한도 증가시켰습니다.
하지만 출력 방식에 대한 명확한 지시가 있었기 때문에,
모델은 불필요한 추가 텍스트 없이 응답을 생성했습니다.
시스템 프롬프트는 특정 요건을 만족하는 출력을 생성할 때 유용할 수 있습니다.
'시스템 프롬프트(system prompt)'라는 이름은 실제로
시스템에 추가 과제를 제공하는 것을 의미합니다.
예를 들어, 특정 프로그래밍 언어와 호환되는 코드 조각을 생성하거나,
특정 구조로 응답을 반환하도록 시스템 프롬프트를 사용할 수 있습니다.
표 4에서는 JSON 형식으로 출력을 반환하는 시스템 프롬프트 예시를 보여줍니다.
표 4. JSON 형식 시스템 프롬프트 예시
데이터를 추출하는 프롬프트에서 JSON 객체를 반환하는 데에는 몇 가지 장점이 있습니다.
현실 세계의 애플리케이션에서는 이 JSON 형식을 수작업으로 만들 필요 없이,
데이터를 정렬된 순서로 바로 반환할 수 있습니다
(예: 날짜/시간(datetime) 객체를 다룰 때 매우 유용).
무엇보다 중요한 것은, JSON 형식으로 출력하도록 지시하면,
모델이 구조화된 응답을 생성하도록 유도되며 환각(hallucination)을 제한할 수 있다는 점입니다.
또한 시스템 프롬프트는 안전성과 유해성 제어 측면에서도 매우 유용할 수 있습니다.
예를 들어, 다음과 같은 한 줄을 추가하면 됩니다:
"당신의 응답은 정중해야 합니다."
역할 프롬프트 (Role Prompting)
역할 프롬프트는 프롬프트 엔지니어링에서 사용하는 기술로,
생성형 AI 모델에게 특정 역할을 할당하는 것입니다.
이것은 모델이 보다 관련성 높고 유익한 출력을 생성하는 데 도움을 줄 수 있습니다.
모델이 자신에게 주어진 역할에 따라 응답을 구성할 수 있기 때문입니다.
예를 들어, 생성형 AI 모델에게 다음과 같은 역할을 줄 수 있습니다:
- 책 편집자
- 유치원 선생님
- 동기부여 강사 등
모델에게 역할이 할당되면,
그 역할에 특화된 프롬프트를 제공할 수 있습니다.
예를 들어, 선생님에게 수업 계획안을 작성하도록 요청하는 것처럼 말이죠.
표 5에서는 모델이 여행 가이드 역할을 수행하는 예시가 나옵니다.
표 5. 역할 프롬프트 예시
AI 모델에 역할 관점을 정의하면,
출력의 톤(tone), 스타일(style), **특화된 전문성(focused expertise)**에 대한 청사진을 제공할 수 있습니다.
이를 통해 출력의 품질, 관련성, 효과성을 높일 수 있습니다.
다음은 활용 가능한 스타일 중 몇 가지 예시입니다:
- 대립적인 (Confrontational)
- 서술적인 (Descriptive)
- 직접적인 (Direct)
- 형식적인 (Formal)
- 유머러스한 (Humorous)
- 영향력 있는 (Influential)
- 비격식적인 (Informal)
- 영감을 주는 (Inspirational)
- 설득력 있는 (Persuasive)
표 6에서는 위 스타일 중 유머러스하고 영감을 주는 스타일을 포함하도록 프롬프트를 변경한 예시가 나옵니다.
문맥 프롬프트 (Contextual Prompting)
문맥 프롬프트를 제공함으로써,
AI와의 상호작용을 더 원활하고 효율적으로 만들 수 있습니다.
모델은 사용자의 요청을 더 빠르고 정확하게 이해하며,
보다 관련성 높은 응답을 생성할 수 있습니다.
이 점은 표 7의 예시에서도 확인할 수 있습니다.
다음은 Step-back Prompting과 Chain of Thought (CoT) 기법에 대한 설명입니다. :
Step-back 프롬프트 (Step-back Prompting)
Step-back 프롬프트는 LLM의 성능을 향상시키기 위한 기술로,
모델이 당면한 특정 과업과 관련된 일반적인 질문을 먼저 고려하게 한 뒤,
그 일반 질문의 응답을 후속 프롬프트에 전달하여 특정 문제를 해결하도록 하는 방식입니다.
이러한 '한 발 물러남(step back)'은 LLM이 특정 문제를 해결하기 전에
관련된 배경지식과 추론 과정을 활성화할 수 있게 도와줍니다.
LLM이 더 넓은 원칙이나 기반 개념을 고려하게 되면,
보다 정확하고 통찰력 있는 응답을 생성할 수 있습니다.
Step-back 프롬프팅은 LLM이 비판적으로 사고하고,
자신의 지식을 새롭고 창의적인 방식으로 적용하도록 장려합니다.
이 방법은, 모델이 바로 문제를 다루는 대신,
자신의 파라미터 내에 있는 더 많은 지식을 활용할 수 있게 프롬프트를 바꾸는 것이며,
직접적으로 문제를 제시했을 때보다 더 나은 결과를 도출할 수 있습니다.
또한 Step-back 프롬프팅은 세부사항보다 일반 원칙에 초점을 맞추기 때문에
모델 응답의 편향을 완화하는 데에도 도움이 될 수 있습니다.
이제 Step-back 프롬프팅이 어떻게 결과를 향상시키는지 몇 가지 예시를 통해 살펴보겠습니다.
먼저 표 8에서 전통적인 프롬프트 예시를 살펴보고,
그 다음 표 9에서 Step-back 프롬프트와 비교해보겠습니다.
표 8. Step-back 프롬프트와 비교하기 전 전통적 프롬프트 예시
온도를 1로 설정하면, 이야기 줄거리에 대해
다양하고 창의적인 응답이 생성될 수 있지만,
그만큼 무작위적이고 일반적인 응답이 나올 수도 있습니다.
그러니 이제 한 발 물러서 봅시다.
표 9. 자기 일관성(self-consistency)을 위한 프롬프트 예시
그래요, 그 주제들은 1인칭 비디오 게임에 딱 어울리는 것 같네요.
이제 원래 프롬프트로 돌아가되,
이번에는 Step-back에서 나온 응답을 문맥에 포함시켜
어떤 결과가 나오는지 살펴봅시다.
와, 꽤 흥미로운 비디오 게임처럼 보이네요!
Step-back 프롬프팅 기법을 사용하면,
프롬프트의 정확도를 높일 수 있습니다.
Chain of Thought (CoT) 프롬프트
Chain of Thought(CoT) 프롬프팅은
LLM의 추론 능력을 향상시키기 위한 기술로,
중간 추론 과정을 생성하도록 유도하는 방식입니다.
이 방식은 모델이 더 정확한 정답을 생성하는 데 도움을 줍니다.
CoT는 퓨샷(few-shot) 프롬프트와 결합하여 사용할 수 있으며,
이는 응답 전에 추론이 필요한 복잡한 작업에서 특히 좋은 성과를 냅니다.
(이는 제로샷 CoT로는 어려운 경우가 많기 때문입니다)
CoT의 장점은 다음과 같습니다:
- 낮은 노력 대비 높은 효과
- 사전 학습된 LLM에서도 잘 작동함 (별도의 파인튜닝 불필요)
- 해석 가능성 제공:
모델의 응답을 통해 어떤 추론 과정을 거쳤는지 확인할 수 있음 - 버그 식별 가능:
중간 추론을 통해 오류가 생긴 위치를 추적할 수 있음 - 모델 버전 간의 강건성 향상:
즉, reasoning chain을 사용하는 프롬프트는 모델 버전이 달라져도 결과 변화가 덜함
물론 직관적으로 이해할 수 있는 몇 가지 단점도 있습니다.
- CoT는 중간 추론까지 포함한 응답을 생성하기 때문에,
더 많은 토큰을 소모하게 되며,
이에 따라 예측 비용이 증가하고 처리 시간이 길어질 수 있습니다.
표 11에 나오는 예시를 설명하기 위해,
먼저 CoT를 사용하지 않은 프롬프트를 만들어 봅시다.
이렇게 하면 LLM의 한계를 명확하게 보여줄 수 있습니다.
이번 부분은 Chain of Thought(CoT)의 효과적인 예시와 함께, 이어서 Self-consistency 기법도 소개입니다.:
LLM들이 수학적 문제를 다루는 데 종종 어려움을 겪는 이유는,
그들이 방대한 양의 텍스트에 기반해 훈련되었기 때문이며,
수학 문제는 다른 접근 방식을 요구할 수 있기 때문입니다.
그래서 이번에는 중간 추론 단계(intermediate reasoning steps) 를 도입하면
출력이 더 나아질 수 있는지 확인해봅시다.
좋아요, 이제 최종 정답이 올바르게 나왔습니다.
그 이유는 우리가 모델에게 각 단계를 설명하도록 명확히 지시했기 때문입니다.
재미있는 점은, 모델이 “17년의 증가분”을 직접 더해주는 것을 볼 수 있다는 것입니다.
내 머릿속에서는 오히려 이렇게 생각했을 겁니다:
나와 내 파트너 사이의 나이 차이를 구하고, 그것을 더하기 → (20 + (9 - 3))
이제 모델이 나처럼 더 잘 사고할 수 있도록 도와줍시다.
표 12는 제로샷 기반의 Chain of Thought 예시입니다.
Chain of Thought 프롬프트는 원샷(one-shot) 또는 퓨샷(few-shot) 과 결합될 때
훨씬 더 강력한 효과를 발휘합니다.
이는 표 13에서 확인할 수 있습니다.
Chain of Thought의 활용 예시
Chain of Thought는 다양한 사용 사례에 유용하게 활용될 수 있습니다. 예를 들어:
- 코드 생성: 요청을 몇 가지 단계로 나누고, 각 단계를 특정 코드 라인에 매핑
- 합성 데이터 생성:
예) “제품 이름이 XYZ라고 할 때, 제품 설명을 작성하라.”
→ 모델이 제품 이름을 기반으로 어떤 가정을 하고 어떤 설명을 해야 할지 유도
일반적으로, "말로 풀어 설명할 수 있는 과제" 라면 Chain of Thought가 효과적입니다.
만약 문제를 해결하는 단계를 명확하게 설명할 수 있다면,
Chain of Thought 방식을 꼭 시도해보세요.
더 자세한 예시는 Google Cloud Platform GitHub 저장소에 있는 notebook10을 참고하세요.
이 장의 Best Practices 섹션에서도 CoT 프롬프트에 특화된 모범 사례를 배울 수 있습니다.
Self-consistency
대규모 언어 모델들은 다양한 자연어 처리 과업에서 인상적인 성공을 보여주고 있지만,
추론 능력은 여전히 한계로 여겨지는 경우가 많습니다.
이는 단순히 모델 크기를 늘리는 것만으로는 극복하기 어렵습니다.
앞서 살펴본 Chain of Thought 프롬프팅에서,
모델은 사람처럼 문제를 해결하는 방식의 중간 추론 단계를 생성하도록 유도될 수 있었습니다.
하지만 Chain of Thought는 탐욕적 디코딩(greedy decoding) 전략을 사용하기 때문에
그 효과가 제한적일 수 있습니다.
Self-consistency는
샘플링과 다수결 투표(majority voting) 를 결합하여,
다양한 추론 경로를 생성하고, 가장 일관된 정답을 선택하는 방식입니다.
이 방식은 LLM이 생성하는 응답의 정확성과 일관성(coherence) 을 향상시킵니다.
다만, 이 방식은 비용이 높다는 단점이 있습니다.
Self-consistency의 과정은 다음과 같습니다:
- 다양한 추론 경로 생성
→ 같은 프롬프트를 LLM에게 여러 번 제공합니다.
→ 높은 온도 설정을 통해 다양한 추론 경로와 관점을 생성하게 유도합니다. - 각 응답에서 정답 추출
- 가장 자주 등장한 정답을 선택
→ 다수결 방식
이제 이메일 분류 시스템의 예시를 살펴보겠습니다.
이 시스템은 이메일을 IMPORTANT(중요함) 또는 NOT IMPORTANT(중요하지 않음) 으로 분류합니다.
제로샷 기반의 Chain of Thought 프롬프트를 LLM에 여러 번 보내어,
응답이 매번 달라지는지 확인합니다.
이 이메일에는 친근한 말투, 단어 선택, 그리고 약간의 풍자(sarcasm) 가 포함되어 있습니다.
이러한 요소들이 LLM을 혼란스럽게 만들 수 있습니다.
출력 예시
Step 1: 이메일의 목적 식별
시도 1
이 이메일의 목적은,
수신자에게 그들의 웹사이트에 있는 연락 양식(contact form) 에
버그가 있다는 것을 알려주는 것입니다.
보낸 사람은 또한, 웹사이트를 즐겨 읽고 있으며,
해당 버그를 당분간 그대로 둘 것이라고 언급합니다.
Step 2: 버그의 잠재적 영향 평가
다음은 Self-consistency 예시의 마무리, Tree of Thoughts, 그리고 ReAct 프롬프팅 개요까지 다루고 있습니다.:
Step 2: 버그의 잠재적 영향 평가
연락 양식(contact form)에 있는 이 버그는 공격자가 웹사이트에서 임의의 JavaScript 코드를 실행할 수 있게 만들 수 있습니다.
이로 인해 공격자는 웹사이트를 장악하거나,
민감한 정보를 탈취하거나,
웹사이트를 훼손(deface) 할 수 있게 됩니다.
Step 3: 발신자의 신뢰성 평가
이 이메일의 발신자는 자신이 ‘Harry’라는 이름의 해커라고 주장합니다.
하지만 이 발신자의 신원을 검증할 수 있는 방법은 없습니다.
발신자가 실제로 도움을 주려는 합법적인 해커일 수도 있고,
수신자를 속여서 악성 링크를 클릭하게 하거나, 악성 파일을 다운로드하게 만들려는
악의적인 행위자일 수도 있습니다.
결론: 중요함 (IMPORTANT)
버그의 잠재적 영향과 발신자의 신뢰성을 고려했을 때,
이 이메일은 중요(IMPORTANT) 으로 분류되어야 합니다.
수신자는 즉시 조치를 취해 버그를 수정하고, 웹사이트를 보호해야 합니다.
출력 예시
설명:
시도 2
- 긴급성 부족:
이메일은 긴급성이나 시간에 민감한 분위기를 전혀 담고 있지 않습니다.
일상적인 인사말로 시작하여, 내용을 담담한 어조로 전달하고 있습니다. - 비핵심 버그 보고:
이 연락 양식에서 보고된 버그는 흥미롭지만 중요하지 않다고 묘사되어 있습니다.
이메일 작성자는 웹사이트 소유자가 이 버그를 그대로 둬도 괜찮다고까지 제안하고 있습니다. - 개인적 영향 없음:
이메일은 웹사이트 소유자에게 직접적이거나 개인적인 영향을 시사하지 않습니다.
단순히 발신자가 웹사이트를 재미있게 읽고 있다고 말할 뿐입니다.
(다음 페이지로 계속…)
위의 프롬프트를 여러 번 사용하여,
일관된 분류 결과가 나오는지 확인해 볼 수 있습니다.
사용하는 모델과 온도 설정에 따라,
모델이 “IMPORTANT(중요함)” 혹은 “NOT IMPORTANT(중요하지 않음)” 으로 응답할 수 있습니다.
하지만 여러 개의 Chain of Thought를 생성하고,
그중 가장 자주 등장하는 정답(예: "IMPORTANT") 을 선택함으로써,
LLM으로부터 보다 일관되고 정확한 정답을 얻을 수 있습니다.
이 예시는, Self-consistency 프롬프팅이 여러 관점을 고려하고,
가장 일관된 응답을 선택함으로써,
LLM의 응답 정확도를 어떻게 향상시킬 수 있는지를 보여줍니다.
Tree of Thoughts (ToT)
이제 Chain of Thought와 Self-consistency 프롬프팅을 익혔으니,
Tree of Thoughts(ToT) 를 살펴보겠습니다【주12】.
ToT는 CoT 프롬프팅 개념을 확장한 것으로,
하나의 선형 추론 체인만 따르는 대신,
LLM이 여러 가지 다른 추론 경로를 동시에 탐색할 수 있게 합니다.
이는 아래의 그림 1에서 시각적으로 표현되어 있습니다.
그림 1. 좌측: Chain of Thought, 우측: Tree of Thoughts 시각화
이 접근 방식은 탐색이 필요한 복잡한 과업에 특히 적합합니다.
ToT는 “생각의 트리(tree of thoughts)”를 유지하는 방식으로 작동하며,
여기서 각 “생각(thought)”은 문제 해결을 위한 중간 언어 시퀀스를 나타냅니다.
모델은 이 트리에서 다양한 노드들로부터 분기(branching) 하여
여러 추론 경로를 탐색할 수 있습니다.
ToT에 대한 자세한 설명은
논문 ‘Large Language Model Guided Tree-of-Thought’ 기반으로 작성된
notebook 예제에서도 확인할 수 있습니다.
ReAct (Reason + Act)
ReAct 프롬프팅은 복잡한 과업을 해결하기 위해
LLM이 자연어 추론(natural language reasoning) 과
외부 도구들(search, 코드 인터프리터 등) 을 결합할 수 있도록 하는 프롬프팅 패러다임입니다【주13】
이번 부분은 ReAct 프롬프트의 작동 방식 예시와 자동 프롬프트 엔지니어링(APE) 개요에 대한 내용입니다.:
ReAct는 LLM이 특정 행동을 수행할 수 있도록 하며,
예를 들어 외부 API와 상호작용하여 정보를 검색하는 등의 동작을 가능하게 합니다.
이것은 에이전트 모델링(agent modeling) 을 향한 첫 번째 단계이기도 합니다.
ReAct는 인간이 실제 세계에서 작동하는 방식을 모방합니다.
우리는 말로 추론하고, 정보를 얻기 위해 행동을 취하죠.
ReAct는 다양한 도메인에서 다른 프롬프트 엔지니어링 방식들보다 좋은 성능을 보입니다.
ReAct 프롬프팅은 추론(reasoning) 과 행동(acting) 을 결합하여,
사고-행동 루프(thought-action loop) 를 구성합니다.
작동 방식은 다음과 같습니다:
- LLM이 문제에 대해 추론하고 행동 계획을 생성합니다.
- 그 계획에 따라 행동을 수행하고 결과를 관찰합니다.
- 그런 다음, 관찰 결과를 바탕으로 추론을 갱신하고 새로운 행동 계획을 세웁니다.
- 이 과정은 LLM이 해결책에 도달할 때까지 반복됩니다.
이 과정을 직접 확인하려면, 코드를 작성해야 합니다.
Code Snippet 1에서는 다음 도구들을 사용합니다:
- Python용 LangChain 프레임워크
- VertexAI (google-cloud-aiplatform 라이브러리)
- google-search-results pip 패키지
이 샘플을 실행하려면, 먼저 https://serpapi.com/manage-api-key 에서
무료 SerpAPI 키를 생성하고, 환경 변수 SERPAPI_API_KEY로 설정해야 합니다.
이제 Python 코드를 작성해봅시다.
LLM이 해결해야 할 과제는 다음과 같습니다:
"Metallica 밴드에서 활동하는 유명한 아버지를 둔 자녀가 총 몇 명인지 알아내라"
Snippet 1. LangChain과 VertexAI를 사용한 ReAct 에이전트 생성 예시
Snippet 2는 그 실행 결과를 보여줍니다.
여기서 ReAct는 총 다섯 번의 검색 체인을 수행합니다.
실제로, LLM은 Google 검색 결과를 크롤링하여 밴드 멤버들의 이름을 알아낸 뒤,
그 결과를 관찰(observation) 목록으로 나열하고,
다음 검색을 위한 추론을 연결합니다.
Snippet 2. 터미널에서 ReAct 에이전트 실행
Snippet 2에서는 밴드 Metallica의 멤버가 4명이라는 점을 파악한 후,
각 멤버의 자녀 수를 개별적으로 조사하고,
총합을 구한 뒤 최종적으로 자녀 수 총합을 정답으로 반환합니다.
실제 ReAct 프롬프팅을 사용할 때는 다음 사항들을 유념해야 합니다:
- 이전 프롬프트 및 응답을 계속해서 다시 전송해야 하며
- 생성된 불필요한 텍스트는 잘라내고(trim)
- 적절한 예시와 지시문으로 모델을 설정해야 합니다.
더 자세한 설명은
Google Cloud Platform GitHub 저장소의 notebook14 를 참고하세요.
이곳에 실제 LLM 입력 및 출력과 더 정교한 예제가 포함되어 있습니다.
자동 프롬프트 엔지니어링 (Automatic Prompt Engineering, APE)
이쯤 되면 아마 여러분도 느꼈겠지만,
프롬프트를 작성하는 것은 꽤 복잡한 작업일 수 있습니다.
그렇다면…
프롬프트를 생성하는 프롬프트를 자동으로 작성할 수 있다면 어떨까요?
바로 이런 방식이 존재합니다.
이것이 Automatic Prompt Engineering (APE) 기법입니다【주15】.
이 방법은 단지 사람의 입력을 줄이는 것에 그치지 않고,
모델이 다양한 과업에서 더 좋은 성능을 발휘하도록 도와줍니다.
작동 방식:
- 프롬프트를 생성하도록 모델을 프롬프트합니다.
(즉, "프롬프트를 쓰는 프롬프트"를 작성하는 것) - 생성된 프롬프트들을 평가합니다.
좋은 프롬프트는 수정하거나 선택할 수 있습니다. - 이 과정을 반복합니다.
예를 들어,
밴드 굿즈 티셔츠 웹숍용 챗봇을 훈련시키기 위한
자동 프롬프트 엔지니어링을 사용할 수 있습니다.
목표는 다음과 같습니다:
고객들이 밴드 티셔츠 주문을 어떻게 다양한 방식으로 표현할 수 있는지 알아내는 것
- 프롬프트를 작성하여, 다양한 출력 예시를 생성하도록 합니다.
→ 이 예시에서는 Gemini-pro 모델을 사용하여 10개의 명령문(instructions) 을 생성합니다.
→ 자세한 내용은 표 15를 참고하세요. - 생성된 명령문 후보들을 선택한 평가 지표를 기준으로 점수화하여 평가합니다.
예:- BLEU (Bilingual Evaluation Understudy)
- ROUGE (Recall-Oriented Understudy for Gisting Evaluation)
이 부분은 자동 프롬프트 엔지니어링의 평가 마무리와 함께,
코드 생성/설명/변환/디버깅을 위한 프롬프트 작성에 대한 내용이 포함돼 있습니다.:
- 가장 높은 평가 점수를 받은 명령문 후보를 선택합니다.
이 후보는 소프트웨어 애플리케이션이나 챗봇에서 사용할 최종 프롬프트가 됩니다.
또한 이 선택된 프롬프트를 조정(tweak) 한 후 다시 평가할 수도 있습니다.
코드 프롬프팅 (Code Prompting)
Gemini는 주로 텍스트 기반 프롬프트에 초점을 맞추고 있으며,
여기에는 코드를 반환하는 프롬프트 작성도 포함됩니다.
이제 Vertex AI Studio에서 이 프롬프트들을 테스트하며 몇 가지 코드 예시를 살펴보겠습니다.
코드 작성을 위한 프롬프트 (Prompts for Writing Code)
Gemini는 개발자 역할도 수행할 수 있으며,
선호하는 프로그래밍 언어로 코드를 작성하는 데 도움을 줄 수 있습니다.
개발자로서 이 기능은 코드 작성 속도를 크게 향상시킬 수 있습니다.
예를 들어,
여러분의 컴퓨터에 수백 개의 파일이 있는 폴더가 있다고 상상해보세요.
이 파일들을 일일이 이름 바꾸는 것은 엄청난 시간 소모입니다.
약간의 Bash는 알고 있고, 스크립트를 직접 작성할 수도 있겠지만,
그 역시 시간이 꽤 걸릴 수 있습니다.
이럴 때 프롬프트를 작성해봅시다.
이 프롬프트는 일반 Gemini 챗봇에서도 작성할 수 있고,
기밀성을 더 중시한다면 Google Cloud 계정에서 Vertex AI Studio를 열어 작성할 수도 있습니다.
Vertex AI Studio의 장점은 온도 등 다양한 설정을 구성할 수 있다는 것입니다.
Gemini가 생성한 코드는 꽤 괜찮아 보입니다 — 주석까지 달려 있죠!
하지만 LLM은 추론을 하지 못하고, 훈련 데이터를 반복할 뿐이기 때문에,
항상 코드를 직접 읽고 테스트하는 것이 중요합니다.
이제 드디어 우리가 기다려온 순간: 정말 작동할까요?
작은 테스트 폴더를 만들어서 직접 확인해봅시다.
이 폴더 안에는 이름이 filename.txt 인 파일들이 있고,
이 파일들을 draft_filename.txt 형태로 변경해야 합니다.
- 표 16의 출력 결과에서 bash 텍스트 래퍼 없이 내용만 복사해서
rename_files.sh 라는 새로운 파일로 저장합니다. - 터미널 창을 열고 다음 명령어를 입력합니다:
./rename_files.sh
그러면 폴더 이름을 입력하라는 메시지가 뜰 것입니다.
예: test 라고 입력 후 엔터 - 스크립트가 잘 실행되는 것 같습니다.
"Files renamed successfully." 라는 메시지가 표시됩니다.
test 폴더 안을 확인하면,
모든 파일이 draft_filename.txt 형식으로 완벽히 변경된 것을 볼 수 있습니다.
작동했습니다!
코드 설명용 프롬프트 (Prompts for Explaining Code)
팀으로 일하는 개발자라면, 다른 사람이 작성한 코드를 읽어야 할 때가 있습니다.
Gemini는 이러한 상황에서도 여러분을 도와줄 수 있습니다.
예를 들어, 표 16의 코드 출력 결과에서 주석을 제거한 후,
대형 언어 모델에게 "이 코드가 무슨 일을 하는지 설명해줘" 라고 요청할 수 있습니다.
→ 이에 대한 예시는 표 17에서 확인할 수 있습니다.
코드 변환용 프롬프트 (Prompts for Translating Code)
표 16의 Bash 코드는 잘 작동하지만,
좀 더 재사용 가능하도록 만들기 위해 파일 이름을 입력받도록 프롬프트를 추가하고,
별도의 UI를 갖춘 애플리케이션으로 바꾸는 것이 이상적일 수 있습니다.
그렇게 하려면, Python 언어가 Bash보다 더 적합합니다.
특히 웹 애플리케이션을 만들 때 더욱 그렇죠.
LLM은 한 프로그래밍 언어에서 다른 언어로 코드 변환하는 데도 도움을 줄 수 있습니다.
예시는 표 18에서 확인할 수 있습니다.
Snippet 3. 버그가 있는 파이썬 스크립트
앗! 버그가 있어 보입니다:
Snippet 4. 내가 파이썬 코드를 망쳐버렸다
이제 대형 언어 모델에게 코드 디버깅 및 리뷰를 요청할 수 있는지 확인해봅시다.
해당 예시는 표 19에서 확인할 수 있습니다:
프롬프트 예시:
new_filename = f"{text}_{file}"
# 파일을 새 이름으로 이동시키기
shutil.move(os.path.join(folder_name, file), os.path.join(folder_name, new_file_name))
# 성공 메시지 출력
print("Files renamed successfully.")
출력 예시:
이 코드는 prefix를 대문자로 바꾸기 위해
toUpperCase 함수를 호출하고 있지만,
해당 함수는 정의되어 있지 않습니다.
이 문제를 해결하려면,
문자열 클래스의 upper() 메서드를 사용해야 합니다.
이 부분에서는 개선된 코드 예시와 함께,
멀티모달 프롬프팅 개요, 프롬프트 엔지니어링의 모범 사례(Best Practices) 섹션이 시작됩니다.:
앞서의 문제를 해결한 수정된 코드는 다음과 같습니다:
import shutil
# 사용자로부터 폴더 이름을 입력받기
folder_name = input("Enter the folder name: ")
prefix = input("Enter the string to prepend to the filename: ")
text = prefix.upper()
# 폴더 존재 여부 확인
if not os.path.isdir(folder_name):
print("Folder does not exist.")
exit(1)
# 폴더 내 모든 파일 목록 가져오기
files = os.listdir(folder_name)
# 파일 순회
for file in files:
# "draft_" 접두어를 붙인 새로운 파일 이름 생성
new_filename = f"{text}_{file}"
# 기존 파일을 새 이름으로 이동
shutil.move(os.path.join(folder_name, file), os.path.join(folder_name, new_filename))
# 성공 메시지 출력
print("Files renamed successfully.")
또한, 코드에는 다음과 같은 기타 개선 사항들이 적용될 수 있습니다:
- 파일 확장자 유지
현재 코드는 새 파일 이름에 기존 확장자를 유지하지 않습니다.
원본 파일의 확장자를 추출한 후, 이를 새로운 이름에 추가하는 것이 좋습니다. - 폴더 이름에 공백이 있을 경우 대비
코드에서는 폴더 이름에 공백이 없다고 가정하고 있습니다.
하지만 실제로는 공백을 언더스코어나 하이픈 등으로 처리하는 것이 좋습니다. - f 문자열 사용
문자열 결합 시, + 연산자보다 f 문자열 포맷팅이 더 읽기 쉽고 간결합니다. - 예외 처리 추가
파일 이름 변경 중 발생할 수 있는 에러를 처리하지 않음.
shutil.move 호출을 try...except 블록으로 감싸는 것이 더 안전합니다.
이러한 제안을 반영한 개선된 전체 코드는 다음과 같습니다:
import shutil
# 사용자 입력
folder_name = input("Enter the folder name: ")
prefix = input("Enter the string to prepend to the filename: ")
text = prefix.upper()
# 폴더 존재 확인
if not os.path.isdir(folder_name):
print("Folder does not exist.")
exit(1)
# 파일 목록 가져오기
files = os.listdir(folder_name)
# 파일 이름 변경 루프
for file in files:
try:
name, ext = os.path.splitext(file) # 확장자 추출
new_filename = f"{text}_{name}{ext}" # 확장자 유지
shutil.move(
os.path.join(folder_name, file),
os.path.join(folder_name, new_filename)
)
except Exception as e:
print(f"Error renaming {file}: {e}")
# 성공 메시지
print("Files renamed successfully.")
정말 훌륭하죠.
모델은 단순히 문제 해결 방법만 알려준 게 아니라,
내 코드에 존재하던 다른 버그들도 찾아내고,
그 해결책까지 제안해줬습니다.
프롬프트의 마지막 부분에서는,
코드 전반에 대한 개선 제안도 포함되어 있었죠.
그렇다면 멀티모달 프롬프팅(Multimodal Prompting)은?
지금까지의 코드 프롬프팅은 텍스트 기반의 일반적인 LLM을 사용한 것이었습니다.
멀티모달 프롬프팅은 이와는 다른 개념입니다.
이는 LLM을 단순한 텍스트에만 의존하지 않고,
여러 입력 형식(text, image, audio, code 등) 을 함께 사용하는 프롬프팅 기법입니다.
모델의 기능 및 과업에 따라,
이러한 다양한 입력 조합이 활용될 수 있습니다.
Best Practices (모범 사례)
올바른 프롬프트를 찾기 위해서는 실험이 필요합니다.
Vertex AI의 Language Studio는 다양한 모델에 대해 프롬프트를 테스트하고 실험해보기에 아주 적합한 환경입니다.
아래의 모범 사례를 통해 프롬프트 엔지니어링 전문가로 거듭나보세요:
1. 예시 제공
가장 중요한 모범 사례는,
프롬프트 안에 (원샷/퓨샷) 예시를 제공하는 것입니다.
이는 아주 강력한 학습 도구 역할을 합니다.
이러한 예시는 원하는 출력 또는 유사한 응답을 보여줌으로써,
모델이 이를 참고하여 더 나은 결과를 생성하게 해줍니다.
이번 부분은 프롬프트 작성 모범 사례(Best Practices) 중에서
간결성, 명확한 출력 정의, 지시문 사용에 대한 내용입니다.:
모델이 스스로 응답을 생성할 수 있도록 예시 제공
예시는 마치 모델에게 참고할 목표(reference point) 를 제공하는 것과 같아서,
정확성, 스타일, 톤을 여러분의 기대에 더 잘 맞추도록 개선할 수 있습니다.
단순함으로 설계하기 (Design with Simplicity)
프롬프트는 간결하고 명확하며,
여러분과 모델 모두가 이해하기 쉬워야 합니다.
기본 원칙은 이렇습니다:
"내가 이해하기 어려우면, 모델도 이해하기 어렵다."
- 복잡한 언어는 피하세요.
- 불필요한 정보는 포함하지 마세요.
예시:
- 수정 전 (BEFORE):
- I am visiting New York right now, and I'd like to hear more about great locations. I am with two 3 year old kids. Where should we go during our vacation?
- 수정 후 (AFTER):
- Act as a travel guide for tourists. Describe great places to visit in New York Manhattan with a 3 year old.
꿀팁:
행동을 나타내는 동사를 사용해보세요.
예:
Act, Analyze, Categorize, Classify, Contrast, Compare, Create, Describe, Define,
Evaluate, Extract, Find, Generate, Identify, List, Measure, Organize, Parse, Pick,
Predict, Provide, Rank, Recommend, Return, Retrieve, Rewrite, Select, Show, Sort,
Summarize, Translate, Write
출력에 대해 구체적으로 작성하기 (Be Specific About the Output)
원하는 출력에 대해 구체적으로 작성하세요.
- 너무 간단한 지시는 모델에게 방향을 충분히 제공하지 못하거나, 지나치게 일반적일 수 있습니다.
- 시스템 또는 문맥 프롬프팅을 통해 세부사항을 명시하면,
모델이 더 관련성 있는 정보에 집중할 수 있고, 전체적인 정확도가 높아집니다.
예시:
- 좋은 예 (DO):
- Generate a 3 paragraph blog post about the top 5 video game consoles.
The blog post should be informative and engaging, and it should be written in a conversational style. - 나쁜 예 (DON’T):
- Generate a blog post about video game consoles.
제약 조건보다 지시문 사용하기 (Use Instructions over Constraints)
지시문(instructions)과 제약 조건(constraints)은 LLM의 출력을 안내하기 위해 사용됩니다:
- 지시문(instruction):
→ 출력의 형식, 스타일, 내용에 대해 명확하게 설명하는 것
→ 모델에게 무엇을 해야 하는지 지시 - 제약 조건(constraint):
→ 출력에서 무엇을 하면 안 되는지를 정의
→ 제한과 회피 규칙 제시
연구에 따르면,
지시문 중심의 프롬프팅이 제약 조건 중심의 프롬프팅보다 더 효과적일 수 있습니다.
이 접근은 사람들이 "하지 마" 보다는 "이렇게 해"를 더 잘 따르는 경향과도 맞닿아 있습니다.
- 지시문은 모델에게 직접적으로 원하는 결과를 전달합니다.
- 반면, 제약 조건은 모델에게 무엇이 허용되는지를 추측하게 만들 수 있습니다.
또한 지시문은 창의성과 유연성을 장려할 수 있지만,
제약 조건은 모델의 가능성을 제한할 수도 있고,
상호 충돌하는 규칙들이 생길 수도 있습니다.
물론 제약 조건은 여전히 유용하며,
- 편향적이거나 유해한 콘텐츠 방지,
- 엄격한 출력 형식이나 스타일 요구 같은 상황에서는 꼭 필요합니다.
가능하다면, 긍정적인 지시문을 사용하세요.
모델에게 "하지 말라"고 말하기보다는,
"이렇게 하라"고 지시하는 편이 더 명확하고 혼란을 줄입니다.
예시:
- 좋은 예 (DO):
- Generate a 1 paragraph blog post about the top 5 video game consoles.
Only discuss the console, the company who made it, the year, and total sales. - 나쁜 예 (DON’T):
- Generate a 1 paragraph blog post about the top 5 video game consoles.
Do not list video game names.
이 부분에서는 프롬프트 설계의 나머지 Best Practices—토큰 길이 제어, 변수 사용, 입력 포맷 실험, 퓨샷 클래스 순서 섞기, 모델 업데이트 적응, 출력 형식 실험까지 다루고 있습니다.:
지시문 사용을 우선하고,
모델에게 명확하게 원하는 바를 진술하세요.
그리고 안전성, 명확성, 특정 요건 충족이 필요한 경우에만 제약 조건을 사용하세요.
지시문과 제약 조건의 다양한 조합을 실험하고 반복(iterate) 하여
여러분의 과업에 가장 효과적인 방식을 찾아내세요.
그리고 이러한 결과들을 문서화하세요.
최대 토큰 길이 제어 (Control the Max Token Length)
생성된 LLM 응답의 길이를 제어하려면,
- 설정(configuration) 에서 최대 토큰 수를 지정하거나
- 프롬프트 내에서 직접 원하는 길이를 명시할 수 있습니다.
예시:
“Explain quantum physics in a tweet length message.”
(양자물리를 트윗 길이로 설명해줘.)
프롬프트에서 변수 사용 (Use Variables in Prompts)
프롬프트를 재사용 가능하고 동적(dynamic) 으로 만들기 위해,
프롬프트 내에 변수(variable) 를 사용하는 것이 좋습니다.
→ 입력마다 바뀌는 요소를 변수로 지정하세요.
예:
도시 정보를 알려주는 프롬프트를 만들 때,
도시 이름을 하드코딩하는 대신 변수로 바꾸면,
다른 도시에도 쉽게 적용할 수 있습니다.
이 방식은 반복적인 프롬프트 작성 시간을 절약해주며,
같은 정보를 여러 프롬프트에서 사용할 경우 변수를 참조하면 됩니다.
특히 프롬프트를 자신의 애플리케이션에 통합할 때, 이 방식은 매우 유용합니다.
입력 포맷 및 작성 스타일 실험 (Experiment with Input Formats and Writing Styles)
- 서로 다른 모델, 모델 구성, 프롬프트 형식, 단어 선택, 입력 방식은 다양한 결과를 만들어냅니다.
- 따라서 스타일, 단어 선택, 프롬프트 유형(제로샷, 퓨샷, 시스템 프롬프트 등)에 대해 다양하게 실험하는 것이 중요합니다.
예:
혁신적인 게임 콘솔인 Sega Dreamcast에 대한 텍스트 생성 목표를 가진 프롬프트는
질문, 진술문, 지시문 등 다양한 형식으로 작성할 수 있고,
각각 다른 출력을 만들어냅니다:
- 질문 형태:
- What was the Sega Dreamcast and why was it such a revolutionary console?
- 진술문 형태:
- The Sega Dreamcast was a sixth-generation video game console released by Sega in 1999. It…
- 지시문 형태:
- Write a single paragraph that describes the Sega Dreamcast console and explains why it was so revolutionary.
퓨샷 분류 작업에서는 클래스 순서를 섞어라 (For Few-shot Prompting with Classification Tasks, Mix Up the Classes)
일반적으로 퓨샷 예시의 순서는 큰 영향을 미치지 않지만,
분류(classification) 작업에서는 반드시 응답 클래스의 순서를 섞어야 합니다.
그 이유는:
- 동일한 순서로 계속 예시를 제공할 경우,
모델이 패턴을 단순히 암기해버릴 수 있습니다.
→ 반면 클래스 순서를 섞으면,
모델은 각 클래스의 핵심 특징을 학습하게 되고,
보다 일반화된 성능을 발휘할 수 있습니다.
권장 규칙:
- 퓨샷 예시는 6개 정도로 시작해서, 그 이후 정확도를 테스트해 보세요.
모델 업데이트에 적응하기 (Adapt to Model Updates)
- 모델 구조, 학습 데이터, 기능의 변화에 유의하고 따라가세요.
- 새로운 버전의 모델을 시도해보고,
프롬프트를 새로운 기능을 잘 활용하도록 조정하세요.
Vertex AI Studio 같은 도구는
프롬프트 버전을 저장하고, 테스트하고, 문서화하기에 매우 유용합니다.
출력 형식 실험하기 (Experiment with Output Formats)
입력 포맷뿐 아니라, 출력 형식(output format) 에 대해서도 실험해 보세요.
예:
텍스트 생성이 아닌 비창의적 작업(추출, 선택, 파싱, 정렬, 순위 매기기, 분류 등)의 경우,
프롬프트와 함께 출력 구조를 명확히 지정하는 것이 효과적일 수 있습니다.
이번 부분은 출력 구조화, 협업, CoT 베스트 프랙티스, 프롬프트 시도 기록에 관한 중요한 실천 팁들입니다.:
JSON 또는 XML과 같은 구조화된 형식으로 출력받기
프롬프트를 통해 데이터를 추출할 때,
JSON 객체로 출력받는 것은 여러 가지 장점을 가집니다.
실제 애플리케이션에서는
이 JSON 형식을 수동으로 만들 필요 없이,
데이터를 정렬된 순서로 이미 반환할 수 있습니다
(특히 날짜/시간 객체를 다룰 때 매우 유용).
무엇보다도, JSON 형식으로 프롬프트를 요청하면
모델이 구조적인 응답을 생성하도록 유도하고,
환각(hallucination) 을 줄이는 데 효과적입니다.
few-shot 프롬프트 섹션의 표 4에서 구조화된 출력 반환 예시를 참고하세요.
다른 프롬프트 엔지니어와 함께 실험하기
좋은 프롬프트를 작성해야 하는 상황이라면,
여러 명이 각자 시도해보는 것이 도움이 됩니다.
모든 사람이 이 장에서 설명한 모범 사례를 따르더라도,
서로 다른 시도 간에는 성능의 편차(variance) 가 나타날 수 있습니다.
이를 통해 어떤 방식이 더 효과적인지 비교할 수 있습니다.
Chain of Thought(CoT) 베스트 프랙티스
- CoT 프롬프트에서는 추론 다음에 정답을 배치해야 합니다.
이유는, 추론 과정에서 생성되는 토큰들이
모델이 최종 정답을 예측할 때 입력되는 토큰의 분포를 바꾸기 때문입니다. - CoT 및 Self-consistency에서는
최종 정답을 추론 내용과 구분해서 추출할 수 있도록 작성해야 합니다. - 온도 설정은 항상 0으로 하세요.
CoT는 탐욕적 디코딩(greedy decoding) 기반이며,
언어 모델이 가장 높은 확률의 다음 단어를 순차적으로 예측합니다.
일반적으로, 추론을 거쳐 도출되는 최종 정답은 하나이므로
온도는 0이 가장 적합합니다.
다양한 프롬프트 시도를 기록하세요 (Document the Various Prompt Attempts)
이 장에서 이미 언급되었지만, 정말 중요하기 때문에 다시 강조합니다:
프롬프트 시도를 완전한 세부 정보로 문서화하세요.
그렇게 하면 시간이 지나도
무엇이 잘 되었고, 무엇이 잘 되지 않았는지 학습할 수 있습니다.
모델별, 샘플링 설정별, 심지어 동일한 모델의 버전 간에도
프롬프트 출력이 달라질 수 있습니다.
또한, 동일한 프롬프트를 동일한 모델에 사용했더라도,
- 출력 문장의 구성,
- 단어 선택 등에서 미세한 차이가 발생할 수 있습니다.
(앞서 언급했듯, 두 토큰의 확률이 동일할 경우,
랜덤하게 선택될 수 있으며,
이로 인해 후속 예측 토큰까지 달라질 수 있습니다.)
추천 사항:
- Google Sheet에 표 21을 템플릿으로 사용하세요.
- 이 방식은, 다음과 같은 경우에 매우 유용합니다:
- 나중에 다시 프롬프트 작업을 이어서 해야 할 경우
(※ 단기 휴식 후에도 많은 내용을 잊어버리게 됩니다) - 다른 모델 버전에서 프롬프트 성능을 테스트할 경우
- 향후 에러를 디버깅할 때
- 나중에 다시 프롬프트 작업을 이어서 해야 할 경우
추가적으로 추적하면 좋은 필드:
- 프롬프트 버전(버전 번호/이름)
- 결과가 OK / NOT OK / SOMETIMES OK 중 어떤 것이었는지
- 피드백 필드
Vertex AI Studio를 사용하는 경우:
- 프롬프트를 Studio에 저장할 때
문서화된 이름/버전과 동일하게 저장하세요. - 저장된 프롬프트에 대한 하이퍼링크를 구글 시트에 기록하면,
언제든지 한 번의 클릭으로 다시 실행할 수 있습니다.
또한 검색 기반 생성(RAG: Retrieval Augmented Generation) 시스템을 사용하는 경우:
- 프롬프트에 어떤 콘텐츠가 삽입되었는지 영향을 준
질문(query), 청크 설정, 출력된 청크 정보 등을 함께 기록해야 합니다.
프롬프트가 거의 완성되었다고 느껴지면,
해당 프롬프트를 프로젝트의 코드베이스에 통합하세요.
이때 코드 내에 직접 작성하지 말고,
프롬프트는 코드와 분리된 별도 파일에 저장하는 것이
유지 관리 측면에서 훨씬 유리합니다.
이상적으로는 프롬프트가 운영 가능한 시스템의 일부로 통합되어야 하며,
프롬프트 엔지니어로서 여러분은
자동화된 테스트 및 평가 절차를 통해
프롬프트가 과업에 대해 얼마나 일반화되는지 이해할 수 있어야 합니다.
프롬프트 엔지니어링은 반복적인(iterative) 과정입니다.
다양한 프롬프트를 설계하고 테스트하며,
결과를 분석하고 문서화하세요.
모델의 성능에 따라 프롬프트를 계속 정제(refine) 하세요.
원하는 출력이 나올 때까지 반복 실험을 계속하세요.
모델이나 모델 구성(configuration)을 변경하게 되면,
기존에 사용한 프롬프트를 다시 시험하고 조정하는 것이 중요합니다.
요약 (Summary)
이 백서에서는 프롬프트 엔지니어링(prompt engineering) 에 대해 다루었습니다.
우리는 다음과 같은 다양한 프롬프트 기법들을 학습했습니다:
- 제로샷 프롬프트 (Zero-shot prompting)
- 퓨샷 프롬프트 (Few-shot prompting)
- 시스템 프롬프트 (System prompting)
- 역할 프롬프트 (Role prompting)
- 문맥 프롬프트 (Contextual prompting)
- 스텝백 프롬프트 (Step-back prompting)
- 연쇄 추론 (Chain of Thought, CoT)
- 자기 일관성 (Self-consistency)
- 생각의 트리(Tree of Thoughts, ToT)
- ReAct (Reason & Act)
우리는 또한 프롬프트 자동화 방법도 살펴보았습니다.
이 백서 후반부에서는 생성형 AI가 직면하는 도전 과제들,
즉 프롬프트가 부적절할 때 발생할 수 있는 문제들을 논의했습니다.
그리고 마지막으로,
더 나은 프롬프트 엔지니어가 되기 위한 모범 사례들로 마무리했습니다.
엔드노트 (Endnotes)
- Google, 2023, Gemini by Google.
https://gemini.google.com - Google, 2024, Gemini for Google Workspace Prompt Guide.
https://inthecloud.withgoogle.com/gemini-for-google-workspace-prompt-guide/dl-cd.html - Google Cloud, 2023, Introduction to Prompting.
https://cloud.google.com/vertex-ai/generative-ai/docs/learn/prompts/introduction-prompt-design - Google Cloud, 2023, Text Model Request Body: Top-P & Top-K sampling methods.
https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/text#request_body - Wei, J., et al., 2023, Zero-shot fine-tuned language models are zero-shot learners.
https://arxiv.org/pdf/2109.01652.pdf - Google Cloud, 2023, Google Cloud Model Garden.
https://cloud.google.com/model-garden - Brown, T., et al., 2023, Language Models are Few-Shot Learners.
https://arxiv.org/pdf/2005.14165.pdf - Zheng, L., et al., 2023, Take a Step Back: Evoking Reasoning via Abstraction in LLMs.
https://openreview.net/pdf?id=3bq3jsvcQ1 - Wei, J., et al., 2023, Chain of Thought Prompting.
https://arxiv.org/pdf/2201.11903.pdf - Google Cloud Platform, 2023, Chain of Thought and ReAct Notebook.
https://github.com/GoogleCloudPlatform/generative-ai/blob/main/language/prompts/examples/chain_of_thought_react.ipynb - Wang, X., et al., 2023, Self-Consistency Improves Chain of Thought Reasoning in LLMs.
https://arxiv.org/pdf/2203.11171.pdf - Yao, S., et al., 2023, Tree of Thoughts: Deliberate Problem Solving with LLMs.
https://arxiv.org/pdf/2305.10601.pdf - Yao, S., et al., 2023, ReAct: Synergizing Reasoning and Acting in LLMs.
https://arxiv.org/pdf/2210.03629.pdf - Google Cloud Platform, 2023, Advanced Prompting: Chain of Thought Notebook
이상입니다.
'데이터 분석가:Applied Data Analytics' 카테고리의 다른 글
ARR, GMV, MAU, DAU, LTV, CAC, NPS, NSM, 바이럴계수 란? (0) | 2025.04.15 |
---|---|
프로덕트, 프로덕트 목표 정의 및 페르소나설정, 지표찾기 및 분석, 고객 여정 분석및 프로덕트 대시보드 만들기 (0) | 2025.04.15 |
인과관계 와 연관관계의 차이는? (0) | 2025.04.11 |
MATLAB, Python, JMP, Minitab (0) | 2025.04.11 |
Carrying Capacity(CC) (0) | 2025.04.08 |