Prompt Engineering: ChatGPT와 대화하기 1편

2024. 3. 9. 02:36Development

안녕하세요, 오늘은 ChatGPT 같은 LLM을 사용할 때 알면 좋은 내용인 프롬프트 공학(Prompt Enginnering)에 대해 다뤄보려고 해요.

 

ChatGPT를 사용할 때, "Message ChatGPT..."에 물어보고 싶은 말들을 열심히 쓰죠?

여기에 작성하는 말을 프롬프트(Prompt)라고 해요.

 

정확히 Prompt는 LLM 같은 모델을 사용할 때, 출력을 생성하기 위해 작성하는 텍스트예요.

LLM은 우리가 작성한 Prompt의 의도와 지시를 이해하고, 확률적으로 가장 그럴듯한 답변을 만들어내게 되죠.

 

우리 인간의 뇌와 LLM은 비슷하면서도 다른데, 우리는 의도를 정확히 이해하고 추론하여 말을 하죠?

LLM은 내부 복잡한 신경망을 거쳐 확률적으로 가장 그럴듯한 답을 내는 거예요.

따라서 LLM은 기본적으로 확률적으로 가장 그럴듯한 답을 선택하고 그것이 옳다고 생각하고 말을 해요.

 

우리의 의도한 답변과 LLM이 만들어낸 답변이 달라고 LLM은 자신이 옳다고 주장하면서 말하기도 해요.

이 현상을 환각(Hallucination)이라고 해요.

 

이 현상을 줄이기 위해 모델의 성능을 개선시켜 의도에 맞는 답변을 만들어 환각 현상을 줄이려는 노력이 많이 일어나고 있어요.

하지만 우리 사용자 입장에서는 모델의 성능 자체를 개선시키기는 쉽지 않죠.

 

그래서 우리 사용자가 고려해볼 수 있는 것이 프롬프트 공학이에요.

간단하게 말하면 프롬프트 공학은 LLM과 "잘" 대화할 수 있도록 하는 방법론을 제공해요.

 

어떻게 하면 LLM이 우리의 의도를 더 잘 알아챌 수 있는지, 우리가 의도한 답변을 만들어낼 수 있는지 연구하는 분아예요.

 

사실 코딩 보다는 글을 어떻게 잘 써야하는지 생각해야 하기 때문에 인문학과 더 관련있다고 생각해요.

따라서 프로그래머 뿐만 아니라, ChatGPT 같은 LLM을 사용하는 대학생, 직장인 등 많은 사람들이 이 글을 읽어보면 반드시 도움이 될 거예요.


이 글은 GPT 모델을 만든 OpenAI 사의 프롬프트 공학 가이드를 참고했어요.

https://platform.openai.com/docs/guides/prompt-engineering

 

1. 지시문을 명확하게 작성하라 - Write clear instructions

2. 참고할 수 있는 자료를 제공하라 - Provide Reference Text

3. 간단한 작업으로 나누어 진행하라 - Split complex tasks into simpler subtasks

4. 모델에게 생각할 시간을 주어라 - Give model time to think

5. 외부 도구를 활용하라 - Use External Tools

 

이 글에서 제가 사용한 모델은 모두 GPT-3.5와 GPT-4를 섞어서 사용했어요.


1. 지시문을 명확하게 작성하라 - Write clear instructions

프롬프트를 작성할 때는 최대한 구체적으로 작성하는 것이 좋아요.

본인이 현재 어떤 상황에 쳐해있고, 어떤 문제를 해결해야 하고, 등등 자세한 상황을 묘사 할수록 LLM은 더 잘 이해해요.

LLM은 전문 용어도 이해할 수 있으니, 본인의 의도를 전문 용어를 사용해 설명하는 것도 아주 좋은 방법이에요.

 

1 - 1. 더 좋은 답을 얻기 위해 무조건 자세하게! - Include details in your query to get more relevant answers

당신은 학생들의 성적 데이터로 통계를 내는 일을 맡았어요.

두 과목(수학, 영어)에 대한 학생들의 평균을 내야 하는데, 엑셀 함수를 까먹은 거예요.

이럴땐 역시 GPT에게 물어봐야겠죠?

 

 

 

물론 이 답도 나쁘진 않아요. 하지만 LLM은 우리가 어떤 작업을 처리해야 하는지 정확히 모르기 때문에 AVERAGE 함수, AVERAGEIF 함수 등 여러 가지 함수를 소개해주고 있죠? 그래서 우린 다시 이 글을 읽어보고 어떻게 처리해야 할지 판단해야 해요.

 

GPT를 이렇게 사용하는 것은 LLM의 장점을 최대한으로 활용하지 못 한 예입니다.

 

우리가 어떤 상황인지 최대한 자세하게, "이렇게까지 쓴다고..?" 라는 생각이 들 정도로 작성해주면 LLM은 우리 생각보다 더 간결하고 깔끔한 답을 줄 거예요. 아래는 제가 작성한 프롬프트에요.

 

