OpenAI 패키지를 활용한 프로그래밍 방식의 프롬프트 공학은 전통적인 UI를 이용한 방식에 비해 여러 면에서 우수성을 보인다. 먼저, API를 통해 다양한 매개변수를 조정하고 복잡한 로직을 구현할 수 있어 유연성이 매우 높다. 또한 다른 시스템이나 워크플로우와 쉽게 통합할 수 있고 대량의 요청을 자동화할 수 있어 효율적이다.

프로그래밍 방식은 프롬프트를 체계적으로 테스트하고 결과를 분석하는 실험을 쉽게 설계할 수 있어 실험과 반복에 유리하다. 특정 요구사항에 맞는 복잡한 프롬프트 전략을 구현할 수 있어 맞춤형 솔루션 개발에도 적합하다. 코드로 관리되므로 버전 관리 시스템을 통한 추적과 팀 협업이 용이하다는 장점도 있다.

초기 진입 장벽이 있지만 숙달 시 강력한 도구로 활용 가능하며, API 호출 단위로 비용이 발생하므로 대규모 사용 시 비용 효율적이다. 복잡한 대화 흐름과 컨텍스트 관리가 가능해 실시간 상호작용에도 우수한 성능을 보인다.

반면 UI 방식은 주어진 인터페이스 내에서만 조작이 가능하므로 상대적으로 제한적이다. 수동 조작이 필요해 대규모 작업에는 비효율적이며, 체계적인 실험과 결과 분석이 어렵다. 일반적인 사용 사례에 맞춰진 기능만 제공되어 맞춤형 솔루션 개발에 한계가 있다.

기본완성 프롬프트

OpenAI의 API를 사용하여 텍스트 분류, 요약, 그리고 엔티티 추출과 같은 다양한 작업을 수행한다. dotenv를 사용하여 API 키를 관리하여 외부에 API키가 공개되는 것을 방지한다.

코드
from openai import OpenAI
from dotenv import load_dotenv
import os

# .env 파일에서 환경 변수 로드
load_dotenv()

# OpenAI 클라이언트 초기화
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def get_response(messages):
    response = client.chat.completions.create(
        model="gpt-3.5-turbo", messages=messages, temperature=0
    )
    return response.choices[0].message.content


def classify_sentiment(text):
    system_prompt = "당신은 텍스트의 감정을 분류하도록 훈련된 AI입니다. '긍정적', '부정적', 또는 '중립적' 중 하나로만 응답하세요."
    user_prompt = f"다음 텍스트의 감정을 분류하세요: '{text}'"
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_prompt},
    ]
    return get_response(messages)


def summarize_text(text, max_words=50):
    system_prompt = f"당신은 텍스트를 요약하도록 훈련된 AI입니다. {max_words}단어 이내로 요약을 제공하세요."
    user_prompt = f"다음 텍스트를 요약하세요: '{text}'"
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_prompt},
    ]
    return get_response(messages)


def extract_entities(text):
    system_prompt = "당신은 텍스트에서 개체명을 추출하도록 훈련된 AI입니다. '사람', '조직', '장소'를 키로 가진 JSON 객체 형태로 결과를 제공하세요."
    user_prompt = f"다음 텍스트에서 개체명을 추출하세요: '{text}'"
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_prompt},
    ]
    return get_response(messages)


# 테스트
sample_text = "애플(Apple Inc.)은 오늘 팀 쿡(Tim Cook) CEO가 다음 달 캘리포니아 쿠퍼티노의 새 캠퍼스를 방문할 예정이라고 발표했습니다."

print("감정 분류:")
print(classify_sentiment(sample_text))

print("\n텍스트 요약:")
print(summarize_text(sample_text))

print("\n개체명 추출:")
print(extract_entities(sample_text))
감정 분류:
중립적

텍스트 요약:
애플은 팀 쿡 CEO가 다음 달에 신규 캠퍼스를 방문할 예정이라고 발표했습니다.

개체명 추출:
{
    "조직": "애플",
    "사람": "팀 쿡",
    "장소": "캘리포니아 쿠퍼티노"
}

사용자 맞춤형 프롬프트

프롬프트 핵심구성요소를 반영한 프롬프트를 작성하고 이를 OpenAI API에 전달하여 감성분석을 수행하는 코드를 다음과 같이 작성할 수 있다.

코드
from openai import OpenAI
from dotenv import load_dotenv
import os

# .env 파일에서 환경 변수 로드
load_dotenv()

# OpenAI 클라이언트 초기화
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))


def get_response(prompt, model="gpt-3.5-turbo", temperature=0.7):
    try:
        response = client.chat.completions.create(
            model=model,
            messages=[
                {"role": "system", "content": "You are a helpful assistant."},
                {"role": "user", "content": prompt},
            ],
            temperature=temperature,
        )
        return response.choices[0].message.content
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

