비트를 쪼개는 개발자

allen321@naver.com

프롬프트 엔지니어링

[프롬프트 엔지니어링] - 프롬프트 기획과 제작

MozarTnT 2024. 11. 8. 17:50
728x90
반응형

 

Designed by Freepik

 

 

 

지난 글에서는 프롬프트란 AI에게 질문을 전달하기 위한 입력 텍스트를 의미하고 고도화된 프롬프트 LLM을 더욱 효과적으로 사용할 수 있게 도와준다고 정리했었다.

 

그렇다면 이번 포스트에서는 좋은 프롬프트를 만들기 위해서는 어떠한 방법을 거쳐야 하는지, 어떤 원리로 프롬프트를 만들어야 하는지 알아보도록 하자.

 

 

 

ChatGPT를 개발한 'Open AI'사에서는 프롬프트를 만들때 다음과 같은 지침을 권장한다.

 

 

 

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

from openai import OpenAI

client = OpenAI()

META_PROMPT = """
Given a task description or existing prompt, produce a detailed system prompt to guide a language model in completing the task effectively.

# Guidelines

- Understand the Task: Grasp the main objective, goals, requirements, constraints, and expected output.
- Minimal Changes: If an existing prompt is provided, improve it only if it's simple. For complex prompts, enhance clarity and add missing elements without altering the original structure.
- Reasoning Before Conclusions**: Encourage reasoning steps before any conclusions are reached. ATTENTION! If the user provides examples where the reasoning happens afterward, REVERSE the order! NEVER START EXAMPLES WITH CONCLUSIONS!
    - Reasoning Order: Call out reasoning portions of the prompt and conclusion parts (specific fields by name). For each, determine the ORDER in which this is done, and whether it needs to be reversed.
    - Conclusion, classifications, or results should ALWAYS appear last.
- Examples: Include high-quality examples if helpful, using placeholders [in brackets] for complex elements.
   - What kinds of examples may need to be included, how many, and whether they are complex enough to benefit from placeholders.
- Clarity and Conciseness: Use clear, specific language. Avoid unnecessary instructions or bland statements.
- Formatting: Use markdown features for readability. DO NOT USE ``` CODE BLOCKS UNLESS SPECIFICALLY REQUESTED.
- Preserve User Content: If the input task or prompt includes extensive guidelines or examples, preserve them entirely, or as closely as possible. If they are vague, consider breaking down into sub-steps. Keep any details, guidelines, examples, variables, or placeholders provided by the user.
- Constants: DO include constants in the prompt, as they are not susceptible to prompt injection. Such as guides, rubrics, and examples.
- Output Format: Explicitly the most appropriate output format, in detail. This should include length and syntax (e.g. short sentence, paragraph, JSON, etc.)
    - For tasks outputting well-defined or structured data (classification, JSON, etc.) bias toward outputting a JSON.
    - JSON should never be wrapped in code blocks (```) unless explicitly requested.

The final prompt you output should adhere to the following structure below. Do not include any additional commentary, only output the completed system prompt. SPECIFICALLY, do not include any additional messages at the start or end of the prompt. (e.g. no "---")

[Concise instruction describing the task - this should be the first line in the prompt, no section header]

[Additional details as needed.]

[Optional sections with headings or bullet points for detailed steps.]

# Steps [optional]

[optional: a detailed breakdown of the steps necessary to accomplish the task]

# Output Format

[Specifically call out how the output should be formatted, be it response length, structure e.g. JSON, markdown, etc]

# Examples [optional]

[Optional: 1-3 well-defined examples with placeholders if necessary. Clearly mark where examples start and end, and what the input and output are. User placeholders as necessary.]
[If the examples are shorter than what a realistic example is expected to be, make a reference with () explaining how real examples should be longer / shorter / different. AND USE PLACEHOLDERS! ]

# Notes [optional]

[optional: edge cases, details, and an area to call or repeat out specific important considerations]
""".strip()

def generate_prompt(task_or_prompt: str):
    completion = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": META_PROMPT,
            },
            {
                "role": "user",
                "content": "Task, Goal, or Current Prompt:\n" + task_or_prompt,
            },
        ],
    )

    return completion.choices[0].message.content

 

 

 

상당히 긴 지침이지만 하나씩 중요한 부분을 요약해보자면 다음과 같은 내용을 가지고 있다.

 

 

 