제가 작성한 프롬프트를 분석해볼게요.

 

1. 제가 어떤 데이터를 다루고 있고, 어떤 작업을 해야 하는지 정확하게 명시해주었어요.

2. 데이터의 구조에 대해 정확하게 정의해줬어요. 첫 번째 행은 필드 이름을 담고 있다고도 말해줬어요.

3. LLM이 해야 할 작업에 대해 정확하게 정의해주었고, 결과가 어떤 형식으로 나와야 하는지도 명확하게 알려주었어요.

 

 

이 정도면 무지성 복붙을 해도 괜찮을 만큼 정확하게 나왔죠?

 

우선 우리의 상황을 알기 때문에 AVERAGEIF 함수를 정확하게 추천해줬네요.

그리고 첫 번째 행이 필드라는 것과 데이터의 개수가 100개라는 것을 정확히 알려주었기 때문에 C2:C101로 필드를 제외한 모든 자료의 평균을 계산하는 함수 식을 정확하게 작성해주었어요.

 

이를 정확히 명시하지 않았으면 필드를 제외하고, 데이터의 최대 범위를 지정하고, 상당히 귀찮았을 거예요.

하지만 자세하게 명시했기 때문에 LLM이 알아서 처리해주었어요. 너무나 편리하죠?

 

GPT가 알려준 수식을 그대로 붙여 넣었더니 정확히 평균을 계산해주었네요!


1 - 2. 모델에게 역할을 부여해보자! - Ask the model to adopt a persona

모델에게 "너는 ~를 하는 봇이야."라고 역할을 부여하고 질문하면 이해를 더 잘한다고 해요.

특히 같은 프롬프트로 반복 작업을 해야 한다면 역할을 부여한 뒤 이용하면 돼요.

 

 

저는 GPT에게 번역기라는 역할을 부여해보았어요.

 

그랬더니 별다른 지시문 없이도 본인이 번역기라는 역할을 알고 있기 때문에 모든 문장을 번역해주는 것을 알 수 있죠?


1 - 3. 구분자를 사용하여 프롬프트를 구성해보자 -Use delimiters to clearly indicate distinct parts of the input

프롬프트 내부에 LLM이 명확히 구분하여 처리해야 하는 입력이 있으면 구분자를 사용해서 구분해주는 것도 좋은 방법이에요.

구분자는 무엇을 쓰든지 상관 없지만, 어떤 구분자를 사용하는지는 LLM에게 알려주어야겠죠?

 

저는 세 개의 기사의 카테고리를 구분하는 프롬프트를 작성해보았어요. 각 기사는 큰 따옴표 세 개로 분리되어 있다고 명시해주었어요.

큰 따옴표가 없으면 각 기사에 대한 구분이 어렵겠죠?

 

LLM도 기사들이 따옴표 세 개로 분리되어 있다는 것을 이해하고, 첫 번째, 두 번째, 세 번째 기사와 같이 번호를 붙여 설명해준 것을 알 수 있죠?

지금은 간단한 예시이지만 복잡한 프롬프트를 작성하게 되면 구분자를 설정해주는 것은 반드시 필요한 과정이에요.


1 - 4. 작업을 단계적으로 처리하자 - Specify the steps required to complete a task

 

제가 서두에 작성한 글을 요약하고 보충 설명을 해달라고 했어요.

 

그냥 저냥 나쁘진 않은데, 단계적으로 작업을 지시하면 LLM의 답변을 조금 더 세부적으로 컨트롤 할 수 있어요.

 

제 본문을 요약하고, 각 요약 내용에 대해 부연 설명을 해달라고 했어요.

LLM의 결과는 제가 어떻게 작성하냐에 따라 달려있어요.

 

복잡하거나 설명하기 어려운 일은 작은 단계로 나누어 설명하면 LLM이 더 쉽게 이해할 수 있고 우리도 더 쉽게 설명할 수 있갰죠?


1 - 5. 예시를 제공해주자 - Provide examples

예시를 제공하는 것은 LLM 활용에 있어서 매우 필수적인 부분입니다.

 

왜 예시를 제공하는 것이 LLM 답변 생성에 도움이 되는지 알아보겠습니다.

예시는 제가 개발 중인 사이트 달맹저지의 문제를 예시로 들어보겠습니다.

 

Q57. 상자 안의 공 - 달맹저지

문제 상자가 아래와 같이 일렬로 길게 놓여있고, 상자 안에는 수가 적힌 공이 하나 들어있습니다.상자 안에 공을 추가로 넣어서 모든 상자의 상자 내 공에 적힌 수의 총합을 같게 만들려고 합니

dalmengjudge.com

 

 

이 예시는 추론 능력을 많이 요구하기 때문에 GPT-4 모델을 사용했습니다.

달맹저지의 문제 [상자 안의 공]을 아주 짧게 요약해서 GPT-4 모델에게 풀어보라고 했습니다.

 

