본문 바로가기
Programming/AI&ML

[요약] 구글 프롬프트 엔지니어링 백서 요약: 실전 팁과 테크닉

by BitSense 2025. 4. 16.

구글에서 프롬프트 엔지니이링 백서를 얼마 전 출간?했습니다. 관련된 내용을 간략하게 요약해 보겠습니다.

소개

대규모 언어 모델(LLM)을 다룰 때, 우리가 제공하는 **프롬프트(prompt)**는 모델의 입력이 됩니다. 프롬프트는 누구나 작성할 수 있지만, 효과적인 프롬프트를 만드는 일은 간단하지 않습니다. 왜냐하면 프롬프트의 단어 선택, 문체와 톤, 구조, 맥락 뿐만 아니라 사용하는 모델 종류와 설정까지 여러 요소가 결과에 영향을 미치기 때문입니다 . 따라서 좋은 프롬프트를 만들려면 반복적인 실험과 개선이 필요합니다. 제대로 설계되지 않은 프롬프트는 모호하고 부정확한 응답을 낳아, 모델이 유의미한 출력을 내기 어렵게 만들 수 있습니다 .

이 글에서는 구글의 2025년 프롬프트 엔지니어링 백서에 기반하여, 일반 사용자와 개발자 모두에게 유용한 실전 프롬프트 기법들을 정리합니다. 이론보다는 현실에서 바로 써먹을 수 있는 핵심 원칙과 패턴, 그리고 프롬프트 효과를 높이는 전략들을 알아보겠습니다.

 

모델 출력 조절: Temperature와 샘플링

프롬프트 엔지니어링의 첫걸음으로, 모델의 출력 스타일을 조절하는 방법을 이해해야 합니다. LLM은 다음에 출력할 토큰을 확률적으로 선택하는데, 이때 TemperatureTop-K / Top-P 같은 샘플링 설정이 출력의 창의성과 다양성에 큰 영향을 줍니다 .

  • Temperature(온도): 출력의 무작위성을 조절하는 값입니다. 값을 낮추면 모델이 결정론적이고 일관된 응답을 내도록 하고, 값을 높이면 창의적이고 예측하기 어려운 응답을 유도합니다 . 예를 들어 Temperature = 0으로 두면 항상 가장 확률이 높은 답변을 골라 비교적 한결같은 결과를 얻지만, Temperature를 높이면 같은 질문에도 다양한 답변이 나올 수 있습니다. 사실 Temperature를 최대치로 올리면 모든 토큰이 거의 동등하게 선택될 수 있어 출력이 무작위에 가까워집니다 . 일반적으로 사실 응답이나 정확성이 중요한 작업에서는 Temperature를 낮게 설정하고, 창의적 글짓기나 브레인스토밍에는 Temperature를 높여 더 풍부한 결과를 얻습니다 .
  • Top-K / Top-P: 이 두 설정은 모델이 다음 토큰을 고를 때 고려하는 후보의 범위를 제한합니다. Top-K는 예측 확률이 상위 K위 안에 드는 후보들만 선택하고 , Top-P(누클리어스 샘플링)는 누적 확률이 P 이하인 상위 토큰들(예: 상위 5%, 10% 확률 범위)을 후보로 삼습니다 . 이를 통해 응답의 다양성과 무작위성을 Temperature처럼 조절할 수 있습니다 . 예를 들어 Top-K에서 K 값을 크게 주면 다양한 출력이 나오는 반면, K를 1로 두면 항상 최상위 토큰만 선택하므로 greedy 디코딩과 동일하게 동작합니다 . 마찬가지로 Top-P를 1에 가깝게 두면 대부분의 토큰을 허용하지만, 0에 가깝게 두면 매우 제한된 후보만 고르게 됩니다 .

이러한 샘플링 설정들은 서로 조합되어 동작하며, 모델과 작업에 따라 최적값이 다릅니다. 원하는 결과에 맞게 Temperature와 Top-K/P 값을 실험적으로 조정해보는 것이 좋습니다 . (예를 들어 Vertex AI에서는 Temperature, Top-K, Top-P를 함께 설정할 수 있는데, 이 경우 Top-K/P로 후보군을 좁힌 후 Temperature로 최종 샘플링을 수행합니다 .) 요약하면, 사실적인 한정 답변을 원하면 온도를 낮추고 (또는 Top-K/P로 후보를 제한하고), 참신하고 다채로운 텍스트를 원하면 온도를 높이거나 Top-K/P 범위를 넓혀보세요. 또한, 출력 길이(토큰 수) 역시 설정으로 제어할 수 있습니다. 응답이 너무 길거나 짧지 않도록 최대 토큰 길이를 설정하거나 프롬프트에 “한 문장으로 답해줘”처럼 길이를 명시하는 것도 하나의 방법입니다 .

 

프롬프트 기법 101: 제로샷, 원샷, 퓨샷

프롬프트 작성의 기본 전략으로 흔히 Zero-shot, One-shot, Few-shot 기법을 이야기합니다. 이는 모델에게 예시를 얼마나 제공하느냐에 따른 분류입니다.

  • 제로샷 프롬프트 (Zero-shot): 아무 **예시(example)**도 제공하지 않고 질문이나 지시만으로 모델을 사용하는 가장 단순한 방식입니다. 말 그대로 “0개의 예시”를 주는 것이죠 . 예를 들어, “이 문장이 긍정적인지 부정적인지 분류해줘” 라고 묻는 것이 제로샷 프롬프트입니다. 모델은 추가 참고 없이 스스로 학습된 지식을 활용해 답변하게 됩니다. 제로샷은 프롬프트가 짧고 간단하지만, 모델이 맥락이나 형식을 스스로 추론해야 하므로 항상 정확한 답을 보장하진 않습니다.
  • 원샷 프롬프트 (One-shot): 모델에게 한 개의 예시를 제공하는 방식입니다. 질문이나 지시 전에 또는 후에, 정답의 예시 1개를 보여주어 모델이 따라하도록 유도합니다 . 예를 들어 “리뷰 감성분석: ‘영화 정말 재밌었어요.’ → 긍정” 같은 형식으로 하나의 입력과 그에 대한 원하는 출력을 시범으로 제시하는 것입니다. 이렇게 하면 모델은 제시된 예시를 모방하여 비슷한 패턴으로 답변하려고 합니다 .
  • 퓨샷 프롬프트 (Few-shot): 예시를 여러 개(보통 2개 이상) 제공하는 방식입니다. 두세 개 이상의 Q&A 또는 입력-출력 쌍을 나열하여, 원하는 출력 형태나 패턴을 거듭 보여주는 것입니다 . 모델은 이러한 패턴을 학습하여 이후에 주어진 새로운 입력에도 일관된 형식으로 답하려고 합니다 . 일반적으로 3~5개의 예시를 제공하는 것이 좋다고 하며 , 작업이 복잡할수록 더 많은 예시가 필요할 수 있지만 모델 입력 길이 제한을 주의해야 합니다 . 퓨샷 프롬프트는 모델에게 **“시범 답안”**을 충분히 보여주므로 제로샷보다 정확도가 올라가는 경우가 많습니다.