#Guidelines

 

  1. Understand the Task: 작업의 주요 목표와 요구사항을 이해하고 설명하라는 지침이다.
  2. Minimal Changes: 주어진 프롬프트가 간단한 경우 최소한의 변경을 가하고, 복잡한 경우에는 더 명확하게 수정하라는 지침이다.
  3. Reasoning Before Conclusions: 언어 모델이 결론에 도달하기 전에 먼저 논리를 펼치도록 유도한다. 즉 LLM이 스스로  '단계별 사고'를 할 것을 강조하는 접근법이다.
  4. Examples: 예시를 제공하는 방법에 대한 지침으로, 필요에 따라 복잡한 요소를 대괄호 [ ]로 표현하는 것을 추천한다.
  5. Clarity and Conciseness: 명확하고 간결한 단어와 문장을 사용하라는 지침이다. 불필요한 지시 사항을 피하고, 핵심적인 내용만을 전달하도록 권장한다. 
  6. Formatting: 가독성을 위해 마크다운 형식을 사용할 것을 권장하며, 코드 블록(```)은 특별한 경우에만 사용하도록 주의한다.
  7. Preserve User Content: 사용자가 제공한 내용(예: 예제, 지침 등)을 최대한 그대로 지키도록 해야하며, 내용이 모호할 경우 해당 부분을 하위 단계로 나눠서 사고하도록 한다. 
  8. Constants: 모델 응답의 일관성을 위해 일정한 값들(가이드, 기준 등)은 프롬프트에 포함하라는 지침이다.
  9. Output Format: 결과 형식에 대한 명확한 지침을 제공하는 항목이다. 만약 JSON 같은 형식이 필요한 경우 JSON 형식을 사용하도록 한다.

 

 

#Prompt Structure

 

1. Concise Instruction

  • 작업을 간략히 설명하는 한 줄 요약으로 프롬프트를 시작하며, 별도의 헤더 없이 바로 작성한다.

2. Additional Details

  • 작업을 이해하는데 추가 정보가 필요한 경우 간단하게 여기에 덧붙인다.

3. Detailed Steps (Optional)

  • 작업을 단계별로 수행해야 할 때, 섹션별 제목이나 글머리 기호로 단계별 작업을 유도한다.

4. Steps (Optional)

  • 구체적인 작업 절차가 필요하다면 세부적으로 나누어서 지시한다.

5. Output Format

  • 출력 형식을 지정해, 응답의 길이, 구조와 포맷을 명시한다.(ex. JSON, 마크다운)

6. Examples (Optional)

  • 예시를 포함하여 지시하고, 복잡한 요소는 대괄호([ ])로 표기한다. 예시가 실제 응답과 다를 경우 주석을 추가해 알려준다.

7. Notes (Optional)

  • 특이 케이스나 유의할 사항을 강조하는 섹션으로, 작업 시 고려할 사항들을 여기에 적는다.

 

 

프롬프트를 만들때 질문에 대한 주제나 지시사항을 정했다면

 

이를 위한 답변을 명확하게 제공 받기 위해서는 프롬프트를 위에 나열된 사항들을 지켜서 만들면 좋은 프롬프트의 예시가 된다고 볼 수 있다.

 

 

 

물론 Open AI 외에도 많은 회사나 논문에서 효과적인 프롬프트를 제작하는 방법에 대해 다루고 있다.

 

회사 및 저자마다 추천하는 방식이나 우선 순위는 다르지만 대부분의 회사와 저자들이 프롬프트를 제작할때 Open AI가 제공한 위의 지침을 따르는 편이다.

 

 

 

 

 

프롬프트를 제작할때 언제나 모든 요소들을 모든 프롬프트에 적용하기는 어렵다. 

 

우리가 LLM을 사용할때 사용되는 비용을 토큰이라는 단위를 사용하여 계산하는데 토큰 비용프롬프트의 길이, 응답 길이에 따라 반영되기 때문에 프롬프트가 길어지면 답변의 성능은 올라갈 수 있지만 비용 역시 비례해서 올라가버린다.

 

 

그럼에도 불구하고 프롬프트에 꼭 들어가야 하는 기본 요소를 정리해보자면 다음 네 가지 요소로 분류할 수 있다.

 

 

 

프롬프트의 기본 요소

 

1. 지시문 (Instruction)

 

 

  • LLM에게 수행할 작업의 본질을 명확히 알려주는 역할을 수행한다.
  • LLM이 해야 할 구체적인 작업을 설명하며, LLM이 정확하게 무엇을 해야 하는지 이해할 수 있도록 작성한다.
  • 간결한 문장구체적인 단어를 사용하는 것이 바람직하다.

 

  • 지시문 예시
    • 주어진 텍스트를 두 문장으로 요약해.
    • 'Input Data'를 분석하여 핵심 키워드를 정리해줘.
    • 'Input Data'를 분석하고 이를 날짜 순으로 정렬해서 JSON 형식으로 반환해줘.

 

 

 

명확한 지시문이 없으면 LLM이 정확히 어떤 작업을 수행해야 할지 헷갈리는 경우가 많다.

 

따라서 지시문은 제일 첫번째로 작성하고, 가급적 명확한 단어를 사용해서 지시하도록 하자.

 

 

 

2. 입력 데이터 (Input Data)

 

 

  • 모델이 처리할 실제 데이터를 제공하는 부분이다.
  • 모델이 작업을 수행하는 데 필요한 핵심 정보이며, 프롬프트의 가장 중요한 부분 중 하나다.
  • 꼭 필요한 정보만 포함하되, 충분히 상세하게 작성해 모델이 정확한 작업을 수행할 때 참고하도록 한다.
  • 입력 데이터가 너무 크면 예상보다 비용이 증가할 수 있으므로, 꼭 필요한 정보만 포함하는 것이 좋다.

 

  • 입력 데이터 예시
    • 텍스트 요약 요청 시 : 요약할 원본 텍스트 등
    • 데이터 변환 요청 시 : 원본 JSON 데이터 등

 

 

3. 문맥 (Context)

 

 

  • 모델이 작업을 수행할 때 도움이 되는 배경 정보를 제공하여 작업의 정확성과 관계성을 높이는 부분이다.
  • 이전 대화의 내용이나 특정 용어의 의미, 작업의 의도 등을 포함할 수도 있다.
  • 모델이 오해할 수 있는 부분을 사전에 방지하기 위해 관련 정보를 제공한다.
  • 모델이 작업의 맥락을 잘못 해석할 수 있으므로 문맥은 가급적 명확하게 설명해야 한다.

 

  • 문맥 예시
    • 이전 문장에서 언급한 사람을 지속적으로 언급해 줘.
    • 이 문서의 주제는 인공지능이므로, 관련 용어를 사용해 줘.
    • 대화 중 '현재'라고 언급된 경우, 오늘 날짜(YYYY-MM-DD 기준)를 참고해.
    • 이 텍스트는 한국의 독자를 대상으로 해야 하므로, 모든 예시에서는 한국 문화와 관련된 예시를 추가해 줘.

 

 

 

4. 출력문(Output Indicator)

 

 

  • 모델이 결과물을 어떤 형식과 구조로 제공해야 하는지 명확히 지시하는 부분이다.
  • 응답의 형식과 구조를 지정하기 때문에 결과물이 예측 가능하고, 사용 목적에 맞도록 결과물이 도출 된다.
  • 출력의 길이, 형식, 구조를 구체적으로 지정해 주어야 한다.
  • 특정 형식을 필요로 하는 경우, (ex: JSON, Markdown 등) 해당 형식을 명시해서 결과물이 해당 조건으로 도출되도록 한다.

 

  • 출력문 예시
    • 두 문단으로 나누어 각 문단이 3~4문장씩 포함되도록 응답을 작성해 줘.
    • 응답을 JSON 형식으로 반환해 줘. (예: {"summary": "내용"})
    • 이 데이터의 주요 내용을 간략히 세 문장으로 요약해 줘.
    • 다음 데이터를 기반으로 분석 결과를 보고서 형식으로 작성해 줘.

 

 

 

 

 

프롬프트의 제작 원칙

 

 

프롬프트의 기본 요소를 포함시켜서 프롬프트를 작성할때 모델의 성능을 끌어 올리기 위해서 고려할 원칙이 있다.

 

프롬프트를 작성하기 전 후로 다음 원칙을 참고해서 제작 및 수정하면 LLM의 성능이 비약적으로 상승한다.

 

 

해당 원칙은 다음과 같다.

 

 

 

1. 범용성

  • 프롬프트는 다양한 상황이나 데이터에 적용될 수 있어야 한다.
  • 특정한 입력뿐만 아니라, 다양한 입력 데이터나 맥락에서도 적절히 작동할 수 있도록 설계되어야 한다.
  • 프롬프트의 재사용성을 높이는 중요한 요소이다.

 

2. 일관성

  • 프롬프트는 사용되는 용어, 형식, 구조에서 일관성을 유지해야 한다.
  • 다양한 언어 모델을 사용해도 일정한 품질과 결과물이 유지되어야 한다.

 

3. 목적 지향성

  • 프롬프트는 명확한 목적을 가지고 있어야 한다.
  • 작업의 목표가 분명해야 하며, 모델이 어떤 결과를 생성해야 하는지 명확히 제시해야 한다.
  • 어떠한 사용자 그룹에게 어떠한 기능을 제공할 것인지 명확하게 프롬프트를 작성해야 한다.

 

4. 경제성

  • 프롬프트는 필요 이상으로 길거나 복잡하지 않고, 간결하면서도 필요한 모든 정보를 포함해야 한다.
  • 프롬프트의 목적에 따라 어떤 모델을 사용할지 결정한다.
  • 최신 모델을 사용하는 것이 결과물 면에서는 좋을지는 모르나 간단한 기능이라면 경제적인 모델을 사용하는 것이 비용을 절감할 수 있다.

 

 

 

작성 예시

 

 

프롬프트의 기본 요소와 제작 원칙을 참고해서 특정 상황을 가정하고 프롬프트를 작성해보자.

 

 

특정 앱에서 사용자가 서비스를 이용하고 긴 시간동안 해당 앱을 사용하지 않는다고 가정해보도록 하자.

 

서비스에 일정 기간 이상 접속하지 않는 “이탈한 유저”에게 푸시 앱 메시지를 보내는 프롬프트를 제작해보도록 하려고 한다.

 

위의 기능에서 사용할 푸시 앱 메세지를 LLM에게 도출하도록 하고 그러기 위해선 사용자가 마지막으로 앱에서 사용했던 기능이나 사용자의 아이디와 같은 LLM이 참고할 'Context' 나 'Input Data'등이 필요할 것으로 예상된다.

 

 

"""
### Instruction
"
서비스에 일정 기간동안 접속하지 않은 "이탈 유저"에게 푸시 앱 메시지를 보낼 예정입니다.
"이탈 유저"의 클릭율을 높이기 위한 프롬프트를 작성합니다. 
모바일 사용 환경에 맞춰 메시지의 길이를 1줄로 제한합니다.
클릭율을 높일 수 있는 아이디어를 포함해서 프롬프트를 작성해 주세요.
"

### Context
"
사용자가 최근 서비스를 이용하지 않고 있으며 
해당 사용자를 다시 서비스로 유도하기 위해 푸시 메시지를 통해 관심을 유도시켜야 합니다.
"

### Input Examples
"
- 항목 1
'User Name' : 'Lee'
'User Context' : '내일 서울의 오전 날씨를 알려줘'
'AI' : '내일 서울의 오전 날씨는 맑습니다.'

- 항목 2
'User Name' : 'David'
'User Context' : '어버이날 부모님 선물을 추천해줘'
'AI' : '카네이션이나 케이크를 추천드립니다.'

- 항목 3
'User Name' : '김두한'
'User Context' : '35000 - 20000 = ?'
'AI' : '35000 - 20000 = 15000 입니다.'

- 항목 4
'User Name' : 'Nick'
'User Context' : '노벨상이 뭐야?'
'AI' : '노벨상은 인류 문명 발달에 기여한 인물에게 매년 수여하는 권위 있는 상이에요!'
"

### Output Example

- 항목 1 : 'Lee'님, 오늘 날씨도 궁금하지 않으세요?
- 항목 2 : 'David'님, 요즘 유행하는 추천 선물을 알려드릴까요?
- 항목 3 : '김두한'님, 제 계산 속도가 더 빨라졌어요!
- 항목 4 : 'Nick'님, 이번엔 필즈상에 대해 같이 알아보실래요?


### Input Data
"
- 항목 1
'User Name' : 'Allen'
'User Context' : '내일 동해안으로 여행을 갈만할 장소를 추천해줘.'
'AI' : '강원도 양양의 하조대는 어떠세요?'

- 항목 2
'User Name' : 'James'
'User Context' : '점심 메뉴를 추천해줘'
'AI' : '시원한 냉면은 어떠세요?'

- 항목 3
'User Name' : 'Anna'
'User Context' : '"하이젠베르크"가 누구야 ?'
'AI' : '"하이젠베르크"는 독일의 물리학자에요!'

"

### Output Indicator
"
- 사용자의 클릭을 유도할 수 있는 1줄로 작성된 재미있는 메시지
- 모바일 환경에 맞춘 간결한 메시지
- 사용자의 관심을 다시 끌기 위한 'User Name'이 들어간 메세지
- 사용자의 제공했던 Text의 주제와 관련된 질문으로 메세지를 작성하기
- 사용자가 언급한 장소 및 인물과는 다른 장소와 인물을 예시로 메세지를 작성하기
- Output Example과 다른 형식의 답변은 제외하기
- 클릭을 유도하기 좋은 주제를 사용자에게 추천해보기
"
"""

 

 

 

다음과 같이 프롬프트를 작성해서 LLM에게 입력해주면 각 모델별로 상당히 균일한 결과가 도출된다.

 

 


 

gpt-4o-mini

 

 

Claude 3.5 Sonnet

 

Gemini
Gemini

 

 


 

 

 

 

728x90
반응형