안녕하세요. 아이들나라Backend팀 안진성입니다.
저는 오늘 프롬프트 엔지니어링을 활용하여 구축한 아이들나라 사전 서비스에 대해 소개하고자 합니다.
1. 개요
아이들나라에서는 도서 컨텐츠 출시에 맞춰 어린이들이 쉽게 책을 읽을 수 있도록 어린이용 사전을 제공하고 있습니다.
위 기능을 구현하기 위해서는 두 가지 요구사항이 충족되어야 합니다.
•
어린이가 이해할 수 있는 쉬운 뜻풀이를 보여주어야 한다.
•
책의 문맥에 맞는 단어를 사전에서 찾아서 보여주어야 한다.
일반적으로 위와 같은 요구사항을 충족하기 위해서는 사람이 직접 뜻풀이를 생성하고 맥락에 맞는 단어에 대응시켜야 합니다. 하지만 이와 같은 방식으로 아이들나라에서 제공하는 수많은 도서들을 모두 처리하는 것은 불가능에 가깝습니다. 요새 주목받는 AI 를 활용해보고자 해도 높은 진입장벽 때문에 쉽사리 도입을 결정하기 어렵습니다. 좀 더 쉽게 AI 를 서비스에 적용할 수 있는 방법이 있을까요?
아이들나라 Backend 팀은 많은 고민 끝에 프롬프트 엔지니어링을 도입하기로 결정하였습니다. 프롬프트 엔지니어링이란 무엇이고, 어떻게 실제 서비스에 활용할 수 있었는지 간략하게 소개하겠습니다.
2. 프롬프트 엔지니어링이란?
프롬프트 엔지니어링에 대한 간단한 설명은 다음과 같습니다.
프롬프트 엔지니어링은 대규모 언어 모델(Large Language Model, LLM)에서 원하는 결과를 얻기 위해 프롬프트를 공들여 만들고 최적화하는 과정이다.
LLM 을 활용하는 대표적인 예시로는 많은 분들이 사용하고 계신 chatGPT 가 있습니다. chatGPT 를 활용해서 다양한 질문에 대한 어느정도 만족스러운(?) 답변을 얻을 수 있습니다. 그리고 우리가 원하는 질문에 대한 답을 해줄 수 있다면, 이를 활용하여 실제 서비스를 구축해 볼 수도 있을 것입니다.
아래는 chatGPT 를 통해 어린이용 사전의 뜻풀이를 만들어내는 아주 간단한 예시입니다.
이런 간단한 질의로도 답을 얻을 수 있지만, 실제 서비스에 활용하기 위해서는 조금의 노력이 더 필요할 거 같다.
3. 기본적인 활용법
프롬프트 엔지니어링을 하기 위해 꼭 알아야 하는 내용을 알아보겠습니다. 모든 내용은 openAI 의 Chat completion API(https://platform.openai.com/docs/api-reference/chat/create )기준으로 작성되었습니다.
3-1. 프롬프트 설정하기
우선, 프롬프트에 활용할 모델을 선택해야 합니다. 일반적으로 많이 사용하는 모델은 gpt-3.5-turbo 이며, 프로젝트에서도 해당 모델을 사용하여 서비스를 구축하였습니다.
다음으로 프롬프트에 적용되는 설정을 살펴보겠습니다. 주로 활용하는 설정은 다음과 같습니다.
설정 | 설명 |
temperature | 토큰 선택의 무작위성을 조정합니다. 일반적으로 값이 낮을수록 선택 가능한 토큰 중 항상 가장 확률이 높은 토큰을 선택합니다. 즉, 반복되는 요청에 대하여 일관된 답변을 얻을 수 있습니다. |
top_p | 답변 가능한 토큰을 샘플링하는 수준을 조정합니다. 마찬가지로 값이 낮을수록 좀 더 일관된 답변을 얻을 수 있습니다. |
일반적으로 temperature 와 top_p 파라미터 중 하나만 제어하는 것을 권장합니다.
실제 서비스에서는 안정된 품질의 답변(= 항상 같은 답변)을 얻는 것이 중요하므로 위 옵션을 조절하여 원하는 결과를 얻을때까지 설정을 조정하는 작업이 필요합니다.
아래는 설명한 내용을 바탕으로 구성한 실제 API 요청 예시입니다.
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"temperature": 1,
"top_p": 1,
"messages": [
{
"role": "user",
"content": "'호랑이'라는 단어를 쉽게 풀어서 설명해줘."
}
]
}'
Plain Text
복사
top_p 와 temperature 옵션의 동작 원리
굳이(?) 두 옵션을 함께 조정하기 위해서는 두 옵션의 동작 원리를 간단하게 이해할 필요가 있습니다.
다음에 등장할 토큰으로 아래와 같은 후보군이 있다고 가정해 봅시다.
•
아이들나라 - 90%
•
기술블로그 - 5%
•
유삐 - 3%
•
리리 - 2%
top_p = 0.9 인 경우, 상위 90% 를 충족하는 ‘아이들나라’ 토큰이 후보군으로 결정됩니다. 만약 top_p = 0.99 인 경우 ‘기술블로그’, ‘유삐’ 토큰까지 후보군에 포함될 수 있습니다.
이 예시에 temperature 옵션을 적용한다면 어떻게 될까요? 만약 temperature 가 높다면, ‘아이들나라’, ‘기술블로그’, ‘유삐’ 중 무작위로 하나의 토큰을 선택하게 되지만, 반대의 경우 높은 확률로 ‘아이들나라’ 토큰을 선택하게 됩니다.
3-2. 프롬프트 구성하기
프롬프트는 보통 아래의 요소들로 구성합니다.
구성 요소 | 설명 |
Instruction | 모델이 수행할 특정 작업 또는 지시 |
Context | 더 나은 응답을 위해 모델을 조종할 수 있는 외부 정보나 추가 문맥 |
Input Data | 응답받고자 하는 입력이나 질문 |
Output Indicator | 출력의 유형이나 형식 |
일반적으로 프롬프트 시작 부분에 지시사항을 명시하고 필요한 구성 요소를 나열합니다. 각 항목들에 최대한 구체적이고 직접적인 프롬프트를 제공할수록 더 정확한 답변을 얻을 수 있습니다. 모든 항목들을 필수적으로 사용할 필요는 없기 때문에 필요에 따라 적절히 응용하시면 됩니다.
위에 언급된 요소들을 바탕으로 예시를 좀 더 발전시켜 보겠습니다.
아까보다 좀 더 낫지만 뭔가 아쉽다.
4. 추가로 고려해야 하는 사항들
아이들나라 어린이용 사전의 품질을 향상시키기 위해 시도했던 몇 가지 기법들을 소개하고자 합니다.
4-1. 예시 제공
프롬프트에 예시를 제공하여 더 나은 품질의 답변을 생성하도록 유도할 수 있습니다. 예를 들어, 일반적인 프롬프트의 경우 아래와 같이 구성됩니다(Zero-shot prompting).
Add 2+2:
Plain Text
복사
예시를 제공하면 더 정확한 답변을 기대할 수 있습니다(Few-shot prompting).
Add 3+3: 6
Add 5+5: 10
Add 2+2:
Plain Text
복사
해당 기법을 적용하여 조금 더 발전된 답변을 도출해 보겠습니다.
점점 원하는 형태를 갖추어 나가고 있다.
4-2. 프롬프트 분할
프롬프트가 너무 길고 복잡한 경우 LLM 이 원하는 결과를 도출하지 않거나 Timeout 이 발생할 수 있습니다(너무 길다면 아예 요청이 불가능할 수도 있습니다). 이를 해결하기 위해 프롬프트를 여러개로 분할하여 요청할 수 있습니다.
사용자: 안녕하세요! 대학원 지원을 위한 자기 소개서를 작성하려고 하는데 도움이 필요해요.
AI: 안녕하세요! 자기 소개서 작성을 도와드릴게요. 무엇을 도와드릴까요?
사용자: 이름은 김철수이고, 25살입니다. 학력은 ○○대학교에 재학 중이고, 경력은 ○○회사에서 인턴 경험이 있어요.
AI: 이해했습니다. 다음으로 학업 및 경력에 대해 자세히 설명해주세요.
사용자: 제 전공은 경영학이고, ○○대학교에 다니고 있어요. 교내에서는 학생회 활동을 하고 있고, ○○회사에서 6개월 동안 인턴으로 근무했어요.
AI: 학업 및 경력 내용을 잘 기록했습니다. 다음으로 대학원 진학의 동기와 목표를 기술해주세요.
사용자: 대학원 진학의 동기는 경영학을 깊이 공부하여 창업에 도전하고 싶어서예요. 대학원에서는 창업 동아리에 참여하여 아이디어를 발전시키고 싶습니다.
AI: 이해했습니다. 마지막으로 자기 소개서 작성이 완료되었습니다. 작성한 내용을 확인하시겠습니까?
사용자: 네, 확인할게요. 감사합니다!
AI: 언제든지 도움이 필요하시면 말씀해주세요.
Plain Text
복사
일반적으로 한글 단어는 동음이의어 또는 다의어로 구성되어 있기 때문에 같은 형태의 단어가 여러개의 의 뜻을 가지고 있습니다. 다양한 의미 중 책에서 사용하는 의미를 찾기 위해 아래와 같은 프롬프트를 작성해 봅시다.
잘 동작하긴 하지만 뜻이 많아질 경우 문제가 생길 거 같다.
이 경우 프롬프트를 아래와 같이 N 개로 분할할 경우 좀 더 안정적인 성능을 기대할 수 있습니다.
N 개로 분할한 경우에도 잘 동작한다.
복잡한 질의를 처리할 때도 프롬프트 분할을 활용할 수 있습니다. 작업을 하위 작업으로 분할하여 이전 작업의 응답을 다음 작업의 요청으로 활용합니다(Prompt chaining).
사용자: 안녕하세요! 목적지까지의 이동 시간을 알고 싶어요.
AI: 안녕하세요! 무엇을 도와드릴까요?
사용자: 출발지는 서울역이고, 목적지는 강남역입니다.
AI: 출발지와 목적지를 알려주셔서 감사합니다. 이동에 사용할 교통 수단을 선택해주세요. (ex: 자동차, 대중교통)
사용자: 대중교통을 이용할 거에요.
AI: 대중교통을 선택하셨군요. 이동 시간을 계산하고 있습니다.
AI: 계산 결과, 서울역에서 강남역까지 대중교통으로 이동하는 데 약 30분이 소요됩니다. 결과가 맞나요?
사용자: 네, 맞아요. 감사합니다!
AI: 언제든지 더 도움이 필요하시면 말씀해주세요.
Plain Text
복사
이 방법을 활용하면 더 복잡하고 많은 일을 시킬 수 있습니다. 단어의 뜻을 찾아주는 작업 뿐만 아니라 단어의 뜻을 만들어내는 작업도 함께 지시해보겠습니다.
이제는 단어의 뜻까지 알아서 생성해 준다!
5. 마무리하며
LLM 을 활용하여 실제 사용자에게 제공되는 서비스를 구축하는 데에는 한계가 있을 것이라고 생각했습니다. 그런데 이번 프로젝트를 진행하면서 AI 가 가진 가능성에 대하여 다시 생각해보는 계기가 되었습니다. 서비스를 개발하고 운영하기 위한 공수를 획기적으로 줄일 수 있기 때문에 기존에 여러 한계에 부딪혀 시도하지 못했던 서비스들도 충분히 만들어 낼 수 있습니다. 이 글을 읽으시는 분들도 프롬프트 엔지니어링을 실무에 적극적으로 적용해서 매력있는 서비스를 구축해보시길 바랍니다.