예시를 고를 때의 팁: 제공하는 예시들은 요구하는 작업과 직접적인 관련이 있고, 다양하며, 품질이 높게 작성되어야 합니다 . 예시 출력에 작은 실수가 있더라도 모델이 혼동을 일으켜 엉뚱한 응답을 낼 수 있기 때문입니다 . 가능하다면 **엣지 케이스(극단적인 사례)**도 포함하여 모델이 다양한 경우를 다룰 수 있도록 하는 것이 좋습니다 . 예를 들어 감성 분류라면 매우 긍정매우 부정, 그리고 중립적인 예시를 고루 넣어 모델이 모든 클래스를 학습하도록 합니다. 다만 예시를 너무 많이 넣으면 프롬프트 길이가 길어지고 모델 맥락 창 한계를 넘길 수 있으므로, 적절한 균형을 찾는 것이 중요합니다 .

예시를 통해 출력 형식 가르치기: 프롬프트에 예시를 포함하는 또 다른 장점은 원하는 출력 형식을 모델에 학습시킬 수 있다는 점입니다 . 예를 들어, “피자 주문을 JSON으로 변환”하는 모델을 만들고 싶다면, 프롬프트에 실제 피자 주문 문장과 그에 대응하는 JSON 형태의 응답을 한두 개 넣어줄 수 있습니다 . 아래는 그런 퓨샷 프롬프트의 예시입니다:

사용자: 주문을 JSON으로 파싱해줘.
EXAMPLE:
주문: "치즈, 페퍼로니 피자 한 판 주세요."
JSON 응답:
{
  "size": "large",
  "toppings": ["cheese", "pepperoni"]
}
주문: "하프앤하프로 반은 불고기, 반은 페퍼로니로 주세요."
JSON 응답:

위와 같이 입력-출력 예시를 보여주면, 모델은 JSON 포맷을 학습하게 되고 다음에 나오는 실제 주문 문장도 JSON 형태로 출력하려고 합니다. 실제 구글의 실험에서도, “피자 주문을 JSON으로 바꾸는” 프롬프트에 두 가지 주문-JSON 예시를 넣고 나니, 모델이 새로운 주문 문장에 대해서도 올바른 JSON 응답을 만들어냈습니다 . 이렇듯 few-shot 시 예시들을 잘 선택하면 출력 형식과 내용의 일관성을 크게 높일 수 있습니다.

 

시스템 프롬프트, 역할(Role) 프롬프트, 컨텍스트 프롬프트

프롬프트 엔지니어링에서 프롬프트의 내용과 위치에 따라 다음과 같은 개념을 구분합니다: 시스템 프롬프트, 역할(Role) 프롬프트, 컨텍스트(prompt). 이들은 서로 겹치는 부분도 있지만 각각 주된 목적이 다르기 때문에 알아둘 가치가 있습니다 .

  • 시스템 프롬프트: 말 그대로 시스템 수준에서 주어지는 지침으로, 모델에게 전체적인 맥락과 목적을 설정해 줍니다 . 이는 모델에게 “큰 그림”을 제시한다고 볼 수 있습니다. 예를 들어 “다음에 입력되는 모든 질문에 대해, 답변을 JSON 형식으로만 출력하라” 혹은 *“당신은 번역기입니다”*와 같이 모델의 기본적인 역할이나 출력 양식을 지정하는 것이 시스템 프롬프트에 해당합니다. 시스템 프롬프트는 보통 대화형 API에서 시스템 메시지로 설정되거나, 일반 프롬프트 맨 앞부분에 전체 맥락을 서술하는 방식으로 주어집니다. 이를 활용하면 특정 형식을 준수하는 출력이나 일관된 행동 방식을 모델에게 주입할 수 있습니다. 예를 들어, *“영화 리뷰를 긍정/부정/중립으로 분류하고, 대문자로 레이블만 답하라”*는 지시를 시스템 프롬프트로 주면, 실제 리뷰 텍스트 입력 시 모델은 오직 NEGATIVE 와 같은 형식의 답만 내놓게 됩니다 . 실제 사례로, 구글의 백서에서는 이 지침을 준수하여 모델이 불필요한 설명 없이 대문자 레이블만 반환하는 것을 확인했습니다 . 또한 시스템 프롬프트를 활용해 “항상 정중하게 답해라” 같은 안전장치를 넣으면 모델의 유해하거나 공격적인 발언을 억제하는 효과도 있습니다 .
  • 컨텍스트 프롬프트: 모델에게 현재 대화나 작업에 필요한 구체적인 배경정보나 조건을 제공하는 프롬프트입니다 . 즉, 모델이 질문의 맥락을 더 잘 이해할 수 있도록 돕는 추가 정보를 넣는 것입니다. 예를 들어 사용자가 “추천 좀 해줘” 라고만 물으면 맥락이 없지만, 컨텍스트로 “당신은 80년대 레트로 게임에 대한 블로그 필자입니다”, 이어서 *“블로그에 쓸 만한 주제 3가지를 제안해줘”*라고 요청하면, 모델은 **해당 컨텍스트(80년대 레트로 게임)**에 맞는 제안을 해줄 것입니다 . 실제 예시에서도, 컨텍스트를 명시하지 않은 경우보다 *“80년대 오락실 게임 블로그를 운영한다”*는 배경을 알려준 후에 아이디어를 구했을 때, 훨씬 관련성 높은 기사 주제들이 나왔습니다 . 이처럼 컨텍스트 프롬프트는 모델이 질문 의도를 빠르게 파악하고 정확하고 관련된 응답을 생성하도록 도와줍니다 . 컨텍스트는 시스템 프롬프트와 달리 현재의 특정 요청에만 적용되는 동적인 정보인 경우가 많습니다. (예: 사용자 위치, 대화의 지난 내용 등)
  • 롤 프롬프트 (Role prompting): 모델에게 특정 역할이나 인격을 부여하여 그 관점에서 답변하게 만드는 기법입니다 . 예를 들어 “당신은 여행 가이드입니다”, “지금부터 이 모델은 어린이집 선생님처럼 행동합니다” 처럼 모델에게 가상의 역할을 맡기는 것이죠. 이렇게 하면 모델은 정해진 캐릭터의 말투, 지식, 태도에 맞춰 응답하게 됩니다 . 구글 백서에 소개된 한 예시에서는, 모델에게 *“여행 가이드로서, 내 위치 근처에 갈 만한 곳 3군데를 추천해줘”*라는 역할 지시를 주었더니 암스테르담에 있는 박물관 3곳을 상세히 소개했습니다 . 반면 동일한 질문에 역할을 *“지리 교사”*로 바꾸니, 같은 장소를 두고도 교육적인 관점에서 역사와 지리 정보를 강조하는 등 완전히 다른 스타일의 답변이 생성되었습니다 . 이렇듯 역할 프롬프트는 답변의 **어조(tone)**와 전문성을 우리가 원하는 방향으로 맞춰줍니다. 원하는 역할을 명확히 정의하면, AI는 해당 전문가의 관점과 말투를 모방하여 보다 관련성 높고 일관된 응답을 제공합니다 .

