프롬프트 엔지니어링: AI를 속여서 문제를 해결하는 방법

Prompt Engineering: How to Trick AI into Solving Your Problems

언어 모델(LLM)을 실제로 사용하는 방법에 대한 연재의 네 번째 글입니다. 여기서는 프롬프트 엔지니어링(PE)과 LLM 기반 응용 프로그램을 구축하기 위해 어떻게 사용하는지에 대해 논의하겠습니다. 주요 PE 기술을 검토한 후 LangChain을 사용하여 LLM 기반 응용 프로그램을 구축하는 Python 예제 코드를 통해 설명하겠습니다.

프롬프트 엔지니어링에 대해 처음 듣게 되면, 많은 기술 전문가들(나 자신 포함)은 이 아이디어에 대해 비꼬는 경향이 있습니다. 우리는 아마도 생각하게 될 것입니다. “프롬프트 엔지니어링? 허허, 그게 뭐라고. LLM을 처음부터 어떻게 만드는지 알려줘.”

그러나, 이것을 좀 더 깊게 파헤치면, 프롬프트 엔지니어링을 무시하는 개발자들에게 주의를 주고 싶습니다. 나아가, 프롬프트 엔지니어링은 대부분의 LLM 사용 사례의 가치의 80%를 낮은 노력으로 실현할 수 있다고 말하고 싶습니다.

이 글의 목표는 프롬프트 엔지니어링에 대한 실질적인 검토와 설명하는 예시를 통해 전달하는 것입니다. 프롬프트 엔지니어링이 할 수 있는 것에는 분명히 제한이 있겠지만, 그것은 우리의 문제에 대한 간단하고 영리한 해결책을 찾아내는 문을 열어줍니다.

프롬프트 엔지니어링이란 무엇인가?

이 연재의 첫 번째 글에서 프롬프트 엔지니어링을 LLM을 상자에서 그대로 사용하는 것(즉, 내부 모델 파라미터를 훈련시키지 않음)으로 정의했습니다. 그러나, 이것에 대해 많은 것을 더 말할 수 있습니다.

  1. 프롬프트 엔지니어링은 “LLM들이 프롬프트로 프로그래밍되는 수단”입니다. [1]
  2. 프롬프트 엔지니어링은 “원하는 작업에서 모델의 성능을 최대화하기 위해 프롬프트를 구성하고 형식화하는 경험적 예술”입니다. [2]
  3. “언어 모델들은 … 문서를 완성하고 싶어하기 때문에, 가짜 문서를 배열함으로써 그들에게 작업을 수행하게 속일 수 있습니다.” [3]

[논문]A Prompt Pattern Catalog to Enhance Prompt Engineering with ChatGPT

프롬프트 엔지니어링은 ChatGPT와 같은 대규모 언어 모델(LLM)과 효과적으로 대화하기 위해 점점 더 중요해지는 기술입니다. 프롬프트는 규칙을 강제하고, 과정을 자동화하며, 생성된 출력의 특정 품질(및 수량)을 보장하기 위해 LLM에 주어지는 지시사항입니다. 또한 프롬프트는 LLM과의 출력 및 상호작용을 맞춤화할 수 있는 프로그래밍 형태입니다. 이 논문은 LLM과 대화할 때 흔히 발생하는 문제를 해결하기 위해 적용된 패턴 형태로 제시된 프롬프트 엔지니어링 기술 목록을 설명합니다. 프롬프트 패턴은 소프트웨어 패턴과 유사한 지식 전송 방법입니다. 왜냐하면 그것들은 특정 맥락, 즉 LLM과 작업할 때의 출력 생성 및 상호작용에서 직면하는 일반적인 문제에 대한 재사용 가능한 해결책을 제공하기 때문입니다. 이 논문은 LLM을 사용하여 소프트웨어 개발 작업을 자동화하는 데 적용되는 프롬프트 엔지니어링 연구에 다음과 같은 기여를 합니다. 첫째, 다양한 분야에 적용될 수 있도록 문제의 범위를 해결하기 위해 프롬프트를 구조화하는 패턴을 기록하는 프레임워크를 제공합니다. 둘째, LLM 대화의 출력을 향상시키기 위해 성공적으로 적용된 패턴의 목록을 제시합니다. 셋째, 프롬프트가 여러 패턴에서 구축될 수 있으며, 다른 프롬프트 패턴과 결합하여 이점을 얻는 프롬프트 패턴을 보여줍니다.

