Prompt Engineering
최근에 LLAMA 모델 공개를 기점으로 굉장히 다양한 LLM 들이 등장하고 있습니다. 이에 따라 기업은 사내 데이터를 파인튜닝하여 사용하거나, ChatGPT등을 활용하는 등의 니즈가 매우 증가하고 있는 추세입니다. 저 또한 이러한 시대에 빠르게 발 맞추며 Prompt Engineering 의 중요성을 알게 되었고 제대로 된 활용법을 정리해보고자 합니다.
또한 본 글은 DeepLearning.AI <ChatGPT Prompt Engineering for Developers> short course 의 실습자료를 활용한 글임을 알립니다. 누구나 무료로 들을 수 있으니 아래 링크 참고 부탁드립니다. :)
https://www.deeplearning.ai/short-courses/chatgpt-prompt-engineering-for-developers/
ChatGPT Prompt Engineering for Developers
What you’ll learn in this course In ChatGPT Prompt Engineering for Developers, you will learn how to use a large language model (LLM) to quickly build new and powerful applications. Using the OpenAI API, you’ll...
www.deeplearning.ai
Prompt Engineering 이란, LLM을 통해 사용자가 원하는 답을 정확히 얻기 위해 LLM에 던지는 질문(Prompt)에 적절한 원칙과 추가 설명 등을 적용하는 모든 과정들을 의미합니다. 성능에 도움이 될만한 이러한 추가 요소들을 했을 때와, 하지 않았을 때의 답변 수준을 살펴보면 그 중요성을 깨달을 수 있습니다.
Prompting Principles (프롬프트 작성 원칙)
1. 깔끔하고 명확한 Instruction 을 작성하라. (Write clear and specific instructions.)
2. 모델에 "생각"할 시간을 주어라. (Give the model time to "think".)
프롬프트 작성 시 기본적으로 지켜야 할 원칙이 있으며, 이 원칙 두가지를 전제로 하여 적절한 프롬프트를 생성해야 합니다. 위 두가지 원칙이 무엇을 의미하는지, 예제를 보며 살펴보겠습니다.
1️⃣ 깔끔하고 명확한 프롬프트를 작성하기 위한 4가지 기법
첫번째 원칙이었던 깔끔하고 명확한 프롬프트를 작성하기 위한 방법으로 총 4가지를 소개합니다.
1. Use delimiters to clearly indicate distinct parts of the input
(구분기호를 사용하여 Input 을 명확히 표시하라.)
text = f"""
You should express what you want a model to do by \
providing instructions that are as clear and \
specific as you can possibly make them. \
This will guide the model towards the desired output, \
and reduce the chances of receiving irrelevant \
or incorrect responses. Don't confuse writing a \
clear prompt with writing a short prompt. \
In many cases, longer prompts provide more clarity \
and context for the model, which can lead to \
more detailed and relevant outputs.
"""
prompt = f"""
Summarize the text delimited by triple backticks \
into a single sentence.
```{text}```
"""
response = get_completion(prompt)
print(response)
바로, 구분자를 사용하여 Input을 구분하는 방법입니다. 위 예시에서는 ''' (텍스트) ''' 을 사용했고, 작은따옴표 세쌍 안에 들어간 text를 Input이라고 구분지어 주는 것입니다. 이렇게 하면 훨씬 명확한 프롬프트가 되겠죠.
구분자는 ''' 뿐 아니라, """, <>, <tag> </tag>, : 등 모두 가능합니다. Input을 명시하거나 출력 포맷을 지정해줄 때 활용 가능 한 것입니다.
2. Ask for a structured output
(구조화된 출력을 요청하라.)
prompt = f"""
Generate a list of three made-up book titles along \
with their authors and genres.
Provide them in JSON format with the following keys:
book_id, title, author, genre.
"""
response = get_completion(prompt)
print(response)
두번째로는, 출력 형식을 지정해주는 것입니다. 위 예시에서는 JSON 형식으로 출력을 부탁했고, 그때의 key들 까지 명시해주었습니다. Json 형식 말고도 HTML, XML 등 원하는 사용자의 형식이 있다면 명시하여 더 정확한 답변을 얻어낼 수 있을 것입니다.
3. Ask the model to check whether conditions are satisfied
(모델에게 조건충족 여부를 확인하도록 해라.)
text_1 = f"""
Making a cup of tea is easy! First, you need to get some \
water boiling. While that's happening, \
grab a cup and put a tea bag in it. Once the water is \
hot enough, just pour it over the tea bag. \
Let it sit for a bit so the tea can steep. After a \
few minutes, take out the tea bag. If you \
like, you can add some sugar or milk to taste. \
And that's it! You've got yourself a delicious \
cup of tea to enjoy.
"""
prompt = f"""
You will be provided with text delimited by triple quotes.
If it contains a sequence of instructions, \
re-write those instructions in the following format:
Step 1 - ...
Step 2 - …
…
Step N - …
If the text does not contain a sequence of instructions, \
then simply write \"No steps provided.\"
\"\"\"{text_1}\"\"\"
"""
response = get_completion(prompt)
print("Completion for Text 1:")
print(response)
다음은 조건 충족 여부를 확인하는 것입니다. 위 예시에서는 차를 만드는 과정을 Input으로 넣어주었고, 그 과정을 "Step 1- ... , Step 2- ... " 라는 형식에 맞춰 출력해달라는 요구를 하였습니다. 사용자에게 어떠한 원하는 출력 형식이 있다면, 앞서 배웠던 것처럼 출력 포맷을 언급해줄 수 있었죠.
💥이 예시에서 중요한 것은 따로 있습니다. 프롬프트 가장 아랫줄에 보면, 만약 주어진 Instruction에 어떠한 과정이 포함되어있지 않다면, 그냥 "No steps provided"를 출력하라는 문구를 추가하였습니다. 우리는 생성 AI이기 때문에 이러한 일종의 경고 문구 등을 포함 하지 않으면, 어떻게든 요청에 맞는 답을 내놓기 위해 허위 사실을 만드는 경우가 있습니다. 따라서 사용자의 Instruction은 주어진 Input에서 일의 순서를 파악해 나열해달라는 것이지만, 실제로 일의 순서가 포함되어 있지 않은 문서가 주어졌다면, 챗봇은 이를 일의 순서를 파악할 수 없음을 깨달아야 할 것입니다.
text_2 = f"""
The sun is shining brightly today, and the birds are \
singing. It's a beautiful day to go for a \
walk in the park. The flowers are blooming, and the \
trees are swaying gently in the breeze. People \
are out and about, enjoying the lovely weather. \
Some are having picnics, while others are playing \
games or simply relaxing on the grass. It's a \
perfect day to spend time outdoors and appreciate the \
beauty of nature.
"""
prompt = f"""
You will be provided with text delimited by triple quotes.
If it contains a sequence of instructions, \
re-write those instructions in the following format:
Step 1 - ...
Step 2 - …
…
Step N - …
If the text does not contain a sequence of instructions, \
then simply write \"No steps provided.\"
\"\"\"{text_2}\"\"\"
"""
response = get_completion(prompt)
print("Completion for Text 2:")
print(response)
이 예시를 볼까요? 앞에서 본 차를 만드는 과정을 담은 문서와는 달리, 단순히 오늘의 날씨와 현재 상황에 대한 이야기만 늘어놓고 있습니다. 이 Input에 대해 일의 순서를 출력하라는 질문을 했을 때는 일의 순서가 없다고 판단할 줄 알도록 해야 겠죠. 그래서 가장 아래 적었던 If 문을 통해 조건에 충족하지 않음을 확인할 수 있는 것입니다.
4. "Few-shot" prompting
prompt = f"""
Your task is to answer in a consistent style.
<child>: Teach me about patience.
<grandparent>: The river that carves the deepest \
valley flows from a modest spring; the \
grandest symphony originates from a single note; \
the most intricate tapestry begins with a solitary thread.
<child>: Teach me about resilience.
"""
response = get_completion(prompt)
print(response)
다음은 말그대로 Few-shot을 하는 겁니다. Few-shot의 개념은 적은 데이터만을 가지고 정확한 출력을 낼 수 있도록 하는 것인데, 아마 예제를 보면 더 잘 이해가 될 것입니다.
프롬프트를 보면, 일관된 스타일로 답변을 하라는 문구로 시작합니다. 그리고 아래에 답변 예시를 제공해주고 있습니다. Child 와 grandparent의 대화로 보이며, 마지막에 child의 말에 대한 답변을 grandparent 의 스타일로 답변해달라는 의미입니다. 위에서 한번 예시를 들었으니, 그 스타일을 학습하여 일관된 스타일로 답변하라는 것입니다.
2️⃣ 모델에 생각할 시간을 주기 위한 2가지 기법
다음은 두번째 원칙이었던 모델에 생각할 시간을 주기 위한 기법을 소개합니다. 생각할 시간을 주자는 것이 어떤 의미인지 감이 잘 안올 수 있으나 예제를 보면 이해가 쉬울 것입니다. 간단히 말하면, 모델이 깊이 고민없이 답변을 툭툭던지는 것을 방지 하기 위해 일련의 생각하는 "과정"을 제시하고, 그 순서대로 모델이 생각하도록 하면 더 높은 정확도의 답변을 얻어낼 수 있다는 개념입니다.
1. Specify the steps required to complete a task
(일을 처리하는데 필요한 단계를 지정해라.)
text = f"""
In a charming village, siblings Jack and Jill set out on \
a quest to fetch water from a hilltop \
well. As they climbed, singing joyfully, misfortune \
struck—Jack tripped on a stone and tumbled \
down the hill, with Jill following suit. \
Though slightly battered, the pair returned home to \
comforting embraces. Despite the mishap, \
their adventurous spirits remained undimmed, and they \
continued exploring with delight.
"""
# example 1
prompt_1 = f"""
Perform the following actions:
1 - Summarize the following text delimited by triple \
backticks with 1 sentence.
2 - Translate the summary into French.
3 - List each name in the French summary.
4 - Output a json object that contains the following \
keys: french_summary, num_names.
Separate your answers with line breaks.
Text:
```{text}```
"""
response = get_completion(prompt_1)
print("Completion for prompt 1:")
print(response)
이 것은 말 그대로 모델이 일을 처리하는데 있어 적절한 과정을 제시하라는 것입니다. 단순한 텍스트로 일을 부여하는 것보다, 태스크를 하위 단계로 쪼개어 제시하면 모델은 올바른 순서로, 사용자가 원하는 응답을 더 정확하게 답변할 수 있습니다.
prompt_2 = f"""
Your task is to perform the following actions:
1 - Summarize the following text delimited by
<> with 1 sentence.
2 - Translate the summary into French.
3 - List each name in the French summary.
4 - Output a json object that contains the
following keys: french_summary, num_names.
Use the following format:
Text: <text to summarize>
Summary: <summary>
Translation: <summary translation>
Names: <list of names in Italian summary>
Output JSON: <json with summary and num_names>
Text: <{text}>
"""
response = get_completion(prompt_2)
print("\nCompletion for prompt 2:")
print(response)
🔎 더불어, 위와 같이 출력 포맷을 지정할 수도 있습니다. 여기에선 좀 더 깔끔한 출력을 위해 구분자 : 를 활용하여 출력을 정리하도록 하였네요.
2. Instruct the model to work out its own solution before rushing to a conclusion
(성급한 결론을 내리지 않도록 자체 솔루션을 해결하도록 지시해라.)
이번 예제에서는 두가지의 프롬프트 예시를 보겠습니다.
- 첫번째 예시
prompt = f"""
Determine if the student's solution is correct or not.
Question:
I'm building a solar power installation and I need \
help working out the financials.
- Land costs $100 / square foot
- I can buy solar panels for $250 / square foot
- I negotiated a contract for maintenance that will cost \
me a flat $100k per year, and an additional $10 / square \
foot
What is the total cost for the first year of operations
as a function of the number of square feet.
Student's Solution:
Let x be the size of the installation in square feet.
Costs:
1. Land cost: 100x
2. Solar panel cost: 250x
3. Maintenance cost: 100,000 + 100x
Total cost: 100x + 250x + 100,000 + 100x = 450x + 100,000
"""
response = get_completion(prompt)
print(response)
- 두번째 예시
prompt = f"""
Your task is to determine if the student's solution \
is correct or not.
To solve the problem do the following:
- First, work out your own solution to the problem.
- Then compare your solution to the student's solution \
and evaluate if the student's solution is correct or not.
Don't decide if the student's solution is correct until
you have done the problem yourself.
Use the following format:
Question:
```
question here
```
Student's solution:
```
student's solution here
```
Actual solution:
```
steps to work out the solution and your solution here
```
Is the student's solution the same as actual solution \
just calculated:
```
yes or no
```
Student grade:
```
correct or incorrect
```
Question:
```
I'm building a solar power installation and I need help \
working out the financials.
- Land costs $100 / square foot
- I can buy solar panels for $250 / square foot
- I negotiated a contract for maintenance that will cost \
me a flat $100k per year, and an additional $10 / square \
foot
What is the total cost for the first year of operations \
as a function of the number of square feet.
```
Student's solution:
```
Let x be the size of the installation in square feet.
Costs:
1. Land cost: 100x
2. Solar panel cost: 250x
3. Maintenance cost: 100,000 + 100x
Total cost: 100x + 250x + 100,000 + 100x = 450x + 100,000
```
Actual solution:
"""
response = get_completion(prompt)
print(response)
프롬프트를 유심히 살펴보면, question은 동일하지만 첫번째 예시에서는 풀이가 옳다라고, 두번째 예시에서는 풀이가 틀렸다라고 답변하고 있습니다. 두 예시의 차이는 해당 문제를 해결하기 위한 방법 제시 유무에 있습니다.
첫번째 예시에서는 단순히
"Determine if the student's solution is correct or not. (학생의 문제풀이가 맞았는지 틀렸는지를 판단하라.) " 라는 한줄의 프롬프트만 주어졌으나,
두번재 예시에서는 무려
1. 문제 해결을 위한 모델만의 문제풀이
2. 모델의 문제풀이와 학생의 문제풀이를 비교
3. 이를 기반으로 학생의 문제풀이의 정오답 여부 파악
을 하도록 제시하고, 마지막으로 학생의 문제풀이가 올바른지 결정하기 전까지 섣부른 판단을 하지말라고 당부까지 합니다.
이렇게 했더니 모델은 첫번째 예시와 확연히 비교되는 올바르고 정확한 답변을 도출하였습니다.
이렇게 예시를 살펴보니, 모델에 생각할 시간을 준다는 것의 의미는 모델에게 좀 더 세부적인 태스크를 제시하고, 모델이 올바른 방향으로 생각하고 판단할 수 있는 설명서를 제시하는 느낌에 가깝다고 볼 수 있을 듯 합니다.
이렇게 LLM의 발전에 대응하여, 프롬프트 데이터 엔지니어링 기법들을 살펴보았습니다. 본 글에서는 원칙 두가지를 기반으로 꼭 유념해야할 기법들에 대해 알아보았고, 다음 글에서는 활용측면에서 어떤 다양한 상황에서 활용할 수 있을 지 살펴보겠습니다.
다음글 - 응용편 : (작성중)
끝으로, Prompt Engineering을 연구하며 참고하면 좋을 문서들을 공유드립니다. :)
https://platform.openai.com/docs/guides/gpt-best-practices/six-strategies-for-getting-better-results
OpenAI API
Explore developer resources, tutorials, API docs, and dynamic examples to get the most out of OpenAI's platform.
platform.openai.com
https://python.langchain.com/docs/modules/chains/
Chains | 🦜️🔗 Langchain
Using an LLM in isolation is fine for simple applications,
python.langchain.com
'AI' 카테고리의 다른 글
GPT-3.5 기반 한국어 Knowledge Graph 구축 (GraphGPT, Networkx) (2) | 2023.08.15 |
---|---|
사용자 PDF 기반 In-context Learning을 통한 ChatGPT 질의응답 챗봇 구현하기 (feat. LangChain, VectorDB) (0) | 2023.06.19 |
Matrix Factorization : 개요와 원리부터, 최적화(SGD, ALS)까지 이해하기 (0) | 2023.06.01 |
FM(Factorization Machines)을 활용한 학생별 문항 맞힐확률 예측하기 (0) | 2023.02.26 |
시간에 따른 숙련도를 모델링한, DKT(Deep Knowledge Tracing) - 논문정리 및 코드(Pytorch) (0) | 2022.12.30 |