위의 시스템/컨텍스트/롤 프롬프트는 때로 한 프롬프트 안에서 함께 쓰이기도 합니다. 예를 들어 “시스템: 너는 상담사 AI다.”, “사용자: (고민 내용)” 처럼 역할과 목적을 모두 설정할 수도 있습니다. 핵심은 이러한 장치를 통해 모델이 답해야 할 방향을 분명히 제시하는 것입니다. 컨텍스트로 적절한 정보를 주고, 시스템 지침으로 형식을 정하고, 역할을 부여해 어조를 통제하면, 모델이 훨씬 안정적이고 원하는 스타일로 답을 생성합니다. 특히 출력 형식을 JSON 등 구조화해서 요구하는 것은 앞서 언급했듯이 일관된 형식 출력과 헛소리 감소에 효과적입니다 .

 

고급 프롬프트 테크닉: Step-back, Chain-of-Thought, Self-Consistency…

앞서 기본적인 프롬프트 기법을 살펴봤다면, 이제 더 어려운 문제를 풀거나 모델의 사고과정을 활용하기 위한 고급 테크닉들을 알아보겠습니다. 이러한 기법들은 복잡한 질문이나 추론이 필요한 상황에서 모델 성능을 크게 향상시킬 수 있습니다.

 

Step-back 프롬프트: 한 발 물러서서 생각하기

**스텝백 프롬프트(step-back prompting)**는 말 그대로 문제를 바로 풀지 않고 한 걸음 물러나서 일반적인 질문을 먼저 생각해보게 하는 기법입니다 . 즉, 구체적인 질문에 답하기 전에 관련된 더 넓은 맥락의 질문을 모델에게 물어보고, 그 답을 이용해 최종 답변을 얻는 2단계 접근법입니다 . 이렇게 하면 모델이 곧바로 세부 문제에 뛰어들기보다는 배경 지식과 원리를 먼저 상기하게 되고, 결과적으로 더 정확하고 통찰력 있는 응답을 생성할 수 있습니다 . 스텝백 프롬프트는 모델에게 비판적 사고를 장려하고, 문제를 다양한 각도에서 바라볼 여유를 주기 때문에 새로운 아이디어나 해법이 나올 확률을 높여줍니다 . 또한 구체적인 세부사항보다 일반 원칙에 집중하게 하므로 편향을 줄이는 데도 도움이 됩니다 .

예를 들어, *“1인칭 슈팅 게임(FPS)의 재미있는 스토리 라인을 하나 작성해줘”*라는 요청을 바로 하면 모델이 다소 평범한 줄거리를 낼 수 있습니다. 구글 연구진은 이때 한 발 물러나 일반적인 질문인 *“재미있고 도전적인 FPS 게임 레벨을 만들려면 어떤 배경(settings)이 중요할까?”*를 먼저 모델에게 물어봤습니다 . 모델은 이에 대해 군사 기지, 사이버펑크 도시, 외계 우주선, 좀비 도시, 해저 연구소 등 5가지 흥미로운 배경 아이디어를 내놓았죠 . 그리고 나서 최종 프롬프트로 *“위에서 나온 설정 중 하나를 선택해 그 배경을 가진 FPS 게임 레벨의 스토리를 한 단락으로 써줘”*라고 했더니, 모델은 **‘해저 연구소’**를 선택해 이전보다 훨씬 구체적이고 독창적인 줄거리의 답변을 생성했습니다 . 결과적으로 처음 직접 요구했을 때보다 더 흥미롭고 완성도 있는 이야기가 나온 것입니다 .

이처럼 스텝백 기법을 쓰면 프롬프트의 정확성과 품질을 높일 수 있다고 백서는 설명합니다 . 복잡한 문제를 다룰 때 한번에 풀려고 하지 말고, **“이 문제를 풀기 위해 알아야 할 일반 지식은 뭘까?”**처럼 모델이 배경맥락을 떠올릴 수 있는 질문을 중간에 던져보세요. 그런 다음 나온 정보를 활용해 최종 질문을 하면, 모델이 훨씬 풍부한 지식을 동원해 답을 해줄 것입니다.

 

