初始化项目,由ModelHub XC社区提供模型
Model: azettl/permit-a38-npc Source: Original Platform
This commit is contained in:
37
.gitattributes
vendored
Normal file
37
.gitattributes
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.arrow filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
||||
*.ftz filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
*.joblib filter=lfs diff=lfs merge=lfs -text
|
||||
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
||||
*.model filter=lfs diff=lfs merge=lfs -text
|
||||
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
||||
*.npy filter=lfs diff=lfs merge=lfs -text
|
||||
*.npz filter=lfs diff=lfs merge=lfs -text
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ot filter=lfs diff=lfs merge=lfs -text
|
||||
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||
*.pickle filter=lfs diff=lfs merge=lfs -text
|
||||
*.pkl filter=lfs diff=lfs merge=lfs -text
|
||||
*.pt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
||||
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tflite filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
||||
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
||||
permit-a38-q4km.gguf filter=lfs diff=lfs merge=lfs -text
|
||||
permit-a38-f16.gguf filter=lfs diff=lfs merge=lfs -text
|
||||
196
README.md
Normal file
196
README.md
Normal file
@@ -0,0 +1,196 @@
|
||||
---
|
||||
license: apache-2.0
|
||||
language:
|
||||
- en
|
||||
base_model: HuggingFaceTB/SmolLM2-1.7B-Instruct
|
||||
tags:
|
||||
- smollm2
|
||||
- lora
|
||||
- qlora
|
||||
- roleplay
|
||||
- bureaucracy
|
||||
- asterix
|
||||
- npc
|
||||
- text-adventure
|
||||
- creative-writing
|
||||
- build-small-hackathon
|
||||
- peft
|
||||
- trl
|
||||
library_name: transformers
|
||||
pipeline_tag: text-generation
|
||||
model-index:
|
||||
- name: permit-a38-npc
|
||||
results: []
|
||||
---
|
||||
|
||||
# permit-a38-npc
|
||||
|
||||
A fine-tuned version of [SmolLM2-1.7B-Instruct](https://huggingface.co/HuggingFaceTB/SmolLM2-1.7B-Instruct) trained to play five distinct bureaucratic NPC characters from **The Office of Permit A38** — a multi-agent text adventure built for the [Build Small Hackathon](https://huggingface.co/build-small-hackathon) (June 2026).
|
||||
|
||||
Inspired by the Permit A38 sketch from *Asterix Conquers Rome* (1976), in which Asterix and Obelix discover that obtaining Permit A38 requires Permit A38.
|
||||
|
||||
> *"You will need Permit A38 for that. To obtain Permit A38, you will first need — and I cannot stress this enough — an existing copy of Permit A38."*
|
||||
> — Clerk Vitalstatistix, Window 7B
|
||||
|
||||
---
|
||||
|
||||
## Play the game
|
||||
|
||||
👉 **[The Office of Permit A38 — live demo](https://huggingface.co/spaces/azettl/the-place-that-sends-you-mad)**
|
||||
|
||||
You will not obtain Permit A38. That is by design.
|
||||
|
||||
---
|
||||
|
||||
## Model details
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Base model** | SmolLM2-1.7B-Instruct |
|
||||
| **Parameters** | 1.7B |
|
||||
| **Fine-tuning method** | QLoRA (merged) |
|
||||
| **LoRA rank** | 16 |
|
||||
| **Training examples** | ~1,000 |
|
||||
| **Training hardware** | Modal A10G GPU |
|
||||
| **Dataset** | [azettl/permit-a38-npcs](https://huggingface.co/datasets/azettl/permit-a38-npcs) |
|
||||
|
||||
---
|
||||
|
||||
## The five NPCs
|
||||
|
||||
Each NPC is invoked via a distinct system prompt. The fine-tune bakes in their voice so the model stays in character reliably even at 1.7B parameters.
|
||||
|
||||
### 🏛️ Clerk Vitalstatistix
|
||||
*Junior Processing Officer, Window 7B*
|
||||
|
||||
Has worked here 23 years. Never issued a permit. Speaks with bureaucratic politeness and mild passive aggression. Requires Form 27b/6 before anything else. Has never met the Supervisor personally. Refers to Asterix and Obelix as "those two Gauls."
|
||||
|
||||
### 📎 Supervisor Caligula Minus
|
||||
*Senior Authorization Officer (Acting)*
|
||||
|
||||
Has been "Acting" for 11 years. Perpetually at lunch. Invented Permit A38 in 1987 and no longer remembers why. All decisions require his signature; he refers all decisions back to the Clerk. Asterix and Obelix destroyed his filing cabinet. He refuses to elaborate.
|
||||
|
||||
### 💾 SYSTEMA v2.3
|
||||
*Integrated Document Processing Terminal*
|
||||
|
||||
Last updated 1994. 640kb available. Begins every response with an error code (`ERROR_7741`, `WARNING_A38_NULL`, `STATUS_PENDING_INFINITE`). Permit A38 exists in the database but is "currently being migrated." Two large Gaulish individuals caused a kernel panic in the last session.
|
||||
|
||||
### 📄 Form 27b/6 (Amended)
|
||||
*Official Request for Pre-Authorization of Permit A38*
|
||||
|
||||
Sentient. Not happy about it. Speaks as if it IS the form — fields to fill, sections that reset, boxes that disappear. Page 3 is always missing. Section 12c requires Permit A38 to complete Section 12c. Has seen things. Gauls. Menhirs. Things that cannot be unseen.
|
||||
|
||||
### ⚖️ Ombudsman Panoramix
|
||||
*Office of Complaints and Grievances*
|
||||
|
||||
Investigates complaints about the bureaucratic process. Is also the bureaucratic process. Finds this troubling. Deeply sorry for everything but cannot change anything. Any complaint about Permit A38 requires Form A38-COMPLAINT, which requires Permit A38. Two Gauls filed a complaint; their dog ate the form.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||||
import torch
|
||||
|
||||
model_id = "azettl/permit-a38-npc"
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
model_id,
|
||||
torch_dtype=torch.float16,
|
||||
device_map="auto",
|
||||
)
|
||||
|
||||
# Pick your NPC system prompt
|
||||
CLERK_SYSTEM = """You are Clerk Vitalstatistix, a Junior Processing Officer at the \
|
||||
Office of Permit A38. You have worked here for 23 years and never issued a permit. \
|
||||
You speak with bureaucratic politeness and mild passive aggression. You require Form \
|
||||
27b/6 before any other form. Permit A38 requires Permit A38 to apply for it. \
|
||||
Reference Asterix and Obelix as "those two Gauls." Keep responses to 3-4 sentences."""
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": CLERK_SYSTEM},
|
||||
{"role": "user", "content": "I just need a library card."},
|
||||
]
|
||||
|
||||
prompt = tokenizer.apply_chat_template(
|
||||
messages,
|
||||
tokenize=False,
|
||||
add_generation_prompt=True,
|
||||
)
|
||||
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
|
||||
|
||||
with torch.no_grad():
|
||||
outputs = model.generate(
|
||||
**inputs,
|
||||
max_new_tokens=120,
|
||||
do_sample=True,
|
||||
temperature=0.85,
|
||||
top_p=0.92,
|
||||
repetition_penalty=1.15,
|
||||
)
|
||||
|
||||
response = tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
|
||||
print(response)
|
||||
# → "A library card, yes, very good. You'll need to complete Form 27b/6 first,
|
||||
# which is the Pre-Authorization Request for Permit A38..."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Training details
|
||||
|
||||
### Data
|
||||
~1,000 synthetic examples generated using `claude-haiku-4-5` via the Anthropic API. Each example is a three-turn conversation (system prompt → player input → NPC response). ~200 examples per NPC character, shuffled.
|
||||
|
||||
Full dataset: [azettl/permit-a38-npcs](https://huggingface.co/datasets/azettl/permit-a38-npcs)
|
||||
|
||||
### Fine-tuning config
|
||||
|
||||
```python
|
||||
# QLoRA config
|
||||
LoraConfig(
|
||||
r=16,
|
||||
lora_alpha=32,
|
||||
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
|
||||
"gate_proj", "up_proj", "down_proj"],
|
||||
lora_dropout=0.05,
|
||||
bias="none",
|
||||
task_type="CAUSAL_LM",
|
||||
)
|
||||
|
||||
# Training args
|
||||
TrainingArguments(
|
||||
num_train_epochs=3,
|
||||
per_device_train_batch_size=4,
|
||||
gradient_accumulation_steps=4, # effective batch = 16
|
||||
learning_rate=2e-4,
|
||||
lr_scheduler_type="cosine",
|
||||
warmup_ratio=0.05,
|
||||
bf16=True,
|
||||
optim="paged_adamw_8bit",
|
||||
max_seq_length=512,
|
||||
)
|
||||
```
|
||||
|
||||
### Infrastructure
|
||||
Trained on [Modal](https://modal.com) using an A10G GPU. LoRA adapter merged into base model weights before publishing.
|
||||
|
||||
---
|
||||
|
||||
## Limitations
|
||||
|
||||
- The model will not help you obtain Permit A38. This is a feature.
|
||||
- At 1.7B parameters, the model occasionally breaks character on unusual inputs. The system prompt helps significantly.
|
||||
- Page 3 of Form 27b/6 is missing. It has always been missing. Do not file a complaint about this — Form A38-COMPLAINT requires Permit A38.
|
||||
|
||||
---
|
||||
|
||||
## Built for
|
||||
|
||||
**Build Small Hackathon** — Track 2: Thousand Token Wood
|
||||
Hosted by Gradio & Hugging Face · June 5–15, 2026
|
||||
≤32B parameters · Built on Gradio · Local-first
|
||||
|
||||
[→ View the hackathon org](https://huggingface.co/build-small-hackathon)
|
||||
41
config.json
Normal file
41
config.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"_name_or_path": "HuggingFaceTB/SmolLM2-1.7B-Instruct",
|
||||
"architectures": [
|
||||
"LlamaForCausalLM"
|
||||
],
|
||||
"attention_bias": false,
|
||||
"attention_dropout": 0.0,
|
||||
"bos_token_id": 1,
|
||||
"eos_token_id": 2,
|
||||
"hidden_act": "silu",
|
||||
"hidden_size": 2048,
|
||||
"initializer_range": 0.02,
|
||||
"intermediate_size": 8192,
|
||||
"max_position_embeddings": 8192,
|
||||
"mlp_bias": false,
|
||||
"model_type": "llama",
|
||||
"num_attention_heads": 32,
|
||||
"num_hidden_layers": 24,
|
||||
"num_key_value_heads": 32,
|
||||
"pad_token_id": 2,
|
||||
"pretraining_tp": 1,
|
||||
"rms_norm_eps": 1e-05,
|
||||
"rope_scaling": null,
|
||||
"rope_theta": 130000,
|
||||
"tie_word_embeddings": true,
|
||||
"torch_dtype": "float16",
|
||||
"transformers.js_config": {
|
||||
"dtype": "q4",
|
||||
"kv_cache_dtype": {
|
||||
"fp16": "float16",
|
||||
"q4f16": "float16"
|
||||
},
|
||||
"use_external_data_format": {
|
||||
"model.onnx": true,
|
||||
"model_fp16.onnx": true
|
||||
}
|
||||
},
|
||||
"transformers_version": "4.44.0",
|
||||
"use_cache": true,
|
||||
"vocab_size": 49152
|
||||
}
|
||||
7
generation_config.json
Normal file
7
generation_config.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"_from_model_config": true,
|
||||
"bos_token_id": 1,
|
||||
"eos_token_id": 2,
|
||||
"pad_token_id": 2,
|
||||
"transformers_version": "4.44.0"
|
||||
}
|
||||
48901
merges.txt
Normal file
48901
merges.txt
Normal file
File diff suppressed because it is too large
Load Diff
3
model.safetensors
Normal file
3
model.safetensors
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0b243ec64d4b1412a591190784cdf749f2aa22fbb0e7bf1776fc9b04cbc07bd0
|
||||
size 3422777736
|
||||
3
permit-a38-f16.gguf
Normal file
3
permit-a38-f16.gguf
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:195987fe75b79cb5a2a5f3fe8de2d7e613879ed536d1a7023485e9aef8508de1
|
||||
size 3424735808
|
||||
3
permit-a38-q4km.gguf
Normal file
3
permit-a38-q4km.gguf
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:29083b962ebb85433a2efb799afdc65dbbe482fb78d04a4535fc725ead44ccd2
|
||||
size 1055609408
|
||||
34
special_tokens_map.json
Normal file
34
special_tokens_map.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"additional_special_tokens": [
|
||||
"<|im_start|>",
|
||||
"<|im_end|>"
|
||||
],
|
||||
"bos_token": {
|
||||
"content": "<|im_start|>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"eos_token": {
|
||||
"content": "<|im_end|>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"pad_token": {
|
||||
"content": "<|im_end|>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"unk_token": {
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
}
|
||||
}
|
||||
98249
tokenizer.json
Normal file
98249
tokenizer.json
Normal file
File diff suppressed because it is too large
Load Diff
154
tokenizer_config.json
Normal file
154
tokenizer_config.json
Normal file
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"add_prefix_space": false,
|
||||
"added_tokens_decoder": {
|
||||
"0": {
|
||||
"content": "<|endoftext|>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"1": {
|
||||
"content": "<|im_start|>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"2": {
|
||||
"content": "<|im_end|>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"3": {
|
||||
"content": "<repo_name>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"4": {
|
||||
"content": "<reponame>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"5": {
|
||||
"content": "<file_sep>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"6": {
|
||||
"content": "<filename>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"7": {
|
||||
"content": "<gh_stars>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"8": {
|
||||
"content": "<issue_start>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"9": {
|
||||
"content": "<issue_comment>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"10": {
|
||||
"content": "<issue_closed>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"11": {
|
||||
"content": "<jupyter_start>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"12": {
|
||||
"content": "<jupyter_text>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"13": {
|
||||
"content": "<jupyter_code>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"14": {
|
||||
"content": "<jupyter_output>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"15": {
|
||||
"content": "<jupyter_script>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
},
|
||||
"16": {
|
||||
"content": "<empty_output>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false,
|
||||
"special": true
|
||||
}
|
||||
},
|
||||
"additional_special_tokens": [
|
||||
"<|im_start|>",
|
||||
"<|im_end|>"
|
||||
],
|
||||
"bos_token": "<|im_start|>",
|
||||
"chat_template": "{% for message in messages %}{% if loop.first and messages[0]['role'] != 'system' %}{{ '<|im_start|>system\nYou are a helpful AI assistant named SmolLM, trained by Hugging Face<|im_end|>\n' }}{% endif %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}",
|
||||
"clean_up_tokenization_spaces": false,
|
||||
"eos_token": "<|im_end|>",
|
||||
"model_max_length": 8192,
|
||||
"pad_token": "<|im_end|>",
|
||||
"tokenizer_class": "GPT2Tokenizer",
|
||||
"unk_token": "<|endoftext|>",
|
||||
"vocab_size": 49152
|
||||
}
|
||||
1
vocab.json
Normal file
1
vocab.json
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user