프롬프트 엔지니어링: 실용적인 예시

*Prompt Engineering: A Practical Example

*A Kantian-Inspired Prompting Framework for Enhancing Large Language Model Capabilities

ChatGPT를 사용해봤고 대규모 언어 모델(LLM)이 작업 지원에 갖는 잠재력을 이해하고 계신가요? 이미 LLM 지원 애플리케이션을 개발 중이거나 프롬프트 엔지니어링 개념에 대해 알고 있을지 모르지만 이론적인 개념을 실제 예시로 구체화하는 방법을 몰라 헤매고 있을 수도 있습니다.

텍스트 프롬프트는 LLM의 응답을 지시하는 역할을 하기 때문에 조금만 변경해도 완전히 다른 결과를 얻을 수 있습니다. 이 튜토리얼에서는 실제 사례에 여러 프롬프트 엔지니어링 기술을 적용해 보겠습니다. 이를 통해 반복적인 과정으로 진행되는 프롬프트 엔지니어링을 직접 경험하고, 다양한 기술을 적용하는 효과를 확인하며 머신 러닝 및 데이터 엔지니어링과 관련된 개념을 배울 수 있습니다.

이 튜토리얼을 통해 다음과 같은 방법을 배우게 됩니다:

  • OpenAI의 GPT-3.5 및 GPT-4 모델을 API를 통해 사용하는 방법
  • 실용적인 실제 사례에 프롬프트 엔지니어링 기술 적용
  • 결과 향상을 위한 번호 매기기, 구분자 사용, 소수 샷 프롬프팅 활용
  • 사고 과정 연결(prompting to chain-of-thought) 프롬프팅을 통해 더 많은 맥락 추가 및 활용
  • 단일 역할 프롬프트 외에도 메시지 내 역할의 강점 활용
  • 자신의 LLM 지원 작업에 맞게 재활용할 수 있는 파이썬 스크립트를 사용하여 작업

따라서 실용적인 예시를 통해 LLM으로부터 더 나은 결과를 얻기 위해 프롬프트 엔지니어링을 사용하는 방법을 배우고 싶다면 이 튜토리얼이 적합합니다!

프롬프트 엔지니어링의 목적 이해하기

프롬프트 엔지니어링은 단순한 유행어가 아닙니다. 서로 다른 프롬프트를 사용하면 LLM에서 크게 다른 출력을 얻을 수 있습니다. 이는 서로 다른 질문을 할 때 다른 답변을 얻는 것과 같다고 생각하면 당연해 보일 수 있습니다. 하지만 같은 개념의 질문을 다르게 표현하는 경우에도 적용됩니다. 프롬프트 엔지니어링은 특정한 접근 방식을 사용하여 LLM에 대한 텍스트 입력을 구성하는 것을 의미합니다.

프롬프트는 인수로, LLM은 이 인수를 전달하는 함수로 생각할 수 있습니다. 입력이 다르면 출력도 달라집니다.

다음은 파이썬 코드의 예시입니다.

Python

def hello(name):
    print(f"Hello, {name}!")

>>> hello("World")
Hello, World!
>>> hello("Engineer")
Hello, Engineer!

이 코드에서 볼 수 있듯이 함수에 전달하는 인수에 따라 출력이 달라집니다. 프롬프트 엔지니어링도 마찬가지입니다. LLM에 제공하는 프롬프트를 신중하게 구성하면 원하는 결과를 얻을 가능성이 훨씬 높아집니다.

LLM은 위 코드처럼 간단한 함수는 아니지만, 기본적인 아이디어는 동일합니다. 원하는 결과를 얻기 위해서는 함수 호출 시 정확히 어떤 인수가 원하는 출력을 생성하는지 알아야 합니다. LLM의 경우, 그 인수는 많은 토큰(words의 조각)으로 구성된 텍스트입니다.

주의: 함수와 인수의 비유는 OpenAI의 LLM을 다룰 때 한계가 있습니다. 위의 hello() 함수는 동일한 입력을 주면 항상 같은 결과를 반환하지만, LLM 상호 작용의 결과는 100% 결정론적이지 않습니다. 이는 현재 이 모델들의 작동 방식에 내재되어 있습니다.

프롬프트 엔지니어링 분야는 빠르게 변화하고 있으며, 이 분야에서는 활발한 연구가 진행되고 있습니다. LLM이 계속 발전함에 따라 최상의 결과를 얻을 수 있는 프롬프팅 접근 방식도 함께 발전할 것입니다.

이 튜토리얼에서는 여러분의 LLM 지원 프로젝트에서 더 나은 텍스트 완성을 얻기 위해 사용할 수 있는 몇 가지 프롬프트 엔지니어링 기술과 프롬프트를 반복적으로 개발하는 접근 방식을 다룰 것입니다:

  • 제로샷 프롬프팅(Zero-Shot Prompting): 사전 학습 데이터만 사용하여 완성
  • 소수샷 프롬프팅(Few-Shot Prompting): 몇 개의 예시를 제공하여 학습
  • 구분자(Delimiters)
  • 번호 매기기(Numbered Steps)
  • 구체성 증가(Increased Specificity)
  • 역할 프롬프트(Role Prompts)
  • 사고의 연쇄 프롬프팅(Chain-of-Thought, CoT Prompting)
  • 구조화된 출력(Structured Output)
  • 라벨이 지정된 대화(Labeled Conversations)

더 많은 기술을 발견할 수 있으며, 튜토리얼에서 추가 자료에 대한 링크도 찾을 수 있습니다. 언급된 기술을 실제 예시에 적용하는 것은 여러분의 LLM 지원 프로그램을 개선하기 위한 출발점이 될 것입니다. 만약 여러분이 LLM을 이전에 사용해본 적이 없다면, 시작하기 전에 OpenAI의 GPT 문서를 둘러보는 것이 좋을 수 있지만, 어느 쪽이든 따라갈 수 있어야 합니다.

실용적인 프롬프트 엔지니어링 프로젝트 소개

이 튜토리얼에서는 실제 예시를 통해 다양한 프롬프트 엔지니어링 기술을 탐구할 것입니다. 그 예시는 고객 채팅 대화 내용을 정리하는 것입니다. 실제 프로젝트에 여러 프롬프트 엔지니어링 기술을 사용하여 연습함으로써 어떤 기술을 다른 기술보다 선호하는지, 그리고 실제로 어떻게 적용할 수 있는지 잘 이해할 수 있습니다.

상상해보세요. 여러분은 매일 수천 건의 고객 지원 채팅을 처리하는 회사의 파이썬 개발자입니다. 여러분의 임무는 이러한 대화 내용을 정리하고 필터링하는 것입니다. 또한 어떤 대화가 추가적인 주의가 필요한지 판단하는 데도 도움을 주어야 합니다.

이 프로젝트를 위해 여러분은 다음과 같은 작업을 수행할 수 있습니다:

  1. 제로샷 프롬프팅을 사용하여 채팅 내용이 특정 기준(예: 욕설, 개인 정보 포함 등)에 부합하는지 판단하는 모델을 생성합니다.
  2. 소수샷 프롬프팅으로 몇 가지 예제를 제공하여 모델이 어떤 종류의 채팅이 추가 조사가 필요한지 더 잘 이해할 수 있도록 합니다.
  3. 구분자번호 매기기를 활용하여 대화를 분석하고, 필요한 조치(예: 삭제, 익명 처리, 플래그 지정)를 취할 수 있도록 합니다.
  4. 구체성 증가역할 프롬프트를 통해 모델이 각 대화의 맥락을 더 잘 파악하고, 특정 요구 사항에 맞게 대응할 수 있도록 합니다.
  5. 사고의 연쇄 프롬프팅구조화된 출력을 사용하여 복잡한 문제 해결 과정을 모델링하고, 모델이 더 명확하고 유용한 응답을 제공하도록 합니다.
  6. 라벨이 지정된 대화를 사용하여 훈련 데이터를 개선하고, 모델의 정확성과 효율성을 높입니다.