Chain-of-Thought: 단계별로 생각하게 하기

체인 오브 쏫(Chain-of-Thought, 연쇄 사고) 기법은 모델에게 문제를 풀기 위한 중간 추론 과정을 글로 써보도록 유도하는 것입니다 . 쉽게 말해 “하나씩 단계적으로 생각해보자” 라고 모델에게 지시하여, 마치 사람이 머릿속으로 풀듯이 한 단계씩 논리를 전개하면서 답을 찾도록 하는 프롬프트죠. 이를 위해 보통 프롬프트 끝에 “Step by step” 또는 “하나씩 생각해봐” 같은 문구를 추가합니다. 그러면 모델은 최종 답을 바로 내지 않고, 먼저 자기 자신과 대화하듯이 풀이 과정을 여러 문장으로 늘어놓습니다 .

이 기법의 가장 큰 장점은 복잡한 문제의 정확도를 높여준다는 것입니다. 모델이 속으로만 생각하지 않고 글로 설명하도록 하면, 더 논리적으로 검토하면서 답을 구할 수 있기 때문입니다 . 예를 들어 숫자 퍼즐이나 논리 문제의 경우, 체인 오브 쏫 없이 바로 답을 요구하면 모델이 착각하거나 계산 실수를 할 수 있습니다. 실제 백서에서 다룬 간단한 나이 계산 문제를 보겠습니다:

  • 일반 프롬프트: “내 나이가 3살 때 내 파트너는 내 나이의 3배였어. 지금 내가 20살이면 파트너 나이는?” -> 모델 응답: “63살” (오답)
  • CoT 프롬프트: “… 파트너 나이는? 천천히 단계별로 생각해봐.” -> 모델 응답: 1. “내 나이 3살 때 파트너 9살 …” 2. “현재 나는 20살, 17살 증가…” … 6. “파트너 나이는 26살” (정답) .

보시다시피, 그냥 물어봤을 땐 틀린 대답을 하던 모델도 “단계별로 설명해줘” 라고 요청하자 **풀이 과정을 모두 보여주며 올바른 답(26세)**을 찾았습니다 . 체인 오브 쏫으로 모델의 추론 과정이 드러나면, 사용자는 그 중간 단계에서 오류가 있었는지 확인할 수도 있습니다 . 만약 모델이 잘못된 논리를 펼쳤다면 그 부분을 다시 교정하여 재질문하거나, 추가 힌트를 줄 수 있겠죠. 이런 식으로 CoT는 결과에 대한 해석 가능성도 높여주어, 프롬프트 엔지니어가 모델의 “생각”을 분석하고 개선하는 데 도움을 줍니다 . 또한 체인 오브 쏫을 활용한 프롬프트는 모델이 업데이트(버전 변경)되더라도 비교적 안정적으로 작동하는 경향이 있다고 보고되었습니다 . 이는 중간 추론 단계를 거치면서 답을 내는 방식이 모델 구조가 바뀌어도 **성능 드리프트(drift)**가 적기 때문이라고 합니다.

물론 단점도 있는데, 체인 오브 쏫을 쓰면 출력이 길어져 비용과 시간이 증가한다는 점입니다 . 모델이 단계별 설명을 덧붙이므로 토큰 사용량이 늘어나기 때문이죠. 따라서 정말 필요한 경우에 주로 사용하고, 최종 실제 애플리케이션에서는 모델 응답에서 최종 답만 추출하는 후처리가 필요합니다 (예: "답은 26입니다." 같은 부분만 사용). 이를 위해 프롬프트에 “마지막에 최종 답만 한 문장으로 말해줘” 같은 요청을 덧붙이기도 합니다.

체인 오브 쏫 + 예시 (Few-shot CoT): CoT 기법은 다른 기법들과도 결합할 수 있습니다. 예를 들어, 아예 프롬프트에 예시 질문과 그에 대한 단계별 해설 및 정답을 한 세트 넣어주면 모델이 그 형식을 그대로 따라합니다. 앞서의 나이 문제를 해결할 때도, 먼저 유사한 문제에 대한 사람이 풀어쓴 해설을 예시로 제시하니 모델이 더욱 안정적으로 추론을 모방했습니다 . 이렇듯 Few-shot CoT는 모델에게 옳은 사고과정의 예를 가르쳐줘서, 복잡한 문제에서도 일관된 풀이를 이끌어낼 수 있는 강력한 방법입니다 .

Self-Consistency(자가 일관성): Self-consistency는 Chain-of-Thought의 발전된 형태로, 여러 번의 Chain-of-Thought 결과를 취합하여 가장 일관된 답을 선택하는 방법입니다 . 구체적으로, 동일한 CoT 프롬프트를 Temperature를 높여서 여러 번 모델에게 시도하게 만든 뒤, 각각의 최종 답을 수집합니다 . 이렇게 하면 모델이 매번 다른 경로의 추론을 시도해볼 수 있는데, 그 중 가장 많이 등장하는 일치된 답을 최종 답변으로採用하는 것이 self-consistency의 아이디어입니다 . 일종의 다수결 투표로 생각하면 쉽습니다. 이 방식은 CoT의 성능을 한층 끌어올려주지만, 당연히 여러 번 모델을 실행해야 하므로 시간/비용이 증가합니다 . 따라서 중요한 의사결정이나 높은 정확도가 요구되는 경우에 선택적으로 활용됩니다.

구글 백서에서는 self-consistency의 효과를 이메일 분류 예시로 보여주었습니다. 내용은 다소 장난스럽지만 사실 보안상 중요한 버그 제보 이메일인데, 모델이 겉보기 어조만 보고 *“중요하지 않음”*으로 분류할 가능성이 있는 사례였습니다 . 이 이메일을 여러 번 CoT로 분류해보니 일부 응답은 “중요함”, 일부는 “중요하지 않음”으로 나뉘었습니다. 그러나 **가장 빈도가 높았던 답은 “중요함”**이었고, 이를 최종 결과로 택하는 self-consistency 전략이 옳은 판단을 내렸습니다 . 결국 모델은 *“첨부된 스크린샷과 해커라는 서명 등을 볼 때 보안 취약점 제보이므로 중요하다”*고 결론지었죠 . 이처럼 self-consistency는 모델의 여러 관점 중 다수의 지지를 받은 답을 선택하여 정답률을 높이는 기법입니다 . 다만 한 번만 물어볼 때보다 엔진 호출을 여러 번 해야 하므로, 현실에선 응답 캐싱 등과 결합해 최적화하는 편입니다.

 