# 사용자 정의 프롬프트
def create_sentiment_analysis_prompt(text):
    # 페르소나(Persona)
    persona = "당신은 텍스트의 감정을 정확하게 분석하는 전문 언어학자입니다."

    # 지시사항 (Instruction)
    instruction = "주어진 텍스트의 감정을 분석하고, 그 감정의 강도를 평가하세요. 텍스트에 나타난 단어 선택, 문장 구조, 전반적인 톤을 고려하여 분석하세요."

    # 예시/맥락 (Examples/Context)
    examples = """
    예시 1:
    텍스트: "오늘은 정말 최고의 날이었어! 모든 것이 완벽했어."
    분석: 감정: 매우 긍정적, 강도: 강함

    예시 2:
    텍스트: "이 영화는 그저 그랬어. 특별히 좋지도 나쁘지도 않았어."
    분석: 감정: 중립적, 강도: 약함
    """

    # 입력 데이터 (Input data)
    input_data = f"분석할 텍스트: '''{text}'''"

    # 출력 지표 (Output indicator)
    output_format = """
    다음 형식으로 출력을 제공하세요:
    - 주요 감정: [긍정적/부정적/중립적 중 하나]
    - 감정 강도: [약함/중간/강함 중 하나]
    - 근거: [분석의 근거를 2-3문장으로 설명]
    """

    # 전체 프롬프트 조합
    full_prompt = (
        f"{persona}\n\n{instruction}\n\n{examples}\n\n{input_data}\n\n{output_format}"
    )

    return full_prompt

# 사용 예시
sample_text = "이번 여행은 기대 이상으로 좋았어요. 풍경도 아름답고 음식도 맛있었어요. 다만, 날씨가 조금 흐린 날이 있어서 아쉬웠죠."
prompt = create_sentiment_analysis_prompt(sample_text)
response = get_response(prompt)
print(response)
- 주요 감정: 긍정적
- 감정 강도: 중간
- 근거: 텍스트에서 나타나는 단어들을 고려하면 여행이 기대 이상으로 좋았다는 긍정적인 느낌이 강하게 전달됩니다. 그러나 흐린 날씨로 인해 조금 아쉬움이 있었다는 부정적인 감정도 표현되어 있어 감정의 강도는 중간 정도로 판단됩니다.

Multi-step과 few-shot 프롬프트

Multi-step 프롬프트와 few-shot 프롬프트는 각각 고유한 특성과 용도를 가지고 있다. Multi-step 프롬프트는 복잡한 작업을 여러 단계로 나누어 수행하도록 AI를 안내한다. 문제 해결 과정을 명확하게 구조화하고, 각 단계에서 중간 결과를 확인할 수 있어 복잡한 추론이 필요한 작업에 적합하다. 또한 사용자가 프롬프트의 각 단계를 직접 제어할 수 있어 결과의 정확성을 높일 수 있다. 그러나 Multi-step 프롬프트는 설계가 복잡하고 시간이 많이 소요될 수 있으며, 각 단계에서 오류가 누적될 가능성이 있다.

반면 Few-shot 프롬프트는 AI에게 몇 가지 예시를 제공하여 원하는 출력 형식이나 패턴을 학습하도록 한다. 새로운 작업이나 도메인에 AI를 빠르게 적응시킬 수 있어 유연성이 높다. 또한 예시를 통해 AI의 이해를 돕기 때문에 복잡한 설명 없이도 원하는 결과를 얻을 수 있다. 그러나 Few-shot 프롬프트는 제공된 예시에 과도하게 의존할 수 있어 일반화 능력이 떨어질 수 있으며, 예시 선택에 따라 결과의 품질이 크게 달라질 수 있다.

Multi-step 프롬프트는 단계별 추론이 필요한 복잡한 문제 해결, 수학적 계산, 코드 생성 등에 적합하다. 반면 Few-shot 프롬프트는 텍스트 분류, 감정 분석, 간단한 번역 작업 등 패턴 인식이 중요한 작업에 효과적이다. 실제 응용에서는 두 방식을 혼합하여 사용하는 것도 가능하며, 이를 통해 각 방식의 장점을 극대화할 수 있다.

Multi-step 프롬프트

텍스트 분석 및 요약 작업을 여러 단계로 나누어 수행하는 Multi-step 프롬프트를 다음과 같이 구현할 수 있다.

코드
from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))


def get_response(messages):
    response = client.chat.completions.create(
        model="gpt-3.5-turbo", messages=messages, temperature=0.7
    )
    return response.choices[0].message.content


