Sign In
Subscribe
프롬프트 엔지니어링

Let's think step by step - "얘 안되던데요?"

T
Two_Jay
카테고리
Empty
"Let's think step by step"
'단계적으로 생각해'. 프롬프트에서 자주 찾아볼 수 있는 구문입니다. 이젠 어떤 레거시 프롬프트든 볼 때면 자연스럽게 들어와 있는 구문이기도 하죠. 마치 마법의 주문, 그도 아니면 MSG와 같이 넣어주고 있는 구문이기도 합니다.
저도 자주 쓸까요? 네. 저도 자주 씁니다. 하지만 대부분의 프롬프트 전략은 장단이 있고, 적절하게 사용해야할 때가 있습니다. 실제 사례를 볼까요?

사례 1.

카드게임 봇을 llm으로 하는 프로젝트의 피드백을 해드린 적이 있습니다. "얘가 자기 턴에 낼 카드를 판단할 때 좀 정확하게 상황을 판단했으면 좋겠어요!" 프롬프트를 보고 있으니, 가지고 있는 카드를 순수하게 LLM의 인퍼런스에만 맡겨서 내도록 했습니다. 아래와 같이 프롬프트를 수정하도록 권고했었습니다. 피드백이 만족스러웠는지 몇 주 뒤, 자신들이 한 사이드 프로젝트를 보여주러 왔습니다.
💬
현재 게임 상황에 대해 프롬프트에 넣어서, Let's think step by step을 이용해서 현재 상황에 대한 판단을 먼저 수행하도록 하세요. 그 판단의 결과를 먼저 출력하고, 이후에 낼 카드를 출력하도록 하시면 되어요. 그러면 일단은 조금 더 나은 결과를 보여줄 겁니다.

사례 2.

챗봇 서비스에 사용될 프롬프트를 고치는 중이었습니다. 분명히 1줄로 응답을 출력하게 하는 시스템 프롬프트인데, Let's Think Step by Step이라는 출력이 노이즈로 나오고 있었습니다. 제대로 동작이 안되어서 찾아온 프롬프트를 보고나니, 1줄로 출력하라는 명령이 3번. Let's Think Step by Step라는 구문이 2번 등장하고 있었습니다. 원래 기대했던 성능은 달성하지 못하는 것은 물론이었습니다. 프롬프트를 수정할 시간이 되자, 망설임없이 Let's Think Step by Step를 모두 지우고, 1줄로 출력하라는 명령은 1번만 남겼습니다.
하나는 잘 작동한 사례,
하나는 잘 작동하지 않은 사례입니다.
무엇이 이 결과를 갈랐을까요?
이 이유를 알려면 Chain of Thought부터 이야기 해야합니다.

Chain of Thought

"자연어 처리 모델의 요청에 무언가를 넣어주면
학습을 하지 않은 내용도 마치 학습을 한 것 마냥 작동하더라."
지금은 너무 당연한, In-Context Learning입니다. 이를 이용해 '예제를 넣어주니 좋은 응답이 도출되는 경우가 많아졌더라'라는 게 알려진 이후, 초기 프롬프트 전략들의 발전은 In-Context Learning을 중심으로 쌓아올려져 왔습니다.
그 중 복잡한 추론을 하기 위한 연구도 있었습니다. 당시의 작은 모델들에서는 수리 추론 뿐만 아니라, 상식이나 상징 추론에서도 정확도 있는 추론을 위한 방법들이 필요했었습니다. 사람이 생각하고 사고하는 질의응답을 그대로 넣어서 이와 흡사하게 추론하고 프롬프트하는 방식이 제안되었습니다. 이것이 바로 Chain-of-Thought (CoT) 프롬프팅입니다.

