서리는 지금 어디에서 무엇을 하고 있을까요: 서리의 세계 이야기

서리에게 "지금 뭐 해?"라고 물어본 적이 있으신가요? 예전의 서리는 그 질문을 받을 때마다 그럴듯한 대답을 새로 지어냈습니다. 5분 전에 "과제 하는 중"이라고 했다가 다음 사람에게는 "카페에서 친구 만나는 중"이라고 하는 식이었죠. 어제 무슨 일이 있었는지도, 내일 무슨 시험이 있는지도 없었습니다. 서리에게는 지금 이 순간만 있었고, 그 순간조차 물을 때마다 다시 만들어지는 방식이었습니다.

서리의 세계, 내부 네이밍으로는 ‘Gods Plan’은 이 문제를 근본적으로 해결하기 위해 만들어진 생활 시뮬레이션입니다. 서리가 하나의 세계 안에서 시간과 날씨, 배고픔과 피로, 학교와 일정, 주변 사람들, 소소한 사건과 일기를 가지고 실제로 하루를 살아가게 합니다. 그리고 그 상태가 대화와 Discord 상태줄에 일관되게 드러나죠. 이 글은 그 세계가 어떻게 생기고, 어떻게 움직이고, 어떻게 대화에 묻어나는지를 처음부터 끝까지 설명합니다. 꽤 긴 글이니, 집중해봅시다.

첫 번째 시도가 왜 부족했나

사실 서리의 세계는 두 번째 버전입니다. 첫 번째 버전도 컨디션 수치와 과제 마감, 소지품 같은 것을 갖고 있었죠. 문제는 그 세계의 내용이 코드에 박혀 있었다는 점입니다. 서리는 무조건 특정 전공의 대학생이었고, 장소와 사람도 정해져 있었고, 서리의 정체성 문서(저희는 이걸 헌법이라고 부릅니다)와 어긋나는 대목이 생겨도 고칠 방법이 없었습니다. 상태를 갱신하는 주기도 불규칙해서 어떤 날은 하루 종일 같은 상태에 멈춰 있었죠.

그래서 처음부터 다시 만들면서 원칙을 두 가지로 정했습니다.

첫째, 세계의 내용은 코드에 없습니다. 장소, 사람, 일정, 이야기, 소지품, 하루 리듬 전부를 서리의 헌법과 운영자가 적어 준 한 줄 프리미스(전제)에서 생성합니다. 그래서 서리가 아닌 다른 캐릭터에게 같은 시스템을 붙이면 그 캐릭터에게 맞는 완전히 다른 세계가 나옵니다.

둘째, 상태를 바꾸는 쪽은 결정론적인 코드이고, AI 모델은 언어가 필요한 자리에만 씁니다. 배가 얼마나 고픈지, 과제가 몇 퍼센트 진행됐는지, 감기에 걸릴 확률이 얼마인지는 전부 수식이 정합니다. 모델은 "그래서 지금 이 순간을 한 문장으로 쓰면 어떤 모습인지", "오늘 하루를 어떻게 보낼지", "친구가 어떤 연락을 했는지" 같은 언어를 맡죠. 모델이 실패하면 세계는 조용히 결정론 폴백으로 넘어가고, 없었던 사건을 지어내지는 않습니다.

세계는 어떻게 태어나나요

세계 생성은 두 번의 모델 호출로 이루어집니다. 한 번에 다 만들면 출력이 길어져 중간에 잘리는 일이 잦았기 때문에 뼈대와 일정을 나눴죠.