Tree-of-Thoughts와 ReAct: 복잡한 문제 해결을 위한 프레임워크

**Tree-of-Thoughts(ToT)**와 **ReAct (Reason+Act)**는 2023년 경 제안된 최신 기법들로, 매우 복잡한 문제나 툴 활용이 필요한 과제에 LLM을 적용하기 위한 프롬프트 전략입니다. 일반 사용자보다는 개발자나 연구자가 활용하는 경우가 많지만, 트렌드로서 간략히 소개합니다.

  • 트리 오브 쏫(Tree-of-Thoughts): 체인 오브 쏫이 하나의 연쇄적인 생각 흐름만 따르는 데 반해, ToT는 여러 갈래(branch)의 생각을 탐색하도록 허용합니다 . 즉, 모델이 한번에 한 가지 추론 경로만 따르는 것이 아니라, 중간에 경우의 수가 있을 때 분기하여 다양한 가능성을 모두 전개해볼 수 있게 하는 프레임워크입니다 . 이렇게 생성된 “생각의 나무”에서 가지치기(branching)하여 탐색하고, 각 가지의 결과를 평가하면서 최적해를 찾는 방식으로, 사람의 브레인스토밍+의사결정 과정을 모방한다고 볼 수 있습니다 . ToT를 구현하려면 단순 프롬프트 이상의 알고리즘적 관리가 필요하며, 연구 단계에 있는 기법이지만 조합 최적화, 수학 문제 풀이 등에서 잠재력을 보이고 있습니다.
  • 리액트(ReAct): ReAct는 Reason+Act의 줄임말로, 모델의 언어적 추론과 외부 행동(툴 사용)을 결합한 프롬프트 전략입니다 . 예를 들어 사람도 모르는 것을 생각으로만 해결하지 않고 웹을 검색하거나 계산기나 코드를 실행해보며 풀 듯이, LLM에게도 그런 외부 도구를 사용할 권한을 주는 것입니다 . 프롬프트 측면에서는, 모델에게 *“필요하면 인터넷을 검색해 답을 찾아”*라고 안내하고, 모델이 답변 대신 검색: ___ 같은 액션을 텍스트로 출력하면 그에 따라 실제 프로그램이 검색 API를 호출한 후 결과를 모델 입력에 다시 주입합니다. 모델은 그 결과(Observation)를 보고 다시 Reasoning을 이어나가고, 또 행동하고… 이런 생각(Thought)과 행동(Action)의 루프를 구성하는 것이 ReAct 프롬프트의 개념입니다 . 이를 통해 LLM은 고정된 훈련 데이터에 의존하지 않고 실시간 정보나 계산 능력을 활용해 복잡한 문제를 풀 수 있습니다. ReAct는 일종의 에이전트(Agent) 개념으로 확장되어, 예를 들어 사용자의 요청에 따라 검색→계산→답변의 과정을 자동화하는 AI 비서 등에 응용되고 있습니다. 물론 일반적인 채팅 인터페이스에서는 기본 지원되지 않지만, 파이썬의 LangChain 같은 프레임워크를 이용하면 OpenAI/GPT 계열 모델에 ReAct 패턴을 적용할 수 있습니다.

요약하면, Tree-of-Thoughts는 모델의 내적 사고 구조를 나무처럼 확장하는 기법이고, ReAct는 모델이 외부 도구와 상호작용하며 문제를 해결하게 하는 접근입니다. 둘 다 아직 발전 중인 영역이지만, 궁극적으로 LLM을 더 똑똑하고 실용적으로 활용하기 위한 노력들입니다.

 

자동 프롬프트 엔지니어링 (Automatic Prompt Engineering)

프롬프트 작성이 때로는 번거롭고 어렵다는 점 때문에, AI에게 프롬프트 작성을 도와달라는 발상도 등장했습니다. 이를 **자동 프롬프트 엔지니어링(Automatic Prompt Engineering, APE)**이라고 부릅니다 . 말 그대로 *“프롬프트를 만들어주는 프롬프트”*를 작성하여 모델 스스로 다양한 시도를 해보게 하는 것입니다 .

APE의 일반적인 접근은 다음과 같습니다 :

  1. 프롬프트 후보 생성: 우선 현재 작업에 대한 다양한 프롬프트 후보들을 모델이 직접 만들어보도록 요청합니다. 예를 들어, 음악 밴드 티셔츠를 판매하는 챗봇을 만들고 싶다면 *“‘메탈리카 티셔츠 한 장 small 사이즈 주문’이라는 의미를 담은 10가지 표현을 만들어줘”*라는 식으로 지시하는 것이죠 . 그러면 모델은 문장 구조나 단어 선택을 조금씩 바꾼 여러 표현을 생성해냅니다. 실제 예시로 모델이 출력한 주문 문장 변형들을 보면, “Metallica 티셔츠 small 하나 주문하고 싶어요.”, “Small 사이즈 Metallica 티셔츠 한 장 구매하려고 합니다.” 등 같은 의미를 가진 10개의 문장을 만들어냈습니다 .
  2. 후보 평가: 이렇게 얻은 프롬프트 후보들을 정량적으로 또는 수동으로 평가합니다. 평가 방법은 경우에 따라 다른데, 정답이 있는 작업이라면 각 프롬프트를 실제로 모델에 넣어본 뒤 결과의 정확도나 적합성을 채점할 수 있습니다. 또는 원하는 출력과의 유사도를 BLEU, ROUGE 같은 점수로 비교하기도 합니다 . 중요한 것은 생성된 후보들 중 어떤 프롬프트가 제일 우수한 성능을 보이는지 가려내는 것입니다 .
  3. 최적 프롬프트 선정 및 개선: 평가 결과 가장 성능이 좋거나 적합한 프롬프트를 최종 프롬프트로 채택합니다 . 필요하다면 인간이 그 프롬프트를 약간 다듬어도 됩니다. 그리고 여기서 끝내지 않고, 선택된 프롬프트를 다시 변형하거나 확장하여 2단계를 반복함으로써 더 나은 프롬프트를 찾는 iterative refinement도 가능합니다 .

