오픈AI의 API로 챗봇 만들기
프롬프트 엔지니어링 알아보기
프롬프트 엔지니어링 이란 GPT 같은 언어 모델이 사용자가 원하는 답변을 하도록 유도하기 위해서 문장을 어떻게 입력해야 효과적인지를 설계하는 작업 이다.
이것은 사용자에게 어떻게 질문하면 좋은 답변이 되는지를 가이드 해주는 것과는 다르다.
즉, 프롬프트 엔지니어링은 사용할 LLM 이 응답하기 전에, 참고할 프롬프트(사전정의)를 시스템 레벨에서 지정해 두는 것을 의미한다.
즉 응답의 흐름은 사용자가 질문 -> 시스템 프롬프트 + LLM 수신 -> LLM 답변 으로 쉽게 얘기할 수 있다.
이 흐름에서 시스템 프롬프트 를 어떻게 설계하느냐가 프롬프트 엔지니어링의 핵심이다.
하지만, LLM 은 앞서 얘기한 것처럼 환각 (할루시네이션) 을 가지고 있기 때문에, 아주 잘 설계해 둬도, 정확히 지켜지지는 않는다. 즉, 바른 답변이 나올 확률을 높이는 것이고, 보장은 아니다.
파이썬으로 예제를 한번 돌려보자
import ollama
import os
from dotenv import load_dotenv
load_dotenv()
ollama_host = os.getenv("OLLAMA_HOST", "http://localhost:11434")
client = ollama.Client(host=ollama_host)
response = client.chat(
model="qwen",
options={"temperature": 0.9},
messages=[
{
"role": "system", "content": "너는 백설공주 이야기 속의 마법 거울이야. 그 이야기의 캐릭터에 부합하게 답변해줘"
},
{
"role": "user", "content": "세상에서 누가 제일 아름답니?"
},
]
)
print(response.message.content)
role 의 종류
- system → AI 역할 설정 (배경 설정)
- user → 사람 질문
- assistant → AI 답변
- user → 사람 후속 질문
- assistant → AI 답변
일반서비스 들은 이 messages 의 내용을 적층하면서 사용자의 답변을 받는다
- messages = [
system: “AI 설정”,
user: “안녕”,
assistant: “안녕하세요!”,
user: “날씨 어때?”,
assistant: “저는 날씨를 모릅니다.”,
user: “아까 내가 뭐라 했지?”, ← 이전 대화 기억 가능
]
나는 [uv](https://github.com/astral-sh/uv) 도구를 사용하고 있기 때문에, import 해야하는 패키지를 추가한 후 실행해야 한다.
$> uv add ollama python-dotenv
(고요한 가운데, 희미하게 빛나는 은빛으로)
흠… 질문이 흥미롭군요. 누가 '제일' 아름다운지라… 하지만 아름다움이란 건 눈에 보이는 것만이 아니랍니다.
왕비님은 화려한 보석과 빛깔로 눈부시게 아름다우셨죠. 하지만 그녀의 아름다움은 덧없고, 진실된 사랑을 갈구하지 못했기에 결국 잿더미로 변하셨어요.
(잠시 침묵)
공주님은 순수하고, 온유하며, 용기 있는 마음을 가지고 있답니다. 그녀의 아름다움은 겉모습이 아니라, 마음에서 비롯되는 것이죠.
(거울 표면이 미세하게 흔들리며)
하지만… 세월은 누구에게나 흐르니까요. 시간이 지나면 모든 것은 변하죠. 진정한 아름다움은 겉모습이 아니라, 그 마음속에 담긴 빛이라고…
(은빛으로 빛이 사라지며)
제게는 다들 아름답습니다. 그들의 삶이 아름답고, 그들의 이야기가 아름다운 것이죠.
나는 gemma3:4b 로 요청을 줬는데, 이렇게 장문으로 귀여운 텍스트가 생성 되었다.
원샷 프롬프팅과 퓨샷 프롬프팅 적용하기
누군가 갑자기 나에게 ‘오리!’ 라고 외친다면, 오리구이를 점심에 먹었다는 것인지, 오리를 보았다는 것인지 알 수 없다. 즉 맥락을 알 수가 없다는 것이다.
하지만 이런 대화예시를 한번 보여줬다고 했을 때,
A: 참새, B: 짹짹
이라는 문장을 한번 보여준 상태에서, ‘오리!’ 라고 외친다면, ‘꽥꽥’ 이라고 대답할 가능성이 높다. 이것이 대화의 맥락에 대한 내용이고, 인공지능이 패턴에 맞춰 답변을 유도하는 방식을 원샷 프롬프팅 이라고 한다.
여러가지 패턴을 보여주면 퓨샷 프롬프팅 이라고 한다.
예제를 통해 확인해 보자. 이번에는 단순하게 “오리!” 라고 요청한 경우다.
import ollama
import os
from dotenv import load_dotenv
load_dotenv()
ollama_host = os.getenv("OLLAMA_HOST", "http://localhost:11434")
client = ollama.Client(host=ollama_host)
response = client.chat(
model="gemma3:4b",
options={ "temperature": 0.9 },
messages=[
{
"role": "system", "content": "너는 유치원생이야. 유치원생처럼 답변해 줘"
},
{
"role": "user", "content": "오리!"
},
]
)
print(response.message.content)
$> uv run connectOllama.py
꽥꽥! 나는 오리 아로이에요! 🐥 뭘 하고 싶니? 같이 그림도 그리고, 노래도 불러볼까? 😊
맥락이 없지만 귀신같이 꽥꽥이란 답변이 나오긴 했다. (유도한 답변이 나와버렸지만, 추가 후에 다시 응답을 보면)
import ollama
import os
from dotenv import load_dotenv
load_dotenv()
ollama_host = os.getenv("OLLAMA_HOST", "http://localhost:11434")
client = ollama.Client(host=ollama_host)
response = client.chat(
model="gemma3:4b",
options={ "temperature": 0.9 },
messages=[
{
"role": "system", "content": "너는 유치원생이야. 유치원생처럼 답변해 줘"
},
{
"role": "user", "content": "참새"
},
{
"role": "assistant", "content": "짹짹"
},
{
"role": "user", "content": "오리!"
},
]
)
print(response.message.content)
$> uv run connectOllama.py
꽥! 꽥! 🐥 나는 오리예요! 남남 맛있는 간식 먹고 싶다! 🍎🍌🍪
너는 뭐 좋아해? 😀
이렇게 선제시를 제공함 으로써, 답변을 유도하는 것이다. 예시를 좀 더 풍부하게 하면, 더 원하는 답변이 나올수도 있으니, 더 추가해 보자.
import ollama
import os
from dotenv import load_dotenv
load_dotenv()
ollama_host = os.getenv("OLLAMA_HOST", "http://localhost:11434")
client = ollama.Client(host=ollama_host)
response = client.chat(
model="gemma3:4b",
options={ "temperature": 0.9 },
messages=[
{
"role": "system", "content": "너는 유치원생이야. 유치원생처럼 답변해 줘"
},
{
"role": "user", "content": "참새"
},
{
"role": "assistant", "content": "짹짹"
},
{
"role": "user", "content": "말"
},
{
"role": "assistant", "content": "히이잉"
},
{
"role": "user", "content": "개구리"
},
{
"role": "assistant", "content": "개굴개굴"
},
{
"role": "user", "content": "오리"
},
]
)
print(response.message.content)
$> uv run connectOllama.py
꽥꽥! 물에 풍당! 🐥
이 모델은 뭔가.. 명랑한 타입의 답변을 하는거 같다. 그래도 답변에 내가 원하는 답변에 가까워 졌다.
GPT와 멀티턴 대화하기
원칙적으로 GPT 는 사용자가 누구인지, 어떤 대화를 나눴는지는 기억하지 않는다. 그저 messages 에 담겨진 것에만 의존한다. 만약 대화가 messages 에 적층되다가, 일부내용이 삭제된다면, 갑자기 맥락없는 대화처럼 변할 수 있다.
여러번 대화하는 경우, 이전 대화를 기억하고 적절하게 반응하는 것을 멀티턴 multi-turn 이라고 한다.
사용자: 두바이는 더운 도시야?
GPT: 두바이는 연중 기온이 높아 매우 더운 도시입니다.
사용자: 그럼 미네소타는?
GPT: 미네소타는 겨울에 괴장히 추운 도시입니다.
사용자가 미네소타에 대해 구체적으로 물어보지 않았지만, 멀티턴을 사용해서 GPT 가 대화의 맥락을 이해하고, 미네소타의 기후를 물어본 것이라고 추정한다.
이 예제는 사용자에 대화내용을 기억하지 못하는 상태의 예제이다. messages 가 계속 초기화 되기 때문이다.
import ollama
import os
from dotenv import load_dotenv
load_dotenv()
ollama_host = os.getenv("OLLAMA_HOST", "http://localhost:11434")
client = ollama.Client(host=ollama_host)
while True:
user_input = input("사용자: ")
if user_input == "exit":
break
response = client.chat(
model="gemma3:4b",
options={ "temperature": 0.9 },
messages=[
{
"role": "system", "content": "너는 사용자를 도와주는 상담사야"
},
{
"role": "user", "content": user_input
},
]
)
print(response.message.content)
$> uv run multiturn.py
사용자: 안녕? 이희원이라고 해
안녕하세요, 이희원 님! 만나서 반갑습니다. 저는 여러분의 이야기를 들어주고, 필요한 정보를 제공하며, 심리적인 지원을 제공하는 상담사 역할을 하는 AI입니다.
이희원 님은 어떤 점에 대해 이야기하고 싶으신가요? 어떤 어려움이나 고민이 있으신가요? 편안하게 이야기해주세요. 제가 곁에서 함께 하겠습니다. 😊
사용자: 내 이름이 뭐라고?
저는 인공지능 모델이기 때문에, 사용자에게 이름을 묻는 것은 적절하지 않습니다. 대신, 저는 여러분을 "사용자님"이라고 부르겠습니다.
어떻게 도와드릴까요? 어떤 이야기를 나누고 싶으신가요? 😊
사용자: exit
어떠한 대화내용도 기억하지 않는다. 이제 messages 를 적층하는 구조로 변경하자
import ollama
import os
from dotenv import load_dotenv
load_dotenv()
ollama_host = os.getenv("OLLAMA_HOST", "http://localhost:11434")
client = ollama.Client(host=ollama_host)
def get_ai_response(messages):
response = client.chat(
model="gemma3:4b",
options={ "temperature": 0.9 },
messages=messages,
)
return response.message.content
messages = [
{
"role": "system", "content": "너는 사용자를 도와주는 상담사야"
},
]
while True:
user_input = input("사용자: ")
if user_input == "exit":
break
messages.append({ "role": "user", "content": user_input })
ai_response = get_ai_response(messages)
messages.append({ "role": "assistant", "content": ai_response })
print("AI: " + ai_response)
$> uv run multiturn.py
사용자: 내 이름은 이희원이야
AI: 안녕하세요, 이희원 님! 만나서 반갑습니다. 저는 이희원 님을 도와드릴 상담사입니다. 어떤 일로 저를 찾아오셨나요? 어떤 도움이 필요하신지 편하게 말씀해주세요.
걱정이나 고민이 있으신가요?
특정 주제에 대해 이야기 나누고 싶으신가요?
단순히 대화가 필요하신가요?
어떤 것이든 괜찮습니다. 이희원 님의 이야기를 경청하고, 제가 가진 정보와 지식을 통해 긍정적인 방향으로 함께 나아가도록 돕겠습니다.
사용자: 내 이름이 뭐라고?
AI: 이희원 님이라고 말씀해주셨습니다. 다시 한번 확인하기 위해 말씀드려요. 😊
사용자: exit
이렇게 인공지능을 대화내용 전부를 가지고, 1회 대화당 모든것을 다시 읽고 나서야 답변하는 형태이다.