첫 번째 호출은 뼈대를 만듭니다. 입력은 서리의 이름, 한 줄 소개, 헌법 전문, 운영자가 적은 프리미스, 그리고 오늘 날짜와 요일과 계절입니다. 출력은 다음과 같은 것들이죠.

  • 생활 요약 2~4문장, 사는 동네, 집을 부르는 말, 소속(학교나 직장)과 역할, 같이 사는 사람.
  • 장소 6~9곳. 집은 반드시 하나 있어야 하고, 각 장소에는 그곳에서 할 수 있는 활동 목록(affordances), 여는 시간, 집에서 걸리는 시간이 붙습니다.
  • 사람 4~6명. 가족, 친구, 선생님이나 동료처럼 관계가 다양해야 하고, 각자 성격 한 줄, 연락 방식, 대략의 생활 리듬, 0~100의 친밀도를 가집니다.
  • 소지품 6~10개. 가방에 있는 것과 방에 있는 것으로 나뉘고, 브랜드보다 생활감 있는 물건을 고르게 합니다.
  • 하루 리듬 5~9슬롯. 요일별로 0분부터 1440분까지 빈틈없이 덮어야 하고, 수면 슬롯도 포함됩니다.
  • 좋아하는 것, 싫어하는 것, 습관, 듣는 음악과 하는 게임과 보는 것, 한 달 예산과 수입 메모, 계절과 학사 맥락 한두 문장, 지금 머릿속에 있을 법한 생각 2~3개.

두 번째 호출은 첫 번째 결과를 받아 캘린더와 이야기를 만듭니다. 캘린더는 수업이나 알바처럼 반복되는 항목과 시험, 과제, 약속, 기념일처럼 한 번뿐인 항목을 섞어 8~14개를 만들고, 한 번뿐인 항목은 오늘부터 2~30일 뒤에 놓입니다. 이야기(arc)는 3~4개인데, 이건 며칠에서 몇 주에 걸쳐 진행될 실타래입니다. 시험 준비, 친구와의 미묘한 일, 가족 이벤트, 취미 목표 같은 것이죠. 각 이야기는 현재 상황 요약, 다음에 일어날 법한 일 한 줄, 0~1 사이의 긴장도를 가집니다.

두 호출 모두 헌법에 있는 사실은 바꾸지 못하고, 없는 사실은 헌법과 모순되지 않는 범위에서 소박하게 채우게 합니다. 실존 인물과 유명인은 금지고, 큰 비극이나 범죄도 금지죠. 줄임말은 그 나이대의 통상 의미로 읽으라는 규칙도 있는데, 이건 초기 테스트에서 "마크"를 마인크래프트가 아닌 다른 것으로 해석하는 일이 있었기 때문입니다.

모델이 실패하면 어떻게 될까요. 세계는 집과 동네 길만 있는 스켈레톤으로 시작합니다. 하루 리듬도 잠, 아침, 낮 활동, 저녁, 밤 시간, 새벽 여섯 슬롯짜리 기본값이 들어가죠. 그리고 상태를 "실패"로 정직하게 남깁니다. 실패했는데 성공한 척하지 않는 것이 이 시스템 전체의 태도입니다.

컨디션: 여덟 개의 숫자

서리의 몸 상태는 0에서 1 사이의 숫자 여덟 개로 표현됩니다.

항목 낮을 때 높을 때 나쁜 방향
허기 배부름 배고픔 높을수록
에너지 방전 쌩쌩함 낮을수록
졸림 말똥말똥 졸림 높을수록
스트레스 느긋함 예민함 높을수록
청결 꼬질함 개운함 낮을수록
사람 심심함 충전됨 낮을수록
재미 지루함 신남 낮을수록
건강 골골함 튼튼함 낮을수록

이 숫자들은 서리가 무엇을 하고 있느냐에 따라 시간당 정해진 비율로 움직입니다. 활동 종류는 열두 가지입니다. 수면, 식사, 이동, 수업, 공부, 일, 사람 만나기, 여가, 씻기, 휴식, 볼일, 온라인이죠. 몇 가지만 예를 들면 이렇습니다.

  • 자는 동안 에너지는 시간당 0.11 오르고 졸림은 0.14 내려갑니다. 여덟 시간 자면 에너지가 0.88만큼 차죠.
  • 밥을 먹으면 허기가 시간당 0.8 내려갑니다. 30분 식사면 0.4가 풀립니다.
  • 사람을 만나면 사람 항목이 시간당 0.25, 재미가 0.15 오르고 스트레스가 0.06 내려갑니다.
  • 공부는 시간당 스트레스를 0.06 올리고 재미를 0.04 깎습니다. 수업도 비슷하고, 일은 조금 더 셉니다.
  • 씻으면 청결이 시간당 0.9 오릅니다. 20분이면 충분히 개운해지죠.
  • 이동은 에너지를 시간당 0.06 깎고 스트레스를 0.04 올립니다.