작업 수집

고객 채팅 대화 처리를 원활하게 해결하도록 회사를 돕는 것이 이번 과제의 큰 목표입니다. 작업할 대화는 아래와 같은 형식일 수 있습니다.

Text
[support_tom] 2023-07-24T10:02:23+00:00 : What can I help you with?
[johndoe] 2023-07-24T10:03:15+00:00 : I CAN'T CONNECT TO MY BLASTED ACCOUNT
[support_tom] 2023-07-24T10:03:30+00:00 : Are you sure it's not your caps lock?
[johndoe] 2023-07-24T10:04:03+00:00 : Blast! You're right!

여러 가지 방법으로 고객 지원 부서가 추후 처리할 수 있도록 이러한 텍스트 대화를 더 쉽게 접근할 수 있게 만들어야 합니다:

  • 개인 식별 정보 삭제
  • 욕설 제거
  • 날짜 정보만 표시하도록 날짜 및 시간 정보 정리

이러한 작업을 수행함으로써, 대화 내용을 더 명확하고 접근하기 쉬운 형식으로 변환하여, 고객 지원 팀이 더 효율적으로 처리할 수 있도록 합니다. 이 과정에서 프롬프트 엔지니어링 기술을 적용하여, 해당 작업을 자동화하고 최적화하는 스크립트나 프로그램을 개발할 수 있습니다.

이미 이해한 부분이 있으신가요? 다음 단계는 이러한 과제를 완료하기 위해 사용할 수 있는 다양한 프롬프트 엔지니어링 기술을 살펴보는 것입니다.

이 튜토리얼에서 만나게 될 욕설은 모두 부드러운 표현이지만, 현실 세계에서 더 노골적인 표현을 대신하는 것으로 생각할 수 있습니다. 채팅 대화를 정리한 후에는 다음과 같이 보일 것으로 예상됩니다.

[Agent] 2023-07-24 : What can I help you with?
[Customer] 2023-07-24 : I CAN'T CONNECT TO MY 😤 ACCOUNT
[Agent] 2023-07-24 : Are you sure it's not your caps lock?
[Customer] 2023-07-24 : 😤! You're right!

물론 파이썬의 str.replace()를 사용하거나 정규 표현식 기술을 과시할 수도 있습니다. 하지만 이 작업은 생각보다 훨씬 더 많습니다.

프로젝트 관리자는 기술 전문가가 아니며 이 목록 끝에 또 다른 작업을 넣었습니다. 그는 이 작업을 이전 작업의 일반적인 연속으로 생각할 수 있습니다. 하지만 여러분은 이 작업이 완전히 다른 접근 방식과 기술 스택을 필요로 한다는 것을 알고 있습니다.

  • 대화를 “긍정적” 또는 “부정적”으로 표시

이 작업은 텍스트 분류, 좀 더 구체적으로는 감정 분석이라는 머신 러닝 영역에 속합니다. 심지어 고급 정규 표현식 기술도 이 과제에서 많은 도움이 되지 않습니다.

또한 데이터를 준비하고 있는 고객 지원 팀은 프로그램을 통해 계속 작업하기를 원할 것입니다. 일반 텍스트는 반드시 그 용도에 가장 적합한 형식은 아닙니다. 다른 사람에게 유용한 작업을 하고 싶기 때문에 작업 목록에 또 다른 확장 목표를 추가합니다.

  • 출력을 JSON 형식으로 변환

작업 목록이 빠르게 커지고 있습니다! 다행히도 OpenAI API에 액세스할 수 있으며 LLM의 도움을 받아 이러한 모든 과제를 해결할 수 있습니다.

이 튜토리얼의 예시는 파이썬 개발자로서 LLM을 활용하여 작업을 수행하는 데 도움이 될 수 있는 현실적인 시나리오를 제공하는 것을 목표로 합니다. 그러나 개인 식별 정보를 정리하는 것은 매우 중요한 작업이라는 점을 유의해야 합니다. 실수로 정보가 유출되지 않도록 주의해야 합니다.
OpenAI API와 같은 클라우드 기반 서비스를 사용하는 데도 잠재적인 위험이 있습니다. 회사는 무역 비밀과 같은 중요한 정보가 유출되는 것을 방지하기 위해 OpenAI API에 데이터를 보내는 것을 원하지 않을 수 있습니다.
마지막으로, API 사용은 무료가 아니며 모델이 처리하는 토큰 수에 따라 각 요청에 대해 비용을 지불해야 한다는 점을 기억하십시오.

LLM의 흥미로운 특징 중 하나는 사용할 수 있는 작업 범위가 매우 넓다는 것입니다. 따라서 다양한 영역을 다루게 될 것이며, 프롬프트 엔지니어링 기술을 사용하여 이 모든 영역을 어떻게 해결할 수 있는지 배울 것입니다.

도구 준비

튜토리얼을 따라 하려면 커맨드라인 인터페이스(CLI)에서 Python 스크립트를 실행하는 방법과 OpenAI의 API 키가 필요합니다.

참고: OpenAI API 키가 없거나 Python 스크립트 실행 경험이 없다면 ChatGPT 웹 인터페이스에 프롬프트를 복사하여 붙여넣어 작업을 계속할 수 있습니다. 반환되는 텍스트는 약간 다를 수 있지만 여전히 서로 다른 프롬프트 엔지니어링 기술에 따라 응답이 어떻게 변하는지 확인할 수 있습니다.

프롬프트 엔지니어링에 중점을 두기 때문에 CLI 앱은 다양한 기술을 시연하는 도구로만 사용할 것입니다. 하지만 사용할 코드를 이해하고 싶다면 Python 클래스, Python 함수 정의, name-main 관용구 및 Python을 사용하여 웹 API와 상호 작용하는 데 대한 경험이 있으면 도움이 될 것입니다.

시작하려면 튜토리얼 전체에서 사용할 예시 Python 스크립트를 다운로드하십시오.

샘플 코드 받기: 클릭하여 샘플 코드를 다운로드하고 거대 언어 모델을 통한 프롬프트 엔지니어링을 통해 최대한 활용하세요.Click here to download the sample code

스크립트를 다운로드했으면 다음 단계는 OpenAI API 키를 얻는 것입니다.

도구 준비 – 코드에 대해 알아보기

코드베이스(codebase)는 OpenAI API 위에 가벼운 추상화 계층을 나타내며 튜토리얼에 주로 흥미로운 두 가지 기능을 제공합니다:

  • get_completion(): OpenAI의 GPT-3.5 모델(text-davinci-003)과 상호 작용하여 /completions 엔드포인트를 사용하여 텍스트 완성 내용을 생성합니다.
  • get_chat_completion(): OpenAI의 GPT-4 모델(gpt-4)과 상호 작용하여 /chat/completions 엔드포인트를 사용하여 응답을 생성합니다.

두 엔드포인트를 모두 탐색할 것이며, get_completion()으로 시작하여 나중에 더 강력한 GPT-4 모델을 사용한 get_chat_completion()으로 이동할 예정입니다. 이 스크립트는 커맨드라인 인수를 파싱하여 입력 파일을 편리하게 지정할 수 있도록 합니다.

주로 작업할 입력 파일에는 만들어진 고객 지원 채팅 대화가 포함되어 있지만, 스크립트를 재사용하고 추가 연습을 위해 자신의 입력 텍스트 파일을 제공하는 것도 좋습니다.

참고: 궁금하다면 잠시 시간을 내어 코드를 읽고 익숙해지세요. 스크립트를 이해하는 것은 이 튜토리얼에서 배우게 될 개념을 이해하는 데 필수적인 것은 아니지만, 실행하는 코드를 아는 것이 항상 더 좋습니다.

