[7기 랭체인방]일관되지만 창의적인 답변을 위한 프롬프트 엔지니어링 팁

랭체인외에도 LLM을 이용해서 제품을 만들때 우리를 가장 괴롭히는 점은 오히려 너무 똑똑하게 대답하는 AI입니다.

물어본 혹은 지시한 내용에 대해서 창의적인 답변을 원할때가 대부분이지만 이 창의성을 해치지 않으면서 우리 제품에 바로 이식할수있게끔 대답을 유도하는것은 절대 쉬운일이 아닙니다.

이러한 문제를 해결하는 방법을 나눠 보려 합니다.

—-

먼저, 우리 가장 많이 사용하는 GPT-3.5, GPT-4모델 그리고 우리 주변에서 보는 LLM을 조금 이해할 필요가 있습니다.

멀리서 편하게 쓸때에 LLM은 그냥 마술 지팡이처럼 보입니다. 질문 혹은 요청을 하면 그에 맞은 답변을 척척해주니까요.

그래서일까요? 가끔 LLM이 스스로 생각해서 답변을 생성한다고 생각하시는 분들이 있습니다.

다소 의견이 갈릴수 있지만 아주아주 단순하게 생각하면 우리가 사용하는 LLM은 학습된 데이터를 바탕으로 완성된 엄청나게 변수가 많은 방정식입니다. 따라서 대답을 생성하는 과정은 입력된 데이터를 기반하여 확률적으로 생성됩니다.

이 지점이 우리가 이해해야하는 첫번째 포인트입니다.

few-shot 프롬프팅은 여러 예시를 입력함으로써 원하는 결과와 가까운 결과를 얻을수 있는 매우 좋은 프롬프팅입니다.
하지만 그 예시로 인해 답변의 확률이 few-shot과 가까워지고 이 부작용으로 비슷비슷한 결과만 계속 생성하게 됩니다.
이를 해결하기 위해서는 few-shot없이 답변의 방향(형식)을 결정해야합니다.


다음으로 우리가 이미 알고있지만 이용하지 못하던 지점이 있습니다.

우리가 사용하는 llm은 ‘자연어만’ 이해하는 것이 아닙니다. 프로그래밍 언어, 마크다운, Json 같은 문서작성법등도 잘 이해하고 있습니다. 특히 파이썬은 gpt가 가장 잘 이해하는 언어중 하나입니다.

이것이 우리가 이해해야할 두번째 포인트입니다.

앞에서 제가 지적한 형식을 고정할때 이러한 문서 작성법, 코딩방법을 적극적으로 사용하시면 형식을 어느정도 고정할수있습니다. 예시를 통해 이해해보시길 권장드립니다.


기존에 우리는 이런식으로 질문했습니다.

Q : 파이썬에서 변수란 무엇입니까? 라는 주제로 객관식 문제를 만들어주세요.
A : 
다음은 "파이썬에서 변수란 무엇입니까?"를 주제로 한 객관식 문제입니다:

---
파이썬에서 변수(variable)란 무엇을 의미합니까?

A) 프로그램에서 사용되는 데이터의 종류
B) 데이터를 저장하기 위한 메모리 상의 공간
C) 오류를 찾기 위해 사용되는 도구
D) 프로그램 실행을 중단시키는 명령어

정답: B) 데이터를 저장하기 위한 메모리 상의 공간

해설: 파이썬에서 변수는 데이터를 저장하는 데 사용되는 메모리 상의 공간입니다. 변수는 데이터에 이름을 부여하여 해당 데이터 값을 저장하고, 나중에 그 이름을 통해 데이터에 접근할 수 있게 합니다.
--- 

객관식 문제는 직관적인 이해를 돕기 위해 간단한 해설을 포함하는 것이 좋습니다. 위 문제는 파이썬 초보자들에게 변수의 개념을 설명하는 데 적합합니다.


우리가 일반적인 질문을 하고 요청을 할때에는 이미 충분한 답변을 해주지만 이 답변을 사용자가 사용하기 쉽게 만드는 것은 전혀 다른 프롬프트가 필요해 집니다.

저라면 다음과 같이 질문하겠습니다.

Q :
```instrcution
{주제 = "변수"}
질문 : 파이썬에서 {주제}란 무엇입니까? 
---
A) : {객관식 A)
B) : {객관식 B)
C) : {객관식 C)
D) : {객관식 D)
---
정답 :  {정답 ? {객관식 A) : {객관식 B) : {객관식 C) : {객관식 D)}
---
해설 :
"{질문}"의 답은 {정답} 입니다.
그 이유는 {해석} 입니다.
{예시}
```