[논문]LoRA: Low-Rank Adaptation of Large Language Models

자연어 처리의 중요한 패러다임 중 하나는 일반 도메인 데이터에서 대규모 사전 훈련과 특정 작업이나 도메인에 대한 적용으로 구성됩니다. 더 큰 모델을 사전 훈련할수록, 모든 모델 파라미터를 다시 훈련하는 전체 미세 조정이 덜 실행 가능해집니다. GPT-3 175B를 예로 들면, 각각 175B의 파라미터로 미세 조정된 독립된 인스턴스를 배포하는 것은 과도하게 비쌉니다. 우리는 Low-Rank Adaptation 또는 LoRA를 제안합니다. 이는 사전 훈련된 모델 가중치를 고정하고 각 트랜스포머 아키텍처 계층에 훈련 가능한 랭크 분해 행렬을 주입함으로써 다운스트림 작업에 대한 훈련 가능한 파라미터 수를 크게 줄입니다. GPT-3 175B가 Adam으로 미세 조정된 것에 비해 LoRA는 훈련 가능한 파라미터 수를 10,000배, GPU 메모리 요구량을 3배 줄일 수 있습니다. RoBERTa, DeBERTa, GPT-2 및 GPT-3에서 미세 조정보다 같거나 더 나은 모델 품질을 보이며, 훈련 가능한 파라미터가 적고 훈련 처리량이 높으며 어댑터와 달리 추가 추론 대기 시간이 없습니다. 또한, 언어 모델 적용에서의 랭크 결핍에 대한 경험적 조사를 제공하여 LoRA의 효과성에 대한 인사이트를 제공합니다. PyTorch 모델과 LoRA의 통합을 용이하게 하는 패키지를 출시하며, 이 https URL에서 RoBERTa, DeBERTa 및 GPT-2에 대한 우리의 구현 및 모델 체크포인트를 제공합니다.

첫 번째 정의는 컴퓨터가 이제 평범한 영어를 사용하여 프로그래밍될 수 있다는 LLMs에서 나오는 주요 혁신을 전달합니다. 두 번째 포인트는 프롬프트 엔지니어링을 주로 경험적인 노력으로 틀을 짜며, 이 새로운 프로그래밍 방식의 주요 탐험가들은 실무자, 실험가들입니다.

세 번째 포인트(Andrej Karpathy로부터)는 우리에게 LLMs가 우리가 LLMs에게 요청하는 거의 모든 것을 명시적으로 훈련받지 않았다는 것을 상기시켜 줍니다. 따라서 어떤 의미에서는 이 언어 모델들을 속여 문제를 해결하고 있다고 할 수 있습니다. 이것은 프롬프트 엔지니어링의 본질을 포착한 것 같습니다. 프롬프트 엔지니어링은 기술적인 능력보다는 창의력에 더 의존합니다.

더 쉬운 방법과 조금 덜 쉬운 방법: 프롬프트 엔지니어링의 2단계
이 시리즈의 첫 번째 글에서 프롬프트 엔지니어링을 할 수 있는 두 가지 구별되는 방법에 대해 소개했는데, 나는 이를 “쉬운 방법”과 “조금 덜 쉬운 방법”이라고 부르겠습니다.

쉬운 방법
대부분의 사람들이 프롬프트 엔지니어링을 하는 방법으로, ChatGPT(또는 유사한 것)를 통해 이루어집니다. 이는 직관적이고 코드 없이, 비용 없이 LLM과 상호 작용하는 방법입니다.

이 방법은 텍스트 페이지를 요약하거나 이메일을 다시 쓰거나 생일 파티 계획에 대한 브레인스토밍을 돕는 것과 같이 빠르고 간단한 작업에 대해 좋은 접근 방법이지만 단점이 있습니다. 큰 단점 중 하나는 이 방법을 더 큰 자동화 프로세스나 소프트웨어 시스템에 쉽게 통합하기가 어렵다는 것입니다. 이를 위해서는 한 단계 더 나아가야 합니다.

