Spaces:
Running
Running
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) | |
--- |