A : 
질문 : 파이썬에서 변수란 무엇입니까? 
---
A) : 데이터를 저장하기 위한 메모리 상의 위치
B) : 프로그램의 실행을 제어하는 명령어
C) : 오류를 추적하는 시스템 도구
D) : 파이썬 프로그램의 파일 이름
---
정답 : A) 데이터를 저장하기 위한 메모리 상의 위치
---
해설 :
"파이썬에서 변수란 무엇입니까?"의 답은 A) 데이터를 저장하기 위한 메모리 상의 위치 입니다.
그 이유는 변수는 값을 저장하고 참조하기 위해 프로그램에서 사용하는 식별자(이름)이며, 실제로 이 값들은 컴퓨터의 메모리에 위치하게 됩니다. 변수는 이 값에 이름을 붙여서 프로그램 코드 내에서 쉽게 접근하고 조작할 수 있게 해줍니다.
예를 들어, `x = 10` 이라는 코드에서 `x`는 변수명이고, `10`은 `x`가 참조하는 값입니다. 이때 `10`이 메모리 상에 저장되며, `x`를 통해 접근할 수 있습니다.


이제 GPT가 답변하는 형식은 주었으나 그 외에 다른 지점은 최소한의 정보를 줌으로서 다양한 답변이 나올수 있게 되었습니다.


이러한 방법론을 사용하면 두가지 이점이 있습니다. 첫번째는 앞에서 이야기했듯 일관되지만 창의적인 답변을 유도할수있습니다. 두번째는 템플릿을 만들수있습니다. 주제는 달라지지만 항상 비슷한 형식으로 사용해야하는 작업이 있다면 이러한 탬플릿을 이용해 최소한의 값만 변경하며 사용하실수 있습니다. 앞에서 제가 배포한 commitbot도 이러한 방법론을 응용해 완성되었으며 새로 배포를 준비중인 문제 생성기도 같은 방법론을 사용했습니다.

코드는 참고만 하시고 프롬프트에 집중하셔서 이후 작업에 활용하시길 바라겠습니다.

import streamlit as st
import openai
import os
import json

openai.api_key_path = os.path.join(os.getcwd(), "2.env")

def generate_question(question_type):
    with st.spinner('문제를 생성하는 중입니다...'):
        response = openai.ChatCompletion.create(
            model="gpt-4",
            messages=[
                {"role": "system", "content": """객관식 문제를 아래와 같은 JSON 형식으로 작성하세요.
        예시 : {
        "questions": [
            {
            "question": {question},
            "options": {
                "A": {options_A},
                "B": {options_B},
                "C": {options_C},
                "D": {options_D}
            },
            "answer": {answer}
            },
            // 추가 문제 형식
        ]
        }"""},
                {"role": "user", "content": f"{question_type}에 대한 객관식 문제를 하나 만들어 주세요."}
            ],
        )
        response = response['choices'][0]['message']['content']

        data = json.loads(response)

        # 각 문제에 대한 데이터 추출
        question_data = data['questions'][0]
        question = question_data['question']
        options = question_data['options']
        answer = question_data['answer']

        choices_values = list(options.values())
        return question, choices_values, answer

def get_option_label(choice, options):
    try:
        index = options.index(choice)
        return ["A", "B", "C", "D"][index]
    except ValueError:
        return None



def main():
    st.title("간단한 문제 출제 사이트")

    question_subtypes = {
        "수학": ["초급 수학", "중급 수학", "고급 수학"],
        "과학": ["초급 과학", "중급 과학", "고급 과학"],
        "영어": ["초급 영어", "중급 영어", "고급 영어"]
    }

    question_select = st.selectbox("문제 유형을 선택하세요:", ["선택하세요", "수학", "과학", "영어"], index=0)

    # 문제 생성 및 표시
    if question_select != "선택하세요":
        user_choices = []
        for i in range(3):
            key_prefix = f'{question_select}_{i}'
            question_type = question_subtypes[question_select][i]

            # 새로운 문제 유형이 선택되었을 때만 문제를 생성합니다.
            if question_select != st.session_state.get('last_question_type', None):
                question, choices, answer = generate_question(question_type)
                st.session_state[f'question_{key_prefix}'] = question
                st.session_state[f'choices_{key_prefix}'] = choices
                st.session_state[f'answer_{key_prefix}'] = answer

            st.write(f"### 문제 {i + 1}")
            st.write(st.session_state[f'question_{key_prefix}'])
            user_choice = st.radio("선택지:", st.session_state[f'choices_{key_prefix}'], key=f'user_choice_{i}')
            user_choices.append(user_choice)

        # 사용자의 마지막 선택 유형 업데이트
        st.session_state['last_question_type'] = question_select


    # 답안 제출 버튼
    if st.button("답안 제출"):
        for i in range(3):
            key_prefix = f'{question_select}_{i}'
            correct_answer = st.session_state[f'answer_{key_prefix}']
            user_choice = st.session_state.get(f'user_choice_{i}', None)
            
            # 옵션 내용을 레이블로 변환
            user_choice_label = get_option_label(user_choice, st.session_state[f'choices_{key_prefix}'])

            # 로그 출력
            st.write(f"문제 {i + 1}")

            if user_choice_label == correct_answer:
                st.success(f"문제 {i + 1} 정답입니다.")
            else:
                st.error(f"문제 {i + 1} 오답입니다.")




if __name__ == "__main__":
    main()



5
3개의 답글

(채용) 마케팅 리드, AI 엔지니어, 유튜브 PD, SNS 크리에이터

지피터스의 콘텐츠 플라이휠로 고속 성장할 팀원을 찾습니다!

👉 이 게시글도 읽어보세요