def multi_step_text_analysis(text):
    messages = [
        {
            "role": "system",
            "content": "당신은 텍스트 분석 및 요약 전문가입니다. 주어진 단계에 따라 텍스트를 분석하고 요약해주세요.",
        }
    ]

    # 1단계: 주요 주제 식별
    messages.append(
        {
            "role": "user",
            "content": f"다음 텍스트의 주요 주제를 3개 이내로 식별해주세요: \n\n{text}",
        }
    )
    topics = get_response(messages)
    messages.append({"role": "assistant", "content": topics})
    print("주요 주제:", topics)

    # 2단계: 감정 분석
    messages.append(
        {"role": "user", "content": "이 텍스트의 전반적인 감정 톤을 분석해주세요."}
    )
    sentiment = get_response(messages)
    messages.append({"role": "assistant", "content": sentiment})
    print("감정 분석:", sentiment)

    # 3단계: 핵심 문장 추출
    messages.append(
        {
            "role": "user",
            "content": "이 텍스트에서 가장 중요한 2-3개의 문장을 추출해주세요.",
        }
    )
    key_sentences = get_response(messages)
    messages.append({"role": "assistant", "content": key_sentences})
    print("핵심 문장:", key_sentences)

    # 4단계: 요약 생성
    messages.append(
        {
            "role": "user",
            "content": "지금까지의 분석을 바탕으로 이 텍스트를 100단어 이내로 요약해주세요.",
        }
    )
    summary = get_response(messages)
    messages.append({"role": "assistant", "content": summary})
    print("요약:", summary)

    return {
        "topics": topics,
        "sentiment": sentiment,
        "key_sentences": key_sentences,
        "summary": summary,
    }


# 사용 예시
sample_text = """
인공지능(AI) 기술의 발전은 우리 사회에 큰 변화를 가져오고 있습니다. 
의료 분야에서는 AI가 질병 진단의 정확성을 높이고 있으며, 교육 분야에서는 개인화된 학습 경험을 제공하고 있습니다. 
그러나 AI의 확산은 일자리 감소와 같은 사회적 문제도 야기하고 있습니다. 
예를 들어, 자동화로 인해 일부 직종이 사라질 위험이 있습니다. 
따라서 우리는 AI 기술의 혜택을 최대화하면서도 그 부작용을 최소화할 수 있는 방안을 모색해야 합니다. 
이를 위해서는 정부, 기업, 시민 사회가 협력하여 AI 윤리 가이드라인을 수립하고, 
새로운 기술 환경에 적응할 수 있는 교육 프로그램을 개발하는 등의 노력이 필요합니다.
"""

result = multi_step_text_analysis(sample_text)
주요 주제: 1. 인공지능(AI) 기술의 사회적 영향
2. 의료 분야와 교육 분야에서의 AI 활용
3. AI 기술의 부작용 및 대응 방안
감정 분석: 주어진 텍스트의 전반적인 감정 톤은 중립적이고 객관적입니다. 텍스트는 인공지능 기술의 발전이 가져오는 긍정적인 면과 동시에 부정적인 측면을 다루고 있으며, 이에 중립적인 입장에서 사회적 영향과 대응 방안을 제시하고 있습니다. 주로 사실적인 정보와 분석을 다루고 있어서 주정적이나 부정적인 감정이 특히 강조되지는 않고 있습니다.
핵심 문장: 1. 인공지능(AI) 기술의 발전은 우리 사회에 큰 변화를 가져오고 있습니다.
2. 우리는 AI 기술의 혜택을 최대화하면서도 그 부작용을 최소화할 수 있는 방안을 모색해야 합니다.
3. 이를 위해서는 정부, 기업, 시민 사회가 협력하여 AI 윤리 가이드라인을 수립하고, 새로운 기술 환경에 적응할 수 있는 교육 프로그램을 개발하는 등의 노력이 필요합니다.
요약: 인공지능(AI) 기술의 발전으로 의료와 교육 분야에서 진단 정확성 향상과 개인화된 학습 경험이 가능해지고 있지만, 사회적 문제도 동반하고 있습니다. AI의 확산으로 인한 일자리 감소 우려도 존재합니다. 따라서 AI의 혜택은 최대화하고 부작용은 최소화하기 위해 정부, 기업, 시민 사회가 협력하여 AI 윤리 가이드라인을 수립하고 교육 프로그램을 개발하는 노력이 요구됩니다. AI 기술의 발전은 사회적 변화를 이끌고 있으며, 이에 적절히 대응하여 사회적 이슈를 해결할 필요가 있습니다.

few-shot 프롬프트

few-shot 프롬프트는 특정 도메인에 대한 빠른 프로토타이핑이나 모델 튜닝이 필요한 경우에 유용할 뿐만 아니라, 레이블이 지정된 대규모 데이터셋 없이도 합리적인 성능을 얻을 수 있어 리소스가 제한된 상황에서도 효과적이다. 텍스트 분류(감성) 작업을 수행하는데, 특정 도메인(이 경우 영화 리뷰)에 대한 감정 분석을 수행하는 코드를 다음과 같이 작성할 수 있다.