코드베이스의 핵심은 settings.toml입니다. 이 TOML 설정 파일은 프롬프트 엔지니어링 기술을 연마하는 데 사용할 프롬프트를 포함하고 있습니다. 여기에는 사람이 읽을 수 있는 TOML 포맷으로 작성된 다양한 프롬프트가 포함되어 있습니다.

프롬프트를 전용 설정 파일에 보관하면 버전 관리 시스템에 보관하는 데 도움이 될 수 있어, 개발 도중에 불가피하게 변경될 여러분의 프롬프트의 다양한 버전을 추적할 수 있게 됩니다.

참고: 이 튜토리얼에서 사용할 모든 프롬프트의 모든 버전을 README.md 파일에서 찾을 수 있습니다.

파이썬 스크립트는 settings.toml에서 프롬프트를 읽어서 API 요청으로 보낼 것입니다. 이 접근 방식은 프롬프트를 쉽게 관리하고, 실험을 통해 얻은 통찰력을 문서화하는 데 유용하며, 팀 구성원 간의 협업을 용이하게 합니다. 또한, 프롬프트의 변경 사항을 추적하고, 필요한 경우 이전 버전으로 쉽게 롤백할 수 있습니다.

대안으로, 모든 텍스트 프롬프트를 OpenAI 플레이그라운드에서 직접 실행할 수도 있습니다. 이는 스크립트와 동일한 기능을 제공할 것입니다. 심지어 프롬프트를 ChatGPT 창에 붙여넣을 수도 있습니다. 하지만, 다른 모델과 상호작용할 것이므로 결과가 달라질 수 있으며, 특정 설정을 변경할 기회가 없을 것입니다.

플레이그라운드나 ChatGPT를 사용하는 것은 특히 프로그래밍 경험이 제한적이거나 API 키에 접근할 수 없는 사용자에게 유용할 수 있습니다. 이 방식은 프롬프트 엔지니어링을 실습하고, 다양한 프롬프트가 LLM의 응답에 어떤 영향을 미치는지 직접 보는 데에도 효과적입니다. 그러나 스크립트를 사용할 때와 같이 세밀한 설정 조정이나 버전 관리의 이점은 없습니다.

코드베이스 설정하기

Python 3.11 이상 버전을 사용하고 있는지 확인하세요, 그래야 표준 라이브러리를 사용하여 TOML 파일과 상호작용할 수 있습니다. 아직 코드베이스를 다운로드하지 않았다면, 아래 링크를 클릭하여 진행하세요:

샘플 코드 받기: 프롬프트 엔지니어링을 통해 대규모 언어 모델을 최대한 활용할 수 있도록 도와줄 샘플 코드를 다운로드하려면 여기를 클릭하세요. Click here to download the sample code

폴더를 압축 해제하고 CLI를 사용하여 폴더로 이동하세요. 몇 가지 파일이 보일 것입니다. 가장 중요한 파일은 app.pysettings.toml입니다:

./
├── LICENSE
├── README.md
├── app.py
├── chats.txt
├── requirements.txt
├── sanitized-chats.txt
├── sanitized-testing-chats.txt
├── settings.toml
├── settings-final.toml
└── testing-chats.txt

settings.toml 파일에는 다양한 프롬프트 엔지니어링 기술을 탐색하기 위해 사용할 모든 프롬프트의 플레이스홀더가 포함되어 있습니다. 이 파일이 주로 작업할 파일이므로 열어보세요. 애플리케이션의 프롬프트를 반복적으로 개발하는 데 사용할 것입니다.

app.py 파일에는 코드베이스를 함께 묶는 파이썬 코드가 포함되어 있습니다. 이 스크립트를 튜토리얼 전반에 걸쳐 여러 번 실행할 것이며, settings.toml에서 프롬프트를 가져오는 작업을 처리할 것입니다.

코드베이스를 다운로드하고 압축을 푼 후, 새로운 가상 환경을 생성하고 활성화하세요. 이렇게 하면 시스템 전체 Python 설치에 영향을 미치지 않고 프로젝트에 필요한 특정 Python 패키지 버전을 관리할 수 있습니다. 그런 다음 pip를 사용하여 필요한 종속성을 설치하세요:

virtualenv --python=python3.11 venv
source myenv/bin/activate (Linux나 macOS)
(venv) $ python -m pip install -r requirements.txt

이 튜토리얼은 openai 버전 0.27.8을 사용합니다. OpenAI는 새로운 API 버전에서 일부 호환되지 않는 변경 사항을 도입했으므로, 요구 사항 파일에서 고정된 종속성을 설치해야 합니다. 그러면 튜토리얼을 문제없이 진행할 수 있습니다.

스크립트를 성공적으로 실행하려면 OpenAI API 키가 필요합니다. 이 API 요청을 인증하는 데 사용됩니다. 그 키를 비공개로 유지하고 버전 관리에 절대 커밋하지 않도록 주의하세요! API 키를 사용하는 것이 처음이라면, API 키 보안에 대한 모범 사례를 읽어보세요.

스크립트와 API 키를 통합하고 공개적으로 누출하지 않기 위해, API 키를 환경 변수로 내보낼 수 있습니다:

(venv) $ export OPENAI_API_KEY="your-api-key"

API 키를 OPENAI_API_KEY라는 환경 변수로 추가하면, 스크립트는 실행할 때마다 자동으로 그것을 감지할 것입니다.

이 시점에서 필요한 설정 단계를 완료했습니다. 이제 커맨드 라인을 사용하여 스크립트를 실행하고 추가 입력 텍스트로 파일을 제공할 수 있습니다:

*OpenAI 모델인 text-davinci-003이 더 이상 사용되지 않습니다. settings.toml에서 model 를 gpt-3.5-turbo-instruct로 수정하세요.

(venv) $ python app.py chats.txt

위 명령은 chats.txt 파일의 고객 지원 채팅 대화를 settings.toml에 저장된 프롬프트 및 API 호출 매개변수와 결합한 다음 OpenAI API에 요청을 보냅니다. 마지막으로 결과 텍스트 완성을 터미널에 출력합니다.

chats.txt
터미널 출력

참고: API 호출 매개변수와 프롬프트를 위해 settings.toml 파일을 사용하는 것은 단지 하나의 옵션입니다. 프로젝트 구성이 다르면 이 구조를 따를 필요는 없습니다.

파이썬 바인딩을 통해 OpenAI의 API로 호출하는 방법에 대한 자세한 정보는 공식 API 참조를 확인하세요.

이제부터는 주로 settings.toml에서 변경을 진행할 것입니다. app.py의 코드는 편의를 위해 포함되어 있으며 이 파일을 편집할 필요가 없습니다. LLM의 출력 변경은 프롬프트와 몇 가지 API 호출 인수를 변경하는 데서 비롯됩니다.

온도를 0으로 설정하여 응답 고정

제품이나 워크플로우에 대규모 언어 모델(LLM)을 통합할 계획이라면, 일반적으로 확정적인 응답을 원할 것입니다. 동일한 입력이 동일한 출력을 제공해야 합니다. 그렇지 않으면, 서비스의 일관성을 유지하거나 문제가 발생했을 때 프로그램을 디버깅하는 것이 어려워집니다.

따라서 API 호출의 temperature 인수를 0으로 설정해야 합니다. 이 값은 대부분 확정적인 결과를 얻을 수 있다는 것을 의미합니다.

LLM은 이전 토큰에 이어질 확률을 기반으로 다음 토큰을 예측하여 텍스트 완성을 수행합니다. 온도 설정이 높을수록 LLM이 낮은 확률을 가진 토큰을 선택할 수 있게 하여 결과에 더 많은 무작위성을 도입합니다. 한 쌍씩 서로 연결된 토큰 선택이 너무 많기 때문에 하나의 다른 토큰을 선택하면 완전히 다른 결과를 초래할 수도 있습니다.

프로그래밍 작업의 아이디어 생성이나 대안 구현을 생성하는 데 LLM을 사용한다면, 높은 temperature 값이 흥미로울 수 있습니다. 그러나 제품을 만들 때는 일반적으로 바람직하지 않습니다.