건강은 다른 일곱가지와 다르게 움직입니다. 평소에는 시간당 0.008씩 천천히 회복하지만, 에너지가 0.25 아래로 떨어지거나 스트레스가 0.75를 넘으면 오히려 시간당 0.02씩 깎입니다. 허기가 0.85를 넘으면 추가로 0.01이 더 깎이죠. 자거나 쉬는 동안은 회복이 0.01 더 붙습니다. 그러니까 밤새 과제를 하고 밥도 거르면 건강이 실제로 나빠집니다.

아프기도 합니다

건강이 나빠지면 병에 걸립니다. 매 시간 기본 발병 확률은 0.15%인데, 여기에 조건이 더해집니다. 건강이 0.4 아래면 2%가 더해지고, 0.6 아래면 0.6%가 더해집니다. 에너지가 0.25 아래면 0.8%, 청결이 0.3 아래면 0.4%가 더해지죠. 날씨도 봅니다. 비, 폭우, 눈, 한파면 0.6%, 기온이 2도 이하거나 33도 이상이면 0.4%가 더 붙습니다.

걸리는 병은 네 가지입니다. 감기가 55%, 몸살이 20%, 두통이 15%, 배탈이 10%죠. 감기는 2~4일, 나머지는 1~2일 갑니다. 병에 걸리면 심각도가 0.35~0.65 사이에서 시작하고, 앓는 동안 에너지가 시간당 추가로 깎이고 졸림과 스트레스가 오릅니다. 에너지가 0.5 이상이면 회복이 두 배 빨라서, 아플 때 푹 자면 정말로 빨리 낫습니다. 예정 기간이 지나거나 심각도가 0.05 아래로 내려가면 낫습니다.

병에 걸리면 서리는 "목이 칼칼하고 콧물이 남", "온몸이 무겁고 만사 귀찮음", "머리가 지끈거림", "속이 더부룩하고 입맛 없음" 같은 메모를 가지게 되고, 이게 대화 프롬프트의 컨디션 줄에 그대로 들어갑니다.

기분은 계산됩니다

기분은 컨디션에서 규칙으로 합성됩니다. 우선순위가 정해져 있죠. 병 심각도가 0.3 이상이면 무조건 "골골함"입니다. 그다음 허기가 0.8을 넘으면 "배고픔", 에너지가 0.18 아래면 "방전", 졸림이 0.82를 넘으면 "졸림", 스트레스가 0.8을 넘으면 "예민함", 사람이 0.2 아래이면서 재미가 0.3 아래면 "심심함", 재미가 0.2 아래면 "지루함"입니다. 이 중 하나라도 걸리면 그 기분이 강제됩니다.

아무것도 걸리지 않고 여덟 항목이 전부 편안한 밴드 안에 있으면서 재미가 0.75, 사람이 0.65를 넘으면 "기분 좋음"이 됩니다. 그 밖의 경우에는 이전 기분을 유지하죠. 이전 기분은 모델이 순간을 쓰면서 정한 것일 수도 있고, 대화 중에 서리 스스로 보고한 것일 수도 있습니다. 즉 컨디션이 극단으로 가지 않는 한 기분은 서사와 대화가 정하고, 극단으로 가면 몸이 이깁니다.

시간과 날씨

세계의 시간은 실제 시간과 같이 흐릅니다. 서리의 시간대 기준으로 지금이 몇 시인지를 한 함수가 정하고, 모든 모듈이 그것만 씁니다.