코드
from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))


def get_response(messages):
    response = client.chat.completions.create(
        model="gpt-3.5-turbo", messages=messages, temperature=0.3
    )
    return response.choices[0].message.content


def few_shot_movie_review_classifier(review):
    # Few-shot 예시를 포함한 프롬프트 구성
    prompt = """다음은 영화 리뷰의 감정을 분류하는 작업입니다. 각 리뷰를 '긍정', '중립', '부정' 중 하나로 분류해주세요.

예시 1:
리뷰: "이 영화는 정말 훌륭했어요! 배우들의 연기가 일품이었고, 스토리도 매우 흥미진진했습니다."
분류: 긍정

예시 2:
리뷰: "그저 그런 영화였습니다. 특별히 좋지도 나쁘지도 않았어요."
분류: 중립

예시 3:
리뷰: "시간 낭비였어요. 스토리도 지루하고 연기도 어색했습니다."
분류: 부정

예시 4:
리뷰: "기대했던 것보다는 조금 실망스러웠지만, 몇몇 장면은 인상적이었습니다."
분류: 중립

이제 다음 리뷰를 분류해주세요:
리뷰: "{}"
분류:"""

    messages = [
        {"role": "system", "content": "당신은 영화 리뷰를 분석하는 전문가입니다."},
        {"role": "user", "content": prompt.format(review)},
    ]

    return get_response(messages)


def analyze_reviews(reviews):
    results = []
    for review in reviews:
        classification = few_shot_movie_review_classifier(review)
        results.append({"review": review, "classification": classification})
    return results


# 테스트 리뷰
test_reviews = [
    "이 영화는 올해 본 영화 중 최고예요! 연출, 음악, 연기 모두 완벽했습니다.",
    "음... 글쎄요. 나쁘지는 않았지만 특별히 좋지도 않았어요.",
    "정말 별로였어요. 2시간이 정말 길게 느껴졌습니다.",
    "기대보다는 좀 실망스러웠지만, 몇몇 장면은 정말 인상적이었어요.",
    "독특한 스토리와 뛰어난 영상미가 인상적이었습니다. 다만 결말이 조금 아쉬웠어요.",
]

results = analyze_reviews(test_reviews)

for result in results:
    print(f"리뷰: {result['review']}")
    print(f"분류: {result['classification']}")
    print()
리뷰: 이 영화는 올해 본 영화 중 최고예요! 연출, 음악, 연기 모두 완벽했습니다.
분류: 긍정

리뷰: 음... 글쎄요. 나쁘지는 않았지만 특별히 좋지도 않았어요.
분류: 중립

리뷰: 정말 별로였어요. 2시간이 정말 길게 느껴졌습니다.
분류: 부정

리뷰: 기대보다는 좀 실망스러웠지만, 몇몇 장면은 정말 인상적이었어요.
분류: 중립

리뷰: 독특한 스토리와 뛰어난 영상미가 인상적이었습니다. 다만 결말이 조금 아쉬웠어요.
분류: 긍정

CoT 프롬프트

생각의 사슬(Chain-of-Thought, CoT) 프롬프팅은 복잡한 추론 작업에서 AI 모델의 성능을 크게 향상시킨다. 모델이 최종 답변을 제시하기 전에 중간 사고 과정을 명시적으로 보여주도록 유도하기 때문에, 모델은 복잡한 문제를 단계별로 접근하고, 각 단계에서의 논리적 흐름을 명확히 할 수 있다. 결과적으로 최종 답변의 정확성이 높아지고, 오류가 줄어드는 효과를 얻을 수 있다.

CoT 프롬프팅은 AI 모델이 처리하는 작업의 복잡성이 증가함에 따라 더욱 부각된다. 수학 문제 해결, 논리적 추론, 다단계 의사결정 등의 작업에서 CoT는 모델의 사고 과정을 투명하게 만들어 사용자가 결과를 이해하고 검증하는 데 도움을 줄 뿐만 아니라, 모델 자체의 학습에도 긍정적인 영향을 미쳐, 보다 체계적이고 논리적인 사고 능력을 기를 수 있게 한다.

CoT 방식이 제공하는 상세한 풀이 과정과 일반적인 방식의 간단한 답변을 비교할 수 있다. 한 가게에서 20% 할인하는 상품에 대한 할인가격을 구하는 코드를 다음과 같이 작성할 수 있다. CoT 방식은 특히 복잡한 추론이 필요한 문제에서 그 우수성이 두드러지며, 사용자가 AI의 사고 과정을 이해하고 검증하는 데 큰 도움을 준다.

코드
from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def get_response(messages):
    response = client.chat.completions.create(
        model="gpt-3.5-turbo", messages=messages, temperature=0.2
    )
    return response.choices[0].message.content