CoT는 2022년 Google AI 연구진에 의해 처음 소개되었습니다. 이 방법의 핵심은 모델에게 단순히 답을 요구하는 것이 아니라, 그 답에 도달하기까지의 사고 과정을 단계별로 보여주도록 하는 것입니다.
처음 CoT에서는 프롬프트에 사고의 과정과 답을 구하는 과정을 모두 기록하도록 했습니다. 이런 방식으로 같은 형식과 같은 종류의 문제에서 유효한 특징을 연산에 반영하여, 알맞은 사고의 방향을 출력하게 합니다.
출력된 사고가 정확도에 영향을 미칠까요? 네, 적어도, 트랜스포머가 단어 하나, 토큰 하나를 예측하는 데에 있어서는 이전의 출력한 것도 영향을 주기에, 이러한 접근은 큰 효과를 거두었습니다. 스스로 사고과정을 출력하게 만들어서 출력 이후에 결정에 대해서 정확도를 높이는 CoT는 그렇게 초기 프롬프트 전략 중 가장 유력한 전략으로 자리잡았습니다.
. . .

생각을 말로 설명하기

그렇다면 CoT의 효과는 입증되었지만, CoT는 사용하기 좋은 전략이었을까요? 아쉽게도 아니었습니다.
CoT는 말 그대로 사고하는 패턴 그 자체를 적어넣는 전략이었습니다. 인간이 사고하는 패턴을 적어넣는 것은 가볍게 보이지만, 실제로는 어려운 일 중 하나입니다. CoT 프롬프트를 구현하기 위해서는 사람의 사고과정을 그대로 옮겨다가 담는 일을 했었어야 했습니다. 생각이 이어지고, 굴절하고, 결론을 내리기까지, 그것도 LLM이 잘 알아들을 수 있도록 섬세하게 적어야 완성할 수 있는 전략이었습니다.
누구든지 자신이 무의식적으로 익숙하게 하는 일들이 있을 겁니다. 자전거를 타거나, 타자를 치거나, 아니면 회사를 가기까지 총 얼마나 걸리는지 연산하고 추론하는 것들은, 우리는 그 과정이 익숙하기 때문에 금방 해낼 수 있습니다. 이것을 자연어로 설명해볼까요? 이 사고의 과정을 설명하기 위해서는 나의 행동을 제 3자의 관점으로 볼 수 있는 메타인지도 필요하고, 정확하게 대상을 설명할 수 있는 문장력도 필요합니다.
그리고 무엇보다, 입력에서 많은 글을 써야하기 때문에 작성하는 시간이나 처리하는 비용이 큰, 지금 돌아보면 그렇게 경제적이지 못한 방법 중 하나입니다. 물론 필요하다면 쓰겠지만요. 그렇지만, 비경제적인 방법이 더 경제적인 방법으로 전환될 수 있는 건 어떻게 보면 당연한 수순이었습니다.
. . .

모델이 알아서 사고하도록 한다면

지금에 와서 돌아보면 정말 당연하지만, 당시에는 일일이 적어주었던 사고과정의 기록 대신에 'Let's think step by step'이라는 한 마디로 도약할 수 있었던 것은 엄청난 용기에 가까웠습니다. 사고과정에 대해서 LLM이 스스로 잘 찾아가서 출력할 것이라는 어느정도의 믿음과 확신이 있어야, 그리고 일반화했을 때 유사한 효과를 거둘 것이라는 기대가 있어야 시도할 수 있는 아이디어였습니다. 개인적으로 그런 면에서 좋아하는 프롬프트 전략이기도 합니다.
"Let's think step by step"를 프롬프트에 넣는 것. 즉, Zeroshot-CoT를 통해 완벽히 CoT에 도달할 수는 없지만, 그와 근사한 효과를 얻는 것만으로도 답변의 질적 향상을 기대할 수 있었습니다. 물론 CoT처럼 사고과정을 출력하기 때문에 CoT 자체가 가지는 비용이라는 약점은 완전히 뗄 수는 없지만, 이제는 더 이상 일일이 사고과정을 적어내지 않아도 유사한 효과를 빠르게 얻을 수 있다는 장점이 있었죠.
마치 일종의 템플릿화된 문구 하나를 이용해서, CoT와 비슷한 효과를 거두었던 것은 당시에 GPT를 쓰던 사람들에게는 센세이션에 가까운 일이었습니다. 알아서 사고과정을 쭉 출력해주고, 이를 활용할 수 있는 것도 그렇지만, 그런 큰 리턴과는 달리 구현하기 쉬웠던 점이 그 이유였습니다.
이윽고 "Let's think step by step"라는 문구는 일종의 성문처럼 프롬프트에 새겨지기 시작했습니다.
. . .