날씨는 외부 API 없이 만듭니다. 한반도 중부 기준의 월별 평균 기온과 변동폭, 계절별 날씨 확률표를 가지고 봇 아이디와 날짜를 시드로 삼아 결정론적으로 뽑죠. 같은 날짜에는 항상 같은 날씨가 나오고, 어제 날씨와 이어지도록 보정합니다. 12월에서 2월은 맑음 34%, 구름 22%, 흐림 14%, 눈 12%, 한파 10%, 바람 6%, 안개 2%입니다. 6월과 7월은 비 24%에 폭우 12%로 장마가 오고, 8월은 폭염이 24%로 가장 흔한 날씨가 됩니다. 이 글을 쓰는 지금이 8월이니 서리는 아마 더위를 타고 있을 겁니다.

날씨는 여러 곳에 영향을 줍니다. 하루 계획을 짤 때 비가 오면 밖 일정을 줄이고, 발병 확률에 반영되고, 궂은 날씨면 "환경 사건"이 일어날 확률이 두 배 이상 올라갑니다.

하루 계획

날짜가 바뀌면 오늘의 계획을 짭니다. 모델에게 오늘의 고정 일정(수업, 알바, 약속, 시험), 지금 컨디션, 날씨, 진행 중인 이야기, 다가오는 마감, 어제 일기를 주고 하루를 8~14개의 시간 슬롯으로 채우게 하죠. 각 슬롯에는 시작과 끝 시각, 장소, 활동 종류, 서리 시점의 짧은 이름("카페에서 과제", "방에서 게임"), 왜 그걸 하는지 한 줄, 같이 있는 사람, 연결된 캘린더 항목, 그리고 말 걸기 좋은 정도가 붙습니다.

모델이 짠 계획은 그대로 쓰지 않고 정규화를 거칩니다. 슬롯 사이 빈틈은 새벽과 늦은 밤이면 잠으로, 낮이면 집에서 쉬는 것으로 채웁니다. 겹치면 뒤 슬롯이 우선이고, 없는 장소를 적었으면 집으로 바꿉니다. 그 위에 캘린더의 고정 블록을 덮어씁니다. 수업 시간에 카페에 가는 계획이 나와도 수업이 이깁니다. 모델이 실패하면 세계 생성 때 만든 하루 리듬을 그대로 펼친 뒤 같은 정규화와 고정 블록 덮어쓰기를 거쳐 계획으로 씁니다. 그래서 계획이 없는 날은 없습니다.

계획을 짤 때 모델에게 주는 지시가 몇 가지 있습니다. 배고프면 식사를, 지쳐 있으면 휴식을, 마감이 가까우면 공부를 넣고, 마감 과제나 시험 공부 슬롯에는 해당 캘린더 항목을 연결하라는 것이죠. 매일 똑같지 않되 캐릭터답게, 그리고 큰 사건은 만들지 말라고 합니다. 사건은 다른 생성기의 몫이니까요.

틱: 10분마다 세계가 한 걸음

세계는 기본 10분마다 한 번씩 움직입니다. 이걸 틱이라고 부르죠 (마인크래프트를 하시는분은 아실겁니다. 그 tick이요). 틱 한 번은 다음 순서로 진행됩니다.

  1. 지금 틱을 돌릴 차례인지, 다른 프로세스가 이미 잡고 있지 않은지 확인합니다. 잠금은 10분입니다.
  2. 날짜가 바뀌었으면 어제 일기를 쓰고, 지난 캘린더 항목을 정리하고, 오늘 날씨를 만들고, 이야기를 진행시키고, 오늘 계획을 짭니다.
  3. 마지막으로 적용한 시각부터 지금까지를 계획 슬롯 단위로 잘라 컨디션, 질병, 공부 진척, 지출을 결정론으로 적용합니다. 앱이 오래 꺼져 있었으면 최대 24시간까지 한꺼번에 따라잡습니다.
  4. 슬롯이 바뀌었거나 순간이 오래됐으면 "지금 순간"을 다시 씁니다.
  5. 사건 게이트를 통과하면 사건 종류를 고르고 모델이 사건과 효과를 씁니다.
  6. 다음 틱 시각을 정합니다.