def solve_problem_with_cot(problem):
    prompt = f"""문제를 단계별로 해결해주세요. 각 단계에서의 사고 과정을 명확히 설명하고, 최종 답변을 제시하세요.

문제: {problem}

풀이 과정:
1) """

    messages = [
        {
            "role": "system",
            "content": "당신은 수학 문제를 논리적으로 해결하는 전문가입니다.",
        },
        {"role": "user", "content": prompt},
    ]

    return get_response(messages)


def solve_problem_without_cot(problem):
    prompt = f"""다음 문제의 답을 구하세요:

문제: {problem}

답변:"""

    messages = [
        {"role": "system", "content": "당신은 수학 문제를 해결하는 전문가입니다."},
        {"role": "user", "content": prompt},
    ]

    return get_response(messages)


# 테스트 문제
problem = """
한 가게에서 20% 할인 행사를 하고 있습니다. 원래 가격이 80,000원인 제품을 구매하고 5,000원 쿠폰을 사용했다면, 최종 지불 금액은 얼마인가요?
또한, 이 금액은 원래 가격의 몇 퍼센트에 해당하나요? (퍼센트는 소수점 첫째 자리까지 계산하세요.)
"""

print("Chain-of-Thought 방식의 풀이:")
cot_solution = solve_problem_with_cot(problem)
print(cot_solution)

print("\n일반적인 방식의 풀이:")
normal_solution = solve_problem_without_cot(problem)
print(normal_solution)
Chain-of-Thought 방식의 풀이:
원래 가격이 80,000원이고 20% 할인을 받는다면, 할인된 가격은 얼마인지 계산해보겠습니다.

할인된 가격 = 원래 가격 - (원래 가격 * 할인율)
할인된 가격 = 80,000 - (80,000 * 0.20)
할인된 가격 = 80,000 - 16,000
할인된 가격 = 64,000원

따라서, 할인된 가격은 64,000원입니다.

2) 5,000원 쿠폰을 사용했으므로, 최종 지불 금액은 할인된 가격에서 쿠폰 금액을 빼면 됩니다.

최종 지불 금액 = 할인된 가격 - 쿠폰 금액
최종 지불 금액 = 64,000 - 5,000
최종 지불 금액 = 59,000원

따라서, 최종 지불 금액은 59,000원입니다.

3) 최종 지불 금액이 원래 가격의 몇 퍼센트에 해당하는지 계산해보겠습니다.

할인된 가격과 최종 지불 금액의 비율을 구하면 됩니다.

비율 = (최종 지불 금액 / 원래 가격) * 100
비율 = (59,000 / 80,000) * 100
비율 = 0.7375 * 100
비율 = 73.75%

따라서, 최종 지불 금액은 원래 가격의 73.75%에 해당합니다.

일반적인 방식의 풀이:
먼저 20% 할인을 적용한 가격은 80,000원에서 20% 할인을 적용하여 80,000원 * 0.8 = 64,000원 입니다. 이후 5,000원 쿠폰을 사용하면 최종 지불 금액은 64,000원 - 5,000원 = 59,000원 입니다.

따라서 최종 지불 금액은 59,000원이며, 이는 원래 가격 80,000원의 몇 퍼센트인지 계산하면 (59,000원 / 80,000원) * 100 ≈ 73.8% 입니다. 

따라서 최종 지불 금액은 원래 가격의 약 73.8%에 해당합니다.

자기검증 프롬프트

자기 검증 프롬프팅(Self-consistency prompting)은 AI 모델의 일관성과 신뢰성을 향상시키는 중요한 기법으로 동일한 문제에 대해 여러 번의 추론 과정을 생성하고, 그 결과들 중 다수결로 최종 답변을 선택한다. 이를 통해 모델의 단일 추론 과정에서 발생할 수 있는 오류나 편향을 줄일 수 있으며, 특히 복잡하거나 모호한 문제에 직면했을 때, 다양한 관점에서의 접근을 통해 더 균형 잡힌 결론을 도출할 수 있다.

Self-consistency prompting의 우수성은 그 안정성과 신뢰성에 있다. 여러 번의 추론 과정을 통해 모델은 자체적으로 결과를 검증하고 보완할 수 있는 기회를 갖게 된다. 이는 단일 추론에 의존할 때보다 더 견고한 결과를 제공하며, 모델의 불확실성을 줄이는 데 도움을 준다. 또한, 이 방법은 모델이 다양한 사고 경로를 탐색하도록 유도하여, 더 창의적이고 포괄적인 해결책을 찾는 데 기여한다. 결과적으로 Self-consistency prompting은 AI 시스템의 신뢰성을 높이고, 더 정확하고 일관된 결과를 제공하는 데 중요한 역할을 한다.