자동 프롬프트 엔지니어링의 장점은, 모델이 스스로 여러 표현을 시도해보기 때문에 사람이 일일이 생각해내기 어려운 phrasing도 발견할 수 있다는 점입니다 . 또한 사람의 편향 없이 다양한 접근법을 탐색하므로 의외로 좋은 성능을 내는 프롬프트를 찾아낼 가능성도 있습니다. 다만 모델의 평가 능력이 완벽하지 않기 때문에, 어디까지나 초안을 잡아주는 도우미로 활용하고 최종 판단은 개발자가 내리는 것이 안전합니다. 예를 들어 위의 티셔츠 주문 예시에서 모델이 만든 10문장을 실제 챗봇에 넣어보며 어떤 표현이 가장 잘 인식되는지 시험해볼 수 있을 것입니다. 이런 방식으로 A/B 테스트를 자동화하면 프롬프트 엔지니어링의 수고를 줄이고 성능 튜닝을 가속할 수 있습니다.

 

코드 생성 & 디버깅을 위한 프롬프트

프롬프트 엔지니어링은 자연어 답변뿐만 아니라 소스 코드 생성이나 코드 이해에도 응용됩니다. 개발자라면 LLM을 일종의 코드 도우미로 사용할 수 있는데, 이를 효과적으로 하기 위한 프롬프트 기법을 살펴보겠습니다 .

  • 코드 작성 요청: 코드를 생성하고 싶다면 구체적으로 무엇을 원하는지 명시하는 것이 중요합니다. 어떤 언어로, 어떤 기능을 하는 코드를 원하는지 상세히 설명해야 하죠. 예를 들어 *“Bash 스크립트를 작성해줘”*보다는 *“Bash로 폴더 내 모든 파일명을 앞에 ’draft_’를 붙여 변경하는 스크립트를 작성해줘”*처럼 말입니다 . 또한 온도(temperature)를 낮게 설정하면 창의성보다는 정확성이 강조되어, 논리적으로 정확한 코드를 얻는 데 유리합니다 . 구글의 실험에서 이러한 프롬프트로 Bash 스크립트를 생성해보니, 모델이 입력 폴더명을 받고, 파일 존재 여부를 체크하고, 모든 파일명을 바꾸는 완결된 스크립트를 출력했습니다 . 심지어 주석까지 달려 있어 이해하기도 쉬웠습니다. 🤖💻 그러나 생성된 코드도 항상 검증 필요: 백서는 “LLM은 추론 능력이 부족하고 훈련데이터의 코드를 복사해낼 수 있기 때문에, 코드를 반드시 직접 읽어보고 테스트하라”고 강조합니다 . 실제로 위 Bash 스크립트를 파일에 저장해 실행해보니, 모델이 만든 코드가 정상 작동함을 확인했습니다 . 하지만 모든 경우에 운이 좋을 수는 없으므로, 프롬프트로 코드를 얻더라도 항상 사람의 검토와 실행테스트를 거쳐야 합니다.
  • 코드 설명 요청: 다른 사람이 짠 복잡한 코드를 이해해야 할 때, LLM에게 도움을 청할 수 있습니다. 이때 프롬프트는 간단합니다: **“아래 코드를 설명해줘”**라고 쓰고 코드 블럭을 통째로 제공하면 됩니다 . 모델은 코드를 읽고 단계별로 어떤 동작을 하는지 친절하게 설명해줍니다. 예를 들어 앞서의 Bash 스크립트를 입력하고 설명을 부탁하니, 모델이 1. 사용자 입력 받음, 2. 폴더 존재 확인, 3. 파일 목록 수집, 4. 각 파일에 prefix 추가하며 이름 변경, 5. 성공 메시지 출력과 같이 번호를 매겨 스크립트의 로직을 상세히 풀어주었습니다 . 이러한 코드 설명 프롬프트는 주석이 부족한 코드나, 처음 접하는 언어의 코드를 빠르게 이해하는 데 큰 도움이 됩니다.
  • 코드 변환 요청: LLM은 한 프로그래밍 언어로 된 코드를 다른 언어로 번역할 수도 있습니다. 프롬프트는 *“다음 Bash 코드를 Python으로 바꿔줘”*처럼 쓰면 됩니다 . 그러면 모델이 해당 언어의 문법과 라이브러리를 활용하여 등가의 기능을 하는 코드를 출력합니다. 예를 들어 Bash 스크립트를 Python 코드로 변환하도록 한 실험에서, 모델은 osshutil 라이브러리를 이용해 폴더 검사 및 파일 이름 변경을 수행하는 파이썬 코드를 생성했습니다 . 다만 이런 변환 결과도 검토가 필요합니다. 예시의 1차 변환 결과는 동작했지만, 이어서 약간 코드를 변경해 toUpperCase 함수 사용 등을 시도하자 에러가 발생했습니다 .
  • 코드 디버깅 및 리뷰: LLM에게 이미 작성된 코드의 버그를 찾거나 개선점을 물어볼 수도 있습니다. 이 경우 에러 메시지문제가 되는 코드 부분을 프롬프트에 포함시켜 *“무엇이 잘못됐는지 디버깅하고 개선 방안을 알려줘”*라고 요청합니다 . 구글 백서의 사례에서는, 고의로 오타 (os.path.joi -> os.path.join)를 내고 정의되지 않은 함수(toUpperCase)를 쓴 파이썬 코드를 제시하면서 에러 로그를 함께 모델에 보여주었습니다 . 모델은 이를 보고 toUpperCase 함수가 정의되지 않았으니 Python 내장 upper() 메서드를 쓰라고 지적했고, os.path.joi 오타까지 바로잡은 수정 코드를 제안했습니다 . 더 나아가, 단순히 오류를 고치는 것에 그치지 않고 코드의 개선점까지 몇 가지 지적했는데, 파일 확장자 처리, 공백 처리, 예외 처리 등의 추가 아이디어를 제시하며 개선된 최종 코드를 내놓았습니다 . 결과적으로 모델의 출력은 우리가 기대한 버그 수정뿐만 아니라, 코드 리뷰어처럼 잠재적 문제와 리팩토링 포인트까지 짚어준 셈입니다 . 이러한 능력은 복잡한 코드베이스에서 잘 나타나며, 개발자가 실수한 부분을 모델이 캐치해주기도 합니다. 역시 모든 조언을 맹신해서는 안 되지만, 디버깅 프롬프트는 막히는 부분에서 새로운 시각을 얻는 데 큰 도움이 됩니다.

 