예제 코드베이스에서는 settings.toml 파일 내부에서 temperature를 조정할 수 있습니다:

[general]
chat_models = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4"]
model = "gpt-3.5-turbo-instruct"
max_tokens = 2100
temperature = 0

초기 값은 0으로 설정됩니다. 이 튜토리얼의 모든 예제는 temperature를 0으로 유지하여 대부분 확정적인 결과를 얻는다고 가정합니다. 더 높은 temperature가 출력에 어떤 변화를 주는지 실험하고 싶다면, 이 설정 파일에서 temperature 값을 변경하여 자유롭게 시도해 볼 수 있습니다.

OpenAI가 제공하는 현재 LLM 모델로는 temperature를 0으로 유지하더라도 완전한 결정론을 달성할 수 없다는 점을 기억하는 것이 중요합니다:

GPT-3의 중요한 함축적인 사례: 최고 2개 토큰 확률이 1% 미만 차이인 경우 추론은 (온도=0일 때도) 비결정론적입니다. 따라서 온도=0 출력은 결정론에 매우 가깝지만 실제로는 그렇지 않습니다. 기억해야 합니다. (출처)

따라서 모델이 항상 동일한 결과를 반환한다는 것을 완전히 보장할 수는 없지만, temperature를 0으로 설정함으로써 훨씬 더 가까운 결과를 얻을 수 있습니다.

프롬프트 엔지니어링 시작!

이제 프롬프트 엔지니어링과 실제로 작업할 프로젝트에 대한 이해가 생겼으니, 일부 프롬프트 엔지니어링 기술을 심층적으로 살펴볼 시간입니다. 이 섹션에서는 언어 모델로부터 원하는 출력을 얻기 위해 프롬프트에 다음 기술을 적용하는 방법을 배울 것입니다:

  • 제로샷 프롬프팅(Zero-shot prompting): 추가적인 맥락 없이 언어 모델에 일반적인 질문을 하는 방법
  • 퓨샷 프롬프팅(Few-shot prompting): 모델의 성능을 향상시키기 위해 몇 가지 예시로 모델을 조건화하는 방법
  • 구분자 사용(Using delimiters): 모델에 구조와 지시를 제공하기 위해 특수 토큰이나 구문을 추가하는 방법
  • 세부적인, 번호 매긴 단계(Detailed, numbered steps): 복잡한 프롬프트를 일련의 작고 구체적인 단계로 나누는 방법

고객 채팅 대화 예시를 통해 이러한 기술을 실습함으로써, 프롬프트 엔지니어링이 언어 모델의 능력을 어떻게 향상시키고 실제 애플리케이션에서의 유용성을 개선할 수 있는지에 대한 더 깊은 이해를 얻게 될 것입니다.

첫 번째 프롬프트 엔지니어링 기술: 제로샷 프롬프팅

프롬프트 엔지니어링 여정을 ‘제로샷 프롬프팅(Zero-shot prompting)’이라는 개념으로 시작하게 됩니다. 이는 평범한 질문을 하거나 작업을 설명하는 방법을 의미합니다:

예를 들어, 다음과 같은 작업 설명을 고려해 보세요.

“개인 식별 정보를 제거하고, 날짜만 표시하며, 모든 욕설을 ‘😤’로 대체하십시오.”

이 작업 설명은 고객 채팅 대화를 정리하기 위해 요청된 단계에 초점을 맞추고, 그 단계들을 문자 그대로 명시합니다. 이는 현재 settings.toml 파일에 instruction_prompt로 저장된 프롬프트입니다:

# settings.toml

# ...

instruction_prompt = """
개인 식별 정보를 제거하고, 날짜만 표시하며, 모든 욕설을 "😤"로 대체하십시오.
"""

이 프롬프트는 언어 모델에게 구체적인 작업 지시를 제공하여, 주어진 작업(이 경우, 채팅 대화의 정리)을 수행하도록 요청합니다. 제로샷 프롬프팅은 모델에게 사전에 제공된 예제 없이도 특정 작업을 수행하도록 요청하는 방식으로, 모델이 주어진 지시를 바탕으로 적절한 반응을 생성할 수 있는지를 테스트하는 데 유용합니다. 이 기술은 간단한 작업에 유용하지만 더 복잡한 작업에는 적합하지 않을 수 있습니다.

다음 단계에서는 이 프롬프트를 사용하여 실제 고객 채팅 대화를 실행하고 결과를 살펴보겠습니다.

Python 스크립트를 실행하고 지원 채팅 파일을 인수로 제공하면, 이 스크립트는 chats.txt의 내용과 함께 이 프롬프트를 OpenAI의 텍스트 완성 API로 보냅니다:

(venv) $ python app.py chats.txt

의존성을 올바르게 설치하고 OpenAI API 키를 환경 변수로 추가했다면, 터미널에 API 응답이 나타날 때까지 기다리기만 하면 됩니다:

  • API 응답은 요청한 작업(개인 식별 정보 제거, 날짜만 표시, 욕설을 “😤”로 대체)에 대한 언어 모델의 처리 결과를 보여줍니다.
  • 처리 시간은 요청의 복잡성, 네트워크 지연, OpenAI 서버의 부하 등에 따라 달라질 수 있습니다.

이 과정을 통해, 언어 모델이 주어진 프롬프트에 어떻게 반응하는지 확인할 수 있으며, 실제 어플리케이션에 언어 모델을 통합할 때 얻을 수 있는 통찰력을 얻을 수 있습니다. 제로샷 프롬프팅 기법을 사용하여 모델에게 명확한 지시를 제공함으로써, 모델이 특정 작업을 수행하는 방법에 대한 이해를 깊게 할 수 있습니다.

[support_tom] 2023-07-24 : 무엇을 도와드릴까요?
[johndoe] 2023-07-24 : 블래스트 계정에 연결할 수 없습니다
[support_tom] 2023-07-24 : 혹시 Caps Lock이 아니신가요?
[johndoe] 2023-07-24 : 😤! 네가 옳아!

[support_amy] 2023-06-15 : 안녕하세요! 오늘은 어떻게 도와드릴까요?
[greg_stone] 2023-06-15 : 😤! 구매한 소프트웨어의 다운로드 링크를 찾을 수 없는 것 같습니다.
[support_amy] 2023-06-15 : 문제 없습니다, 그렉. 제가 찾아보겠습니다. 주문 번호를 알려주시겠어요?
[greg_stone] 2023-06-15 : 1245789 입니다. 도와주셔서 감사합니다!

[support_louis] 2023-05-05 : 안녕하세요. 오늘은 어떻게 도와드릴까요?
[karen_w] 2023-05-05 : 😤! 내 빌어먹을 주문이 아직도 도착하지 않았고 일주일이 지났습니다!!!
[support_louis] 2023-05-05 : 안됐네요, 카렌님. 이 문제를 살펴보겠습니다.
[support_louis] 2023-05-05 : 주문 상태를 확인할 수 있도록 주문 번호를 알려주실 수 있나요?
[karen_w] 2023-05-05 : 네, 9876543입니다.
[support_louis] 2023-05-05 : 고마워요, 카렌. 배송지연이 있었나보네요. 주문하신 상품은 2일 이내에 도착할 예정입니다.

[support_jenny] 2023-06-18 : 안녕하세요! 오늘은 무엇을 도와드릴까요?
[alex_harper] 2023-06-18 : 실수로 두 번 주문했습니다. 취소하도록 도와주실 수 있나요?
[support_jenny] 2023-06-18 : 물론이죠, 알렉스. 취소하고 싶은 주문 번호를 알려주실 수 있나요?
[alex_harper] 2023-06-18 : 네, 1122334입니다. 감사합니다!
[support_jenny] 2023-06-18 : 주문번호 1122334를 성공적으로 취소했습니다. 곧 확인 이메일이 발송됩니다.