코드
from openai import OpenAI
import os
from dotenv import load_dotenv
from collections import Counter

load_dotenv()

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))


def get_response(messages):
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        temperature=0.7,  # 다양한 답변을 얻기 위해 temperature를 높입니다
    )
    return response.choices[0].message.content


def solve_problem_with_self_consistency(problem, num_attempts=5):
    solutions = []

    for _ in range(num_attempts):
        prompt = f"""문제를 단계별로 해결해주세요. 각 단계에서의 사고 과정을 명확히 설명하고, 최종 답변을 제시하세요.
        마지막에는 "최종 답변: [당신의 답변]" 형식으로 답을 명확히 적어주세요.

        문제: {problem}

        풀이 과정:
        1) """

        messages = [
            {
                "role": "system",
                "content": "당신은 수학 문제를 논리적으로 해결하는 전문가입니다.",
            },
            {"role": "user", "content": prompt},
        ]

        solution = get_response(messages)
        solutions.append(solution)

    return solutions


def extract_final_answer(solution):
    lines = solution.split("\n")
    for line in reversed(lines):
        if line.startswith("최종 답변:"):
            return line.split(":")[1].strip()
    return "답변을 찾을 수 없습니다."


def get_majority_vote(answers):
    return Counter(answers).most_common(1)[0][0]


# 테스트 문제
problem = """
한 농장에서 닭, 소, 돼지를 키우고 있습니다. 
이 농장의 동물들의 다리 수의 합계는 180개이고, 머리 수의 합계는 60개입니다.
닭의 수는 소의 수의 두 배입니다. 
각 동물의 수를 구하세요.
"""

solutions = solve_problem_with_self_consistency(problem)

print("각 시도의 풀이 과정과 답변:")
for i, solution in enumerate(solutions, 1):
    print(f"\n시도 {i}:")
    print(solution)
    print("-" * 50)

final_answers = [extract_final_answer(solution) for solution in solutions]
majority_answer = get_majority_vote(final_answers)

print("\n최종 다수결 답변:")
print(majority_answer)
각 시도의 풀이 과정과 답변:

시도 1:
1) 문제를 이해하고, 주어진 정보를 식으로 표현합니다.
   - 닭의 수를 C, 소의 수를 S, 돼지의 수를 P라고 하겠습니다.
   - 닭, 소, 돼지의 다리 수를 각각 2, 4, 4로 가정합니다.
   - 머리 수의 합계는 60개입니다. 즉, C + S + P = 60
   - 다리 수의 합계는 180개입니다. 즉, 2C + 4S + 4P = 180
   - 닭의 수는 소의 수의 두 배입니다. 즉, C = 2S

2) 주어진 식을 정리합니다.
   - 첫 번째 식: C + S + P = 60
   - 두 번째 식: 2C + 4S + 4P = 180
   - 세 번째 식: C = 2S

3) 세 번째 식을 첫 번째 식에 대입합니다.
   - C = 2S이므로, 첫 번째 식은 2S + S + P = 60이 됩니다.
   - 따라서, 3S + P = 60

4) 세 번째 식을 두 번째 식에 대입합니다.
   - C = 2S이므로, 두 번째 식은 2(2S) + 4S + 4P = 180이 됩니다.
   - 따라서, 4S + 4S + 4P = 180
   - 즉, 8S + 4P = 180

5) 네 번째 식을 정리합니다.
   - 8S + 4P = 180을 양변을 4로 나누면, 2S + P = 45가 됩니다.

6) 3S + P = 60과 2S + P = 45를 연립해서 풀어봅니다.
   - 3S + P = 60
   - 2S + P = 45

7) 두 식을 빼서 S를 구합니다.
   - (3S + P) - (2S + P) = 60 - 45
   - S = 15

8) S 값을 첫 번째 식에 대입해서 P를 구합니다.
   - 2S + P = 45에서 2(15) + P = 45
   - 30 + P = 45
   - P = 15

9) C 값을 세 번째 식에서 구합니다.
   - C = 2S에서 C = 2(15)
   - C = 30

최종 답변: 닭의 수는 30마리, 소의 수는 15마리, 돼지의 수는 15마리입니다.
--------------------------------------------------

시도 2:
풀이 과정:
1) 문제를 이해하고, 각 동물의 다리 수와 머리 수의 관계를 설정합니다.
    - : 다리 2개, 머리 1개
    - : 다리 4개, 머리 1개
    - 돼지: 다리 4개, 머리 1개

2) 변수를 설정합니다.
    - 닭의 수를 \( C \) (Chicken)라 하겠습니다.
    - 소의 수를 \( C/2 \) (Cow)라 하겠습니다. (문제에서 닭의 수가 소의 수의 두 배라고 주어졌으므로)
    - 돼지의 수를 \( P \) (Pig)라 하겠습니다.

