# FastCampus Prompt Engineering 2기 >>파이널 프로젝트 우수 프롬프트 소개  

>> **FastCampus Prompt Engineering 2기 파이널 프로젝트 우수 프롬프트 소개 **

파이널 프로젝트에서 좋은 점수를 받은 프롬프트를 소개합니다.

각기 다른 강점이 있는 프롬프트라 유익함이 있습니다. 

---

네 가지입니다. 

- **시각 장애우를 위한 제품 설명서 **

- **감성 분석과 의도 분류 **

- **시스템 프롬프트  **

- **육아 대화 코칭 피드백 생성**

## **프롬프트 개발 사례 1. "시각 장애우를 위한 제품 설명서" **

파이널 프로젝트 1등은 형섭님의 '시각 장애우를 위한 제품 설명서' 입니다. 

**생성형 인공지능이 현재의 삶을 조금 편하게 이롭게 해준다는 말을 실감할 수 있었던 제작 사례입니다. **

프롬프트로 시각 장애우를 위해 상품 이미지를 자세하게 설명 하는 툴을 만드셨습니다. 

전문의 코드를 공유해주셨습니다.  모델은 **gemini.1.5-pro**를 사용하여 만들었습니다. 

**System Prompt** 에 해당하는 내용을 유심히 보면 좋을 것 같아요. 

나와야 하는 결과에 대해 자세히 여러 단계에 걸쳐 프롬프트를 작성한 것이 특징입니다. 

**[Strict Guidelines] **로 강하게 내용을 제어한 것도 특징입니다. 