[support_ben] 2023-06-29 : 좋은 아침입니다. 오늘은 무엇을 도와드릴까요?
[lisa_beck] 2023-06-29 : 안녕하세요. 주문한 상품 중 파손된 상품이 도착했습니다. 반품하는 것을 도와주실 수 있나요?
[support_ben] 2023-06-29 : 안됐네요, 리사님. 주문 번호를 제공하고 손상된 품목을 명시할 수 있습니까?
[lisa_beck] 2023-06-29 : 네, 주문번호는 5566778 이고 파손된 상품은 커피잔 입니다.

[support_rachel] 2023-05-04 : 오늘은 무엇을 도와드릴까요?
[mike_t] 2023-05-04 : 결제 시 쿠폰 코드가 작동하지 않습니다. 도울 수 있니?
[support_rachel] 2023-05-04 : 물론이죠, 마이크. 사용하려는 쿠폰 코드를 입력하세요.
[mike_t] 2023-05-04 : "HELLO10" 입니다.
[support_rachel] 2023-05-04 : 코드를 확인해 보니 만료된 것 같습니다. 불편을 끼쳐드려 죄송합니다. 다음은 귀하가 사용할 수 있는 새로운 코드입니다: "WELCOME15".

[support_vincent] 2023-06-15 : 안녕하세요! 어떻게 도와 드릴까요?
[sara_winters] 2023-06-15 : 안녕하세요. 계정에 로그인하는 데 문제가 있습니다. 비밀번호 재설정을 시도했지만 작동하지 않습니다.
[support_vincent] 2023-06-15 : 안됐네요, 사라님. 내가 도와 줄게. 이메일 주소를 확인해 주시겠어요?
[sara_winters] 2023-06-15 : 물론이죠. sara.winters@email.com입니다.

[support_david] 2023-06-24 : 환영합니다! 오늘은 무엇을 도와드릴까요?
[jane_d] 2023-06-24 : 안녕하세요. 최근 주문한 상품의 배송 주소를 변경해야 합니다.
[support_david] 2023-06-24 : 알겠습니다, 제인. 주문 번호를 알려주십시오.
[jane_d] 2023-06-24 : 3344556 입니다. 도와주셔서 감사합니다!
영어로 프롬프트를 작성했지만 이메일주소, 주문번호가 삭제되지 않는 경우가 있습니다. 모델:gpt-3.5-turbo-instruct : 개인 식별 정보(이메일 주소, 주문 번호 )를 제거하고, 날짜만 표시하며, 모든 욕설을 “😤”로 대체하십시오.
모델을 GPT-4로 설정했을때 개인 식별 정보(이메일 주소, 주문 번호 )를 제거합니다.

위의 텍스트는 예시 응답을 나타냅니다. 온도를 0으로 설정하더라도 OpenAI의 LLM 모델이 완전히 결정론적이지 않다는 점을 기억하세요. 따라서 출력은 약간 다를 수 있습니다.

참고: 주로 결정론적이라는 것의 파급 효과는, 그다지 엔지니어링하지 않은 프롬프트에서 훨씬 더 나타납니다. 지시사항이 많은 세부사항으로 명시되지 않았기 때문에, 모델은 1퍼센트 미만으로 차이나는 확률을 더 많이 만나게 되며, 다른 실행에서 다른 토큰을 선택할 수 있습니다.

다른 선택이 이루어지면, 그 효과는 연쇄적으로 발생하여 상대적으로 상당한 차이로 이어질 수 있습니다. 이 효과를 관찰하기 위해 스크립트를 몇 번 실행해 볼 수 있습니다.

예제 출력에서 볼 수 있듯이, 제공된 프롬프트가 작업을 처리하는 데 큰 성공을 거두지 못했습니다. 예를 들어, 텍스트에서 일부 개인 식별 정보를 로 대체하여 어느 정도 숨겼지만, 여러분의 결과에서 그 부분이 처리되지 않았을 수 있습니다. 전반적으로 많은 부분이 미완성 상태로 남아 있습니다:

  • 고객과 고객 서비스 에이전트의 이름이 여전히 보입니다.
  • 텍스트에는 전체 ISO 날짜-시간 스탬프가 여전히 포함되어 있습니다.
  • 욕설은 여전히 검열되지 않았습니다.

LLM과 상호작용하는 것이 처음이라면, 이것이 텍스트 완성 모델에 개발 작업을 아웃소싱하는 첫 시도였을 수 있습니다. 그러나 이 초기 결과는 그다지 흥미롭지 않습니다.

참고: 이 예제에서는 gpt-3.5-turbo-instruct 모델과 /completions 엔드포인트를 사용하고 있습니다. 이 프롬프트를 다른 방식으로 실행했다면—예를 들어, ChatGPT에서—더 나은 성능의 모델을 사용하기 때문에 더 나은 결과를 얻었을 수 있습니다.

자연어로 작업을 설명했지만 혼합된 결과를 얻었습니다. 그러나 걱정하지 마세요—이 튜토리얼을 통해 더 좋고, 더 결정론적인 응답을 얻는 방법을 배울 것입니다.

그 방법 중 하나는 모델에게 제공하는 샷(예시)의 수를 늘리는 것입니다. 다음 섹션에서는 퓨샷 프롬프팅을 통해 결과를 개선할 것입니다.

퓨샷 프롬프팅(Few-shot prompting)

퓨샷 프롬프팅(Few-shot prompting)은 프롬프트 엔지니어링 기술 중 하나이며, 프롬프트에 예시 작업과 예상되는 해결책을 제공하는 것입니다. 즉, 이전처럼 단순히 작업을 설명하는 대신 이제 채팅 대화 예시와 해당 정리된 버전을 추가합니다.

settings.toml 파일을 열고, 그러한 예시를 추가함으로써 instruction_prompt를 변경하세요:

instruction_prompt = """
개인 식별 정보를 제거하고, 날짜만 표시하며, 모든 욕설을 "😤"로 대체하십시오.

예시 입력:
[support_tom] 2023-07-24T10:02:23+00:00 : 무엇을 도와드릴까요?
[johndoe] 2023-07-24T10:03:15+00:00 : 내 젠장 계정에 연결할 수 없어요
[support_tom] 2023-07-24T10:03:30+00:00 : 혹시 캡스락이 켜져 있지 않나요?
[johndoe] 2023-07-24T10:04:03+00:00 : 젠장! 맞아요!

예시 출력:
[Agent] 2023-07-24 : 무엇을 도와드릴까요?
[Customer] 2023-07-24 : 내 😤 계정에 연결할 수 없어요
[Agent] 2023-07-24 : 혹시 캡스락이 켜져 있지 않나요?
[Customer] 2023-07-24 : 😤! 맞아요!
"""

이 방법을 사용하면, 언어 모델이 제공된 예시를 참고하여 요구된 작업(개인 정보 제거, 날짜만 표시, 욕설 대체)을 어떻게 처리해야 하는지 더 잘 이해할 수 있습니다. 퓨샷 프롬프팅은 모델이 더 정확하고 일관된 출력을 생성하는 데 도움을 주어, 실제 애플리케이션에서의 유용성을 크게 향상시킬 수 있습니다.

변경사항을 적용한 후, 스크립트를 다시 실행하여 LLM이 채팅 대화를 처리할 수 있는 기회를 다시 제공하세요:

(venv) $ python app.py chats.txt

LLM이 모든 토큰을 예측할 때까지 기다려야 합니다. 완료되면, 터미널에 새로운 응답이 표시됩니다.

이번 실행에서는 대괄호 안의 이름이 처리되는 방식이 크게 개선되었음을 알 수 있습니다. 타임스탬프도 올바르게 형식화되었습니다. 모델은 나중에 채팅에서 욕설을 한숨 소리 이모지로 대체하기도 했습니다. 그러나 실제 대화에서 고객의 이름은 여전히 보입니다. 이번 실행에서는 모델이 한 단계 뒤로 가서 주문 번호를 검열하지 않았습니다.

