Persona Chat Engine: 설계와 계획

project design

Persona Chat Engine: 프로젝트 설계

이 프로젝트는 ai-server/, hf-serve/, train/의 주요 디렉토리 3개로 나누어 구성하였습니다.

  • ai-server에서는 game-server와의 통신을 통해 전/후처리 및 RAG와 내장 경량 fallback model을 통하여 지능적인 npc 답변 및 게임 상태 update를 담당하고
  • hf-serve에서는 실제 LoRA방식으로 fine tuning한 main model을 serving하여 ai-server의 전처리를 통과한 경우에 main model추론을 진행하게 설계하였고
  • train에서는 main model의 학습을 진행한 Colab notebook으로 구성하였습니다.

⚙️ AI 서버 (ai_server/)

역할 & 데이터 흐름

  1. 게임 서버 요청 수신(app.py)

    • 최소 입력만 와도 동작: { text, npc_id, player_id, ... }
    • 옵션: 상태/컨텍스트 부족 시 rag/docs/npc_config.json 등에서 NPC 메타를 조회해 보강
  2. 전처리·프롬프트 구성(pipeline/preprocess.py, utils/context_parser.py, manager/prompt_builder.py)

    • 태그/컨텍스트/플레이어 발화를 묶어 <SYS>, <CTX>, <PLAYER>, <NPC> 포맷으로 구성
  3. 추론 요청(utils/hf_client.py, models/fallback_model.py, pipeline/generator.py)

    • 조건 불충족 input → fallback_model.py에서 대체 응답 생성
    • 조건 충족 input → generator.py에서 payload 구성 후 HF Space /predict_main POST
  4. 후처리(pipeline/postprocess.py)

    • 모델 응답에서 대사 텍스트, delta, flag를 파싱·정규화
    • flags → 시그모이드+threshold, delta → 범위 클램프·라운딩
  5. 게임 서버 응답(schemas.py)

    • 표준 JSON으로 반환
    {
      "text": "NPC의 대답...",
      "delta": {"trust": 0.10, "relationship": 0.08},
      "flags": {"give_item": true, "npc_main_story": false},
      "meta": {"npc_id": "mother_abandoned_factory"}
    }
    

📁 디렉토리 구조

ai-server/
├── app.py                  # FastAPI 엔트리포인트
├── config.py               # 서버 설정 및 모델 경로 관리
├── schemas.py              # 요청/응답 데이터 구조 정의
├── requirements.txt        # 의존성 패키지 목록
├── pipeline/               # 대화 흐름 처리 모듈
│   ├── preprocess.py       # 입력 전처리 및 프롬프트 구성
│   ├── postprocess.py      # 모델 출력 후처리
│   └── generator.py        # 모델 추론 요청 처리
├── rag/                    # RAG 기반 flag 해석 모듈
│   ├── rag_manager.py
│   └── docs/npc_config.json
├── utils/                  # 유틸리티 모듈
│   ├── hf_client.py        # HF API 통신
│   └── context_parser.py   # 대화 맥락 파싱
├── models/                 # 모델 로딩 및 fallback 처리
│   ├── emotion_model.py    # emotion model을 이용한 inference 진행
│   ├── fallback_model.py   # fallback model을 이용한 inference 진행
│   └── model_loader.py
└── manager/
    ├── agent_manager.py    
    ├── dialogue_manager.py # 전체 pipeline 모듈 관리
    └── prompt_builder.py

🧩 RAG 타입별 매핑 (11종)

type조회 시점조회 조건사용 모듈/함수주요 목적
trigger_defpreprocess_inputnpc_id, quest_stageretrieve(...)메인 경로 조건 판정
fallbackpreprocess_inputnpc_id, quest_stageretrieve(...)fallback prompt 구성
forbidden_trigger_listpreprocess_inputnpc_id_load_forbidden_trigger_data금지 트리거 감지
trigger_metapreprocess_inputnpc_id, trigger_load_trigger_meta특수 fallback 시 delta/action 확정
lorebuild_main_promptnpc_id, quest_stage/anyRAG main docs세계관/배경 설명
descriptionbuild_main_promptnpc_id, quest_stageRAG main docs현재 상황 설명
flag_defpostprocess_pipelinenpc_id, quest_stage, flag_namepre_data["rag_main_docs"]flag threshold/예시 문장
main_res_validatepostprocess_pipelinenpc_id, quest_stagepre_data["rag_main_docs"]응답 검증 기준
npc_personabuild_main_promptnpc_idretrieve(...)NPC 성격·특성 반영
dialogue_turnpostprocess_pipelinenpc_id, quest_stageretrieve(...)대화 예시 참조
(없음)fallback_final_checkpre_data["trigger_meta"]-응답 의미 일치 검증