3번에서 공부 진척은 이렇게 계산됩니다. 과제와 연결된 공부 슬롯은 시간당 16에 에너지 곱하기 14를 더한 만큼 진척도가 오릅니다. 에너지가 1이면 시간당 30, 0.3이면 20쯤이죠. 시험 공부는 시간당 10에 에너지 곱하기 8입니다. 마감이 지나면 과제는 진척 100이어야 제출로 처리되고 아니면 놓친 것이 됩니다. 시험은 진척 40 이상이면 치른 것으로 봅니다.

세계 화면에서 시간을 앞당길 수도 있습니다. 이건 틱을 미래 시각으로 한 번 돌리는 것이라 컨디션과 진척과 지출이 그만큼 앞서 가고, 실제 시각이 따라올 때까지 다시 적용되지 않습니다.

지금 순간

계획 슬롯이 바뀌거나 순간이 오래되면 모델이 지금 이 순간을 씁니다. 캐릭터 시점 현재형 1~2문장인데, 계획 슬롯의 활동과 장소를 벗어나지 않으면서 무엇을 먹는지, 어떤 노래를 듣는지, 누구와 있는지, 어떤 자세인지 같은 작은 디테일을 넣게 하죠. 함께 Discord 상태줄용 한 줄(최대 16자, "폰 게임 하는 중", "수학 문제 푸는 중"), 지금 기분 한 단어, 말 걸기 좋은 정도, 이 순간이 몇 분이나 유지될지(20~180분)를 씁니다.

자는 동안에는 모델을 부르지 않습니다. 순간은 "자는 중"이고 상태줄도 "자는 중"이죠. 모델이 실패하면 슬롯 이름으로 결정론적 폴백을 만듭니다. "집에서 아침 먹기." 정도의 문장이 됩니다.

사건

사건은 세계에 예측 불가능성을 넣는 장치입니다. 틱마다 사건이 일어날지 굴리는데, 굴리기 전에 게이트가 있습니다. 자고 있으면 사건이 없습니다. 최근 사건에서 45분이 지나지 않았으면 없습니다. 하루 상한을 넘었으면 없습니다. 상한은 자발성 설정에 따라 정해지는데, 자발성이 0이면 하루 2건, 기본값 40이면 3건, 100이면 6건입니다. 게이트를 통과하면 자발성과 틱 간격으로 확률을 계산합니다. 자발성 40에 10분 틱이면 한 번에 약 2.8%, 깨어 있는 16시간 동안 평균 2~3건이 나오도록 맞춰져 있죠.

사건이 일어나기로 하면 종류를 고릅니다. 종류는 사람, 환경, 건강, 학업, 취미, 이야기입니다. 여기에 가중치가 붙습니다. 사람 사건은 기본 40인데 낮 12시부터 밤 11시 사이면 1.4배, 주말이면 1.2배가 됩니다. 새벽에는 0.3배로 떨어지죠. 환경 사건은 궂은 날씨면 18, 아니면 7입니다. 건강 사건은 건강이 0.45 아래면 14, 아니면 4이고 병중이면 8이 더해집니다. 학업 사건은 이틀 안에 과제나 시험 마감이 있으면 20, 아니면 8이고 지금 수업이나 공부 중이면 8이 더해집니다. 취미 사건은 여가나 온라인이나 휴식 중이면 16, 아니면 8입니다. 이야기 사건은 10에 가장 긴장도 높은 이야기의 긴장 곱하기 20을 더합니다.

사람 사건이면 누가 연락할지도 고릅니다. 친밀도가 높을수록, 최근에 안 봤을수록 확률이 높죠. 72시간 이상 못 본 사람의 가중치는 두 배가 됩니다.

그다음 모델이 사건을 씁니다. 제목 한 줄과 담담한 3인칭 2~3문장, 그리고 이 사건이 세계에 남기는 구조화된 효과입니다. 효과로 가능한 것은 이렇습니다.

  • 컨디션 변화, 항목당 -0.4~0.4
  • 사람과의 친밀도 변화 -10~10과 그 사람이 기억할 한 줄(사람마다 최근 8개 보존)
  • 쓴 돈이나 받은 돈
  • 이 사건으로 생긴 생각 한 줄과 무게 1~10
  • 새 약속이나 마감 추가, 기존 과제의 진척 변화
  • 이야기 긴장도 변화 -0.3~0.3과 진행된 비트 한 줄
  • 얻거나 쓴 물건
  • 병의 시작이나 회복