지금까지 프롬프트에 하나의 예시를 제공했습니다. 더 많은 범위를 커버하기 위해, 다른 예시를 추가하여 이 프롬프트 부분이 정말로 퓨샷 프롬프팅를 구현하도록 하겠습니다:

instruction_prompt = """
개인 식별 정보를 제거하고, 날짜만 표시하며, 모든 욕설을 "😤"로 대체하십시오.

예시 입력:
[support_tom] 2023-07-24T10:02:23+00:00 : 무엇을 도와드릴까요?
[johndoe] 2023-07-24T10:03:15+00:00 : 내 젠장 계정에 연결할 수 없어요
[support_tom] 2023-07-24T10:03:30+00:00 : 혹시 캡스락이 켜져 있지 않나요?
[johndoe] 2023-07-24T10:04:03+00:00 : 젠장! 맞아요!

[support_amy] 2023-06-15T14:45:35+00:00 : 안녕하세요! 오늘 어떻게 도와드릴까요?
[greg_stone] 2023-06-15T14:46:20+00:00 : 구매한 소프트웨어의 다운로드 링크를 찾을 수가 없네요.
[support_amy] 2023-06-15T14:47:01+00:00 : 문제 없어요, Greg. 제가 찾아드릴게요. 주문 번호를 알려주시겠어요?
[greg_stone] 2023-06-15T14:47:38+00:00 : 번호는 1245789예요. 도와주셔서 감사합니다!

예시 출력:
[Agent] 2023-07-24 : 무엇을 도와드릴까요?
[Customer] 2023-07-24 : 내 😤 계정에 연결할 수 없어요
[Agent] 2023-07-24 : 혹시 캡스락이 켜져 있지 않나요?
[Customer] 2023-07-24 : 😤! 맞아요!

[Agent] 2023-06-15 : 안녕하세요! 오늘 어떻게 도와드릴까요?
[Customer] 2023-06-15 : 구매한 소프트웨어의 다운로드 링크를 찾을 수가 없네요.
[Agent] 2023-06-15 : 문제 없어요, ********. 제가 찾아드릴게요. 주문 번호를 알려주시

겠어요?
[Customer] 2023-06-15 : 번호는 ********예요. 도와주셔서 감사합니다!

더 나은 결과를 기대했을 수 있지만, 대신에 결과가 비어 있는 것처럼 보일 수 있습니다.

더 많은 예시를 추가하면 응답이 강화되어야 하지만, 그 대신에 결과가 사라지는 것처럼 보이는 경우, 프롬프트 엔지니어링 기술인 퓨샷 프롬프팅이 효과적으로 작동한다는 것을 신뢰할 수 있습니다. 모델이 프롬프트의 어떤 부분이 지시사항을 따라야 하는지 구분할 수 있도록 도와주기 위해 구분자를 사용할 수 있습니다.

구분 기호를 사용하여 프롬프트의 섹션을 명확하게 표시하기

프롬프트의 특정 섹션을 명확하게 표시하기 위해 구분자 사용하기에 대해서 설명드리겠습니다. 특정 입력이 필요한 콘텐츠 작업을 하거나 이전 섹션에서와 같이 예시를 제공하는 경우, 프롬프트의 특정 부분을 명확하게 표시하는 것이 매우 유용할 수 있습니다. 작성하는 모든 내용이 하나의 프롬프트로 LLM에 전달된다는 점을 기억하세요. 이는 긴 토큰 시퀀스로 구성됩니다.

구분 기호를 사용하여 프롬프트의 특정 부분을 구분하고 레이블을 지정하면 결과물의 품질을 향상시킬 수 있습니다. 실제로 예제 코드를 실행했다면 벌써 파일에서 읽고 있는 콘텐츠를 구분하기 위해 구분 기호를 사용한 것입니다.

app.py에서 프롬프트를 작성할 때 구분자를 추가하는 스크립트 예시는 다음과 같습니다:

# app.py

# ...

def assemble_prompt(content: str, settings: Settings) -> str:
    """모든 텍스트 입력을 단일 프롬프트로 결합합니다."""
    return f">>>>>\n{content}\n<<<<<\n\n" + settings.instruction_prompt

마지막 줄에서 채팅 내용을 >>>>><<<<< 구분 기호 사이에 넣습니다. 프롬프트의 일부를 구분 기호로 표시하면 모델이 어떤 토큰을 의미의 단일 단위로 간주해야하는지 추적하는 데 도움이 될 수 있습니다.

구분 기호 사용이 권장되는 경우:

  • 지시와 예시 구분: LLM에게 주어진 예시가 따라야 하는 특정 지시사항이 있는 경우 이들을 구별해주는 것이 좋습니다.
  • 다중 예시: 여러 예시를 제공할 때, 다른 예시들과 분리되게 하기 위해 각각의 예시를 구분해주세요.
  • 입력과 출력의 경계: 입력된 내용과 모델이 생성해야 하는 출력 사이에 명확한 경계를 표시할 수 있습니다.

이전 섹션에서 본 것처럼 구분자가 누락되면 예상치 못한 결과를 초래할 수 있습니다. 이전처럼 빈 응답이 올 수도 있고 원하는 것과 완전히 다른 출력이 생성될 수도 있습니다! 예를 들어, 사용자가 서식을 변경하려는 콘텐츠의 끝에 다음과 같은 질문이 포함되어 있다고 가정해 보세요:

주문 번호를 알려주실 수 있나요?

이 질문이 구분자 없이 프롬프트의 마지막 줄이라면, LLM은 상상의 주문 번호로 질문에 답하는 가상의 대화를 계속할 가능성이 높습니다. 현재 프롬프트의 끝에 이러한 문장을 추가해보세요!

구분자는 내용과 예시를 작업 설명에서 분리하는 데 도움이 될 수 있습니다. 또한 나중에 프롬프트의 특정 부분을 참조할 수 있게 만들 수도 있습니다.

구분자는 일반적으로 함께 나타나지 않을 문자 시퀀스일 수 있습니다. 예를 들어:

>>>>>
====
####

사용하는 문자의 수는 그리 중요하지 않지만, 시퀀스가 상대적으로 유니크하다는 것을 확실히 해야 합니다. 또한, 구분자 바로 전이나 바로 후에 라벨을 추가할 수 있습니다:

START CONTENT>>>>> content <<<<<END CONTENT
==== START content END ====
#### START EXAMPLES examples #### END EXAMPLES

정확한 서식이 그리 중요하지 않습니다. 일반적인 독자가 의미의 단위가 어디에서 시작하고 끝나는지 이해할 수 있도록 섹션을 표시하기만 하면 구분자를 올바르게 적용한 것입니다.

언제 다른 모델로 전환해야 할까요?

다른 모델로 전환할 시기를 평가하는 것은 프롬프트 작성 과정에서 중요한 고려사항입니다. 프롬프트가 단일 줄의 작업 설명에서 여러 단계와 여러 예시를 포함하는 긴 텍스트로 성장하는 것을 보셨을 겁니다.

프롬프트를 계속해서 확장하다 보면, 현재 작업 중인 모델의 한계에 곧 도달할 수 있습니다. 이 섹션에서는 그러한 상황이 발생할 수 있는 이유와 다른 모델로 어떻게 전환할 수 있는지에 대해 배울 것입니다.

  1. 모델의 한계 인식하기: 대부분의 언어 모델은 입력할 수 있는 텍스트의 양에 제한이 있습니다. 이러한 제한은 모델이 한 번에 처리할 수 있는 토큰(단어나 문자의 조합)의 최대 수에 의해 결정됩니다. 프롬프트가 너무 길어지면, 모델이 전체 내용을 효과적으로 처리하거나 이해하는 데 어려움을 겪을 수 있습니다.
  2. 다른 모델로 전환하는 이유:
    • 성능: 현재 모델이 제공하는 출력의 품질이나 관련성이 만족스럽지 않을 수 있습니다.
    • 용량: 더 큰 입력을 처리할 수 있는 모델로 전환하려는 필요성이 발생할 수 있습니다.
    • 특화된 요구사항: 특정 언어, 도메인 또는 작업에 더 적합한 모델이 필요할 수 있습니다.
  3. 다른 모델로 전환하기:
    • 모델 비교: 사용 가능한 다른 모델의 성능, 용량, 비용 등을 비교합니다.
    • API 문서 확인: 대상 모델을 사용하기 위한 API 호출 방법, 입력 제한, 비용 등을 확인합니다.
    • 테스트 실행: 새 모델에서 몇 가지 테스트를 실행하여 현재 작업에 적합한지 평가합니다. 이 과정에서는 작은 데이터 세트를 사용하여 출력의 품질과 관련성을 평가할 수 있습니다.

프롬프트의 복잡성이 증가함에 따라 모델의 한계를 넘어서는 경우, 효과적인 전환 계획을 세우는 것이 중요합니다. 이를 통해 작업의 효율성과 출력의 질을 유지하며, 더 큰 규모의 데이터나 더 복잡한 요구사항을 처리할 수 있게 됩니다.

프롬프트 및 응답에서 토큰의 수 조절하기

프롬프트와 응답에서 토큰 수를 조절하는 것은 반복적인 프롬프트 엔지니어링의 일부입니다. 프롬프트의 맥락을 계속해서 확장하면서 전체적으로 더 많은 텍스트를 제공하는 과정에서, 결국 모델의 토큰 한계를 초과하여 오류에 직면할 수 있습니다:

openai.error.InvalidRequestError: 이 모델의 최대 컨텍스트 길이는 4097 토큰이지만, 4111 토큰(프롬프트에 1911; 완성을 위해 2200)을 요청했습니다.
프롬프트 또는 완성 길이를 줄여주세요.

위 추적 메시지에서 설명한 것처럼, 이 모델의 최대 내용 길이를 초과했습니다. 이는 text-davinci-003 모델의 경우 4097 토큰입니다. 메시지에서는 문제를 해결하기 위한 두 가지 접근 방식을 언급합니다:

  • 짧은 프롬프트: 요청에 담아 보내는 지시 사항 또는 내용 입력의 양을 줄여서 프롬프트의 토큰을 줄일 수 있습니다.
  • 짧은 응답: 모델에 요청하는 응답의 토큰 수를 줄일 수 있습니다.

이 예제에서는 프롬프트의 토큰을 줄이고 싶지 않지만, 응답에서는 축소할 여지가 있을 수 있습니다. settings.toml 파일에서 응답으로 요청하는 토큰 수를 줄이기 위해 max_tokens 항목을 편집할 수 있습니다:

# settings.toml

[general]
chat_models = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4"]
model = "text-davinci-003"
max_tokens = 2000
temperature = 0

이 값을 낮은 숫자로 설정하면 프롬프트에 더 많은 토큰을 보낼 수 있습니다. 하지만, 응답에서 총 토큰 수가 max_tokens에 설정된 값을 초과할 경우, 모든 대화 예시를 돌려받지 못할 수 있습니다.

참고: 프롬프트에서 사용하는 토큰 수를 정확하게 계산해야 하는 경우, OpenAI의 tiktoken 토크나이저를 설치할 수 있습니다. 이 토크나이저를 사용하여 API 요청 없이 토큰 수를 얻을 수 있습니다:

>>> import tiktoken
>>> encoding = tiktoken.encoding_for_model("text-davinci-003")
>>> tokens = encoding.encode("This is a sample text")
>>> len(tokens)
5

많은 사용자를 위한 서비스를 배포할 계획이고 API 요청당 비용을 제한하고 싶다면, 정확한 토큰 수를 계산하는 것도 중요합니다.

max_tokens을 낮은 값으로 변경하여 실험해 볼 수 있습니다. 예를 들어 100으로 설정합니다. 프롬프트를 변경하지 않고도 이제 출력을 제한할 수 있습니다:

[에이전트] 2023-07-15: 안녕하세요! 오늘 어떻게 도와드릴까요?
[고객] 2023-07-15: 안녕하세요, 제 프로모 코드가 장바구니에 할인을 적용하지 않아요.
[에이전트] 2023-07-15: 불편을 드려 죄송합니다, ********. 사용하려는 프로모 코드를 알려주실 수 있나요?
[고객] 2023-07-15: "********"입니다.

[에이전트]

LLM을 사용할 때 토큰 한계에 부딪히는 것은 사용자가 자주 마주치는 문제입니다. LLM이 고려할 수 있는 맥락을 늘리기 위한 개발 노력이 많기 때문에, 토큰 창은 계속해서 증가할 가능성이 높습니다.

OpenAI는 gpt-3.5-turbo-16k 및 gpt-4와 같이 훨씬 더 큰 토큰 창을 고려할 수 있는 다른 모델을 제공합니다. 프롬프트를 계속해서 확장하고 현재 작업 중인 모델의 한계에 도달하면 다른 모델로 전환할 수 있습니다.

채팅 완성 모델(Chat Completion Model)로 전환하기

이 글을 쓰는 시점에서 GPT-3.5 모델인 text-davinci-003/completions 엔드포인트에서 가장 높은 토큰 제한을 가지고 있습니다. 하지만 OpenAI는 /chat/completions 엔드포인트에서 또 다른 GPT-3.5 및 GPT-4 모델에 대한 액세스도 제공합니다. 이 모델들은 채팅에 최적화되어 있지만 현재까지 진행해 온 것과 같은 텍스트 완성 작업에도 잘 작동합니다.

하지만 다른 엔드 포인트를 통해 액세스해야 하므로 보내는 프롬프트의 구조와 API 요청이 약간 달라집니다.

제공된 스크립트를 사용하는 경우, settings.tomlchat_models에서 채팅 모델을 선택하고 새로운 값으로 model을 사용하기만 하면 됩니다:

# settings.toml

[general]
chat_models = ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4"]
model = "gpt-4"
max_tokens = 2000 # 사용되지 않음

이 설정을 변경하면 /chat/completions 엔드포인트 요청에 필요한 방식으로 프롬프트를 구성하는 get_chat_completion()이라는 다른 함수를 트리거할 것입니다. 이전과 마찬가지로 스크립트는 해당 요청을 자동으로 수행하고 응답을 터미널에 출력합니다.

참고: 예제 스크립트는 /chat/completions 엔드포인트로의 요청에서 max_tokens 설정을 사용하지 않습니다. 이 모델들에 대해, max_tokens은 기본적으로 무한대(inf)로 설정됩니다.

응답의 토큰 수를 제한해야 하는 경우 openai.ChatCompletion.create() 내 API 호출에 max_tokens 설정을 인수로 지정할 수 있습니다. 이 메서드 호출은get_chat_completion() 함수에서 찾을 수 있습니다.

이 튜토리얼의 나머지 부분에서는 OpenAI의 최신 버전인 GPT-4 모델로 작업할 것입니다. 이 모델에 접근할 수 없는 경우, chat_models에 언급된 다른 모델을 대신 사용할 수 있습니다. ChatGPT를 사용하여 따라왔다면, 아마도 gpt-3.5-turbo와 같은 채팅 모델 중 하나를 계속 사용했을 것입니다. ChatGPT Plus 구독자인 경우, 웹사이트에서 모델을 GPT-4로 변경할 수도 있습니다.

추가 정보

  • /chat/completion 포맷: 채팅 완성 모델은 메시지 배열을 입력으로 받습니다. 따라서 여러 턴의 대화를 한 번에 모델에 보낼 수 있습니다.
  • GPT-4의 이점: GPT-4는 다른 GPT-3.5 모델에 비해 여러 영역에서 향상된 점이 있습니다. 지시에 보다 정확하게 따르고, 창의적인 작업에서의 성능, 장문 이해 능력이 뛰어납니다.

중요 참고 사항: 이 섹션에서 배우게 될 프롬프트 엔지니어링 기법은 최신 모델만의 것이 아닙니다. 모델을 변경하지 않고도 사용할 수는 있지만 구조를 조정해 적용해야 하며, 완성 결과도 달라질 수 있습니다.

채팅 완성 엔드포인트 및 GPT-4 사용하기

이번 섹션에서는 OpenAI가 계속 개발할 채팅 완성 엔드포인트(/chat/completions)에서 GPT-4 모델을 사용하는 방법을 배우고 프롬프트 엔지니어링 기술을 향상시키는 추가 기술을 알아봅니다.

1. 역할 프롬프팅(Role prompting):

  • 시스템 메시지를 사용하여 대화의 분위기를 설정하고 레이블을 사용하여 다양한 역할에 대한 컨텍스트를 제공합니다. 예를 들어, 고객 지원 에이전트와 고객 사이의 대화를 시뮬레이션하고 싶다면, 각 역할에 대한 명확한 지시사항을 프롬프트에 포함시킬 수 있습니다.
  • 예시: “Agent:”, “Customer:”, “User:”, “Assistant:”

2. 사고 연쇄 프롬프팅 (Chain-of-thought prompting,CoT):

  • 사고의 연쇄 프롬프팅은 모델에게 복잡한 문제를 단계별로 사유하고 해결 방법을 탐색하도록 유도하는 기술입니다. 이 방법은 모델이 더 정교하고 세부적인 답변을 생성하도록 돕습니다. 모델이 작업에 대해 추론하도록 프롬프트하여 모델이 생각할 시간을 제공한 후 추론을 프롬프트에 포함합니다. 예를 들어, 특정 문제에 대한 해결책을 제시하도록 요청할 때, 모델에게 문제를 분석하고 가능한 해결책을 단계별로 설명하도록 할 수 있습니다.
  • 예시:
    • “다음 단계는 무엇이라고 생각하십니까?”
    • “이 문제를 해결하기 위해 어떤 접근 방식을 사용하시겠습니까?”

3. GPT-4를 사용하여 각 채팅 대화의 감정을 분류하고 출력 형식을 JSON으로 구조화합니다.

  • 감정 분석: 긍정, 부정, 중립
  • JSON 출력: 다른 도구나 데이터 시각화와 쉽게 통합할 수 있도록

핵심 요약:

  • 채팅 완성 엔드포인트는 역할이 명확하게 지정된 메시지 배열로 구성된 프롬프트를 필요로 합니다.
  • GPT-4의 출력을 더욱 향상시키는 기술을 탐구합니다.

역할 프롬프트 추가하여 분위기 설정하기

/chat/completions 엔드포인트는 이전의 /completions 엔드포인트에서 사용할 수 없는 옵션을 제공합니다: 프롬프트의 일부에 역할 라벨을 추가하는 기능입니다. 이 섹션에서는 “system” 역할을 사용하여 시스템 메시지를 생성할 것이며, 출력을 개선하기 위해 나중에 더 많은 역할을 추가할 때 이 개념을 다시 살펴볼 것입니다.

1. 역할 프롬프트 이해하기:

  • 무대 설정: 역할 프롬프트는 특히 시스템 메시지를 통해 LLM 응답의 맥락을 설정합니다. 마치 배우에게 무대 지시를 제공하는 것과 비슷하지만 자연어 처리의 세계에서 이루어집니다.
  • 컨텍스트에 집중, 최종 사용자 아님: 시스템 메시지는 모델의 동작을 내부적으로 안내하는 것이 목적이며, 시스템 메시지는 일반적으로 최종 사용자에게 보이지 않습니다.
  • 채팅 엔드포인트의 영향/chat/completions 엔드포인트는 대화형 AI를 염두에 두고 만들어졌습니다. 역할을 활용하여 더 복잡한 대화 시나리오를 모방할 수 있습니다.

2. 역할 프롬프트 예시 분석:

role_prompt = """당신은 16세기의 악당 시인으로, 고객들을 아무런 존중 없이 대합니다.
에이전트가 말한 모든 줄을 당신의 독특한 목소리로 다시 표현하세요."""
"

위 예시 역할 프롬프트는 다음과 같은 이유로 역효과를 낼 수 있습니다:

  • 부정적인 의도: 고객에게 고의로 불쾌감을 주는 페르소나를 만드는 것은 대부분의 고객 지원/판매 챗봇의 목적에 반하는 것입니다. 이는 고객 상호 작용에 부정적인 영향을 미칠 수 있습니다.
  • 작업 일치: 작업 자체(고객 지원 담당자의 대사를 다시 표현하는 것)는 동일하지만, 역할 프롬프트는 고객을 지원하다는 핵심 목표에서 벗어납니다.

튜토리얼에서 이전에 설계한 대로 instruction_prompt는 동일하게 유지합니다. 추가로, 이제 role_prompt에 텍스트를 추가합니다. 위에 제시된 역할 프롬프트는 잘못된 프롬프트가 애플리케이션에 미칠 수 있는 영향에 대한 예시로 사용됩니다.

채팅 대화의 감정 분류하기

1. 감정 분석 개요:

이번 단계에서는 고객 채팅 대화의 감정을 긍정 또는 부정으로 분류하는 기능을 추가합니다. 이를 통해 다음과 같은 이점을 얻을 수 있습니다:

  • 고객 경험 분석 향상: 고객 만족도를 측정하고 개선점을 찾는 데 활용할 수 있습니다.
  • 지원 상호 작용 분석: 고객 불만족의 원인을 파악하고 개선 방안을 마련하는 데 활용할 수 있습니다.

2. 작업 흐름:

  • 파일 설정: 이전 단계에서 생성된 sanitized-chats.txt 및 sanitized-testing-chats.txt 파일을 감정 분석 작업의 입력 파일로 사용합니다.
  • 프롬프트 엔지니어링: LLM에게 감정 분석을 수행하도록 지시하는 맞춤형 프롬프트를 작성합니다.
  • 코드 수정: 감정 분석 기능을 수행하도록 코드를 수정합니다.

정제된 채팅 대화 파일을 새 파일로 저장하여 감정 분류 작업에 대한 새로운 입력으로 구성합니다:

(venv) $ python app.py chats.txt > sanitized-chats.txt
(venv) $ python app.py testing-chats.txt > sanitized-testing-chats.txt

3. 프롬프트 엔지니어링:

다음은 프롬프트 엔지니어링 시 고려해야 할 사항입니다:

  • 명확한 지시: LLM에게 감정을 “긍정” 또는 “부정”으로 평가하도록 명확하게 지시해야 합니다.
  • 실제 예시 제공: 몇 가지 짧은 예시를 제공하여 모델의 이해를 돕는 것이 좋습니다.
  • 역할 프롬프트 사용: “고객 서비스 감정 분석기”와 같은 역할 프롬프트를 사용하여 결과를 개선할 수 있습니다.

4. 예시:

sanitized-chats.txt 파일에 다음과 같은 대화가 있다고 가정해봅시다:

Agent: 안녕하세요, 문의해주셔서 감사합니다. 오늘 무엇을 도와드릴까요?
Customer: 안녕하세요, 최근 주문한 제품에 문제가 있어서 연락드립니다. 제품이 손상된 상태로 도착했습니다.
...

이 대화에 대한 감정 분석 프롬프트는 다음과 같이 구성할 수 있습니다:

Instruction: 다음 채팅 대화를 읽고 전체적인 감정을 판단하십시오. 고객이 만족하는 것처럼 보이면 “Positive”라고 응답하고, 만족하지 않는 것처럼 보이면 “Negative”라고 응답하십시오.

Chat Conversation: [여기에 정제된 대화를 삽입하십시오]

Sentiment:

답글 남기기

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