조금 덜 쉬운 방법
이 방법은 LLMs와 프로그래밍 방식으로 즉, 파이썬을 사용하여 상호 작용함으로써 “쉬운 방법”의 많은 단점을 해결합니다. 이 시리즈의 이전 두 글에서 OpenAI의 Python APIHugging Face Transformers 라이브러리를 탐구하면서 이것을 어떻게 할 수 있는지 감을 얻었습니다.

이 방법은 더 많은 기술적 지식을 필요로 하지만, 프롬프트 엔지니어링의 진정한 힘이 여기에 있습니다. 왜냐하면 이를 통해 개발자들이 LLM 기반의 모듈을 더 큰 소프트웨어 시스템에 통합할 수 있기 때문입니다.

이에 대한 좋은 (아마도 아이러니한) 예는 ChatGPT입니다. 이 제품의 핵심은 사전 훈련된 모델 (즉, GPT-3.5-turbo)을 챗봇처럼 작동하게 하는 것이고, 그것을 사용하기 쉬운 웹 인터페이스로 감싸는 것입니다.

물론, GPT-3.5-turbo를 개발하는 것이 어려운 부분이지만, 여기서 우리가 걱정할 필요가 없습니다. 우리 손끝에 있는 모든 사전 훈련된 LLMs 덕분에, AI 연구원이나 기계 학습 박사가 아니더라도 기본 프로그래밍 능력을 가진 거의 모든 사람이 ChatGPT와 같은 강력한 AI 응용 프로그램을 만들 수 있습니다.

프롬프트 엔지니어링으로 AI 앱 만들기

조금 덜 쉬운 방법은 프로그래밍 및 소프트웨어 개발의 새로운 패러다임을 열어줍니다. 더 이상 개발자들이 소프트웨어 시스템에서 모든 로직을 정의해야 하는 것은 아닙니다. 그들은 이제 LLMs에게 중요한 부분을 위임하는 옵션을 가지게 되었습니다. 이것이 어떻게 보일지 구체적인 예를 살펴보겠습니다.

고등학교 역사 수업을 위한 자동 채점기를 만들고 싶다고 가정해보십시오. 그러나 문제는 모든 질문에 대한 답이 작성된 응답이 있으므로 올바른 대답의 여러 버전이 있을 수 있다는 것입니다. 예를 들어 “미국의 35대 대통령은 누구였습니까?”라는 질문에 대한 다음의 응답이 올바를 수 있습니다.

  1. John F. Kennedy
  2. JFK
  3. Jack Kennedy (흔한 별명)
  4. John Fitzgerald Kennedy (추가 점수를 얻으려고 하는 것 같습니다)
  5. John F. Kenedy (마지막 이름을 잘못 적었습니다)

전통적인 프로그래밍 패러다임에서는 개발자가 이러한 모든 변형을 고려해야 했습니다. 이를 수행하기 위해 개발자는 모든 가능한 올바른 답변을 나열하고 정확한 문자열 일치 알고리즘을 사용하거나, 오타가 있는 단어를 도와주기 위해 퍼지 일치를 사용할 수도 있습니다.

그러나 이 새로운 LLM(대규모 언어 모델)을 활용한 패러다임에서는 간단한 프롬프트 엔지니어링을 통해 문제를 해결할 수 있습니다. 예를 들어, 학생의 답변을 평가하기 위해 다음과 같은 프롬프트를 사용할 수 있습니다.

“‘미국의 35대 대통령은 누구였습니까?’라는 질문에 대한 답변을 평가해주세요. 학생의 응답은 ‘[학생의 답변]’입니다. 이 답변이 정확한가요? 그렇지 않다면 왜 그런가요?”

이 프롬프트를 사용하면 LLM은 답변의 정확성을 검증할 뿐만 아니라 답변이 틀린 경우 그 이유도 제공할 수 있습니다. 이렇게 하면 학생의 답변의 뉘앙스와 가능한 변형을 고려하는 보다 유연하고 포괄적인 채점 메커니즘이 가능해집니다.