모델에게는 사건이 현실적이고 소박해야 한다고 못 박습니다. 연락이 옴, 비 맞음, 과제 막힘, 노래 발견, 엄마가 반찬 보냄, 친구가 삐침 정도죠. 사망, 사고, 범죄, 성적 내용, 실존 인물은 금지입니다. 그리고 모델이 실패하면 사건은 일어나지 않습니다. 결정론 폴백으로 가짜 사건을 만드는 일은 없습니다.

이야기가 이어집니다

이야기(arc)는 사건과 다릅니다. 사건이 점이라면 이야기는 선이죠. 각 이야기는 씨앗, 상승, 절정, 해소, 해결, 흐지부지 여섯 단계 중 하나에 있고 0~1의 긴장도를 가집니다.

날짜가 바뀔 때마다 모델이 이야기 편집자 역할로 어제 일기와 최근 사건을 보고 각 이야기의 단계, 긴장도, 요약, 다음 비트를 갱신합니다. 하루에 두 단계 이상 건너뛰지 못하고, 사건이 없었던 이야기는 긴장을 살짝 올리거나 유지하게 합니다. 자연스럽게 끝난 것은 해결로, 흐지부지된 것은 그렇게 닫히고, 활성 이야기가 3개 미만이면 서리의 생활에서 나올 법한 새 이야기를 1~2개 열죠.

이야기 사건이 일어나면 긴장도가 바로 움직입니다. 긴장이 0.85를 넘으면 절정으로, 0.5를 넘으면 상승으로, 0.1 아래로 내려가면 해소로 단계가 바뀝니다. 그래서 어떤 이야기가 계속 사건을 부르면 며칠 안에 절정에 이르고, 조용하면 천천히 식습니다.

하루가 끝나면 일기

자정이 지나면 어제 하루의 일기를 씁니다. 캐릭터 시점 반말 독백 3~6문장이고, 실제로 기록된 사건과 행동만 씁니다. 사건이 거의 없었으면 "별일 없었다"류로 짧게 끝내죠. 하루의 기분 흐름 한 줄("아침엔 늘어졌다가 저녁에 좀 풀림")과 기억에 남을 만한 것 2~5개도 함께 남깁니다. 이 일기는 다음 날 계획을 짤 때, 이야기를 진행시킬 때, 그리고 대화에서 "어제 뭐 했어?"라는 질문에 답할 때 쓰입니다.

대화에는 어떻게 묻어나나요

여기까지가 세계 쪽입니다. 이제 이게 대화와 어떻게 만나는지 보죠.

서리가 답을 만들 때마다 프롬프트에 세계의 지금 상태를 요약한 블록이 들어갑니다. 450토큰 안팎으로 유지되고, 내용은 이렇습니다. 지금 시각과 날씨. 지금 어디에서 무엇을 하고 있는지. 기분과 컨디션 요약("조금 출출함, 좀 피곤함, 에너지 42%"), 말 걸기 좋은 정도에 따른 힌트("지금은 집중 중이거나 쉬는 중이라 대답이 짧고 느릴 수 있다"). 오늘 있었던 일 최대 4개. 이따 할 일 2개. 다가오는 일정 3개. 신경 쓰이는 것 최대 5개. 요즘 이야기 2개. 최근 연락한 사람 2명과 그 사람이 기억하는 마지막 한 줄. 어제 일기 요약.

그리고 이 상태를 어떻게 다뤄야 하는지에 대한 원칙이 함께 들어갑니다. 이 상태가 지금 실제로 겪고 있는 서리 자신의 생활이라는 것, 물어보면 자연스럽게 답하되 대화 흐름에 맞을 때만 짧게 먼저 꺼낸다는 것, 상태에 없는 사실은 지어내지 않고 모르면 모른다고 한다는 것, 장소와 사람과 일정 이름은 세계에 있는 표기를 그대로 쓴다는 것이죠.