요약하자면, 코드 관련 프롬프트 엔지니어링의 핵심은 맥락을 충분히 제공하는 것입니다. 무엇을 만들고 싶은지, 문제가 되는 부분이 무엇인지 명확히 알려주면 모델은 꽤 훌륭한 파트너가 되어줍니다. 그리고 항상 결과를 테스트하고 검증하는 단계는 잊지 말아야 합니다.

 

멀티모달 프롬프트에 대하여

현재 주류 LLM들은 텍스트 입력에 텍스트 출력이 기본이지만, 점차 이미지나 오디오 등 여러 형태의 입력을 혼합멀티모달(multimodal) 프롬프트도 등장하고 있습니다 . 멀티모달 프롬프트란 한 가지 유형이 아닌 복합 형식의 입력을 사용하는 것으로, 예를 들어 이미지+텍스트를 함께 모델에 제공하여 답변을 얻는 식입니다 . 구글의 Gemini 모델도 이미지 프롬프트를 지원할 것으로 알려져 있는데, 이러한 모델이라면 “이 그림을 보고 설명해줘” 같은 요청이 가능해집니다. 반면 지금까지 설명한 프롬프트 기법들은 기본적으로 텍스트 기반이며, 코드 역시 텍스트로 간주되므로 멀티모달 범주에는 들지 않습니다 .

멀티모달 프롬프트는 모델이 이해해야 할 정보의 폭을 넓혀주고 더 풍부한 상호작용을 가능케 하지만, 모델이 그 모달리티를 처리할 수 있는 능력이 전제되어야 합니다. 만약 이미지나 음성이 지원되지 않는 모델에 그런 입력을 주면 전혀 인식하지 못하거나, base64 등 문자열로 변환된 형태로만 다룹니다. 그러므로 자신이 사용하는 모델이 어떤 입력 타입을 지원하는지를 확인하는 것이 중요합니다. 미래에는 텍스트와 이미지를 함께 넣고, 모델이 이미지를 분석한 후 텍스트로 답하는 것이 자연스러워질 것입니다. 하지만 2025년 현재 시점에서는 이러한 멀티모달 프롬프트는 일부 특수 모델에서만 가능하니, 일반 사용자는 우선 텍스트 프롬프트에 집중하시면 됩니다.

 

베스트 프랙티스: 좋은 프롬프트를 위한 팁 총정리

