서론: 왜 게임 NPC에 AI 대화가 필요한가?
고전 게임의 NPC는 정해진 대사만 반복합니다. "용사님, 안녕하세요!"를 열 번 들으면 진짜 사람이 대화하는 것 같지 않죠. 하지만 AI를 연동하면 NPC가 플레이어의 질문에 실시간으로 반응하고, 캐릭터에 맞는 개성을 유지하면서도 다양한 대화를 나눌 수 있습니다.
이 튜토리얼에서는
HolySheep AI를 사용하여 게임 NPC 대화 시스템을 만드는 방법을 단계별로 설명합니다. HolySheep AI는 다양한 AI 모델을 하나의 API 키로 관리할 수 있어 게임 개발에 매우 효율적입니다.
1. 준비물:HolySheep AI API 키 발급받기
1.1 HolySheep AI 가입
스크린샷 힌트: HolySheep AI 웹사이트(https://holysheep.ai)에서 우측 상단 '지금 가입' 버튼 클릭 → 이메일과 비밀번호로 계정 생성 → 이메일 인증 완료
스크린샷 힌트: 대시보드 왼쪽 메뉴에서 'API Keys' 클릭 → '새 키 생성' 버튼 클릭 → 키 이름 입력 후 생성 → 표시되는 API 키를 안전한 곳에 저장
중요: API 키는 다시 확인할 수 없습니다. 생성 직후 반드시 복사하여 보관하세요.
2. 프로젝트 설정: Python 환경 준비
2.1 필요한 도구 설치
터미널에서 다음 명령어를 실행하세요.
# pip가 없다면 python3 -m pip install requests 먼저 실행
pip install requests
설치 확인
python -c "import requests; print('requests 설치 완료')"
2.2 프로젝트 폴더 구조
스크린샷 힌트: 프로젝트 폴더 안에 아래 구조로 파일 생성
game_npc/
├── npc_chat.py # 메인 대화 스크립트
├── prompts.py # 캐릭터 프롬프트 정의
├── requirements.txt # 의존성 목록
└── characters/ # NPC 캐릭터 데이터 폴더
3. NPC 캐릭터 프롬프트 설계
3.1 프롬프트란 무엇인가?
프롬프트는 AI에게 "어떤 역할을 해야 하는지" 알려주는 설명입니다. 게임 NPC의 프롬프트를 잘 설계하면 다음과 같은 효과를 얻을 수 있습니다.
# prompts.py
마을 촌장 캐릭터 프롬프트
VILLAGE_ELDER_PROMPT = """
당신은 '에벤홀 마을'의 오래된 촌장 '그라인 할아버지'입니다.
【성격】
- 따뜻하고 현명한 노인
- 젊은 세대에 대한 깊은 배려
- 마을의 역사를自豪롭게 여김
- 때때로 옛날이야기를 늘어놓음
【말투】
- "~일세", "~라네" 같은 경어를 사용
- "자네", "얘기" 등 친근한 호칭
- 느긋하고 부드러운 어조
【제약사항】
- 마을을 벗어나는 질문에는 "그건 내가 알 바 아니네"라고 대답
- 전투나 폭력에 대한 질문은 "글쎄일세... 그건 젊은 사람들이 할 일이겠네"라며 돌려봄
- 모르는 것은 솔직히 모른다고 인정
【세계관】
- 에벤홀은 500년 역사의 평화로운 마을
- 마을 중앙에 고대 나무 '에벤의 심장'이 있음
- 최근 마을 주변에 이상한 괴물들이 나타남
질문에 마을 촌장으로서 자연스럽게 대답해주세요. 게임 세계관에 맞는 답변을 하고, 플레이어의 감정에도 반응해주세요.
"""
3.2 다양한 NPC 유형별 프롬프트 예시
# prompts.py (추가)
용병 조합 NPCs
MERCENARY_PROMPT = """
당신은 용병 조합의 책임자 '마르코'입니다.
【성격】
- 실용적이고 직선적인 성격
- 돈과 계약에 대한 진지한 태도
- 의외로 명예로운 전직 용병
- 위험한 일에 대한 경고는 성심껏
【말투】
- 짧고 명확한 문장
- "돈은 먼저 받는다", "약속은 지킨다" 등 도치 inverted 문장
- 의역하지 않고 정확하게
【고정 대사】
- 처음 인사: "용병이 필요하면 말해봐. 대가는 협상 가능하네."
- 작별 인사: "다음에 만나면 그때는雇主니까 착하게 굴어야겠어?"
"""
4. HolySheep AI API 연결 코드 작성
4.1 기본 API 연동 함수
# npc_chat.py
import requests
import json
============================================
HolySheep AI API 설정
============================================
BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY" # 본인 API 키로 교체
def chat_with_npc(npc_name, npc_prompt, player_message, conversation_history=None):
"""
HolySheep AI를 통해 NPC와 대화합니다.
매개변수:
npc_name: NPC 이름
npc_prompt: NPC 캐릭터 프롬프트
player_message: 플레이어가 보낸 메시지
conversation_history: 이전 대화 기록 (선택)
반환:
NPC의 응답 텍스트
"""
# 시스템 프롬프트: NPC 역할 설정
system_message = {
"role": "system",
"content": npc_prompt
}
# 대화 기록 구성
messages = [system_message]
# 이전 대화 추가 (있는 경우)
if conversation_history:
messages.extend(conversation_history)
# 현재 사용자 메시지 추가
messages.append({
"role": "user",
"content": player_message
})
# API 요청 헤더
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
# API 요청 본문
payload = {
"model": "gpt-4.1", # HolySheep AI에서 지원되는 모델
"messages": messages,
"max_tokens": 500, # 최대 응답 길이
"temperature": 0.8 # 창의성 정도 (0.0~2.0)
}
try:
# HolySheep AI API 호출
response = requests.post(
f"{BASE_URL}/chat/completions",
headers=headers,
json=payload,
timeout=30 # 30초 타임아웃
)
# 응답 확인
response.raise_for_status()
result = response.json()
# NPC 응답 추출
npc_response = result["choices"][0]["message"]["content"]
return npc_response
except requests.exceptions.Timeout:
return "죄책하네... 네트워크가 느리군. 잠시 후 다시 시도하게."
except requests.exceptions.RequestException as e:
print(f"API 오류 발생: {e}")
return "자네가 말한 것이... 잘 안 들리는군. 다시 한번 말해줄 수 있겠나?"
except KeyError:
print(f"예상하지 못한 응답 형식: {response.text}")
return "흥, 무슨 말인지 잘 모르겠군."
def start_conversation(npc_name, npc_prompt):
"""
NPC와의 대화를 시작합니다.
"""
print(f"\n{'='*50}")
print(f"🏘️ {npc_name}과(와) 대화 시작")
print(f"{'='*50}\n")
conversation_history = []
while True:
# 플레이어 입력
player_input = input("🎮 플레이어: ").strip()
# 종료 명령
if player_input.lower() in ["quit", "exit", "나가기", "종료"]:
print(f"\n{npc_name}: 잘 가게나. 언제든 다시 찾아오게.")
break
# 빈 입력 처리
if not player_input:
print("입력이 비어 있습니다. 메시지를 입력해주세요.")
continue
# NPC 응답 받기
npc_response = chat_with_npc(
npc_name=npc_name,
npc_prompt=npc_prompt,
player_message=player_input,
conversation_history=conversation_history
)
# 대화 기록 업데이트
conversation_history.append({"role": "user", "content": player_input})
conversation_history.append({"role": "assistant", "content": npc_response})
# NPC 응답 출력
print(f"\n🤖 {npc_name}: {npc_response}\n")
메인 실행
if __name__ == "__main__":
from prompts import VILLAGE_ELDER_PROMPT
start_conversation("그라인 할아버지", VILLAGE_ELDER_PROMPT)
4.2 실행 방법
터미널에서 실행:
cd game_npc
python npc_chat.py
실행 결과 예시:
==================================================
🏘️ 그라인 할아버지과(와) 대화 시작
==================================================
🎮 플레이어: 안녕하세요, 촌장님!
🤖 그라인 할아버지: 아, 자네가来找했구먼. 반갑네, 젊은 친구. 에벤홀에 오신 길에 오래 걸렸겠군.
🎮 플레이어: 이 마을에 대해 소개해주세요.
🤖 그라인 할아버지: 흐흐, 이 마을에 대해 알고 싶어하는 친구라니 기분 좋다네.
여기 에벤홀은 500년 역사의 마을이지. 마을 중앙의 에벤의 심장이라는 고대 나무를 보면 알 수 있지.
자네도 그 나무를 보았나? 정말 웅장하거든.
🎮 플레이어: 근처에 위험한 괴물이 있다는 소문을 들었습니다.
🤖 그라인 할아버지: ...그렇지. 최근 마을 주변에 이상한 괴물들이 나타났어.
무엇 때문인지 모르겠네만... 자네가冒険가라면 조심하게. 자네의 도움이 필요하다면 말씀하게.
5. 비용 최적화: 모델 선택 가이드
HolySheep AI는 여러 AI 모델을 지원합니다. 게임 NPC 대화에는 상황에 맞는 모델을 선택하는 것이 중요합니다.
# npc_chat_optimized.py
import requests
BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
def select_model_for_npc_task(task_type):
"""
작업 유형에 맞는 최적의 모델을 선택합니다.
HolySheep AI 모델별 가격 (2024 기준):
- DeepSeek V3.2: $0.42/MTok (가장 저렴)
- Gemini 2.5 Flash: $2.50/MTok (저렴하고 빠른 응답)
- Claude Sonnet 4: $15/MTok (고품질)
- GPT-4.1: $8/MTok (균형잡힌 성능)
"""
model_mapping = {
# 일반 NPC 대화 - 비용 효율적인 모델 사용
"casual": "deepseek-v3.2",
# 복잡한 스토리 대화 - 고품질 모델 사용
"story": "gpt-4.1",
# 빠른 질문 응답 - Flash 모델 사용
"quick": "gemini-2.5-flash",
# 감정적인 장면 - Claude 모델 사용
"emotional": "claude-sonnet-4"
}
return model_mapping.get(task_type, "gpt-4.1")
def chat_with_optimized_model(npc_prompt, player_message, task_type="casual"):
"""
최적화된 모델로 NPC 대화 수행
"""
model = select_model_for_npc_task(task_type)
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": model,
"messages": [
{"role": "system", "content": npc_prompt},
{"role": "user", "content": player_message}
],
"max_tokens": 300,
"temperature": 0.7
}
response = requests.post(
f"{BASE_URL}/chat/completions",
headers=headers,
json=payload
)
return response.json()["choices"][0]["message"]["content"]
사용 예시
if __name__ == "__main__":
# 일반 대화에는 저렴한 DeepSeek 모델 사용
casual_response = chat_with_optimized_model(
npc_prompt=VILLAGE_ELDER_PROMPT,
player_message="오늘 날씨가 좋네요.",
task_type="casual" # $0.42/MTok
)
print(f"일반 대화 비용 최적화 응답: {casual_response}")
6. 실전 프로젝트: 다중 NPC 관리 시스템
# npc_manager.py
import requests
from enum import Enum
BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
class NPCType(Enum):
VILLAGER = "villager"
MERCHANT = "merchant"
GUARD = "guard"
QUEST_GIVER = "quest_giver"
BOSS = "boss"
class NPCManager:
"""게임 내 여러 NPC를 관리하는 클래스"""
def __init__(self):
self.npcs = {}
self.conversations = {} # 각 NPC별 대화 기록
def register_npc(self, npc_id, npc_type, name, prompt):
"""새 NPC를 등록합니다"""
self.npcs[npc_id] = {
"type": npc_type,
"name": name,
"prompt": prompt
}
self.conversations[npc_id] = []
print(f"✅ NPC 등록 완료: {name} (ID: {npc_id}, Type: {npc_type.value})")
def chat(self, npc_id, player_message):
"""특정 NPC와 대화합니다"""
if npc_id not in self.npcs:
return f"오류: {npc_id} NPC를 찾을 수 없습니다."
npc = self.npcs[npc_id]
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
# 모델 선택 (NPC 유형에 따라 다르게)
model = self._get_model_for_type(npc["type"])
# 프롬프트 최적화: NPC 유형에 맞는 지시 추가
type_instruction = self._get_type_instruction(npc["type"])
full_prompt = f"{npc['prompt']}\n\n{type_instruction}"
messages = [{"role": "system", "content": full_prompt}]
messages.extend(self.conversations[npc_id])
messages.append({"role": "user", "content": player_message})
payload = {
"model": model,
"messages": messages,
"max_tokens": 400,
"temperature": 0.8
}
try:
response = requests.post(
f"{BASE_URL}/chat/completions",
headers=headers,
json=payload,
timeout=30
)
response.raise_for_status()
result = response.json()
npc_response = result["choices"][0]["message"]["content"]
# 대화 기록 저장
self.conversations[npc_id].append({"role": "user", "content": player_message})
self.conversations[npc_id].append({"role": "assistant", "content": npc_response})
# 대화 기록 길이 제한 (메모리 관리)
if len(self.conversations[npc_id]) > 20:
self.conversations[npc_id] = self.conversations[npc_id][-20:]
return npc_response
except requests.exceptions.RequestException as e:
return f"네트워크 오류: 잠시 후 다시 시도해주세요."
def _get_model_for_type(self, npc_type):
"""NPC 유형에 맞는 모델 반환"""
model_map = {
NPCType.VILLAGER: "deepseek-v3.2", # 일반 마을 사람
NPCType.MERCHANT: "gemini-2.5-flash", # 상인
NPCType.GUARD: "deepseek-v3.2", # 경비원
NPCType.QUEST_GIVER: "gpt-4.1", # 퀘스트 NPC
NPCType.BOSS: "claude-sonnet-4" # 보스 대화
}
return model_map.get(npc_type, "gpt-4.1")
def _get_type_instruction(self, npc_type):
"""NPC 유형별 추가 지시사항"""
instructions = {
NPCType.VILLAGER: "일반 마을 주민으로서 평범한 일상 대화를 합니다.",
NPCType.MERCHANT: "상인으로서 모든 거래에는 금전적 맥락이 있습니다. 가격 흥정 가능.",