Text Classification
Transformers
Safetensors
Laya
multilingual
en
zh
ruhui
jev
system-one
calibrated-decisions
rlcd
classification
routing
scoring
guardrails
moderation
reinforcement-learning
commercial-use
Instructions to use anyforge/ruhui with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use anyforge/ruhui with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="anyforge/ruhui")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("anyforge/ruhui", device_map="auto") - Laya
How to use anyforge/ruhui with Laya:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
File size: 8,908 Bytes
fc99637 66a2eed 9e82344 fc99637 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 8cc31a5 f379495 9a8ff52 f379495 62e4304 f379495 9a8ff52 f379495 7e73aa5 f379495 7e73aa5 9a8ff52 7e73aa5 9a8ff52 603a6a3 f379495 28d2945 7e73aa5 f379495 603a6a3 f379495 9a8ff52 7e73aa5 9a8ff52 7e73aa5 f379495 7e73aa5 f379495 7e73aa5 f379495 9a8ff52 7e73aa5 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 9a8ff52 f379495 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | ---
license: apache-2.0
library_name: transformers
pipeline_tag: text-classification
tags: [multilingual, en, zh, ruhui, jev, laya, system-one, calibrated-decisions, rlcd, classification, routing, scoring, guardrails, moderation, reinforcement-learning, commercial-use]
---
[](https://pypi.org/project/ruhui/)
[](https://opensource.org/licenses/Apache-2.0)
[](https://huggingface.co/anyforge/ruhui)
[](https://modelscope.cn/models/anyforge/ruhui)
# Ruhui · 如晦
**A non-autoregressive System 1 decision engine for Chinese & multilingual text, with calibrated probabilities.**
Named after Du Ruhui (杜如晦, courtesy name Keming 克明) of the legendary *Fang Mou Du Duan* (房谋杜断) pair — Fang Xuanling was the strategist, Du Ruhui the decisive judge. *Ruhui* inherits the "decisive" half: it makes a fast System 1 decision, generates no text, has nothing to parse, and therefore cannot hallucinate.
---
## What it is
Ruhui answers **typed questions** — `choice`, `score`, `noul` (yes/no) — over any state (text, email, ticket, or JSON) in a **single forward pass**, returning a **calibrated probability** for every option. No text generation, no parsing, no hallucination.
Two backends share the same interface:
| Backend | Architecture | Size | Latency | Strength |
|---|---|---|---|---|
| **bert** | bidirectional encoder (mmBERT-base) + decision head | 322M | ~33 ms | fast, CPU-friendly, Chinese/English |
| **llm** | Causal LM (Qwen3.5) + LoRA + PointerHead | 0.8B+ | hundreds of ms | stronger generalization |
---
| Resource | Link | Notes |
|---|---|---|
| 📦 **PyPI** | [](https://pypi.org/project/ruhui/) | `pip install ruhui -U` |
| 🐙 **GitHub** | [](https://github.com/anyforge/ruhui) | Source + bilingual README + skill |
| 🧩 **ModelScope** | [](https://modelscope.cn/models/anyforge/ruhui) | Model repo (bert + 0.8B) |
| 🤗 **Hugging Face** | [](https://huggingface.co/anyforge/ruhui) | Model repo (bert + 0.8B) |
| 🛠️ **OpenClaw Skill** | [](https://clawhub.ai/anyforge/skills/ruhui) | Agent skill (ClawHub) |
| 🛠️ **ModelScope Skill** | [](https://www.modelscope.cn/skills/anyforge/ruhui) | Agent skill (ModelScope) |
---
## Installation
```bash
pip install ruhui -U
```
Python 3.10+. Core deps: `torch`, `transformers`, `safetensors`, `huggingface_hub`, `numpy`. The LLM backend additionally needs `peft`.
---
## Quick Start
### llm backend (larger model, stronger generalization)
```python
from ruhui.llm import LLMAgent
# a merged (self-contained) model — no base_dir needed
agent = LLMAgent(checkpoint_dir="/path/to/anyforge/ruhui/0.8B")
# choice task
result = agent.predict(
{"message": "我被重复扣款了,请退款"},
{"intent": {"type": "choice", "instructions": "客户想做什么?",
"criteria": {"refund": "退款", "billing": "账单"}}},
)
print(result["answers"])
# score task
result = agent.predict(
{"message": "我被重复扣款了,客服三天没回复,今天必须解决,不然就取消订阅!"},
{
"frustration": {
"type": "score",
"instructions": "客户有多生气?",
"criteria": ["平静", "有点不满", "明显恼火", "非常愤怒,威胁投诉"],
},
"urgency": {
"type": "score",
"instructions": "这件事有多紧急?",
"criteria": ["不急", "需尽快处理", "紧急且阻塞"],
},
},
)
print(result["answers"])
# noul task
result = agent.predict(
{"message": "不然我就取消订阅,去用你们竞争对手的产品"},
{
"churn_risk": {
"type": "noul",
"instructions": "客户是否威胁要离开或取消?",
},
"refund_requested": {
"type": "noul",
"instructions": "客户是否明确要求退款?",
},
},
)
print(result["answers"])
```
### bert backend (the original, unchanged)
```python
import ruhui
agent = ruhui.load("/path/to/anyforge/ruhui") # hub, or a local directory
result = agent.predict(
{"message": "我被重复扣款了,请退款"},
{
"intent": {"type": "choice", "instructions": "客户想做什么?",
"criteria": {"refund": "退款", "technical": "技术问题", "billing": "账单咨询"}},
"churn_risk": {"type": "noul", "instructions": "客户是否威胁要离开?"},
},
)
print(result["answers"])
```
details repo: [anyforge/ruhui](https://github.com/anyforge/ruhui)。
---
## How the two backends work
### bert backend — encoder + decision head
A bidirectional encoder reads the whole input, then a 2-layer decision head scores each option at its own `[MASK]` slot, all in parallel. Probabilities come from a softmax over those option slots, trained with **RLCD** (reinforcement learning from strictly-proper-scoring-rule rewards) so the reported confidence is statistically meaningful.
```
[CLS] question + [MASK] opt0 [MASK] opt1 ... [SEP] state [SEP]
→ bidirectional encoder
→ gather the [MASK] slot vectors
→ parallel scorer → softmax → calibrated probabilities
```
### llm backend — Causal LM + PointerHead (KEV-style)
A frozen causal LM runs **prefill-only** (never generates tokens). Each question becomes a branch sharing one state prefix, isolated by a block-causal mask. A pointer head then reads the `<decide>` position and "points" at the option boundary tokens — the attention scores become the option probabilities.
```
[state] [q: instr <opt>opt A</opt> <opt>opt B</opt> <decide>]
→ Causal LM (prefill only)
→ PointerHead: q(decide) · k(option) → logits → softmax
```
The LoRA adapter is folded into the base weights at inference (or merged permanently with `merge_model.py`).
---
## Decision primitives
| Primitive | Output |
|---|---|
| `choice` | top label + full probability distribution + confidence |
| `score` | expected level on an ordinal rubric |
| `noul` | calibrated P(true) |
Confidence is normalized entropy (`1 − H(p)/log K`), so it is safe to gate on:
```python
if conf >= 0.85:
route_automatically(dept) # high confidence
else:
escalate_to_human(dept) # low confidence
```
---
## Fine-tuning
### llm backend (KEV-style)
```bash
# 1. convert soft labels to KEV-format training data
python scripts/convert_to_kev.py --soft_dir <dir> --out datas/train.jsonl
# 2. fine-tune from an existing checkpoint (delta mode)
python scripts/finetune.py \
--data datas/train.jsonl \
--base Qwen/Qwen3.5-0.8B-Base \
--init_from anyforge/ruhui/0.8B \
--out runs/ruhui-0.8b \
--epochs 2 --device cuda
# 3. resume if interrupted
python scripts/finetune.py ... --resume
# 4. merge LoRA into the base weights (bf16 halves the size)
python scripts/merge_model.py \
--checkpoint runs/ruhui-0.8b \
--base Qwen/Qwen3.5-0.8B-Base \
--out runs/ruhui-0.8b-merged \
--dtype bf16
```
### bert backend (Laya-style)
```bash
python scripts/train.py \
--model_dir <base_model_dir> \
--train_items <train_items.pt> \
--output_dir <output_dir> \
--epochs 4
```
---
## Repository layout
```
ruhuipro/
ruhui/
bert/ # encoder backend (agent / router / common / presets / ...)
llm/ # LLM backend (model / api / checkpoint / train / data / agent)
scripts/
convert_to_kev.py # soft labels → KEV format
finetune.py # LLM fine-tune (--init_from / --resume)
merge_model.py # LoRA merge + dtype control
train.py # bert fine-tune
tests/
```
---
## Model repositories
- Hugging Face: `anyforge/ruhui` (root = bert model; `0.8B/` = LLM 0.8B merged model)
- ModelScope: `anyforge/ruhui` (same layout)
---
## Acknowledgments
- **Laya** ([NandhaKishorM/laya](https://github.com/NandhaKishorM/laya), Apache 2.0) — the non-autoregressive System 1 decision paradigm and RLCD training that the bert backend is forked from.
- **KEV** ([jaredpalmer/kev](https://github.com/jaredpalmer/kev), Apache 2.0) — the Causal LM + LoRA + PointerHead architecture that the llm backend is built on.
## License
Apache 2.0. Developed by AnyForge.
|