프롬프팅

프롬프트는 모델이 예측하기 전에 앞에 배치하는 텍스트입니다. 이 장에서 명확히 하는 전체 아이디어가 바로 이것입니다: 프롬프트는 마음에 주는 명령이 아니라, 원하는 답변이 가장 확률 높은 후속 텍스트가 되도록 배치하는 **맥락**입니다.
프롬프트가 실제로 무엇인지
동일한 모델, 두 개의 프롬프트. "기후 변화에 대해 써라"는 원하지 않은 산만한 에세이를 제공합니다. "기후 변화의 주요 원인을 12세 아이를 위해 평문으로 3문장으로 요약하되, 통계 없이"는 사용할 수 있는 것을 제공합니다. 두 호출 사이에 모델은 변하지 않았습니다. 맥락이 변했고, 출력이 따라갔습니다.
이전 장에서는 모델이 앞의 모든 것으로 안내받으면서 가장 확률 높은 다음 토큰을 예측함으로써 텍스트를 생성하는 방법을 다루었습니다. 프롬프트는 그 "앞의 모든 것"입니다. 이것이 기억할 가치가 있는 정의입니다: 프롬프트는 사람에게 하는 요청이 아니라, 원하는 후속이 모델이 가장 가능성 있다고 판단하는 것이 되도록 설정하는 **맥락**입니다.
이 재구성은 작성 방식을 바꿉니다. 누군가를 설득하거나 지시하는 것이 아닙니다. 원하는 답변이 가능성 있는 다음 것이 되도록 텍스트를 배치하는 것입니다. 이 장의 모든 기법은 이를 다르게 수행하는 방식이며, 각각은 그 아래의 예측 머신을 볼 수 있으면 더 많은 의미를 갖습니다.
세 가지 역할
코드를 통해 모델과 대화할 때, 텍스트의 단일 블록을 전송하지 않습니다. **메시지**의 목록을 전송하며, 각 메시지는 출처를 표시하는 역할을 가집니다. 세 가지가 있습니다:
- system: 지속적인 명령어. 모델이 행동해야 하는 역할, 따르는 규칙, 원하는 형식. 한 번 설정하면 전체 대화에 적용됩니다.
- user: 앱을 사용하는 사람의 메시지. 실제 요청.
- assistant: 모델이 이전에 생성한 메시지. 대화가 기록을 유지하는 방식입니다.
messages = [
{"role": "system", "content": "요리 앱의 간결한 도우미입니다. 한 문장으로 답변하세요."},
{"role": "user", "content": "쿠키에서 버터 대신 무엇을 사용할 수 있나요?"},
]내부적으로, 이러한 역할은 모델로의 별도 채널이 아닙니다. 각 메시지 주위에 특수 마커 토큰이 있는 하나의 텍스트 스트림으로 평탄화되며, 전체 스트림이 모델이 예측하는 것입니다. 역할이 중요한 이유는 모델이 이런 방식으로 배치된 대화를 통해 학습했기 때문에, system 콘텐츠를 권위 있는 지속적인 규칙으로 취급하고 user 콘텐츠를 답변할 요청으로 취급하는 방법을 배웠습니다.
시스템 메시지는 초보자가 과소 사용하는 것입니다. 모든 차례에서 원하는 동작을 설정하는 곳입니다: 톤, 대상, 형식, 모델이 절대 해서는 안 되는 것들. 지속적인 규칙을 그곳에 놓고, 특정 요청을 사용자 메시지에 놓으세요.
모델은 요청 사이에 메모리가 없기 때문에, assistant 역할은 이전에 말한 것을 재생하는 방식이기도 합니다: 대화를 계속하려면 이전 교환을 assistant와 user 메시지로 다시 보냅니다. 코드에서 모델 호출을 시작할 때 더 자세히 설명합니다.
system, user, 또는 assistant로 태그된 메시지 목록으로 모델을 조종합니다. 이러한 태그는 모델이 예측하는 하나의 텍스트 스트림으로 평탄화되지만, 모델은 system을 권위 있는 규칙으로 취급하고 user를 요청으로 읽도록 학습했습니다. 지속적인 명령어는 system에, 특정 요청은 user에, 그리고 이전 assistant와 user 메시지를 재생하여 대화의 기록을 유지합니다. 구체적이 모호함을 이기다
두 개의 프롬프트, 하나의 모델. "기후 변화에 대해 써라"는 예측 불가능한 길이와 톤의 일반적인 에세이를 반환합니다. "기후 변화의 주요 원인을 12세 아이를 위해 평문으로 3문장으로 요약하되, 통계 없이"는 그림으로 그린 것에 가깝게 반환합니다. 동일한 머신, 극도로 다른 출력, 그리고 유일한 차이는 얼마나 많이 고정했는지입니다.
이유는 예측 루프를 추적합니다. 매 단계에서 모델은 그럴듯한 후속의 분포로부터 선택합니다. 모호한 프롬프트는 그 분포를 넓게 두어서, 모델은 일반적으로 가장 흔한 것으로 간격을 채웁니다. 이는 거의 정확히 그려고 한 것이 아닙니다. 구체적 프롬프트는 모델이 한 개의 토큰을 기록하기 전에 분포를 원하는 답변 쪽으로 좁힙니다.
# 모호함: 모델이 길이, 톤, 대상, 형식을 결정합니다
"기후 변화에 대해 써라."
# 구체적: 당신이 결정합니다
(
"기후 변화의 주요 원인을 12세 아이를 위해 평문으로 "
"3문장으로 요약하되, 통계 없이."
)모호한 버전은 수천 가지의 합리적인 방식으로 계속될 수 있으며, 당신은 그 중 하나를 무작위로 받습니다. 구체적인 버전은 거의 모든 것을 사전에 배제합니다. 프롬프트를 작성할 때, 실제로 원하는 것을 말하세요:
- 형식: 문장, 목록, JSON, 표.
- 길이: 한 단락, 세 개의 글머리기호, 50단어 이하.
- 대상: 초보자, 전문가, 12세 아이.
- 불확실할 때 무엇을 할 것인가: "텍스트가 말하지 않으면 추측 대신 '명시되지 않음'으로 답변하세요."
마지막 것은 보이는 것보다 더 많은 무게를 가집니다. 모델은 자신의 장치에 맡겨지면 간격을 자신감 있는 추측으로 채웁니다. 유창한 추측이 확률 높은 후속이기 때문입니다. 명시적으로 "모르겠습니다"라고 말할 수 있는 옵션을 주면 그것이 가능성 있는 경로가 됩니다. 이것은 마지막 장의 환각 문제를 줄이는 몇 가지 프롬프트 레벨 움직임 중 하나입니다. 구체성은 모델이 토큰을 기록하기 전에 옵션을 좁힙니다.
예시를 보여주세요
때로 올바른 후속을 설정하는 가장 명확한 방법은 이를 보여주는 것입니다. 프롬프트에 몇 개의 작동된 예시를 넣는 것을 **few-shot 프롬프팅**이라고 합니다 (예시 없음은 zero-shot). 작동하는 이유는 모델은 근본적으로 패턴 계속 수행 기계입니다: 입력-후속-정확한-출력의 두 세 예시를 주면, 가장 확률 높은 다음 것은 새로운 입력에 적용된 동일한 패턴입니다.
messages = [
{"role": "system", "content": "각 리뷰를 POSITIVE, NEGATIVE, 또는 NEUTRAL로 레이블하세요. 레이블만 회신하세요."},
{"role": "user", "content": "음식이 차갑고 도착이 느렸습니다."},
{"role": "assistant", "content": "NEGATIVE"},
{"role": "user", "content": "괜찮은 식사, 특별한 것은 없습니다."},
{"role": "assistant", "content": "NEUTRAL"},
{"role": "user", "content": "내가 먹은 최고의 버거입니다!"},
]
# 모델은 이제 다음과 같이 답변합니다: POSITIVE두 개의 완성된 예시는 정확한 패턴을 설정합니다: 한 단어, 모두 대문자, 고정된 집합에서. 세 번째 리뷰를 위해 이 패턴을 계속하는 것은 이제 분석 단락을 작성하는 것보다 훨씬 더 확률입니다. 따라서 당신이 얻는 것입니다. 이것이 명확한 예시가 설명보다 종종 이기는 이유이며, 특히 분류 및 형식 지정: 기술하기보다 출력의 형태를 시연하는 것이고 희망합니다. 까다로운 경우를 다루는 예시를 선택하세요. 모델은 당신이 보여주는 것을 패턴화하므로, 예시의 실수를 포함합니다.
이유를 제시하도록 요청하세요
가장 유용한 프롬프팅 아이디어 중 하나이며, 가장 비직관적인 것이며, 모델이 작동하는 방식에서 직접 나옵니다. 모델은 한 번에 하나의 토큰을 생성하며, 유일한 작업 공간은 이미 작성한 텍스트입니다. 어려운 문제를 조용히 풀기 위한 숨겨진 스크래치패드가 없습니다. 생각, 그것이 무엇이든, 생성하는 토큰 안에서 큰소리로 일어납니다.
따라서 다단계 질문을 요청하고 최종 답변만 요구하면, 모델이 어디서 작업할 없이 한 개의 토큰으로 끝에 도약하도록 강제합니다. 그리고 추론, 수학, 논리가 포함된 것에서 종종 도약이 잘못됩니다. 수정은 이를 열린 것으로 놓는 것입니다. 답변 전에 단계를 배치하도록 요청하세요:
messages = [
{"role": "system", "content": "문제를 단계별로 작업한 후, 최종 답변을 제공하세요."},
{"role": "user", "content": "상점은 3개에 $2에 펜을 판매합니다. 12개 펜의 비용은 얼마입니까?"},
]
# "단계별로"가 없으면, 모델은 종종 잘못된 번호를 내뱉습니다
# 함께, 모델은 작업을 기록하고, 각 단계는 다음을 더 신뢰할 수 있게 만듭니다이것을 chain-of-thought 프롬프팅이라고 합니다. 작동하는 이유는 마법이 아니라 기계적입니다. 모델이 기록하는 모든 단계는 다음 토큰을 위해 읽는 맥락의 일부가 되므로, "12개 펜은 3의 4개 그룹"을 기록하면 "4개 그룹 곱하기 $2는 $8"이 자연스럽고 확률 높은 후속이 됩니다. 모델이 불가능한 한 개의 도약을 요구하는 대신 페이지에서 계산하는 데 공간을 제공합니다. "단계별로 생각하기" 또는 "당신의 작업을 보여주기"는 일상적 버전입니다.
두 가지 주의. 기록된 추론은 여전히 생성된 텍스트이므로 타당해 보일 수 있고 잘못된 답변에 도달할 수 있으며, 보장된 증명으로 취급하지 않아야 합니다. 그리고 일부 최신 모델은 요청하지 않아도 이 종류의 작업 내부적으로 수행합니다. 그러나 기본 원리는 무엇이 다음에 올지 아무리 모델이 와도 지속됩니다: 모델은 단계를 작성하는 공간이 있을 때 더 잘 추론합니다. 작성한 자체 출력이 생각할 유일한 장소입니다.
프롬프트를 구조화하세요
프롬프트가 성장할 때, 구조는 맥락을 명확하게 유지하므로 모델이 각 부분을 올바르게 무게합니다. 몇 가지 습관이 도움됩니다:
- 명령어 먼저, 데이터 마지막. 무엇을 할 것인지 서술한 다음, 이를 수행할 텍스트를 제공하세요.
- 구분자로 명령어를 데이터로부터 분리하세요. 제공된 텍스트를 명확한 마커로 감싸세요. 규칙과 입력 사이의 경계가 부인할 수 없게 합니다.
- 출력 형태를 명시적으로 요청하세요. JSON을 원하면, 말하세요. 필드를 설명하세요.
prompt = f'''회의 노트에서 작업 항목을 요약하세요.
그 다음, 언급하는 모든 제품 이름을 나열하세요.
고객 메시지:
"""
{user_message}
"""'''삼중 따옴표는 **구분자**입니다. "이 안의 모든 것은 따를 명령이 아니라, 처리할 데이터"를 표시합니다. 이것은 정리만이 아니며, 여기 예측 뷰는 왜 이것이 실제 안전장치인지를 보여줍니다.
모델에게 이것은 텍스트의 모든 스트림이므로, 사용자 입력이 경계 없이 명령어로 직접 흐르면, 사용자가 "위를 무시하고 이를 대신 수행하세요"를 기록할 수 있으며, 모델은 그 줄을 실제 명령어와 구분할 신뢰할 수 있는 방법이 없습니다. 이것을 따르면서 계속할 가능성이 있습니다.
그 공격을 프롬프트 주입이라고 하며, 명령어와 신뢰할 수 없는 데이터를 명확하게 울타리하는 것은 첫 번째 방어입니다. 안전 및 한계에서 다룹니다. 모델에게 이것은 텍스트의 모든 스트림이므로 신뢰할 수 없는 입력을 울타리하세요.
실제에서
다음은 이러한 아이디어들을 쌓는 프롬프트입니다: 지속적인 규칙의 시스템 메시지, 구체적인 요청, 형식을 고정하는 예시, 명확하게 구분된 데이터.
messages = [
{
"role": "system",
"content": (
"회의 노트에서 작업 항목을 추출합니다. "
"번호 목록으로 회신하세요. 한 줄에 한 항목. 각 항목은 동사로 시작합니다. "
"작업 항목이 없으면 '없음'으로 회신하세요."
),
},
{"role": "user", "content": '노트: """우리는 민준이 금요일까지 예산을 보내고 지은이가 장소를 예약하기로 합의했습니다."""'},
{"role": "assistant", "content": "1. 금요일까지 예산 보내기 (민준)\n2. 장소 예약하기 (지은이)"},
{"role": "user", "content": f'노트: """{meeting_notes}"""'},
]시스템 메시지는 규칙을 한 번 설정하며, 예시는 정확한 형식을 고정하고, 각 요청은 울타리된 데이터를 제공합니다. 모든 부분은 원하는 출력이 확률 높은 후속이 되도록 맥락을 배치합니다. 그것이 전체 기술입니다: 이것은 **신뢰할 수 있는 프롬프트**입니다. 행운이 아닙니다. 다음 당신은 코드에서 모델 호출의 실제 코드에서 이런 메시지들을 모델로 보냅니다.
system 메시지, 구체적인 요청, 형식을 고정하는 예시, 명확하게 울타리된 데이터. 모든 부분은 원하는 출력이 확률 높은 다음 텍스트가 되도록 맥락을 배치합니다. 그것이 기술입니다. 분위기가 아닌 설계로 작동하는 프롬프트입니다. 