3) 주어진 조건을 수식으로 표현합니다.
    - 머리 수의 합계: \( C + \frac{C}{2} + P = 60 \)
    - 다리 수의 합계: \( 2C + 4 \left( \frac{C}{2} \right) + 4P = 180 \)

4) 각 수식을 단순화합니다.
    - 머리 수의 합계: \( C + \frac{C}{2} + P = 60 \)
    - 다리 수의 합계: \( 2C + 2C + 4P = 180 \)

5) 각 수식을 더 단순화하여 풀기 쉽게 합니다.
    - 머리 수의 합계: \( \frac{3C}{2} + P = 60 \)
    - 다리 수의 합계: \( 4C + 4P = 180 \)

6) 첫 번째 식을 \(P\)에 대해 정리합니다.
    - \( P = 60 - \frac{3C}{2} \)

7) 두 번째 식에 \( P \)의 값을 대입하여 \(C\)에 대해 정리합니다.
    - \( 4C + 4 \left( 60 - \frac{3C}{2} \right) = 180 \)
    - \( 4C + 240 - 6C = 180 \)
    - \( -2C + 240 = 180 \)
    - \( -2C = -60 \)
    - \( C = 30 \)

8) 닭의 수를 구했습니다. 이제 소와 돼지의 수를 구합니다.
    - \( 소의 수 = \frac{C}{2} = \frac{30}{2} = 15 \)
    - \( 돼지의 수 = P = 60 - \frac{3 \times 30}{2} = 60 - 45 = 15 \)

각 동물의 수는:
    - : 30마리
    - : 15마리
    - 돼지: 15마리

최종 답변: 닭 30마리, 소 15마리, 돼지 15마리
--------------------------------------------------

시도 3:
풀이 과정:
1) 문제를 이해하고 변수 정의:
   - 닭의 수를 \( C \),
   - 소의 수를 \( S \),
   - 돼지의 수를 \( P \)로 정의합니다.

2) 주어진 조건을 수식으로 표현:
   - 닭의 수는 소의 수의 두 배: \( C = 2S \)
   - 다리 수의 합계는 180개:
     \( 2C + 4S + 4P = 180 \) (닭은 다리가 2개, 소와 돼지는 각각 다리가 4개)
   - 머리 수의 합계는 60개:
     \( C + S + P = 60 \)

3) 앞서 정의한 변수와 조건을 바탕으로 식을 정리:
   - \( C = 2S \)를 \( C \)의 위치에 대입:
     \( 2(2S) + 4S + 4P = 180 \)
     \( 4S + 4S + 4P = 180 \)
     \( 8S + 4P = 180 \)

4) 식을 간단히 정리:
   - \( 8S + 4P = 180 \)을 4로 나눕니다:
     \( 2S + P = 45 \)

5) 두 번째 조건을 사용하여 두 번째 식을 정리:
   - \( C + S + P = 60 \)에 \( C = 2S \)를 대입:
     \( 2S + S + P = 60 \)
     \( 3S + P = 60 \)

6) 두 식을 연립하여 풉니다:
   - \( 2S + P = 45 \)
   - \( 3S + P = 60 \)

   위의 두 식에서 \( P \)를 제거하기 위해, 두 번째 식에서 첫 번째 식을 뺍니다:
   \( (3S + P) - (2S + P) = 60 - 45 \)
   \( 3S - 2S = 15 \)
   \( S = 15 \)

7) \( S \)의 값을 첫 번째 식에 대입하여 \( P \)를 구합니다:
   - \( 2S + P = 45 \)
   - \( 2(15) + P = 45 \)
   - \( 30 + P = 45 \)
   - \( P = 45 - 30 \)
   - \( P = 15 \)

8) \( C \)의 값을 구합니다:
   - \( C = 2S \)
   - \( C = 2(15) \)
   - \( C = 30 \)

9) 최종 확인:
   - 머리 수: \( C + S + P = 30 + 15 + 15 = 60 \) (조건 만족)
   - 다리 수: \( 2C + 4S + 4P = 2(30) + 4(15) + 4(15) = 60 + 60 + 60 = 180 \) (조건 만족)

최종 답변: 닭 30마리, 소 15마리, 돼지 15마리
--------------------------------------------------

시도 4:
풀이 과정:
1) 문제를 이해하고, 각 동물의 수를 변수로 정의합니다.
    - 닭의 수를 C, 소의 수를 S, 돼지의 수를 P라고 하겠습니다.

2) 문제에서 주어진 조건을 식으로 표현합니다.
    - 닭의 수는 소의 수의 두 배입니다: \( C = 2S \)
    - 다리 수의 합계는 180개입니다: \( 2C + 4S + 4P = 180 \) (닭은 2다리, 소와 돼지는 4다리)
    - 머리 수의 합계는 60개입니다: \( C + S + P = 60 \)