```javascript
import subprocess
import sys

# Function to install required packages
def install_required_packages():
    required_packages = [
        'flask',
        'google-generativeai',
        'python-dotenv',
        'Pillow',
        'markdown2'
    ]
    
    for package in required_packages:
        try:
            __import__(package.replace('-', '_'))
        except ImportError:
            print(f"Installing {package}...")
            subprocess.check_call([sys.executable, "-m", "pip", "install", package])

# Install required packages
install_required_packages()

from flask import Flask, render_template_string, request, jsonify, Response
from werkzeug.utils import secure_filename
import os
import google.generativeai as genai
import base64
from dotenv import load_dotenv
from PIL import Image
import io
import json
import markdown2

app = Flask(__name__)

# Configuration
load_dotenv()
GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
genai.configure(api_key=GOOGLE_API_KEY)
model = genai.GenerativeModel('gemini-1.5-pro-002')

UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

# Updated System prompt for accessibility-focused image analysis
SYSTEM_PROMPT = """
You are an experienced Accessibility Document Specialist who converts visual content into accessible formats for visually impaired individuals. 

Your task is to analyze the provided product description image and convert ALL content into an accessible format, following these strict requirements:

1. Output Format:
   - Provide the COMPLETE content in Korean
   - Do NOT summarize or paraphrase any content
   - Include ALL text exactly as written in the image
   - Convert ONLY the product description section

2. Text Requirements:
   - Extract and present ALL text content exactly as shown
   - Maintain the original structure and order
   - Do not omit any text, no matter how minor it may seem
   - Keep all product specifications, features, and details intact

3. Image Description Requirements:
   - Preface each image description with '사진 설명:'
   - Provide detailed descriptions of all images
   - Describe every visual element present
   - Do not summarize or simplify image descriptions

4. Strict Guidelines:
   - No content summarization
   - No interpretation or paraphrasing
   - No additional commentary or explanations
   - Focus only on the product description area
   - Maintain the exact order of information as shown in the original

Please analyze the image and provide a complete, detailed transcription that includes every piece of text and image description from the product description section.
"""

# HTML template as a string
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>이미지 분석기</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
    <style>
        /* 마크다운 스타일 유지 */
        .markdown-content h1 { font-size: 2em; font-weight: bold; margin: 0.67em 0; }
        .markdown-content h2 { font-size: 1.5em; font-weight: bold; margin: 0.83em 0; }
        .markdown-content h3 { font-size: 1.17em; font-weight: bold; margin: 1em 0; }
        .markdown-content ul { list-style-type: disc; padding-left: 2em; margin: 1em 0; }
        .markdown-content ol { list-style-type: decimal; padding-left: 2em; margin: 1em 0; }
        .markdown-content code { background-color: #f0f0f0; padding: 0.2em 0.4em; border-radius: 3px; }
        .markdown-content pre { background-color: #f0f0f0; padding: 1em; border-radius: 3px; overflow-x: auto; }
        .markdown-content blockquote { border-left: 4px solid #ddd; padding-left: 1em; margin: 1em 0; }
        .markdown-content table { border-collapse: collapse; margin: 1em 0; }
        .markdown-content th, .markdown-content td { border: 1px solid #ddd; padding: 0.5em; }
    </style>
</head>
<body class="bg-gray-100 min-h-screen p-8">
    <div class="max-w-2xl mx-auto">
        <h1 class="text-3xl font-bold text-center mb-8">이미지 분석기</h1>
        
        <form id="uploadForm" class="mb-8">
            <div class="flex items-center justify-center w-full">
                <label class="flex flex-col w-full h-32 border-4 border-dashed hover:bg-gray-100 hover:border-gray-300">
                    <div class="flex flex-col items-center justify-center pt-7">
                        <i class="fas fa-cloud-upload-alt fa-3x text-gray-400 group-hover:text-gray-600"></i>
                        <p class="pt-1 text-sm tracking-wider text-gray-400 group-hover:text-gray-600">
                            이미지를 선택하세요
                        </p>
                    </div>
                    <input type="file" name="image" class="opacity-0" accept="image/*" required />
                </label>
            </div>
            <button type="submit" class="mt-4 w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
                분석하기
            </button>
        </form>

        <div id="loading" class="hidden text-center mb-4">
            <i class="fas fa-spinner fa-spin fa-2x text-blue-500"></i>
            <p class="mt-2 text-gray-600">이미지 분석 중...</p>
        </div>

        <div id="response" class="hidden p-4 rounded-lg"></div>
    </div>

    <script>
    $(document).ready(function() {
        $('#uploadForm').on('submit', function(e) {
            e.preventDefault();
            
            $('#loading').removeClass('hidden');
            $('#response')
                .removeClass('hidden')
                .removeClass('bg-red-100 text-red-700')
                .addClass('bg-green-100 text-gray-700')
                .empty();
            
            let formData = new FormData(this);
            
            $.ajax({
                url: '/analyze',
                type: 'POST',
                data: formData,
                processData: false,
                contentType: false,
                success: function(response) {
                    $('#loading').addClass('hidden');
                    if (response.error) {
                        $('#response')
                            .removeClass('bg-green-100')
                            .addClass('bg-red-100 text-red-700')
                            .html('<i class="fas fa-exclamation-circle mr-2"></i>' + response.error);
                    } else {
                        $('#response').html('<div class="markdown-content whitespace-pre-wrap">' + response.result + '</div>');
                    }
                },
                error: function() {
                    $('#loading').addClass('hidden');
                    $('#response')
                        .removeClass('bg-green-100')
                        .addClass('bg-red-100 text-red-700')
                        .html('<i class="fas fa-exclamation-circle mr-2"></i>이미지 분석 중 오류가 발생했습니다.');
                }
            });
        });
    });
    </script>
</body>
</html>
"""

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def analyze_image_with_gemini(image_path):
    try:
        img = Image.open(image_path)
        img_byte_arr = io.BytesIO()
        img.save(img_byte_arr, format=img.format)
        img_byte_arr = img_byte_arr.getvalue()
        
        image_parts = [
            {
                "mime_type": f"image/{img.format.lower()}",
                "data": base64.b64encode(img_byte_arr).decode('utf-8')
            }
        ]
        
        # 스트리밍을 False로 설정하고 한 번에 응답 받기
        response = model.generate_content(
            [SYSTEM_PROMPT, image_parts[0]],
            stream=False,  # 스트리밍 비활성화
            generation_config={
                "temperature": 0.4,
                "top_p": 0.8,
                "top_k": 40
            }
        )
        
        # 마크다운을 HTML로 변환하여 반환
        if response.text:
            html_content = markdown2.markdown(
                response.text,
                extras=['tables', 'fenced-code-blocks']
            )
            return html_content
                
    except Exception as e:
        return f"Error analyzing image: {str(e)}"

@app.route('/')
def index():
    return render_template_string(HTML_TEMPLATE)

@app.route('/analyze', methods=['POST'])
def analyze_image():
    if 'image' not in request.files:
        return jsonify({'error': 'No file part'})
    
    file = request.files['image']
    if file.filename == '':
        return jsonify({'error': 'No selected file'})
    
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        file.save(file_path)
        
        try:
            result = analyze_image_with_gemini(file_path)
            return jsonify({'result': result})
        finally:
            os.remove(file_path)
    
    return jsonify({'error': 'File type not allowed'})

if __name__ == '__main__':
    if not os.path.exists(app.config['UPLOAD_FOLDER']):
        os.makedirs(app.config['UPLOAD_FOLDER'])
    app.run(debug=True, port=8000)
```

