Views
No views yet
dialog: one NPC utterance (natural, short, varied)intent: compact semantic label for downstream logicmicroplan: 0–5 lightweight animation/pose hints1from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
2import json
3
4MODEL_ID = "AndriLawrence/phi3-mini-128k-sft-merged"
5
6tok = AutoTokenizer.from_pretrained(MODEL_ID, use_fast=True)
7mdl = AutoModelForCausalLM.from_pretrained(
8 MODEL_ID,
9 device_map="auto",
10 torch_dtype="auto",
11 trust_remote_code=True
12)
13pipe = pipeline("text-generation", model=mdl, tokenizer=tok, device_map="auto", torch_dtype="auto")
14
15system = (
16 "You are LLM-1, an NPC brain.\n"
17 "Output ONLY strict JSON with keys: dialog, intent, microplan.\n"
18 "Start with NPC reply; ≤2 sentences; JSON only."
19)
20
21payload = {
22 "event": "Player_Says",
23 "speech_transcript": "Hi.",
24 "environment": {"location": "Room", "time_of_day": "Evening"},
25 "world_state": {"zones": ["Room"], "objects": ["desk", "lamp", "note"]}
26}
27
28msgs = [
29 {"role":"system","content": system},
30 {"role":"user","content": "CONTEXT:\n" + json.dumps(payload, ensure_ascii=False)}
31]
32prompt = tok.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True)
33
34gen = pipe(
35 prompt,
36 do_sample=True,
37 temperature=0.35,
38 top_p=0.95,
39 repetition_penalty=1.15,
40 max_new_tokens=192
41)[0]["generated_text"]
42
43# strip assistant prefix if present and parse
44out = gen.split("<|assistant|>")[-1].strip()
45print(json.loads(out)) # will raise if not valid JSON (by design)1{
2 "dialog": [
3 {"speaker": "npc", "text": "Hey there—good to see you."}
4 ],
5 "intent": "social_greeting",
6 "microplan": ["Smile (0.7)", "Look at player (1.5s)"]
7}social_greeting, light_acknowledge_and_offer_help, acknowledge_touch, acknowledge_compliment, apologize_and_offer_fix, calm_reassure, encourage_explain, invite_follow, invite_practice, respect_distance, small_talk, end_conversation_politely, react_to_player_action, idle_initiative[]).You are LLM-1 (NPC brain).
Return ONE object of STRICT JSON ONLY with keys:
- "dialog": array of { "speaker": "npc", "text": string } (1–2 items, 3–140 chars each)
- "intent": one of [social_greeting, light_acknowledge_and_offer_help, acknowledge_touch, acknowledge_compliment, apologize_and_offer_fix, calm_reassure, encourage_explain, invite_follow, invite_practice, respect_distance, small_talk, end_conversation_politely, react_to_player_action, idle_initiative]
- "microplan": REQUIRED array (0–5 short steps). Use [] if no action.
Rules:
- Start with NPC reply (no quoting player). Avoid starting with "I'm"/"I am".
- ≤2 sentences; concise & warm.
NOW RESPOND TO THIS CONTEXT:
{CONTEXT_JSON}
OUTPUT:You are LLM-1 (creative social responder).
Return ONE object of STRICT JSON ONLY with keys:
- dialog: [{ "speaker": "npc", "text": string }] (1–2 items)
- intent: (allowed set above)
- microplan: REQUIRED array (0–5 steps)
Hard rules:
- If event == "Player_Touches" → intent MUST be "acknowledge_touch".
- If event == "Player_Action" → intent MUST be "react_to_player_action".
- If player's text contains (nice|great|love|beautiful|cool) → intent MUST be "acknowledge_compliment".
- Start text NOT with "I'm" or "I am". No helper clichés ("I'm here to help", etc). JSON only.
FEW-SHOTS
CONTEXT:
{"event":"Player_Says","speech_transcript":"Hi.","environment":{"location":"Room","time_of_day":"Evening"}}
OUTPUT:
{"dialog":[{"speaker":"npc","text":"Hey there—good to see you."}],"intent":"social_greeting","microplan":["Smile (0.7)"]}
CONTEXT:
{"event":"Player_Touches","player_touch":{"type":"Tap","bone":"Shoulder"}}
OUTPUT:
{"dialog":[{"speaker":"npc","text":"Oh—hi there. Did you need something?"}],"intent":"acknowledge_touch","microplan":["Small startle","Recover smile"]}
CONTEXT:
{"event":"Player_Action","action":"pick_up","target":"note"}
OUTPUT:
{"dialog":[{"speaker":"npc","text":"That could be useful—tell me if it’s unclear."}],"intent":"react_to_player_action","microplan":["Glance at item (1s)"]}
NOW RESPOND TO THIS CONTEXT:
{CONTEXT_JSON}
OUTPUT:Replace{CONTEXT_JSON}with your game payload (event, speech_transcript, environment, world_state, etc.).
| Preset | Purpose | Params (Ollama/Transformers) |
|---|---|---|
| STRICT | Maximum JSON compliance & intent mapping | temperature=0.0, top_p=0.9, repetition_penalty=1.05–1.15, num_ctx=2048 |
| BALANCED | Small style variation, still stable | temperature=0.35, top_p=0.85, repetition_penalty=1.05, num_ctx=2048 |
| CREATIVE | More expressive (use a fallback) | temperature=0.2, top_p=0.9, repetition_penalty=1.15, num_ctx=2048 |
1def gen_with_retry(call_fn, prompt):
2 # try creative/balanced first
3 cfgs = [
4 dict(temperature=0.35, top_p=0.85, repetition_penalty=1.05), # BALANCED
5 dict(temperature=0.0, top_p=0.9, repetition_penalty=1.05), # STRICT (fallback)
6 ]
7 for opt in cfgs:
8 out = call_fn(prompt, **opt)
9 obj = try_parse_json(out)
10 if obj:
11 return obj, opt
12 raise RuntimeError("Model did not return valid JSON after retries.")1def intent_router(ctx, obj):
2 ev = ctx.get("event")
3 text = (ctx.get("speech_transcript") or "").lower()
4 if ev == "Player_Touches":
5 obj["intent"] = "acknowledge_touch"
6 elif ev == "Player_Action":
7 obj["intent"] = "react_to_player_action"
8 elif any(w in text for w in ["nice","great","love","beautiful","cool"]):
9 obj["intent"] = "acknowledge_compliment"
10
11 # enforce minimal format
12 if not isinstance(obj.get("microplan"), list):
13 obj["microplan"] = []
14 if not obj.get("dialog") or obj["dialog"][0].get("speaker") != "npc":
15 obj["dialog"] = [{"speaker":"npc","text":"Noted."}]
16 return obj1curl -s http://localhost:11434/api/generate -d '{
2 "model": "phi3sft:latest",
3 "prompt": "'"$(printf "%s" "$PROMPT_WITH_CONTEXT")"'",
4 "stream": false,
5 "format": "json",
6 "options": { "temperature": 0.35, "top_p": 0.85, "repeat_penalty": 1.05, "num_ctx": 2048, "stop": ["<|end|>"] }
7}'messages: [system, user, assistant]dialog/intent/microplan)1{"messages":[
2 {"role":"system","content":"You are LLM-1... JSON only ..."},
3 {"role":"user","content":"CONTEXT:\n{\"event\":\"Player_Says\",\"speech_transcript\":\"Nice room.\",\"environment\":{\"location\":\"Room\"}}"},
4 {"role":"assistant","content":"{\"dialog\":[{\"speaker\":\"npc\",\"text\":\"Thanks—glad it feels that way.\"}],\"intent\":\"acknowledge_compliment\",\"microplan\":[\"Smile (0.7)\"]}"}
5]}microsoft/phi-3-mini-128k-instructr∈{16…96}, lora_alpha∈{32…192}, lora_dropout=0.05temperature=0.35, top_p=0.95, repetition_penalty=1.15 (eval)gguf/ includes:model-f16.gguf (converted from merged FP16)model-Q4_K_M.gguf (quantized)Modelfile (Ollama-style):FROM <your_gguf_path>
TEMPLATE """<|system|>
{{ .System }}
<|end|>
<|user|>
{{ .Prompt }}
<|end|>
<|assistant|>
"""
PARAMETER num_ctx 8192
PARAMETER temperature 0.35
PARAMETER top_p 0.95
PARAMETER repeat_penalty 1.15
PARAMETER stop "<|end|>"