3) 위의 식들을 정리하여 해결해보겠습니다.
    - \( C = 2S \) 이므로, 이를 다른 두 식에 대입합니다.
    - \( 2(2S) + 4S + 4P = 180 \) (다리 수의 식에 대입)
    - \( 4S + 4S + 4P = 180 \)
    - \( 8S + 4P = 180 \)
    - \( 2S + P = 30 \) (양변을 4로 나눔)

    - \( C = 2S \) 이므로, 이를 머리 수의 식에 대입합니다.
    - \( 2S + S + P = 60 \)
    - \( 3S + P = 60 \)

4) 이제 두 개의 연립방정식을 풀어봅니다.
    - \( 2S + P = 30 \)
    - \( 3S + P = 60 \)

    두 식을 빼서 \( P \)를 소거합니다.
    - \( (3S + P) - (2S + P) = 60 - 30 \)
    - \( S = 30 \)

    이제 \( S \)를 구했으므로, 이를 이용해 \( P \)를 구합니다.
    - \( 2S + P = 30 \)
    - \( 2(30) + P = 30 \)
    - \( 60 + P = 30 \)
    - \( P = 30 - 60 \)
    - \( P = -30 \)

    위 식에서 \( P \) 값이 음수가 되므로, \( S = 30 \)이 잘못된 값을 줍니다. 따라서 처음부터 다시 점검해봅니다.
    - \( 2S + P = 30 \)
    - \( 3S + P = 60 \)

    첫 번째 식에서 \( P \)를 구합니다.
    - \( P = 30 - 2S \)

    두 번째 식에 대입합니다.
    - \( 3S + (30 - 2S) = 60 \)
    - \( S + 30 = 60 \)
    - \( S = 30 \)

    위에서 잘못된 값이므로 다른식을 사용해봅니다.
    - \( 2C + 4S + 4P = 180 \)
    - \( C = 2S \)
    - \( 3S + P = 60 \)

    새로운 방식으로
    - \( C = S + P = 180 \)

5) 두 개의 연립방정식을 다시 점검해봅니다.
    - \( 2S + P = 30 \)
    - \( 3S + P = 60 \)

최종 답변: [문제 해결 필요]
--------------------------------------------------

시도 5:
1) 문제의 조건을 수학적으로 정리합니다.
- 닭의 수를 \( C \) (Chicken)라고 합시다.
- 소의 수를 \( S \) (Cow)라고 합시다.
- 돼지의 수를 \( P \) (Pig)라고 합시다.

주어진 조건에 따라 다음과 같은 식을 세울 수 있습니다.

2) 각 동물의 다리 수와 머리 수를 고려합니다.
- 닭은 다리가 2개, 머리가 1개 있습니다.
- 소는 다리가 4개, 머리가 1개 있습니다.
- 돼지는 다리가 4개, 머리가 1개 있습니다.

따라서 다리 수와 머리 수에 대한 식은 다음과 같습니다.
- 다리 수의 합계: \( 2C + 4S + 4P = 180 \)
- 머리 수의 합계: \( C + S + P = 60 \)

3) 추가 조건을 반영합니다.
- 닭의 수는 소의 수의 두 배입니다: \( C = 2S \)

4) 세 개의 식을 정리합니다.
- \( 2C + 4S + 4P = 180 \)
- \( C + S + P = 60 \)
- \( C = 2S \)

5) \( C = 2S \)를 다른 두 식에 대입하여 \( C \)를 제거합니다.
첫 번째 식:
- \( 2(2S) + 4S + 4P = 180 \)
- \( 4S + 4S + 4P = 180 \)
- \( 8S + 4P = 180 \)
- \( 2S + P = 45 \) (양변을 4로 나눔)

두 번째 식:
- \( 2S + S + P = 60 \)
- \( 3S + P = 60 \)

6) 두 식을 연립하여 풉니다.
- \( 2S + P = 45 \)
- \( 3S + P = 60 \)

두 식을 빼서 \( P \)를 제거합니다.
- \( (3S + P) - (2S + P) = 60 - 45 \)
- \( S = 15 \)

7) \( S = 15 \)를 이용해 \( P \)를 구합니다.
- \( 2S + P = 45 \)
- \( 2(15) + P = 45 \)
- \( 30 + P = 45 \)
- \( P = 15 \)

8) \( S = 15 \)를 이용해 \( C \)를 구합니다.
- \( C = 2S \)
- \( C = 2(15) \)
- \( C = 30 \)

따라서 각 동물의 수는:
- : 30마리
- : 15마리
- 돼지: 15마리

최종 답변: 닭 30마리, 소 15마리, 돼지 15마리
--------------------------------------------------

최종 다수결 답변:
닭 30마리, 소 15마리, 돼지 15마리