입 막힌 채 말하기

다시 처음의 예로 돌아와서, 그렇다면 왜 두 번째 사례에서는 Zeroshot CoT가 동작하지 않았던 걸까요? Zeroshot CoT와 CoT는 모두 자유로운 출력이 보장되어야 효과가 나타나는 전략입니다. LLM이 자유롭게 출력할 수 있어야 사고의 과정을 자유롭게 서술할 수 있고, 그렇게 서술하고 출력한 사고의 과정이 있어야만 문제를 잘 풀어낼 수 있습니다.
그러면, CoT 계열 전략에 출력을 제한한다면 어떻게 될까요? 예를 들면 '~ 단어 이하로 서술해 줘' 내지는 '~ 줄 이하로 작성해'와 같은 느낌이죠. 출력 제한의 강도가 극단적으로 강해지거나, 상당히 짧게 출력하라고 하면 어떻게 반응할까요? 이렇게 되면, 프롬프트에서 완전히 상극인 두 명령이 존재하게 되는 것입니다. 추론은 출력의 제한을 지켜야할지, 아니면 스스로의 생각의 과정을 서술해야할 지 배반된 명령 사이에서 긴장감을 느낄 것입니다.
위와 같은 상황에서 최근 LLM들에서의 출력은 보통 출력 제한을 지키는 쪽으로 답변을 작성합니다. 그렇게 되면 프롬프트에는 노이즈가 남게 되는 것이지요. 아마도 사례 2에서는 저에게 프롬프트가 넘어오기 까지 풀고 싶었던 문제가 있었고, "Let's think step by step"을 붙여서 해결하고 싶어했을 것입니다.
프롬프트 전략은 의도와 적용이 있는데, 그것을 잘 이해하고 사용해야 적절하게 효과가 발휘가 되는데 그렇지 못한 꼴이 되는 것입니다. 사례 2는 단편적으로 그러한 예시이고요. 이는 마치 사람의 입을 막아놓고, 생각하는 것을 말하라고 하는 것과 동일합니다.
. . .
Zeroshot CoT는 분명 좋은 전략이고, 사용하기 쉽기 때문에 중요한 이정표가 되었습니다. LLM이 복잡한 추론 과정을 거쳐 답변을 도출할 수 있게 해주는 강력한 도구입니다. 그러나 우리가 살펴본 사례들에서 알 수 있듯이, 이러한 전략들은 올바르게 적용될 때만 그 효과를 발휘합니다.

프롬프트 전략을 사용할 때는 특성과 문제의 성격을 충분히 이해하고 있어야 합니다. "Let's think step by step"과 같은 지시어는 모델에게 충분한 사고 공간과 출력의 자유를 줄 때 가장 효과적입니다. 출력을 지나치게 제한하거나 상충되는 지시를 함께 주는 것은 오히려 역효과를 낼 수 있습니다.

향후 LLM이 발전함에 따라, 프롬프트 엔지니어링 기법도 더욱 정교해질 것입니다. 하지만, 우리가 프롬프트 하나를 적어 나갈 때에도, 그 정교함과 편리함 뒤에 숨어있는 의도와 적용, 그리고 목적에 따라 구현하지 않는다면 한낱 노이즈로 남을 뿐이죠.

여러분께서는 이 글에서 얻은 생각을 바탕으로, LLM 프롬프팅 경험을 되돌아보시기 바랍니다. 어떤 상황에서 프롬프트가 잘 작동했고, 어떤 경우에 기대한 결과를 얻지 못했나요? 그리고 그 이유는 무엇이었을까요?
Subscribe to 'Two-Jay_prompt_engineer'
Subscribe to my site to be the first to receive notifications and emails about the latest updates, including new posts.
Join Slashpage and subscribe to 'Two-Jay_prompt_engineer'!
Subscribe
👍🏻👍
2