예를 들어 학생의 답변이 “John F. Kenedy”라면 LLM은 다음과 같이 응답할 수 있습니다:

“답변은 근접하지만 오타가 있습니다. 올바른 철자는 ‘John F. Kennedy’입니다. 따라서 답변은 부분적으로 정확합니다.”

이러한 뉘앙스 있는 피드백은 채점뿐만 아니라 학생의 학습을 위해서도 매우 유익할 수 있습니다. 이렇게 LLM을 활용한 패러다임은 프롬프트 엔지니어링과 결합할 때 전통적인 프로그래밍 패러다임에서 상당히 복잡하고 노동 집약적인 작업을 처리하는 더 풍부하고 적응성 있는 방법을 제공한다는 것이 명확합니다.

You are a high school history teacher grading homework assignments. \
Based on the homework question indicated by “Q:” and the correct answer \
indicated by “A:”, your task is to determine whether the student's answer is \
correct.
Grading is binary; therefore, student answers can be correct or wrong.
Simple misspellings are okay.
 
Q: {question}
A: {correct_answer}
 
Student Answer: {student_answer}

이 프롬프트를 함수로 생각해볼 수 있습니다. 주어진 질문, 올바른 답변, 학생의 답변을 기반으로 학생의 성적을 생성합니다. 이것은 자동 채점기를 구현하는 더 큰 소프트웨어에 통합될 수 있습니다.

시간 절약 측면에서 이 프롬프트를 작성하는 데 약 2분이 걸렸습니다. 반면 같은 작업을 수행하는 알고리즘을 개발하려면 수 시간 (또는 몇 일)이 걸리고 성능이 더 나쁠 것입니다. 따라서 이런 작업의 경우 시간 절약은 100-1000배에 달합니다.

물론 LLMs가 큰 이점을 제공하지 않는 많은 작업들이 있고, 다른 기존 방법이 훨씬 더 적합합니다 (예: 내일의 날씨 예측). LLMs가 모든 문제의 해결책이 되지는 않지만, 자연어를 효과적으로 처리해야 하는 작업에 대한 새로운 해결책을 제공합니다. 이것은 컴퓨터가 역사적으로 어려워했던 일입니다.

프롬프트 엔지니어링을 위한 7가지 꿀팁

앞서 언급한 프롬프트 예시는 자동 채점 작업을 구성하는 자연스럽고 명백한 방법처럼 보일 수 있지만, 이는 특별히 프롬프트 엔지니어링의 휴리스틱(또는 “꿀팁”이라고 부를 것입니다)을 적용하여 작성되었습니다. 이러한 꿀팁들은 LLM 응답의 품질을 향상시키는 신뢰할 수 있는 방법으로 나타났습니다.

좋은 프롬프트를 작성하기 위한 많은 팁과 꿀팁이 있지만, 여기서는 몇몇의 참고 문헌[1,3-5]을 기반으로 가장 기본적인 것들(IMO)에 대한 논의를 제한합니다. 더 깊은 탐구를 원한다면, 여기에 인용된 자료들을 살펴보는 것을 추천합니다.

꿀팁 1: 풍부한 설명으로 표현하기 (더 많은 것이 좋다)

LLM의 주요 특징 중 하나는 방대한 텍스트 말뭉치에서 훈련받았다는 것입니다. 이를 통해 LLM은 세상에 대한 광대한 지식을 갖추게 되며, 다양한 작업을 수행할 수 있는 능력을 가지게 됩니다. 그러나 이러한 인상적인 범용성은 적절한 맥락이 제공되지 않으면 특정 작업의 성능을 저해할 수 있습니다.

예를 들어, 아버지의 생일 메시지를 생성하기 위한 두 가지 프롬프트를 비교해봅시다.

Without Trick

Write me a birthday message for my dad.

With Trick

Write me a birthday message for my dad no longer than 200 \
characters. This is a big birthday because he is turning 50. To celebrate, \
I booked us a boys’ trip to Cancun. Be sure to include some cheeky humor, he \
loves that.

