Spaces:
Sleeping
Sleeping
| title: NPC Main Model Inference Server | |
| emoji: ๐ค | |
| colorFrom: blue | |
| colorTo: pink | |
| sdk: gradio | |
| sdk_version: "5.44.1" | |
| python_version: "3.10" | |
| app_file: app.py | |
| # NPC ๋ฉ์ธ ๋ชจ๋ธ ์ถ๋ก ์๋ฒ (hf-serve) | |
| ์ด Space๋ **NPC ๋ํ ๋ฉ์ธ ๋ชจ๋ธ**์ ์ถ๋ก API์ ๊ฐ๋จํ Gradio UI๋ฅผ ์ ๊ณตํฉ๋๋ค. | |
| Hugging Face Hub์ ์ ๋ก๋๋ | |
| [Base model](https://huggingface.co/Qwen/Qwen2.5-3B-Instruct)๊ณผ | |
| [LoRA adapter model](https://huggingface.co/m97j/npc_LoRA-fps)์ ๋ก๋ํ์ฌ, | |
| ํ๋ ์ด์ด ๋ฐํ์ ๊ฒ์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก NPC์ ์๋ต, ๊ฐ์ ๋ณํ๋(delta), | |
| ํ๋๊ทธ ํ๋ฅ /์๊ณ๊ฐ์ ์์ธกํฉ๋๋ค. | |
| --- | |
| ## ๐ ์ฃผ์ ๊ธฐ๋ฅ | |
| - **API ์๋ํฌ์ธํธ** `/predict_main` | |
| - JSON payload๋ก prompt๋ฅผ ๋ฐ์ ๋ชจ๋ธ ์ถ๋ก ๊ฒฐ๊ณผ ๋ฐํ | |
| - **์น UI** `/ui` | |
| - NPC ID, ์์น, ํ๋ ์ด์ด ๋ฐํ๋ฅผ ์ ๋ ฅํด ์ค์๊ฐ ์๋ต ํ์ธ | |
| - **์ปค์คํ ํค๋ ์์ธก** | |
| - `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: ๊ฐ}` ํํ์ ๋์ ๋๋ฆฌ๋ก ๋ณํ | |
| ### ๋ฐํ ํ์ | |
| ```json | |
| { | |
| "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)**๊ณผ | |
| **ํ๋๊ทธ ํ๋ฅ /์๊ณ๊ฐ**์ ๋์์ ์์ธกํฉ๋๋ค. | |
| ์ด๋ฅผ ํตํด ๋์ฌ ์์ฑ๊ณผ ๊ฒ์ ์ํ ์ ๋ฐ์ดํธ๋ฅผ **ํ ๋ฒ์ ์ถ๋ก ์ผ๋ก ์ฒ๋ฆฌ**ํ ์ ์์ต๋๋ค. | |
| --- | |
| ## ๐ฏ ์ถ๋ก ํ๋ผ๋ฏธํฐ | |
| | ํ๋ผ๋ฏธํฐ | ์๋ฏธ | ์ํฅ | | |
| |----------|------|------| | |
| | `temperature` | ์ํ๋ง ์จ๋ (0.0~1.0+) | ๋ฎ์์๋ก ๊ฒฐ์ ์ (Deterministic), ๋์์๋ก ๋ค์์ฑ ์ฆ๊ฐ | | |
| | `do_sample` | ์ํ๋ง ์ฌ๋ถ | `False`๋ฉด Greedy/Beam Search, `True`๋ฉด ํ๋ฅ ๊ธฐ๋ฐ ์ํ๋ง | | |
| | `max_new_tokens` | ์๋ก ์์ฑํ ํ ํฐ ์ ์ ํ | ์๋ต ๊ธธ์ด ์ ํ | | |
| | `top_p` | nucleus sampling ํ๋ฅ ๋์ ์ปท์คํ | ๋ค์์ฑ ์ ์ด (0.9๋ฉด ์์ 90% ํ๋ฅ ๋ง ์ฌ์ฉ) | | |
| | `top_k` | ํ๋ฅ ์์ k๊ฐ ํ ํฐ๋ง ์ํ๋ง | ๋ค์์ฑ ์ ์ด (50์ด๋ฉด ์์ 50๊ฐ ํ๋ณด๋ง) | | |
| | `repetition_penalty` | ๋ฐ๋ณต ์ต์ ๊ณ์ | 1.0๋ณด๋ค ํฌ๋ฉด ๋ฐ๋ณต ์ค์ | | |
| | `stop` / `eos_token_id` | ์์ฑ ์ค๋จ ํ ํฐ | ํน์ ๋ฌธ์์ด/ํ ํฐ์์ ๋ฉ์ถค | | |
| | `presence_penalty` / `frequency_penalty` | ํน์ ํ ํฐ ๋ฑ์ฅ ๋น๋ ์ ์ด | OpenAI ๊ณ์ด์์ ์ฃผ๋ก ์ฌ์ฉ | | |
| | `seed` | ๋์ ์๋ | ์ฌํ์ฑ ํ๋ณด | | |
| ์ ํ๋ผ๋ฏธํฐ๋ค์ **ํ์ต ์์๋ ์ฌ์ฉ๋์ง ์๊ณ **, | |
| ๋ชจ๋ธ์ด ์๋ต์ ์์ฑํ๋ **์ถ๋ก ์์ **์๋ง ์ ์ฉ๋ฉ๋๋ค. | |
| ## ๐ก ์ฌ์ฉ ์์ | |
| - **๊ฒฐ์ ์ ๋ถ๋ฅ/ํ์ ์ฉ** | |
| (์: `_llm_trigger_check` YES/NO) | |
| ```python | |
| temperature = 0.0 | |
| do_sample = False | |
| max_new_tokens = 2 | |
| ``` | |
| โ ํญ์ ๊ฐ์ ์ ๋ ฅ์ ๊ฐ์ ์ถ๋ ฅ, ์งง๊ณ ํ์ ์ ์ธ ๋ต๋ณ [ai_server/์ local fallback model์ ํน์ ์กฐ๊ฑด์ ์ง์ํ ๋ ์ฌ์ฉ] | |
| - **์์ฐ์ค๋ฌ์ด ๋ํ/์ฐฝ์์ฉ** | |
| (์: main/fallback ๋์ฌ ์์ฑ) | |
| ```python | |
| temperature = 0.7 | |
| top_p = 0.9 | |
| do_sample = True | |
| repetition_penalty = 1.05 | |
| max_new_tokens = 200 | |
| ``` | |
| โ ๋ค์์ฑ๊ณผ ์์ฐ์ค๋ฌ์ ํ๋ณด [main model ์ถ๋ก ์์ ์ฌ์ฉ] | |
| hf-serve์์๋ ์์ฐ์ค๋ฌ์ด ๋ํ/์ฐฝ์์ฉ์ ํ๋ผ๋ฏธํฐ ์๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ์ต๋๋ค. | |
| --- | |
| ## ๐ API & UI ์ฐจ์ด | |
| | ๊ฒฝ๋ก | ์ ๋ ฅ ํ์ | ๋ด๋ถ ์ฒ๋ฆฌ | | |
| |------|-----------|-----------| | |
| | `/predict_main` | ์์ฑ๋ prompt ๋ฌธ์์ด | ๊ทธ๋๋ก ์ถ๋ก | | |
| | `/ui` | NPC ID, Location, Utterance | `build_webtest_prompt()`๋ก prompt ์์ฑ ํ ์ถ๋ก | | |
| --- | |
| ## ๐ API ์ฌ์ฉ ์์ | |
| ### ์์ฒญ | |
| ```json | |
| POST /api/predict_main | |
| { | |
| "session_id": "abc123", | |
| "npc_id": "mother_abandoned_factory", | |
| "prompt": "<SYS>...<NPC>", | |
| "max_tokens": 200 | |
| } | |
| ``` | |
| ### ์๋ต | |
| ```json | |
| { | |
| "session_id": "abc123", | |
| "npc_id": "mother_abandoned_factory", | |
| "npc_response": "๊ทธ๊ฑด ์ ๋ง ๋๋ผ์ด ์ด์ผ๊ธฐ๊ตฐ์.", | |
| "deltas": { "trust": 0.42, "relationship": -0.13 }, | |
| "flags": { "give_item": 0.87, "end_npc_main_story": 0.02 }, | |
| "thresholds": { "give_item": 0.65, "end_npc_main_story": 0.5 } | |
| } | |
| ``` | |
| --- | |
| ## ๐ ๋ชจ๋ธ ์ ๋ฐ์ดํธ ํ๋ฆ | |
| 1. Colab์์ ํ์ต ์๋ฃ | |
| 2. Hugging Face Hub `latest` ๋ธ๋์น์ ์ ๋ก๋ | |
| 3. Colab์์ `/api/ping_reload` ํธ์ถ | |
| 4. Space๊ฐ ์ต์ ๋ชจ๋ธ ์ฌ๋ค์ด๋ก๋ & ๋ก๋ | |
| --- | |
| ## ๐ ์คํ ๋ฐฉ๋ฒ | |
| ### ๋ก์ปฌ ์คํ | |
| ```bash | |
| git clone https://huggingface.co/spaces/m97j/PersonaChatEngine | |
| cd PersonaChatEngine | |
| pip install -r requirements.txt | |
| python app.py | |
| ``` | |
| ### Hugging Face Space์์ ์คํ | |
| - ์น UI: `https://m97j-PersonaChatEngine.hf.space/ui` | |
| - API: `POST https://m97j-PersonaChatEngine.hf.space/api/predict_main` | |
| --- | |
| ## ๐ ์คํ ํ๊ฒฝ | |
| - Python 3.10 | |
| - FastAPI, Gradio, Transformers, PEFT, Torch | |
| - GPU ์ง์ ์ ์ถ๋ก ์๋ ํฅ์ | |
| --- | |
| ## ๐ก ๋น์ฉ ์ต์ ํ ํ | |
| - Space Settings โ Hardware์์ Free CPU๋ก ์ ํ ์ ๊ณผ๊ธ ์์ | |
| - GPU ์ฌ์ฉ ์ ํ ์คํธ ํ Stop ๋ฒํผ์ผ๋ก Space ์ค์ง | |
| - 48์๊ฐ ์์ฒญ ์์ผ๋ฉด ์๋ sleep | |
| --- | |
| ## ๐ ๊ด๋ จ ๋ฆฌํฌ์งํ ๋ฆฌ | |
| - **์ ์ฒด ํ๋ก์ ํธ ๊ฐ์ & AI ์๋ฒ ์ฝ๋**: [GitHub - persona-chat-engine](https://github.com/m97j/persona-chat-engine) | |
| - **๋ชจ๋ธ ์ด๋ํฐ ํ์ผ(HF Hub)**: [Hugging Face Model Repo](https://huggingface.co/m97j/npc_LoRA-fps) | |
| --- |