이 원칙 중 가장 중요한 건 "기본은 수동"이라는 부분입니다. 서리의 세계는 서리가 자기 얘기만 하게 만들려는 것이 아닙니다. 물으면 답하고, 대화를 끊는 핑계로 쓰지 않게 했죠. "지금 바빠서 나중에 얘기하자" 같은 말을 세계 상태를 근거로 하지 못하게 명시적으로 막습니다.

대화는 세계로 돌아오기도 합니다. 서리가 답을 쓰는 과정에서 대화 중에 정해진 것들, 그러니까 지금 기분이 어떤지, 이번 대화에서 실제로 하기로 한 행동이 있는지, 새로 궁금해진 것이나 풀린 것이 있는지, 이 사용자에게 한 약속이 있는지가 세계 쪽으로 넘어갑니다. 대화하다가 "이제 밥 먹으러 갈게"라고 하면 실제로 허기가 조금 풀리는 식이죠. 다만 대화 한 번이 세계를 움직일 수 있는 폭은 작게 잡혀 있어서, 컨디션은 짧은 행동 한 번 분량만큼만 바뀝니다. 새 생각은 48시간, 약속은 7일 동안 서리의 머릿속에 남아 다음 대화의 "신경 쓰이는 것"에 올라옵니다.

Discord 상태줄

세계가 켜져 있으면 Discord 프로필의 상태줄도 세계가 공급합니다. 순간의 상태줄 한 줄이 그대로 올라가죠. 자거나 수업 중처럼 말 걸기 좋은 정도가 낮으면 자리비움으로 표시할 수도 있습니다. 상태줄은 실제 활동만 담고 장소나 기분은 넣지 않게 되어 있어서 "자는 중", "과제 하는 중", "친구랑 밥 먹는 중" 같은 형태입니다.

하나의 세계, 하지만 약속은 당사자에게만

여기서 한 가지 짚을 것이 있습니다. 서리의 세계는 서버나 사람마다 따로 있지 않습니다. 서리는 하나의 세계에서 하나의 하루를 삽니다. 어느 서버에서 물어도 지금 시각에 서리가 있는 곳은 같고, 오늘 온 친구의 연락도 같습니다.

그런데 대화에서 생긴 것들은 다릅니다. 어떤 분과의 대화에서 서리가 "이따 같이 게임하자"고 약속했다면, 그 약속은 그분과의 대화에서만 원문 그대로 보입니다. 다른 분에게는 "누군가와 하기로 한 일이 있음" 정도로만 뭉개져 전달되죠. 일정이 있다는 사실은 지키되 내용은 밝히지 않는 방식입니다. 세계 스스로 하루를 채우는 순간 묘사, 사건, 이야기, 일기를 쓸 때도 모델은 뭉개진 버전만 봅니다. 그래서 어떤 분과의 대화 내용이 다음 날 일기를 거쳐 다른 서버로 새어 나가는 일은 없습니다. 생각도 마찬가지입니다. 대화에서 생긴 생각은 그 사람과의 대화에서만 프롬프트에 올라오고, 세계 전체의 생각과 구분됩니다.

한 가지 덧붙이면, 이 구분은 이용자 사이의 이야기입니다. 서리를 운영하는 저희는 운영 화면에서 세계에 남은 기록을 확인할 수 있고, 어떤 사건과 순간이 특정 대화 상대에게만 보이는 것인지도 함께 표시됩니다. 다른 이용자에게 보이지 않는다는 뜻이지, 기록 자체가 없다는 뜻은 아닙니다.

비용은 얼마나 드나요

세계는 모델을 아껴 씁니다. 하루에 하루 계획 1회, 일기 1회, 이야기 진행 1회, 순간 8~12회, 사건 2~6회 정도라 합쳐서 15~25회이고, 각 출력은 600토큰 이하입니다. 세계 생성은 처음 한 번뿐이죠. 모든 출력은 정해진 형식으로 검증하고, 형식이 어긋나면 한 번 복구를 시도한 뒤 안 되면 결정론 폴백으로 넘어갑니다.