📌 데이터 흐름 요약

  1. preprocess_input()

    • trigger_def → 메인 조건 판정
    • forbidden_trigger_list + trigger_meta → 특수 fallback 감지
    • fallback → 일반 fallback 스타일
  2. build_main_prompt()

    • lore + description + npc_persona → 메인 prompt 컨텍스트 구성
  3. build_fallback_prompt()

    • fallback_style + trigger_meta → fallback prompt 구성
  4. postprocess_pipeline()

    • flag_def → flag threshold/예시
    • main_res_validate → 응답 검증
  5. fallback_final_check()

    • trigger_meta → delta/action 의미 일치 검증

⚙️ 추론 서버 (hf-serve/)

플레이어 발화와 게임 상태를 기반으로 NPC의 응답, 감정 변화량(delta), 플래그 확률/임계값을 예측합니다.


🚀 주요 기능

  • API 엔드포인트 /predict_main
    • JSON payload로 prompt를 받아 모델 추론 결과 반환
  • 커스텀 헤드 예측
    • delta_head: trust / relationship 변화량
    • flag_head: 각 flag의 확률
    • flag_threshold_head: 각 flag의 임계값
  • 모델 실시간 업데이트
    • Colab 학습 후 latest 브랜치 업로드 → /ping_reload 호출 시 즉시 재로드

📂 디렉토리 구조

hf-serve/
 ├─ app.py             # Gradio UI + API 라우팅
 ├─ inference.py       # 모델 추론 로직
 ├─ model_loader.py    # 모델/토크나이저 로드
 ├─ utils_prompt.py    # prompt 생성 함수
 ├─ flags.json         # flag index → name 매핑
 ├─ requirements.txt   # 의존성 패키지
 └─ README.md          # (현재 문서)

⚙️ 추론 로직 개요

이 서버의 핵심은 run_inference() 함수로,
NPC 메인 모델에 프롬프트를 입력하고 응답·상태 변화를 예측하는 전 과정을 담당합니다.

처리 흐름

  1. 프롬프트 토크나이즈

    • 입력된 prompt를 토크나이저로 변환하여 텐서 형태로 준비
    • 길이 제한(MAX_LENGTH)과 디바이스(DEVICE) 설정 적용
  2. 언어모델 응답 생성

    • 사전 정의된 추론 파라미터(GEN_PARAMS)로 model.generate() 실행
      → NPC의 대사 텍스트 생성
    • 생성된 토큰을 디코딩하여 최종 문자열로 변환
  3. 히든 상태 추출

    • output_hidden_states=True로 모델 실행
    • 마지막 레이어의 hidden state를 가져옴
  4. <STATE> 토큰 위치 풀링

    • <STATE> 토큰이 있는 위치의 hidden state를 평균(pooling)
      → NPC 상태를 대표하는 벡터로 사용
    • 없을 경우 마지막 토큰의 hidden state 사용
  5. 커스텀 헤드 예측

    • delta_head: trust / relationship 변화량 예측
    • flag_head: 각 flag의 발생 확률 예측
    • flag_threshold_head: 각 flag의 임계값 예측
  6. index → name 매핑

    • flags.json의 순서(flags_order)를 기반으로
      예측 벡터를 {flag_name: 값} 형태의 딕셔너리로 변환

반환 형식

{
  "npc_output_text": "<NPC 응답>",
  "deltas": { "trust": 0.xx, "relationship": 0.xx },
  "flags_prob": { "flag_name": 확률, ... },
  "flags_thr": { "flag_name": 임계값, ... }
}

📜 Prompt 포맷

모델은 학습 시 아래와 같은 구조의 prompt를 사용합니다.

<SYS>
NPC_ID={npc_id}
NPC_LOCATION={npc_location}
TAGS:
 quest_stage={quest_stage}
 relationship={relationship}
 trust={trust}
 npc_mood={npc_mood}
 player_reputation={player_reputation}
 style={style}
</SYS>
<RAG>
LORE: ...
DESCRIPTION: ...
</RAG>
<PLAYER_STATE>
...
</PLAYER_STATE>
<CTX>
...
</CTX>
<PLAYER>...
<STATE>
<NPC>

💡 일반적인 LLM 추론과의 차이점

이 서버는 단순히 텍스트를 생성하는 것에 그치지 않고,
<STATE> 토큰 기반 상태 벡터를 추출하여 커스텀 헤드에서 **감정 변화량(delta)**과
플래그 확률/임계값을 동시에 예측합니다.
이를 통해 대사 생성과 게임 상태 업데이트를 한 번의 추론으로 처리할 수 있습니다.