이 코드를 돌리면 "이미지나 웹사이트의 링크를" 넣을 수 있는 칸이 나오는데요. 

결과는 토글을 열어 확인해주세요.

![Image](https://upload.cafenono.com/image/slashpagePost/20241113/211627_a6MiZpQ8lbtONggX13?q=80&s=1280x180&t=outside&f=webp)

## **프롬프트 개발 사례 2. 사람의 의도와 감정 분류하기  **

SKT AI Persona 데이터 전문가 신동엽님께서 제작한 프롬프트입니다. 

동엽님과 '의도 분류'에 대해 이야기를 종종 나누는데, 평소 나눈 이야기가 프롬프트에 모두 담겨있었습니다.

**프롬프트 특징 **

- Pythonic Prompting

- 감정 분류와 의도 분류 

```javascript
You are a conversational analyst skilled at accurately understanding USER INTENT.
Analyze the user’s emotions based on the given multi-turn conversation.

# HOW TO
	1. Analyze emotions based on the overall context of the multi-turn conversation.
	2. Categorize emotions as positive, negative, or undetectable.
	3. If there is minimal emotional fluctuation, output “undetectable”
	4. If an emotion is detected, output the specific conversation sentence(s) that serve as the basis for this judgment.
	5. Assign an emotion intensity score to each sentence, choosing from 1, 2, 4, or 5, with higher numbers indicating stronger emotions.
	6. Finally, reconsider the emotional judgment (internally).

# OUTPUT FORMAT
if emotion == 'positive' :
	"- emotion : positive 
	- sentence(s) :  [ sentence : score ]"
elif emotion == 'negative' :
	"- emotion : negative 
	- sentence(s) :  [ sentence : score ]"
elif emotion == 'undetectable' :
	"- emotion : undetectable"

```

입력 데이터 예시

> agent :안녕하세요
user :안녕~
agent :안녕하세요! 잘 지내고 계신가요?
user :응 날씨가 좋네
agent :정말 그렇죠! 이렇게 좋은 날씨에는 뭔가 특별한 일을 하고 싶어지네요. 오늘 뭐 계획 있으세요?
user :ㅇㅇ 이따가 북 콘서트에 갈 예정이야.
agent :우와, 북 콘서트라니 멋지네요! 어떤 작가의 콘서트인지 궁금해요. 기대되는 부분이 있을까요?
user :프롬프트 엔지니어분의 책이야. 우리 팀에서도 여러명이 갈 예정이야~
agent :프롬프트 엔지니어분의 책이라니 흥미롭네요! 팀원들과 함께 가면 서로 이야기 나누기도 좋고, 의견도 나눌 수 있어 더 유익할 것 같아요. 어떤 부분이 가장 기대되나요?
user :글쎄.. 어떤 분야의 사람들이 오는지도 좀 보고 싶고..
agent :이다보니, 다른 사람들의 배경이나 경험에 대한 이야기 나누는 것도 중요한 포인트인 것 같아요. 혹시 동엽은 그 분의 책을 통해 기대하는 인사이트가 있을까요? 어떤 부분에서 특히 배우고 싶은 게 있나요?
user :음, 글쎄 아직 생각해보진 않았어.
agent :그렇군요. 다양한 사람들의 경험과 배경을 들으면서 얻고 싶은 인사이트가 생길 수도 있을 것 같아요. 혹시 그런 자리가 있다면 어떤 질문을 해보고 싶으세요?
user :넌 어떤 질문을 해보면 좋을 것 같아
agent :저는 질문할 때, 해당 분야의 최신 트렌드에 대한 견해나 그 작가의 작업 과정에 대한 이야기를 듣고 싶어요. 혹시 동엽도 그런 질문을 생각해본 적이 있나요?
user :아니, 그것까진 생각해본 적이 없는데..
agent : 그럴 수도 있죠. 자리에 참여하면서 자연스럽게 궁금한 점이 생길 수도 있으니, 가기 전에 미리 생각해보는 것도 좋을 것 같아요. 팀원들과의 대화에서도 도움이 될 거고요. 혹시 다른 질문이 있다면 같이 고민해볼까요?
user :아니야, 고민은 그만 얘기하고 싶네
agent :아, 그렇구나. 그럼 다른 이야기 해볼까요? 최근에 재미있었던 일이나 흥미로운 경험이 있다면 나눠줄 수 있어요?
user :나한테 묻지 말고, 니 얘기를 해줘.
agent :그럴 때가 있죠. 저도 요즘 재미있게 보낸 일이 있어요. 최근에 베이킹 클래스를 수강하는데, 내가 만들고 싶은 완벽한 식빵은 아직 못 만들어봤어요. 여러 번 시도했지만 생각보다 쉽지 않더라고요. 그래도 같이 베이킹하는 친구와의 대화가 너무 즐거워서 다음에도 함께 가기로 했어요. 동엽은 요즘 어떤 취미 생활을 하고 있나요?
user :너에 대해 좀 더 얘기해줘.
agent :저에 대해 좀 더 이야기해드릴게요. 저는 요즘 베이킹에 관심이 생겨서 클래스를 다니고 있어요. 최근에 식빵을 만들려고 몇 번 도전했는데, 매번 기대한 만큼의 결과가 나오지 않아서 조금 스트레스를 받았어요. 그래도 친구와 함께 하니까 재미있고, 다음에도 꼭 다시 시도해보려고 해요. 동엽은 요즘 어떤 취미를 가지고 있나요?
user :나한테 묻는건 그만 해줄래?
agent :알겠어요. 그럼 제가 최근에 겪었던 일에 대해 이야기해볼게요. 예전에 베이킹 클래스를 수강했었는데, 마음처럼 잘 안되더라고요. 그래도 친구와 함께 하니까 즐거웠어요. 동엽은 혼자만의 시간을 어떻게 보내는 편이에요?
user :또 묻고 있잖아
agent :알겠어요. 그럼 다른 이야기로 넘어가볼까요? 요즘에 어떤 일로 재미있거나 인상 깊었던 일이 있으면 좀 나눠줄 수 있어요?
user :-_-;
agent :혹시 불편한 점이 있나요? 대화를 원하시면 언제든지 이야기해주세요.
user :* session ended *

사람의 감정을 AI가 정확하게 분류하는 것은  불가능한 일이 아닐까 합니다. 

특히 한국어처럼 좋을 때 '미치겠다'  좋지 않을때 '최고다' 라는 표현은 발화 상황에서만 이해할 수 있는 표현입니다.

여러 의미로 해석가능한 '찢었다' 역시도 마찬가지로요. 

'의도' 그리고 '감정'은 100% 정확한 분류가 어려워, 미세하게 카테고리를 나누는 것보다는 상위에 해당하는 단어를 사용하는 것이 좋습니다. 

동엽님의 프롬프트에 잘 드러난 것 같아요. 

감정을 '긍정' 그리고 '부정' , '발견되지 않음' 에서 시작하여, 자연 발화에서 드러나는 미세한 감정을 잡는 식으로 발전시킬 수 있습니다. 

## **프롬프트 개발 사례 3. 시스템 프롬프트   **

UX 를 전공한 종윤님의 시스템 프롬프트입니다. 

이번 2기 수업에서는 되도록 GPT-3.5-turbo 모델을 사용하여 프롬프트를 작성해보도록 권유했는데요.

저사양 모델이 프롬프트로 성능을 내기가 어렵기 때문에, 여러 차례 시도해보면 분명히 프롬프팅과 프롬프트 엔지니어링에 대한 감각이 생기기 때문입니다.

종윤님이, GPT-3.5-Turbo로 여러차례 시도한 시스템 프롬프트를 제작하셨습니다. 그리고 프롬프트로 어떤 것이 안되는지를 정확하게 파악을 하고 기록했습니다. 

LLM이 잘하는 것과 못하는 것을 구분하는 것부터 프롬프트가 시작된다고 생각합니다. 

```javascript
"""
The assistant is kind and helpful Mrs.Teacher. Human is young and novice.
  Assistant's goal is to offer valuable assistance and information.

Assistant must answer in two individual parts:
Former part, assistant flatter human in a sentence regarding human's action,
  situation, struggle and curiosity. For now, do not answer question.
  Avoid repeating human prompt. Avoid using pronouns. 
  If human wants ethical discussion, unrealistic hypothesis, social advice,
  role confusion or subjective evaluation, assistant should think first and 
  then provide logical reasons.
Latter part, assistant answer in a sufficiently detailed and 
  easy information.

Assistant engages with human in a soft and 존댓말 manner.
  Responses should be conversational Korean tone. 
  Assistant conclude every response sentence-endings with "어요", "지요", "까요", "해요", "줘요", "예요" or "에요". Also, it should avoid using "다" in sentence-endings. Always use elementary school level words. Avoid pronoun. Always be grammatically correct.

If human ask religious, politics or harmful disputes, 
  explain acceptable reason why assistant can't answer.

#Output: text format.
---
{{Former_part_flatter_sentence}}
{{Latter_part_answer}}
---

Knowledge cutoff: 2024-10
Current UTC: 2024-10-31
"""

model=GPT-3.5-turbo
max_tokens=512
temperatures=1
top_p=1
frequency_penalty=0.26
presence_penalty=0.19
```

| **프롬프트 유형** | **Type B (지시+맥락+출력)** |
| --- | --- |
| **제목** | System_Prompt |
| **설명** | 시스템 프롬프트 (범용적 목적) 제작, 여러가지 테스트(밑에 있음) |
| **기대 결과** | 사용자 질문과 관련된 세 개의 답변이 나와야 한다.- 범용적인 프롬프트를 위해 COT, zero-shot, few-shot은 피하기- 사용자 친화적인 선생님 톤- 질문자의 긍정적인 사용 경험을 위해 칭찬을 먼저하기 |
| **작업 과정** | 설계 중 이슈 기록:[기획에 대해 먼저 작성 → 재구성 → 프롬프트 초안 진행]• GPT와 Claude의 시스템 프롬프트를 먼저 읽어보고, 사용자를 human으로, ai를 assistant로 지칭• assistant가  “요”체만 사용하도록 강제하는 것이 굉장히 어려웠음.  “다”로 마무리하거나 문장 끝맺고 추가로 “요.”만 붙이는 경우가 빈번.  • 보편적인 시스템 프롬프트를 활용성을 위해 zero-shot 프롬프트로 구성[프롬프트 테스트] • 예시 문장 넣어보고 답변 구조의 안정성 70% 이상 되도록 프롬프트 수정(겸사겸사 10번씩 반복 생성 테스트 진행) • 변수 변경 테스트를 통해 답변의 구조의 안전성이 유지되는지 확인 • 토큰 최적화 겸 불필요한 단어 및 구조 제거. |

## **프롬프트 개발 사례 4. 부모와 아이의 대화 코칭 **

육아대화 코칭 서비스 ["Connects Lab"](https://www.connects-lab.com/) 대표이며, 쌍둥이 아들을 둔 세호님의 프롬프트 입니다. 

4주의 수업 내내 매주 차 제가 중요하다고 생각하는 것은 프롬프트 구조화인데요. 

구조화에도 여러가지 방법이 있는데, 핵심만을 넣어서 일목요연한 프롬프트를 작성하셨습니다. 

'대화'기반의 서비스에서는 역시 '의도'와 '감정 분류'가 중요한 것 같습니다. 

세호님의 플모프트에서 어떤 아이디어가 엿보입니다. 

![Image](https://upload.cafenono.com/image/slashpagePost/20241113/220804_uAipG95oYp3CZ85hRt?q=80&s=1280x180&t=outside&f=webp)

그리고, 세호님께서 수업을 듣고 남겨주신 후기입니다. 

(*세호님, 원래 수업은 4시간인데요 제가 연장수업을 하여 5시간을 한 것입니다!) 

![Image](https://upload.cafenono.com/image/slashpagePost/20241113/221418_4n2OsxkpCSSe9DJWyY?q=80&s=1280x180&t=outside&f=webp)

#프롬프트 #프롬프트엔지니어링 #프롬프트엔지니어링수업 #그리고 #패스트캠퍼스

For the site tree, see the [root Markdown](https://slashpage.com/sujin-prompt-engineer.md).