꿀팁 2: 예시 제공하기 (few-shot learning)

다음 꿀팁은 LLM이 특정 작업에서의 성능을 향상시키기 위해 예시 응답을 제공하는 것입니다. 이를 위한 기술 용어는 퓨샷 학습(few-shot learning)이며, 이는 LLM의 성능을 크게 향상시키는 것으로 나타났습니다[6].

구체적인 예를 들어 보겠습니다. 가령, 우리가 Towards Data Science 기사에 대한 부제를 작성하고 싶다고 가정합시다. 기존의 예시를 사용하여 LLM의 완성을 안내할 수 있습니다.

Without Trick

Given the title of a Towards Data Science blog article, write a subtitle for it.

Title: Prompt Engineering—How to trick AI into solving your problems
Subtitle:

With Trick

Given the title of a Towards Data Science blog article, write a subtitle for it.

Title: A Practical Introduction to LLMs
Subtitle: 3 levels of using LLMs in practice

Title: Cracking Open the OpenAI (Python) API
Subtitle: A complete beginner-friendly introduction with example code

Title: Prompt Engineering-How to trick AI into solving your problems
Subtitle:

꿀팁 3: 구조화된 텍스트 사용하기

프롬프트가 조직적인 구조를 따르게 하면 읽고 쓰기가 더 쉬워지며, 모델이 좋은 완성을 생성하는 데도 도움이 됩니다. 우리는 꿀팁 2의 예에서 제목과 부제를 각각 명시적으로 레이블링함으로써 이 기법을 사용했습니다.

