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
|
Download README.md from anyforge/ruhui: direct link, hf CLI and curl.
- Browser
- Download file 8.91 kB
-
https://huggingface.co/anyforge/ruhui/resolve/main/README.md
- Command line
-
hf download hf://anyforge/ruhui/README.md
-
curl -L -o README.md https://huggingface.co/anyforge/ruhui/resolve/main/README.md
8.91 kB
| 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. | |