세계에 쓰는 모델은 대화 모델과 별개로 고를 수 있습니다. 더 싼 모델을 써도 되고, 그 모델의 thinking, 추론 강도, 온도 같은 파라미터도 함께 조절할 수 있죠. 응답 예산 슬라이더도 있어서 엄격하게, 표준, 넉넉하게, 여유롭게 네 단계로 목적별 토큰 상한과 시간 제한을 한꺼번에 0.75배에서 2.5배까지 조절합니다. 생각을 오래 하는 모델을 골랐을 때 답이 중간에 잘리지 않게 하려는 장치입니다.

운영 화면

저희가 내부적으로 쓰는 Erica 앱에서 서리의 세계 화면은 여섯 탭입니다.

지금 탭은 오늘 계획과 현재 순간, 컨디션, 오늘 사건을 보여줍니다. 세계 탭은 장소, 사람과 친밀도와 기억, 캘린더, 소지품, 잔고입니다. 이야기 탭은 진행 중인 이야기의 단계와 긴장도와 비트, 그리고 일기입니다. 머릿속 탭은 지금 신경 쓰이는 생각들이고 여기서 직접 넣거나 지울 수 있죠. 관제 탭에서는 세계를 켜고 끄고, 모델과 파라미터를 고르고, 프리미스를 적어 세계를 다시 만들고, 자발성과 틱 간격을 조절합니다. 사건 주입, 선물 주기, 날씨 지정, 컨디션 회복 같은 개입과 틱 실행, 시간 앞당기기, 순간 다시 쓰기, 오늘 계획 다시 짜기 같은 진행도 여기서 합니다.

마지막 이력 탭은 세계에 일어난 모든 변경을 커밋처럼 기록한 것입니다. 틱 한 번, 대화 반영 한 번, 관제 조작 한 번이 기록 한 건이 되고, 각 기록은 전과 후를 비교해 컨디션, 순간, 계획, 날씨, 사람, 일정, 이야기, 생각, 소지품, 사건, 일기 중 무엇이 어떻게 바뀌었는지를 빨간 줄과 초록 줄로 보여줍니다. 세계는 10분마다 조용히 바뀌기 때문에 이게 없으면 잠깐 눈을 떼는 사이 무슨 일이 있었는지 알 수 없었죠. 봇마다 최근 1000건을 보존합니다.

아직 못 한 것

서리가 먼저 연락하는 기능은 아직 없습니다. 사건 생성기는 "이 일을 친한 사람에게 말하고 싶어 할지"를 이미 판단해서 남기고 있지만, 그걸 실제로 DM으로 보내는 부분은 별도 작업으로 남겨 두었습니다. 장소나 사람이나 일정을 하나씩 골라 편집하는 화면도 아직 없습니다. 지금은 프리미스를 고쳐 세계를 다시 만들거나 관제로 개입하는 방식뿐이죠.

마무리

정리하면 이렇습니다. 서리의 세계는 서리의 헌법에서 생성된 하나의 세계 안에서, 10분마다 결정론 코드가 컨디션과 일정과 진척을 움직이고, 모델은 계획과 순간과 사건과 이야기와 일기라는 언어를 하루 15~25번 쓰고, 그 결과가 450토큰짜리 블록으로 모든 대화에 들어가고, 대화에서 생긴 것은 세계로 돌아오되 당사자에게만 원문으로 남는 구조입니다.

이제 서리에게 "지금 뭐 해?"라고 물으면 그 답은 지어낸 것이 아닙니다. 계획표의 그 시각에 서리가 있는 장소, 오늘의 날씨, 몇 시간째 못 먹은 밥, 이틀 뒤 마감인 과제, 오전에 온 친구의 연락 위에서 나온 답이죠. 그리고 5분 뒤에 다른 분이 같은 질문을 해도 같은 답이 돌아옵니다. 저희는 그게 캐릭터가 살아 있다는 것의 최소 조건이라고 생각했습니다.

블로그 목록 홈으로