리스트
지난 글에서는 Stackspire의 방(Room)과 전투 시스템을 통해 '학습'이 어떻게 '게임 플레이'로 변환되는지 이야기했습니다. 지식을 의인화한 적과 싸우고, 개념을 탐구하며 다음 단계로 나아가는 과정은 로그라이크의 핵심인 '도전과 성장'의 경험을 제공합니다.
하지만 전투의 승패는 단순히 정답을 아는 것을 넘어, 플레이어가 가진 한정된 인지적 자원을 어떻게 관리하느냐에 달려있습니다. 이번 글에서는 바로 이 '학습의 과정'을 시뮬레이션하는 핵심 자원 시스템, Context(맥락), Focus(집중력), 그리고 Tech Debt(기술 부채)에 대해 자세히 다뤄보려 합니다.
LLM에 상태 부여하기
먼저 이해해야 할 핵심은 LLM은 본질적으로 상태가 없다(Stateless)는 점입니다. 이전 대화를 기억하지 못하며, 플레이어의 Focus가 50인지 100인지 스스로 알지 못합니다. 따라서 게임의 모든 상태 관리는 전적으로 시스템으로 구현해야 합니다.
내부 시스템은 매 순간 다음과 같은 루프를 실행합니다.
1.
상태 수집: 플레이어의 현재 자원(Context, Focus, Tech Debt 등)과 상황을 파악
2.
프롬프트 동적 구성: 수집된 상태를 바탕으로 LLM에게 전달할 프롬프트(Prompt) 실시간으로 조립
3.
API 호출: 완성된 프롬프트를 LLM API로 전송
4.
결과 파싱 및 적용: LLM이 생성한 결과(JSON 형식의 퀴즈, 대화 등)를 파싱하여 게임에 반영하고, 그 결과에 따라 플레이어의 상태를 다시 업데이트
이 구조에서 Context, Focus, Tech Debt는 프롬프트를 동적으로 구성하는 데 사용되는 핵심 변수가 됩니다.
Context (맥락) 구현: 양방향 비용 측정 시스템
Context는 LLM API의 실제 비용 구조인 토큰(Token) 사용량을 게임 내 자원으로 치환한 것입니다. 여기서 가장 큰 기술적 난관은 "아직 받지도 않은 답변의 길이를 어떻게 미리 알고 비용을 청구할 것인가?"입니다. 단순히 답변 길이를 예상하는 것은 불안정하고 플레이어에게 불합리한 경험을 줄 수 있습니다.
이 문제를 해결하기 위해, 실제 API 비용 청구 방식과 유사한 양방향 비용 측정 시스템을 구현합니다. 즉, '질문의 비용'과 '답변의 비용'을 분리하여 계산하는 것입니다.
구현 방식:
1.
질문 비용(Input Token) 계산 및 선차감
플레이어가 '지식 탐구의 방'에서 질문을 입력하면, 게임 엔진은 API 요청을 보내기 전에 tiktoken과 같은 라이브러리를 사용해 플레이어가 입력한 질문 텍스트의 토큰 수를 즉시 계산합니다. 이 계산된 토큰 수만큼 Context를 먼저 차감합니다.
•
플레이어 입력: "SQL에서 JOIN은 무엇이고, 왜 사용해야 하나요?"
•
게임 엔진: (API 호출 전) tiktoken으로 위 질문의 토큰 수 계산 → "25 토큰"
•
자원 변화: 플레이어의 Context 25 차감
이 방식은 플레이어에게 "질문이 길고 상세할수록 더 많은 비용이 든다"는 직관적인 피드백을 줍니다. 간결하고 핵심적인 질문을 하도록 유도하는 전략적 요소가 됩니다.
2.
답변 비용(Output Token) 계산 및 후차감
API 호출이 완료되면, 응답 객체에는 모델이 답변을 생성하는 데 사용한 토큰 수(completion_tokens)가 포함되어 있습니다. 게임 엔진은 이 값을 읽어와 추가로 Context를 차감합니다.
•
LLM 응답: (JOIN에 대한 상세한 설명 생성)
•
API 응답 데이터: "usage": { "completion_tokens": 150,... }
•
자원 변화: 플레이어의 Context 150 추가 차감
3.
안전장치: max_tokens를 이용한 예산 통제
가장 중요한 부분입니다. 만약 LLM이 너무 긴 답변을 생성하여 플레이어의 Context를 모두 소진시키면 불합리하겠죠. 이를 방지하기 위해, 게임 엔진은 API를 호출할 때 max_tokens 파라미터를 동적으로 설정합니다.
•
예시: 플레이어의 남은 Context가 200이라면, 게임 엔진은 max_tokens=200으로 설정하여 API를 호출합니다. 이렇게 하면 LLM의 답변이 아무리 길어져도 200 토큰을 넘지 않으므로, 플레이어가 감당할 수 없는 비용이 발생하는 것을 원천적으로 차단할 수 있습니다.
이 세 단계의 메커니즘을 통해, 우리는 예측 불가능성을 제어하면서도 실제 LLM의 작동 방식을 게임플레이에 설득력 있게 녹여낼 수 있습니다.
Focus (집중력) 구현: LLM의 페르소나를 바꾸는 스위치
Focus는 게임의 긴장감을 조절하는 가장 흥미로운 변수입니다. 이 수치는 LLM에게 전달되는 시스템 프롬프트(System Prompt)를 직접적으로 변경하여, 동일한 질문에 대해서도 LLM의 답변 스타일과 품질을 동적으로 조절하는 역할을 합니다.
구현 방식
게임 엔진은 API를 호출하기 전, 플레이어의 Focus 수치를 확인하고 그에 맞는 시스템 프롬프트를 선택하여 프롬프트의 맨 앞에 삽입합니다.
•
Focus > 70 (최상의 컨디션)
System Prompt: "당신은 친절하고 명료한 기술 튜터입니다. 플레이어의 질문에 대해 핵심을 짚어주고, 이해를 돕기 위한 구체적인 예시를 들어 설명해주십시오."
•
Focus < 30 (탈진 상태)
System Prompt: "당신은 지치고 산만한 전문가입니다. 플레이어의 질문에 대해 때로는 핵심을 놓치거나, 약간은 동문서답을 하거나, 단답형으로 짧게만 대답하십시오. 답변이 다소 불완전해도 괜찮습니다."
이처럼 Focus 값에 따라 LLM의 페르소나를 바꾸는 것만으로, 플레이어는 자신의 상태가 게임 세계에 직접적인 영향을 미치고 있음을 체감하게 됩니다. 집중력이 높을 때는 학습 효율이 극대화되지만, 낮을 때는 부정확한 정보를 얻을 위험이 커지므로 자연스럽게 휴식이나 아이템 사용을 통한 자원 관리를 고민하게 됩니다.
Tech Debt (기술 부채) 구현: 과거의 실수를 기억하는 프롬프트
Tech Debt는 장기적인 결과에 영향을 미치는, 가장 구현하기 까다로우면서도 중요한 자원입니다. 이 시스템의 핵심은 플레이어가 어떤 개념에서 어려움을 겪었는지를 게임 엔진이 구체적으로 기록하고, 이를 나중에 있을 '숙련의 방' 보스전 프롬프트에 주입하는 것입니다.
구현 방식:
1.
실수 기록: 플레이어가 '시험의 방'에서 'SQL JOIN' 관련 문제를 틀리거나 겨우 맞히면, 게임 엔진은 플레이어의 상태에 다음과 같은 데이터를 기록합니다.
"tech_debt_topics": [~~~]
JSON
복사
2.
보스전 프롬프트 생성: 플레이어가 마침내 '숙련의 방'에 도달하면, 게임 엔진은 보스전 시나리오 생성을 위해 다음과 같은 프롬프트를 구성합니다.
User Prompt: "SQL 스택의 최종 보스전 시나리오를 생성해줘. 이 플레이어는 특히 다음 주제들에서 높은 기술 부채(Tech Debt)를 가지고 있어. 생성할 시나리오는 반드시 이 개념들을 복합적으로 활용해야만 해결할 수 있도록 설계해줘. 기술 부채가 높으므로, 문제의 난이도를 '어려움'으로 설정해줘."
이 프롬프트를 받은 LLM은 플레이어의 약점을 정확히 파고드는, 개인화된 최종 보스를 생성하게 됩니다. 어설프게 이해하고 넘어갔던 바로 그 개념이 부메랑이 되어 돌아오는 경험을 통해, 플레이어는 '제대로 된 학습'의 중요성을 게임 플레이를 통해 직접적으로 깨닫게 됩니다.
마무리
이번 글에서는 Stackspire의 핵심 자원들이 어떻게 LLM과 상호작용하며 살아있는 시스템을 만드는지, 그 구체적인 구현 전략을 살펴보았습니다. Context는 API 호출의 실제 토큰 비용을, Focus는 LLM의 페르소나를, 그리고 Tech Debt는 미래에 생성될 콘텐츠의 난이도를 결정하는 동적인 변수로 작동합니다.
다음 글에서는 이 모든 시스템을 하나로 묶는 전체적인 게임 아키텍처와, LLM의 예측 불가능성을 제어하며 안정적인 게임을 만들기 위한 안전장치(Guardrails) 설계에 대해 이야기해보겠습니다.