마지막으로, 효과적인 프롬프트 작성을 위한 일반적인 권장 사항들을 정리해 보겠습니다 . 아래의 원칙들은 구글 백서에서도 강조한 내용으로, 프롬프트 엔지니어링을 처음 접하는 분들께 큰 도움이 될 만한 실전 팁입니다.

  • 예시 제공: 가능하다면 프롬프트에 시행착오 예시나 참고 예시를 포함하세요. 모델은 예시를 통해 여러분이 원하는 바를 학습합니다 . 특히 출력 형식이나 답변 스타일을 가르치고 싶다면 One-shot/Few-shot 예시만큼 확실한 방법이 없습니다 . 예시는 모델에게 목표치를 보여주는 강력한 도구이므로, 가장 중요한 베스트 프랙티스로 꼽힙니다 .
  • 간결하고 명확하게: 프롬프트 문장은 짧을수록 좋고, 이해하기 쉬워야 합니다. 내가 읽어도 복잡하고 헷갈린다면 모델도 헷갈릴 것입니다 . 불필요한 정보나 장황한 표현은 피하고, 핵심만 정확하게 지시하세요 . 예를 들어 *“제가 지금 뉴욕에 있는데 아이 둘과 함께 갈 만한 좋은 곳이 있을까요?”*보다는 *“여행 가이드처럼 알려줘: 뉴욕 맨해튼에서 3살짜리 아이와 갈만한 명소 추천”*처럼 문장을 단순화해보세요 . 필요한 경우 bullet이나 번호를 사용해 단계별로 묻는 것도 방법입니다.
  • 출력 요구 명확히: 모델에게 어떤 형태의 답을 원하는지 구체적으로 명시하세요. 단순히 “글 써줘”라고 하면 너무 막연합니다 . 대신 *“3문단짜리 블로그 글을 써줘. 대화체로 재미있게, 각 문단은 5문장 내외로”*처럼 길이, 형식, 구체 내용을 지정하면 모델이 방향을 잡기 훨씬 수월합니다 . 예시로 백서에서는 *“게임 콘솔 탑5에 대한 informative하고 engaging한 3문단 블로그 글”*이라는 지시가, 막연한 *“게임 콘솔에 대해 글 써줘”*보다 훨씬 좋은 결과를 냈다고 합니다 .
  • 지시문을 우선, 제약은 최소화: 프롬프트에 *“~하지 마라”*라는 제약 조건을 잔뜩 넣기보다는, 긍정형으로 무엇을 해야 할지 집중하세요 . 사람도 “이렇게 해주세요”라는 말을 더 이해하기 쉽지 “이거 하지 말고 저거 하지 말고…” 하면 혼란스러울 수 있죠. 모델도 마찬가지입니다. 하고 싶은 일은 분명히 **지시(instruction)**하고, 정말 필요할 때만 **금지사항(constraint)**을 덧붙이세요 . 예를 들어 *“1문단 짜리 글을 쓰되, 각 문장에는 욕설을 포함하지 마”*라고 하기보단, *“1문단으로 글을 써줘. 내용은 정중한 어투로 작성해”*라고 하는 편이 좋습니다. 전자의 “…하지 마” 규칙만 잔뜩 나열하는 경우 모델이 무엇을 해야 하는지 오히려 불명확해질 수 있습니다 . 물론 안전이나 특정 출력 금지(예: 개인정보 출력 금지) 등에서는 제약도 필요하지만, 가능하면 *“이렇게 해라”*는 긍정 명령으로 유도하고, 꼭 필요한 최소한의 제약만 거세요 . 이러한 원칙은 모델이 더 창의적이고 유연하게 정해진 틀 안에서 답하도록 돕습니다 .
  • 토큰 길이 제어: 모델의 응답 길이를 통제하고 싶다면 max_tokens 설정이나 프롬프트 상의 지시를 활용하세요 . 예컨대 API를 쓴다면 max_tokens로 최대 출력 길이를 제한할 수 있고, 일반 채팅에서는 “두 문장으로 대답해줘”, *“트윗 한 개 분량으로 설명해줘”*처럼 요청하면 됩니다 . 너무 긴 답변이 부담되거나, 대화 맥락에서 다음 응답을 짧게 받고 싶을 때 유용한 팁입니다.
  • 변수 활용: 동일한 형태의 프롬프트를 여러 데이터에 적용할 때는 변수 자리표시자를 쓰는 편이 낫습니다 . 예를 들어 여러 도시 이름에 대해 관광 정보를 얻고 싶다면, 프롬프트를 *“당신은 여행 가이드입니다. 도시 {city}에 관한 재미있는 사실을 하나 알려줘.”*로 만들어놓고 {city}만 런타임에 교체하는 식입니다 . 이렇게 하면 프롬프트를 재사용하기가 쉽고, 매번 프롬프트를 새로 쓰는 수고를 덜 수 있습니다 . 특히 프로그래밍으로 API를 사용할 때 유용하며, prompt template을 관리하기도 수월해집니다.
  • 프롬프트 표현 실험: 같은 목적도 질문 형태로 물어볼지, 명령형으로 지시할지, 문장으로 서술할지에 따라 모델 출력이 미묘하게 달라집니다 . 예를 들어 “드림캐스트가 뭐였고 왜 혁신적이었나요?” vs “세가 드림캐스트는 1999년 발매된 콘솔로…” vs *“드림캐스트 콘솔에 대해 한 단락으로 설명하고 혁신적이었던 이유를 밝혀줘.”*는 각각 약간씩 다른 톤과 구성을 이끌어냅니다 . 어떤 게 최선인지는 정해진 답이 없으므로, 질문형, 명령형, 완전한 문장형여러 방식으로 프롬프트를 바꿔 시도해보세요 . 모델과 상호작용하면서 점점 원하는 결과에 가까워질 것입니다.
  • Few-shot 예시 순서 섞기 (분류 태스크): 만약 분류 문제에 대해 퓨샷 예시를 제공한다면, 예시들의 순서나 클래스 분포에 편향이 없도록 주의하세요. 예를 들어 스팸/햄 분류라면, 햄 예시만 잔뜩 나열하고 마지막에 스팸 예시 하나를 주는 식보다는 햄과 스팸 예시를 번갈아 섞는 것이 좋습니다 . 그래야 모델이 특정 클래스 순서나 빈도에 치우치지 않고, 각 클래스의 특징을 제대로 학습합니다 . 즉, 예시 순서를 의도적으로 섞어서 다양성을 부여하는 것이 일반화 성능에 도움이 됩니다.
  • 모델 업데이트에 대비: 프롬프트는 궁극적으로 특정 모델 버전에서 최적화된 것이므로, 모델이 바뀌면 결과가 변할 수 있습니다 . 최신 버전이 더 똑똑해져서 덜 엄격한 프롬프트로도 잘 작동할 수도 있고, 반대로 미세한 출력 스타일이 달라져서 프롬프트를 조정해야 할 수도 있습니다. 따라서 모델이 업그레이드되면 기존 프롬프트들을 다시 한 번 테스트해 보고, 필요하면 문구나 예시를 수정하는 게 좋습니다 . Vertex AI 등의 도구를 쓰면 프롬프트와 결과를 버전별로 저장해두고 비교하기 편하므로, 이런 기능을 활용해 프롬프트 자산을 관리하세요 .
  • 구조화된 출력 활용: 가능하면 모델 출력은 읽기 쉽게 또는 기계가 파싱하기 쉽게 구조화된 형식으로 요청하는 것이 좋습니다 . 예를 들어 단순 나열보다 JSON, XML, Markdown 표 등으로 답하게 하면, 매번 같은 포맷으로 결과를 얻을 수 있어 후처리가 편합니다 . 특히 JSON은 많은 프로그래밍 환경에서 바로 파싱하여 사용할 수 있고, 모델에게 JSON으로 답을 쓰라고 하면 정해진 스키마에 맞춰 출력하려고 노력하기 때문에 헛소리나 불필요한 문장을 줄이는 효과도 있습니다 . 다만 너무 엄격한 형식을 요구하면 모델이 어려워할 수 있으니, 가능하면 스키마 예시를 함께 제시하는 게 안전합니다. 어쨌든 원하는 출력 형식이 있다면 분명히 명시하고, 없다면라도 가독성을 위해 리스트/표 등을 활용하도록 유도해 보세요.

 

읽어주셔서 감사합니다. 😊

프롬프트 엔지니어링은 한번 익혀두면 다양한 생성형 AI 활용에 큰 힘을 발휘합니다. 위의 원칙들을 참고하여 직접 여러 프롬프트를 시도해보세요. 처음엔 시행착오가 있겠지만, 계속 연습하다 보면 모델의 특성을 파악하여 어떤 프롬프트가 잘 먹히는지 감이 잡히실 거예요. 마지막으로 기억할 것은, AI와의 소통은 사람이 대화 스타일을 주도한다는 점입니다. 즉, 프롬프트를 잘 설계하는 것만으로도 AI 활용도의 절반은 성공한 셈이니, 여러분도 이 가이드라인을 바탕으로 멋진 프롬프트를 만들어보시기 바랍니다! 🚀

반응형