그러나 프롬프트에 구조를 제공하는 방법은 수없이 많습니다. 강조를 위해 대문자를 사용하거나, 텍스트 덩어리를 강조하기 위해 “`와 같은 구분자를 사용하거나, 텍스트를 포맷하기 위해 Markdown이나 HTML과 같은 마크업 언어를 사용하거나, 정보를 조직화하기 위해 JSON을 사용하는 등의 여러 예시가 있습니다.

Without Trick

Write me a recipe for chocolate chip cookies.

With Trick

Create a well-organized recipe for chocolate chip cookies. Use the following \
formatting elements:

**Title**: Classic Chocolate Chip Cookies
**Ingredients**: List the ingredients with precise measurements and formatting.
**Instructions**: Provide step-by-step instructions in numbered format, detailing the baking process.
**Tips**: Include a separate section with helpful baking tips and possible variations.

꿀팁 4: 사고의 연쇄(Chain of Thought, CoT)

이 꿀팁은 Wei 등에 의해 제안되었습니다 [7]. 기본 아이디어는 LLM에게 “단계별로” 생각하도록 안내하는 것입니다. 이렇게 하면 복잡한 문제를 관리 가능한 부분 문제로 분해할 수 있어 LLM에게 “생각할 시간을 주게” 됩니다 [3,5]. Zhang 등은 이것이 프롬프트에 “단계별로 생각하자”라는 텍스트를 포함하는 것만큼 간단할 수 있다고 보여주었습니다 [8].

이 개념은 모든 레시피와 같은 과정에 확장될 수 있습니다. 예를 들어, 내 최근의 Medium 블로그를 기반으로 LinkedIn 게시물을 만들고 싶다면, 나의 단계별 과정을 따르도록 LLM을 안내할 수 있습니다.

Without Trick

Write me a LinkedIn post based on the following Medium blog.

Medium blog: {Medium blog text}

With Trick

Write me a LinkedIn post based on the step-by-step process and Medium blog \
given below.

Step 1: Come up with a one line hook relevant to the blog.
Step 2: Extract 3 key points from the article
Step 3: Compress each point to less than 50 characters.
Step 4: Combine the hook, compressed key points from Step 3, and a call to action \
to generate the final output.

Medium blog: {Medium blog text}

꿀팁 5: 챗봇 페르소나

LLM의 성능을 향상시키는 다소 놀라운 기법 중 하나는 특정 페르소나를 취하도록 그것을 유도하는 것입니다. 예를 들어 “당신은 전문가다“. 이것은 유용합니다. 왜냐하면 LLM에게 어떻게 문제를 최선으로 설명할지 모를 수 있지만, 그 문제를 어떻게 해결할지 도와줄 사람을 알 수 있기 때문입니다 [1]. 실제로 이것이 어떻게 보일지 보겠습니다.

Without Trick

Make me a travel itinerary for a weekend in New York City.

With Trick

Act as an NYC native and cabbie who knows everything about the city. \
Please make me a travel itinerary for a weekend in New York City based on \
your experience. Don’t forget to include your charming NY accent in your \
response.

꿀팁 6: 뒤집힌 접근법

우리가 LLM이 무엇을 알고 있고 어떻게 생각하는지 모를 때 그것을 최적으로 유도하는 것은 어려울 수 있습니다. 이럴 때 “뒤집힌 접근법”이 도움이 될 수 있습니다. 여기서는 LLM에게 문제를 충분히 이해할 때까지 (즉, 문맥) 질문을 하도록 유도합니다.

Without Trick

What is an idea for an LLM-based application?

With Trick

I want you to ask me questions to help me come up with an LLM-based \
application idea. Ask me one question at a time to keep things conversational.

꿀팁 7: 반영, 검토, 및 정제

이 마지막 꿀팁은 모델에게 이전의 응답을 반영하여 개선하도록 합니다. 일반적인 사용 사례는 모델에게 “과제를 완료했는지” 확인하거나 응답 뒤에 “논리와 가정을 설명하라”고 요청하는 것입니다 [1, 3].

또한 LLM에게 응답뿐만 아니라 귀하의 프롬프트도 정제하도록 요청할 수 있습니다. 이것은 모델이 “이해하기” 쉽게 프롬프트를 자동으로 다시 작성하는 간단한 방법입니다.

With Trick

Review your previous response, pinpoint areas for enhancement, and offer an \
improved version. Then explain your reasoning for how you improved the response.

예제 코드: LangChain을 이용한 자동 채점기

이제 우리는 여러 프롬프트 엔지니어링의 원칙들을 검토했습니다. 이러한 원칙들을 특정한 사용 사례에 어떻게 적용할 수 있는지 알아보겠습니다. 이를 위해 이전에 언급했던 자동 채점기 예제로 돌아가보겠습니다.

우리는 앞서 언급된 프롬프트 엔지니어링의 원칙들을 사용하여 기본적인 자동 채점기를 만들 수 있습니다. 이러한 트릭들을 통합함으로써 채점 과정에서 더 높은 정확도와 신뢰성을 보장할 수 있습니다.

You are a high school history teacher grading homework assignments. \
Based on the homework question indicated by "Q:" and the correct answer \
indicated by "A:", your task is to determine whether the student's answer is \
correct.
Grading is binary; therefore, student answers can be correct or wrong.
Simple misspellings are okay.
 
Q: {question}
A: {correct_answer}
 
Student Answer: {student_answer}

이전에 언급된 몇 가지 트릭들이 명확하게 보일 것입니다. 즉, 트릭 6: 챗봇의 패르소나, 트릭 3: 구조화된 텍스트 사용, 트릭 1: 상세하게 설명하기. 이렇게 여러 기법을 하나의 프롬프트에 결합하는 것이 일반적으로 실제에서 좋은 프롬프트를 작성하는 것으로 보입니다.

이 프롬프트 템플릿을 ChatGPT에 복사 및 붙여넣기하여 question, correct_answer, student_answer 필드를 교체할 수 있지만, 이는 자동 채점기를 구현하는 확장 가능한 방법이 아닙니다. 오히려 우리가 원하는 것은 이 프롬프트를 더 큰 소프트웨어 시스템에 통합하는 것이므로, 사람이 사용할 수 있는 사용자 친화적인 애플리케이션을 구축할 수 있습니다.

LangChain

우리가 이를 할 수 있는 한 가지 방법은 LangChain을 사용하는 것입니다. LangChain은 대규모 언어 모델 위에 애플리케이션을 구축하는 것을 단순화하는데 도움을 주는 Python 라이브러리입니다. 이것은 프로그래밍 방식으로 LLM을 사용하기 위한 다양한 편리한 추상화를 제공함으로써 이를 수행합니다.

이것을 하는 중심 클래스는 chain이라고 불립니다. 이것은 프롬프트를 생성하는 과정, LLM에 보내는 과정, 출력을 구문 분석하는 과정을 추상화하여 쉽게 호출되고 더 큰 스크립트에 통합될 수 있게 합니다.

우리의 자동 채점기 사례에 LangChain을 어떻게 사용하는지 살펴보겠습니다. 예제 코드는 이 글을 위한 GitHub 저장소에서 사용할 수 있습니다.

Imports

먼저 필요한 라이브러리 모듈을 가져옵니다.

from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.schema import BaseOutputParser

여기서는 gpt-3.5-turbo를 사용할 것이며, OpenAI의 API를 위한 비밀 키가 필요합니다. 만약 하나가 없다면, 이 시리즈의 이전 글에서 하나를 가져오는 방법에 대한 단계별 가이드를 제공했습니다. 나는 비밀 키를 별도의 파이썬 파일(sk.py)에 저장하고 아래 코드 라인으로 가져오는 것을 선호합니다.

from sk import my_sk #다른 파이썬 파일에서 비밀 키 가져오기

우리의 첫 번째 체인

체인을 정의하려면 두 가지 핵심 요소가 필요합니다: LLM(대형 언어 모델)과 프롬프트입니다. LLM의 객체를 생성하여 시작합니다.

# LLM 객체 정의
chat_model = ChatOpenAI(openai_api_key=my_sk, temperature=0)

LangChain에는 OpenAI (및 많은 다른) 채팅 모델을 위한 클래스가 특별히 있습니다. 내 비밀 API 키를 전달하고 온도를 0으로 설정합니다. 여기의 기본 모델은 gpt-3.5-turbo이지만, “model_name” 입력 인수를 사용하여 gpt-4를 대신 사용할 수 있습니다. 다른 입력 인수를 설정하여 채팅 모델을 더욱 사용자 정의할 수 있습니다.

다음으로, 우리는 우리의 프롬프트 템플릿을 정의합니다. 이 객체를 사용하면 기본 템플릿을 자동으로 업데이트하는 입력 문자열을 통해 프롬프트를 동적으로 생성할 수 있습니다.

# 프롬프트 템플릿 정의
prompt_template_text = """고등학교 역사 선생님으로서 숙제를 채점하고 있습니다. \
“**Q:**”로 표시된 숙제 질문과 “**A:**”로 표시된 정답을 기반으로 학생의 답이 맞는지 \
결정하는 것이 당신의 임무입니다. 채점은 이진적이므로 학생의 답은 올바르거나 틀릴 수 있습니다. \
간단한 철자 오류는 괜찮습니다.

**Q:** {question}
**A:** {correct_answer}

**학생의 답:** {student_answer}
"""

prompt = PromptTemplate(
            input_variables=["question", "correct_answer", "student_answer"], \
            template = prompt_template_text)

이 코드는 프롬프트를 동적으로 생성하기 위한 템플릿을 정의하는 것입니다. 입력 변수 (질문, 정답, 학생의 답)를 사용하여 주어진 정보를 기반으로 프롬프트를 생성합니다.

LLM과 프롬프트가 준비되었으므로 이제 우리의 체인을 정의할 수 있습니다.

# 체인 정의
chain = LLMChain(llm=chat_model, prompt=prompt)

다음으로, 체인에 입력을 전달하고 한 줄의 코드로 채점을 얻을 수 있습니다.

# 입력 정의
question = "미국의 35번째 대통령은 누구였나요?"
correct_answer = "존 F. 케네디"
student_answer =  "FDR"

# 체인 실행
chain.run({'question':question, 'correct_answer':correct_answer, \
    'student_answer':student_answer})

# 출력: 학생의 답은 틀렸습니다.

이 체인은 채점 작업을 효과적으로 수행할 수 있지만, 그 출력은 자동화된 과정에 적합하지 않을 수 있습니다. 예를 들어, 위의 코드 블록에서, LLM은 학생의 답인 “FDR”이 틀렸다고 올바르게 말했지만, LLM이 다운스트림 처리에서 사용될 수 있는 표준 형식으로 출력하는 것이 더 좋을 것입니다.

Output parser

출력 파서는 여기서 중요한 역할을 합니다. 이러한 함수들은 LLM 출력을 표준 형식으로 변환하기 위해 체인에 통합할 수 있습니다. LLM 응답을 부울 (즉, 참 또는 거짓) 출력으로 변환하는 출력 파서를 어떻게 만들 수 있는지 살펴봅시다.

# 출력 파서 정의
class GradeOutputParser(BaseOutputParser):
    """학점이 올바른지 또는 잘못된지 결정합니다."""

    def parse(self, text: str):
        """LLM 호출의 출력을 파싱합니다."""
        return "wrong" not in text.lower()

여기서 우리는 LLM의 출력에 “wrong”이라는 단어가 있는지 확인하는 간단한 출력 파서를 생성합니다. 그렇지 않은 경우 학생의 답이 올바르다는 것을 나타내는 True를 반환합니다. 그렇지 않으면 학생의 답이 잘못되었다는 것을 나타내는 False를 반환합니다.

우리는 이 출력 파서를 체인에 통합하여 체인을 실행할 때 텍스트를 원활하게 파싱할 수 있습니다.

# 체인 업데이트
chain = LLMChain(
    llm=chat_model,
    prompt=prompt,
    output_parser=GradeOutputParser()
)

마지막으로, 우리는 학생의 답변 전체 목록에 대해 체인을 실행하고 출력을 인쇄할 수 있습니다.

# for 루프에서 체인 실행
student_answer_list = ["John F. Kennedy", "JFK", "FDR", "John F. Kenedy", \
                  "John Kennedy", "Jack Kennedy", "Jacquelin Kennedy", \
                  "Robert F. Kenedy"]

for student_answer in student_answer_list:
    print(student_answer + " - " + 
      str(chain.run({'question':question, 'correct_answer':correct_answer, \
                    'student_answer':student_answer})))
    print('\n')

출력 결과:

John F. Kennedy - True
JFK - True
FDR - False
John F. Kenedy - True
John Kennedy - True
Jack Kennedy - True
Jacqueline Kennedy - False
Robert F. Kenedy - False

이렇게 하면 LLM의 출력을 프로그램적으로 사용할 수 있는 표준 형식으로 원활하게 변환하는 방법을 확인할 수 있습니다.

제한 사항

프롬프트 엔지니어링은 ChatGPT에게 이메일 작성 도움을 요청하거나 양자 컴퓨팅에 대해 배우는 것 이상의 것입니다. 이것은 개발자가 응용 프로그램을 구축하는 방법을 변경하는 새로운 프로그래밍 패러다임입니다.

이것은 강력한 혁신이지만 그 제한점도 있습니다. 첫째, 최적의 프롬프트 전략은 LLM에 의존적입니다. 예를 들어, GPT-3에 “단계별로 생각하라”는 프롬프트를 주었을 때 간단한 수학적 추론 작업에서 중요한 성능 향상을 보였습니다[8]. 그러나 최신 버전의 ChatGPT에 대해서는 동일한 전략이 도움이 되지 않는 것 같습니다(이미 단계별로 생각합니다).

프롬프트 엔지니어링의 또 다른 제한 사항은 ChatGPT와 같은 대규모 범용 언어 모델이 필요하며 이로 인해 상당한 연산 및 재정 비용이 발생한다는 것입니다. 이것은 문자열 일치, 감정 분석 또는 텍스트 요약과 같이 좁게 정의된 많은 사용 사례에 과도한 것일 수 있습니다.

이 두 가지 제한 사항을 모두 극복할 수 있는 방법은 사전 훈련된 언어 모델을 세밀하게 조정하는 것입니다. 이것은 기존 언어 모델을 특정 사용 사례에 맞게 조정하는 것입니다. 이 시리즈의 다음 기사에서는 예제 Python 코드를 보완하여 인기 있는 세밀 조정 기법을 탐색하겠습니다.


답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다