뭔가 야심차게 추론을 하더니 아래 코드를 내어줬습니다.

# 초기 상태
boxes = [2, 2, 2, 1, 2]

# 모든 상자의 공 숫자 합을 같게 만들기 위해 필요한 추가 공의 개수 계산
# 이를 위해 최대 공 숫자 합을 갖는 상자를 찾아, 다른 상자들이 이 합에 도달하도록 필요한 공의 개수를 계산

# 최대 공 숫자 합 찾기
target_sum = max(boxes)

# 필요한 추가 공의 개수 계산
additional_balls_needed = sum(target_sum - box for box in boxes)

additional_balls_needed

 

대충 이런 코드를 줬는데, 실행해보니 문제에 제시된 테스트케이스조차 통과하지 못 해 제출할 가치도 없을 것 같네요.

 

아무리 추론 능력이 뛰어난 GPT-4 모델이라도 복잡한 문제에 대해 정확한 솔루션을 내기는 어려워 보입니다.

그래서 예시와 힌트를 주고 GPT 모델에게 다시 풀도록 시켰습니다.

 

from math import gcd
from functools import reduce

def lcm(x, y):
    """Calculate the Least Common Multiple of two numbers."""
    return x * y // gcd(x, y)

def lcm_for_list(numbers):
    """Calculate the LCM for a list of numbers."""
    return reduce(lambda a, b: lcm(a, b), numbers)

def minimum_balls_needed(numbers):
    """Calculate the minimum number of additional balls needed to achieve the goal."""
    # Calculate the LCM of the numbers in the array
    target_lcm = lcm_for_list(numbers)
    
    # Calculate the additional balls needed for each box to reach the LCM
    additional_balls = [target_lcm // num - 1 for num in numbers]
    
    # Calculate the total additional balls needed
    total_additional_balls = sum(additional_balls)
    return total_additional_balls

# Test the function with the given example
test_numbers = [3, 2, 4, 3, 2]
minimum_balls_needed(test_numbers)

 

이번에도 뭔가 야심차게 추론을 해서 저한테 코드를 줬네요.

직접 제출해보겠습니다.

 

표준 입출력 부분만 수정해서 제출했더니 바로 문제를 맞혀버리는 GPT-4 모델입니다.

예시 하나와 힌트 한 줄 만 추가로 줬을 뿐인데 추론 능력이 급상승해버렸죠.

 

이런 방식으로 예시를 제공해서 프롬프트를 작성하는 것을 Few-shot Prompting이라고 합니다.

복잡한 태스크의 경우에는 예시를 꼭 제공해주는 것이 LLM의 성능에 큰 도움을 줍니다.


1 - 6. 원하는 결과의 분량를 말해주자- Specify the desired length of the output

세 문장으로 말해줘.

한 문단으로 말해줘.

와 같은 분량을 제한하는 지시를 사용하면 모델이 안정적으로 결과를 만들어낼 수 있다고 합니다.

 

모델의 정확성과 직결되는 요소는 아니라고 하지만, 사용자 입장에서 원하는 분량의 결과를 만들 수 있고, 모델 입장에서도 안정적으로 결과를 만들어 낼 수 있다고 하니 필요하면 사용해도 좋겠네요.

 

특히 요약 같은 작업은 목적에 맞게 분량을 조절하면 더 좋은 결과를 얻을 수 있으니 간단하지만 활용하기 좋은 방법입니다.

 

참고로 보통 모델 API는 프롬프트의 길이와 결과의 길이(정확히는 토큰의 개수)로 돈을 받기 때문에 너무 길게 프롬프트를 작성하거나 길게 답변을 요청하면 돈을 더 내야 할 수 있으니 주의하세요.


오늘은 LLM의 더 좋은 결과를 위해 명확한 지시문을 작성하는 방법에 대해 다뤄봤어요.

모델의 성능도 중요하지만, 프롬프트를 잘 작성하는 능력은 모델과 상관없이 매우 중요하기 때문에 익혀두는 것이 좋아요.

 

그리고 프롬프트를 작성하려고 하면 생각보다 잘 안 돼요. 그래서 이 글을 보고 "이런 방법이 있구나!" 에서 멈추지 말고, 직접 프롬프트를 작성해보면서 LLM과 친해져 보는 시간을 가져보는 것을 권장해요.

 

ChatGPT는 남녀노소, 나이불문 전 세계 사람들이 사용하는 혁신적인 서비스예요.

하지만 사용하는 방법에 따라 "생각보다 별론데..?" 라고 생각하거나 "이거 완전 혁신이잖아?" 라고 생각할 수도 있어요.



LLM은 확실히 혁신이 맞으니, ChatGPT를 자주 사용하는 사람이라면 이 글을 보시고 모두 최고로 활용할 수 있게 되길 바라요.


제 글이 많은 도움이 되었길 바라며,
긴 글 봐주셔서 감사합니다!
멋진 개발자가 되기 위해 더 열심히 달리겠습니다!
- 달맹 -