xinfer-ai 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +21 -0
- package/README.md +595 -0
- package/bin/xinfer.js +66 -0
- package/docs/add_model.md +88 -0
- package/docs/claude_code.md +95 -0
- package/docs/docker.md +73 -0
- package/docs/embeddings.md +33 -0
- package/docs/get_started.md +93 -0
- package/docs/goose.md +83 -0
- package/docs/guided_decoding.md +474 -0
- package/docs/kilocode.md +69 -0
- package/docs/mcp_tool_calling.md +155 -0
- package/docs/multimodal.md +37 -0
- package/docs/opencode.md +83 -0
- package/docs/performance.md +65 -0
- package/docs/prefix-cache.md +79 -0
- package/docs/rust_crate.md +119 -0
- package/docs/test_model.md +104 -0
- package/docs/tokenizer_api.md +116 -0
- package/docs/tool_parsing.md +74 -0
- package/docs/xbot.md +110 -0
- package/package.json +49 -0
- package/scripts/install.js +211 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Guoqing Bao
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="logo.svg" alt="xInfer" width="400"><br>
|
|
3
|
+
<b>Blazing-fast LLM inference in pure Rust.</b> No PyTorch. No Python runtime. Just fast, portable, production-ready inference.<br>
|
|
4
|
+
<a href="./ReadMe.md">English</a> | <a href="./ReadMe-CN.md">简体中文</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ✨ Why xInfer?
|
|
10
|
+
|
|
11
|
+
| | Feature | Details |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| **0️⃣** | Zero Python dependencies | Pure Rust backend — no PyTorch, no CUDA Python bindings |
|
|
14
|
+
| **⚡** | Fast | Native Flash Attention, FlashInfer, CUDA Graphs, continuous batching, prefix caching, PD disaggregation. Up to **175 tok/s** decode for `30B+` models on consumer GPUs |
|
|
15
|
+
| **🪶** | Tiny footprint | Core scheduling + attention logic in **< 5 000 lines** of Rust |
|
|
16
|
+
| **🌍** | Cross-platform | CUDA (Linux/Windows), Metal (macOS). Same binary, same API |
|
|
17
|
+
| **🏭** | Production-ready | OpenAI/Anthropic-compatible APIs, built-in ChatGPT-style Web UI, MCP tool calling, structured outputs, embedding + tokenizer endpoints |
|
|
18
|
+
| **🗜️** | Aggressive KV compression | TurboQuant (`2–4 bit` KV cache) extends context up to **4.3×** with minimal quality loss. Run `30B+` MoE models with **millions of context** on single 24/32 GB GPUs |
|
|
19
|
+
| **🐍** | Lightweight Python bindings | Optional PyO3 wheel when you need a Python entry point |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 🚀 Quick Start
|
|
24
|
+
|
|
25
|
+
### 📦 Install
|
|
26
|
+
|
|
27
|
+
**Option 1 — Python package**
|
|
28
|
+
```bash
|
|
29
|
+
curl -sSL https://guoqingbao.github.io/xinfer/install.sh | bash
|
|
30
|
+
# python3 -m xinfer.server --m Qwen/Qwen3.6-27B-FP8 --kvcache-dtype turbo4 --ui-server
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Option 2 — npm**
|
|
34
|
+
```bash
|
|
35
|
+
npm install -g xinfer-ai
|
|
36
|
+
# xinfer --m Qwen/Qwen3.6-27B-FP8 --kvcache-dtype turbo4 --ui-server
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Option 3 — Cargo (from source)**
|
|
40
|
+
```bash
|
|
41
|
+
# Prerequisites: Rust compiler, CUDA Toolkit (optional) or Metal Xcode command line tool
|
|
42
|
+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
43
|
+
sudo apt-get install -y git build-essential libssl-dev pkg-config
|
|
44
|
+
|
|
45
|
+
export XINFER_REPO="https://github.com/guoqingbao/xinfer"
|
|
46
|
+
# MacOS/Metal: replace features to `metal`
|
|
47
|
+
# SM_70/SM_75 (e.g., V100): remove `flashinfer` and `cutlass` features
|
|
48
|
+
cargo install --git $XINFER_REPO xinfer --features cuda,nccl,flashinfer,cutlass
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Option 4 — Docker**
|
|
52
|
+
```bash
|
|
53
|
+
# Turing/V100 (sm_70/sm_75): remove `flashinfer` and `cutlass` features
|
|
54
|
+
./build_docker.sh "cuda,nccl,flashinfer,cutlass"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
See [Docker guide →](docs/docker.md)
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
### ▶️ Run
|
|
62
|
+
|
|
63
|
+
**Using HuggingFace Model ID:**
|
|
64
|
+
```bash
|
|
65
|
+
xinfer --m Qwen/Qwen3.6-27B-FP8 --kvcache-dtype turbo4 --ui-server
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Using local model path:**
|
|
69
|
+
```bash
|
|
70
|
+
xinfer --w /home/Qwen3.6-35B-A3B --d 0,1 --ui-server
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Python usage:**
|
|
74
|
+
```bash
|
|
75
|
+
# python3 -m xinfer.chat
|
|
76
|
+
python3 -m xinfer.server --m Qwen/Qwen3.6-27B-FP8 --kvcache-dtype turbo4 --ui-server
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
> **Tip:** Open `http://IP:8001` for the built-in chat UI, or use `http://IP:8000/v1/` as your API `Base URL`.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
### 🗜️ KV Cache Compression
|
|
84
|
+
|
|
85
|
+
Add `--kvcache-dtype` to compress KV cache and extend context length:
|
|
86
|
+
|
|
87
|
+
| Flag (`--kvcache-dtype`) | Compression | Quality | GPU Requirement |
|
|
88
|
+
|---|---|---|---|
|
|
89
|
+
| _(default)_ | 1× (BF16) | Baseline | All |
|
|
90
|
+
| `fp8` | **2×** | Near-lossless | SM70+ / Apple M1 |
|
|
91
|
+
| `turbo8` | **2.6×** | 79–100% throughput | SM70+ / Apple M1|
|
|
92
|
+
| `turbo4` | **3.7×** | Best balance | SM70+ / Apple M1|
|
|
93
|
+
| `turbo3` | **4.7×** | Max compression | SM70+ |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 📈 Performance
|
|
98
|
+
|
|
99
|
+
> Tested on **V100-32G**, **A100-40G**, **Hopper-80G** and **RTX 5090**
|
|
100
|
+
|
|
101
|
+
| Model | Format | Size | Decoding Speed |
|
|
102
|
+
|---|---|---|---|
|
|
103
|
+
| Ministral-3-3B (**Multimodal**) | ISQ (BF16→Q4K) | 3B | **171.92** tokens/s |
|
|
104
|
+
| Qwen3-VL-8B-Instruct (**Multimodal**) | Q8_0 | 8B | **105.31** tokens/s |
|
|
105
|
+
| Llama-3.1-8B | ISQ (BF16→Q4K) | 8B | **120.74** tokens/s |
|
|
106
|
+
| DeepSeek-R1-0528-Qwen3-8B | Q4_K_M | 8B | **124.87** tokens/s |
|
|
107
|
+
| GLM-4-9B-0414 | Q4_K_M | 9B | **70.38** tokens/s |
|
|
108
|
+
| QwQ-32B | Q4_K_M | 32B | **41.36** tokens/s |
|
|
109
|
+
| **Qwen3-30B-A3B** | NVFP4 | **30B (MoE)** | **175.30** tokens/s (**RTX 5090**) |
|
|
110
|
+
| **Qwen3-30B-A3B** | NVFP4 | **30B (MoE)** | **67.10** tokens/s (**V100, Software FP4**) |
|
|
111
|
+
| **Qwen3.5-27B** (**Multimodal**) | Q4_K_M | **27B (Dense)** | **45.20** tokens/s |
|
|
112
|
+
| **Qwen3.5-27B/Qwen3.6-27B** | FP8 | **27B (Dense)** | **42** tokens/s (**Hopper**) |
|
|
113
|
+
| **Qwen3.6-35B-A3B** (**Multimodal**) | FP8 | **35B (MoE)** | **102** tokens/s (**Hopper**) |
|
|
114
|
+
| **GLM4.7 Flash** | NVFP4 | **30B (MoE)** | **79** tokens/s (**Hopper, Software FP4**) |
|
|
115
|
+
| **Gemma4-31B** | ISQ (BF16→Q4K) | **31B (Dense)** | **41** tokens/s (**Hopper**) |
|
|
116
|
+
| **Gemma4-26B-A4B** | NVFP4 | **26B (MoE)** | **131** tokens/s (**RTX 5090**) |
|
|
117
|
+
| **MiniMax-M2.5** | NVFP4 | **229B (MoE)** | **62** tokens/s (**Hopper, Software FP4, TP=2**) |
|
|
118
|
+
|
|
119
|
+
<details>
|
|
120
|
+
<summary><b>Apple Silicon (M4)</b></summary>
|
|
121
|
+
|
|
122
|
+
| Model | Batch Size | Output Tokens | Time (s) | Throughput (tokens/s) |
|
|
123
|
+
|---|---|---|---|---|
|
|
124
|
+
| Qwen3-0.6B (BF16) | 128 | 63488 | 83.13s | 763.73 |
|
|
125
|
+
| Qwen3-0.6B (BF16) | 32 | 15872 | 23.53s | 674.43 |
|
|
126
|
+
| Qwen3-0.6B (BF16) | 1 | 456 | 9.23s | 49.42 |
|
|
127
|
+
| Qwen3-4B (Q4_K_M) | 1 | 1683 | 52.62s | 31.98 |
|
|
128
|
+
| Qwen3-8B (Q2_K) | 1 | 1300 | 80.88s | 16.07 |
|
|
129
|
+
| Qwen3.5-4B (Q3_K_M) | 1 | 1592 | 69.04s | 23.06 |
|
|
130
|
+
| Qwen3.5-2B (NVFP4) | 1 | 1883 | 60.76s | 30.99 |
|
|
131
|
+
| Qwen3.5-2B (NVFP4) | 2 | 3942 | 81.96s | 48.10 |
|
|
132
|
+
|
|
133
|
+
</details>
|
|
134
|
+
|
|
135
|
+
[Full benchmarks →](docs/performance.md)
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 🧠 Supported Models
|
|
140
|
+
|
|
141
|
+
* ✅ LLaMa (LLaMa2, LLaMa3, **LLaMa4**, IQuest-Coder)
|
|
142
|
+
* ✅ Qwen (Qwen2, Qwen3)
|
|
143
|
+
* ✅ Qwen2/Qwen3 MoE
|
|
144
|
+
* ✅ Qwen3 Next
|
|
145
|
+
* ✅ Qwen3.5/3.6 Dense/MoE (27B, 35B, 122B, 397B, Multimodal model)
|
|
146
|
+
* ✅ Mistral v1, v2
|
|
147
|
+
* ✅ Mistral-3-VL Reasoning (3B, 8B, 14B, Multimodal model)
|
|
148
|
+
* ✅ GLM4 (0414, **Not ChatGLM**)
|
|
149
|
+
* ✅ GLM4 MoE (4.6/4.7)
|
|
150
|
+
* ✅ GLM4.7 Flash
|
|
151
|
+
* ✅ DeepSeek V3/R1/V3.2
|
|
152
|
+
* ✅ Phi3 / Phi4 (Phi-3, Phi-4, Phi-4-mini, etc.)
|
|
153
|
+
* ✅ Gemma3/**Gemma4** (Multimodal model)
|
|
154
|
+
* ✅ Qwen3-VL (Dense, Multimodal model)
|
|
155
|
+
* ✅ MiroThinker-v1.5 (30B, 235B)
|
|
156
|
+
|
|
157
|
+
**Formats:** Safetensors (BF16, `FP8-blockwise`, GPTQ, AWQ, MXFP4, `NVFP4`) | GGUF (all quant types) | `ISQ` (on-the-fly quantization)
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### TurboQuant KV Cache — Run 30B+ Models on Consumer GPUs
|
|
162
|
+
|
|
163
|
+
TurboQuant compresses KV cache to 2–4 bits via Walsh-Hadamard transform rotation + per-head absmax quantization. Max context tokens with `turbo4`:
|
|
164
|
+
|
|
165
|
+
| Model | KV budget | BF16 | turbo4 | Gain |
|
|
166
|
+
|---|---|---|---|---|
|
|
167
|
+
| **Qwen3.6-35B-A3B** (NVFP4) | 7 GB (24 GB GPU) | 700k | **2.7M** | **3.9×** |
|
|
168
|
+
| | 15 GB (32 GB GPU) | 1.5M | **5.8M** | **3.9×** |
|
|
169
|
+
| **Qwen3.6-27B** (FP8) | 7 GB | 112k | **434k** | **3.9×** |
|
|
170
|
+
| | 15 GB | 240k | **930k** | **3.9×** |
|
|
171
|
+
| **Qwen3-30B-A3B** (Q4_K_M) | 7 GB | 74k | **281k** | **3.8×** |
|
|
172
|
+
| | 15 GB | 160k | **602k** | **3.8×** |
|
|
173
|
+
| **Gemma4-26B-A4B** (NVFP4) | 7 GB | 32k | **125k** | **3.9×** |
|
|
174
|
+
| | 15 GB | 70k | **271k** | **3.9×** |
|
|
175
|
+
|
|
176
|
+
> Hybrid models (Qwen3.6) have fewer full attention layers, making TurboQuant especially effective. MLA models (DeepSeek, GLM4.7 Flash) use `fp8` instead. The KV budget in the table is the theoretical maximum; actual usage can only utilize up to 90% of the KV budget (`--kv-fraction 0.9`), leaving room for runtime and batching buffers.
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# 35B MoE on single 24/32 GB GPU
|
|
180
|
+
xinfer --m unsloth/Qwen3.6-35B-A3B-NVFP4 --kvcache-dtype turbo4
|
|
181
|
+
|
|
182
|
+
# Production precision
|
|
183
|
+
xinfer --m Qwen/Qwen3.6-35B-A3B-FP8 --kvcache-dtype fp8
|
|
184
|
+
|
|
185
|
+
# 27B Dense + turbo4
|
|
186
|
+
xinfer --m Qwen/Qwen3.6-27B-FP8 --kvcache-dtype turbo4
|
|
187
|
+
|
|
188
|
+
# 30B MoE GGUF + turbo4
|
|
189
|
+
xinfer --m unsloth/Qwen3-30B-A3B-Instruct-2507-GGUF \
|
|
190
|
+
--f Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf --kvcache-dtype turbo4
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 📘 Usage (Rust)
|
|
196
|
+
|
|
197
|
+
### Installation
|
|
198
|
+
|
|
199
|
+
<details>
|
|
200
|
+
<summary><b>CUDA (Linux)</b></summary>
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Prerequisites
|
|
204
|
+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
205
|
+
sudo apt-get install -y git build-essential libssl-dev pkg-config
|
|
206
|
+
|
|
207
|
+
# Optional: CUDA toolkit + NCCL
|
|
208
|
+
sudo apt-get install -y cuda-nvcc-12-9 cuda-nvrtc-dev-12-9 libcublas-dev-12-9 libcurand-dev-12-9
|
|
209
|
+
sudo apt-get install -y libnccl2 libnccl-dev
|
|
210
|
+
|
|
211
|
+
# Build & install
|
|
212
|
+
cargo --install --features cuda,nccl,flashinfer,cutlass
|
|
213
|
+
# Flash Attention backend alternative:
|
|
214
|
+
cargo --install --features cuda,nccl,flashattn,cutlass
|
|
215
|
+
# V100 / older (no flash backends):
|
|
216
|
+
cargo --install --features cuda,nccl
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
</details>
|
|
220
|
+
|
|
221
|
+
<details>
|
|
222
|
+
<summary><b>Metal (macOS)</b></summary>
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# Install Xcode command-line tools first
|
|
226
|
+
cargo install --features metal
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
</details>
|
|
230
|
+
|
|
231
|
+
<details>
|
|
232
|
+
<summary><b>Docker</b></summary>
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# sm_80 = A100, sm_90 = Hopper, sm_120 = Blackwell
|
|
236
|
+
./build_docker.sh "cuda,nccl,flashinfer,cutlass,python" sm_80 12.9.0 0
|
|
237
|
+
# Production image with Flash Attention:
|
|
238
|
+
./build_docker.sh --prod "cuda,nccl,flashattn,cutlass,python" sm_90 13.0.0
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
See [Docker guide →](docs/docker.md)
|
|
242
|
+
|
|
243
|
+
</details>
|
|
244
|
+
|
|
245
|
+
### Running Models
|
|
246
|
+
|
|
247
|
+
> **Tip:** By default, xInfer starts an OpenAI-compatible API server at `http://localhost:8000`. Add `--ui-server` to also launch the built-in ChatGPT-style Web UI at `http://localhost:8001`.
|
|
248
|
+
>
|
|
249
|
+
> For Docker builds, refer to [**Run xInfer in Docker →**](docs/docker.md)
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
# FP8 model (sm90+ with cutlass) + web UI
|
|
253
|
+
xinfer --m Qwen/Qwen3.6-27B-FP8 --ui-server
|
|
254
|
+
|
|
255
|
+
# Unquantized Safetensors (multi-GPU)
|
|
256
|
+
xinfer --d 0,1 --m Qwen/Qwen3-30B-A3B-Instruct-2507 --kvcache-dtype fp8
|
|
257
|
+
|
|
258
|
+
# ISQ on-the-fly quantization
|
|
259
|
+
xinfer --m Qwen/Qwen3.6-35B-A3B --isq q4k
|
|
260
|
+
|
|
261
|
+
# NVFP4 model
|
|
262
|
+
xinfer --m unsloth/Qwen3.6-27B-NVFP4
|
|
263
|
+
|
|
264
|
+
# MXFP4
|
|
265
|
+
xinfer --m olka-fi/Qwen3.5-4B-MXFP4
|
|
266
|
+
|
|
267
|
+
# GGUF model (4-bit KvCache)
|
|
268
|
+
xinfer --m unsloth/Qwen3.5-27B-GGUF --f Qwen3.5-27B-Q4_K_M.gguf --kvcache-dtype turbo4
|
|
269
|
+
|
|
270
|
+
# FP8 on Metal
|
|
271
|
+
xinfer --m Qwen/Qwen3.5-4B-FP8
|
|
272
|
+
|
|
273
|
+
# Gemma4 26B (NVFP4)
|
|
274
|
+
xinfer --m unsloth/gemma-4-26b-a4b-it-NVFP4
|
|
275
|
+
|
|
276
|
+
# MLA model (GLM4.7 Flash)
|
|
277
|
+
xinfer --m GadflyII/GLM-4.7-Flash-NVFP4
|
|
278
|
+
|
|
279
|
+
# Interactive CLI chat
|
|
280
|
+
xinfer --i --m unsloth/Qwen3.5-27B-GGUF --f Qwen3.5-27B-Q4_K_M.gguf
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
<details>
|
|
284
|
+
<summary><b>ISQ (on-the-fly quantization) + KV cache compression</b></summary>
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
# ISQ Q4K + FP8 KV cache
|
|
288
|
+
xinfer --m Qwen/Qwen3.6-35B-A3B --isq q4k --kvcache-dtype fp8
|
|
289
|
+
|
|
290
|
+
# ISQ Q4K + TurboQuant KV cache
|
|
291
|
+
xinfer --m Qwen/Qwen3.6-35B-A3B --isq q4k --kvcache-dtype turbo4
|
|
292
|
+
|
|
293
|
+
# Metal ISQ
|
|
294
|
+
xinfer --w /path/Qwen3-4B --isq q6k
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
</details>
|
|
298
|
+
|
|
299
|
+
<details>
|
|
300
|
+
<summary><b>GGUF models</b></summary>
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Single GPU — GGUF
|
|
304
|
+
xinfer --m unsloth/Qwen3.5-27B-GGUF --f Qwen3.5-27B-Q4_K_M.gguf
|
|
305
|
+
|
|
306
|
+
# Multi-GPU — GGUF
|
|
307
|
+
xinfer --d 0,1 --f /path/Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
</details>
|
|
311
|
+
|
|
312
|
+
<details>
|
|
313
|
+
<summary><b>TurboQuant KV cache (2–4 bit) — see <a href="#turboquant-kv-cache--run-30b-models-on-consumer-gpus">TurboQuant section</a></b></summary>
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
# turbo4: 4-bit K+V — 3.7× compression, best tradeoff
|
|
317
|
+
xinfer --m Qwen/Qwen3.6-27B-FP8 --kvcache-dtype turbo4
|
|
318
|
+
|
|
319
|
+
# turbo3: 3-bit K + 4-bit V — 4.7× compression
|
|
320
|
+
xinfer --m Qwen/Qwen3.6-27B-FP8 --kvcache-dtype turbo3
|
|
321
|
+
|
|
322
|
+
# turbo8: FP8 K + 4-bit V — 2.6× compression, highest quality
|
|
323
|
+
xinfer --m Qwen/Qwen3.6-27B-FP8 --kvcache-dtype turbo8
|
|
324
|
+
|
|
325
|
+
# 35B MoE (NVFP4 + turbo4) — fits on single 24 GB GPU
|
|
326
|
+
xinfer --m unsloth/Qwen3.6-35B-A3B-NVFP4 --kvcache-dtype turbo4
|
|
327
|
+
|
|
328
|
+
# 30B MoE (GGUF Q4_K_M + turbo4) — consumer GPU
|
|
329
|
+
xinfer --m unsloth/Qwen3-30B-A3B-Instruct-2507-GGUF \
|
|
330
|
+
--f Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf --kvcache-dtype turbo4
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
</details>
|
|
334
|
+
|
|
335
|
+
<details>
|
|
336
|
+
<summary><b>Multimodal models (Qwen3-VL, Gemma4, Mistral3-VL)</b></summary>
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Upload images via built-in Chat UI or send image_url in API requests
|
|
340
|
+
|
|
341
|
+
# Qwen3.6 35B MoE (FP8, multimodal)
|
|
342
|
+
xinfer --m Qwen/Qwen3.6-35B-A3B-FP8 --ui-server
|
|
343
|
+
|
|
344
|
+
# Qwen3-VL 8B (GGUF)
|
|
345
|
+
xinfer --m unsloth/Qwen3-VL-8B-Instruct-GGUF --f Qwen3-VL-8B-Instruct-Q8_0.gguf --ui-server
|
|
346
|
+
|
|
347
|
+
# Gemma4 26B MoE (NVFP4, multimodal)
|
|
348
|
+
xinfer --m unsloth/gemma-4-26b-a4b-it-NVFP4 --ui-server
|
|
349
|
+
|
|
350
|
+
# Mistral-3 VL 3B (BF16, multimodal)
|
|
351
|
+
xinfer --m mistralai/Ministral-3-3B --ui-server
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
</details>
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## 📘 Usage (Python)
|
|
359
|
+
|
|
360
|
+
### Running Models
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# FP8 model + web UI
|
|
364
|
+
python3 -m xinfer.server --m Qwen/Qwen3.6-27B-FP8 --ui-server
|
|
365
|
+
|
|
366
|
+
# Unquantized Safetensors (multi-GPU)
|
|
367
|
+
python3 -m xinfer.server --m Qwen/Qwen3.5-122B-A10B --d 0,1 --kvcache-dtype fp8
|
|
368
|
+
|
|
369
|
+
# ISQ on-the-fly quantization
|
|
370
|
+
python3 -m xinfer.server --w /path/Qwen3.6-35B-A3B --isq q4k --d 0 --kvcache-dtype turbo8
|
|
371
|
+
|
|
372
|
+
# NVFP4 / MXFP4
|
|
373
|
+
python3 -m xinfer.server --m unsloth/Qwen3.6-27B-NVFP4
|
|
374
|
+
python3 -m xinfer.server --m olka-fi/Qwen3.5-4B-MXFP4
|
|
375
|
+
python3 -m xinfer.server --m GadflyII/GLM-4.7-Flash-NVFP4
|
|
376
|
+
|
|
377
|
+
# GGUF
|
|
378
|
+
python3 -m xinfer.server --m unsloth/Qwen3.5-27B-GGUF --f Qwen3.5-27B-Q4_K_M.gguf
|
|
379
|
+
|
|
380
|
+
# Multimodal
|
|
381
|
+
python3 -m xinfer.server --m Qwen/Qwen3.6-35B-A3B-FP8 --kvcache-dtype fp8
|
|
382
|
+
|
|
383
|
+
# GPTQ / AWQ
|
|
384
|
+
python3 -m xinfer.server --w /home/Meta-Llama-3.1-8B-Instruct-GPTQ-INT4-Marlin
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
See [more Python examples →](python/ReadMe.md)
|
|
388
|
+
|
|
389
|
+
<details>
|
|
390
|
+
<summary><b>Build Python wheel from source</b></summary>
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
pip install maturin maturin[patchelf]
|
|
394
|
+
|
|
395
|
+
# FlashInfer backend (SM80+)
|
|
396
|
+
./build.sh --release --features cuda,nccl,flashinfer,cutlass,python
|
|
397
|
+
|
|
398
|
+
# Flash Attention backend
|
|
399
|
+
./build.sh --release --features cuda,nccl,flashattn,cutlass,python
|
|
400
|
+
|
|
401
|
+
# macOS Metal
|
|
402
|
+
maturin build --release --features metal,python
|
|
403
|
+
|
|
404
|
+
# Install
|
|
405
|
+
pip install target/wheels/xinfer*.whl --force-reinstall
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
</details>
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## 🔀 Prefill-Decode Disaggregation
|
|
413
|
+
|
|
414
|
+
Split prefill (prompt processing) and decode (token generation) across GPUs or machines. Eliminates decode stalls during long-context prefilling. PD Server and PD Client must use **same** KvCache type (`--kvcache-dtype`). API request(s) must send to PD Client and the PD Server only process internal prefill requests sent from PD Client.
|
|
415
|
+
|
|
416
|
+
| Mode | Config | Use Case |
|
|
417
|
+
|---|---|---|
|
|
418
|
+
| Local IPC | _(default, no flag)_ | Same machine, CUDA |
|
|
419
|
+
| File IPC | `--pd-url file:///path` | Docker containers, shared volume |
|
|
420
|
+
| Remote TCP | `--pd-url tcp://host:port` | Different machines |
|
|
421
|
+
|
|
422
|
+
**Local IPC** (multirank)
|
|
423
|
+
```bash
|
|
424
|
+
# PD Server (prefill GPU, default port 7000)
|
|
425
|
+
xinfer --d 0,1 --m Qwen/Qwen3-30B-A3B-Instruct-2507 --pd-server
|
|
426
|
+
|
|
427
|
+
# PD Client (decode GPU + API)
|
|
428
|
+
xinfer --d 2,3 --w /path/Qwen3-30B-A3B-Instruct-2507 --isq q4k --ui-server --port 8000 --pd-client
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Multinode** (tcp mode)
|
|
432
|
+
```bash
|
|
433
|
+
# Server machine (192.168.1.100)
|
|
434
|
+
target/release/xinfer --d 0,1 --m Qwen/... --pd-server --pd-url tcp://0.0.0.0:8100
|
|
435
|
+
|
|
436
|
+
# Client machine
|
|
437
|
+
target/release/xinfer --d 0,1 --w /path/... --pd-client --pd-url tcp://192.168.1.100:8100 --ui-server --port 8000
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
> Metal/macOS requires `--pd-url` (no LocalIPC support).
|
|
441
|
+
|
|
442
|
+
<details>
|
|
443
|
+
<summary><b>Multi-container (file:// mode)</b></summary>
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
mkdir -p /tmp/pd-sockets
|
|
447
|
+
|
|
448
|
+
# Server container
|
|
449
|
+
docker run --gpus '"device=0,1"' -v /tmp/pd-sockets:/sockets ...
|
|
450
|
+
target/release/xinfer --d 0,1 --m Qwen/... --pd-server --pd-url file:///sockets
|
|
451
|
+
|
|
452
|
+
# Client container
|
|
453
|
+
docker run --gpus '"device=2,3"' -v /tmp/pd-sockets:/sockets ...
|
|
454
|
+
target/release/xinfer --d 0,1 --w /path/... --pd-client --pd-url file:///sockets --ui-server --port 8000
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
</details>
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## 🔌 MCP Tool Calling
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
xinfer --m unsloth/Qwen3-30B-A3B-Instruct-2507-GGUF \
|
|
465
|
+
--f Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf --ui-server --mcp-config ./mcp.json
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
[MCP documentation →](docs/mcp_tool_calling.md)
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## 🔌 Structured Outputs
|
|
473
|
+
|
|
474
|
+
Constraint-based generation via llguidance — Lark grammars, regex, JSON Schema.
|
|
475
|
+
|
|
476
|
+
[Structured outputs documentation →](docs/guided_decoding.md)
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## 📚 Documentation
|
|
481
|
+
|
|
482
|
+
| Guide | Description |
|
|
483
|
+
|---|---|
|
|
484
|
+
| [Get Started](docs/get_started.md) | Build, run, and configure |
|
|
485
|
+
| [Docker](docs/docker.md) | Container builds and deployment |
|
|
486
|
+
| [Performance](docs/performance.md) | Full benchmark tables |
|
|
487
|
+
| [Prefix Cache](docs/prefix-cache.md) | Automatic KV cache reuse |
|
|
488
|
+
| [Multimodal](docs/multimodal.md) | Vision-language models |
|
|
489
|
+
| [Embedding](docs/embeddings.md) | Text embedding API |
|
|
490
|
+
| [Tokenizer API](docs/tokenizer_api.md) | Tokenize / detokenize endpoints |
|
|
491
|
+
| [Tool Parsing](docs/tool_parsing.md) | Tool call detection and parsing |
|
|
492
|
+
| [MCP Integration](docs/mcp_tool_calling.md) | Model Context Protocol |
|
|
493
|
+
| [Guided Decoding](docs/guided_decoding.md) | Structured outputs |
|
|
494
|
+
| [Rust Crate](docs/rust_crate.md) | Use as a library |
|
|
495
|
+
| [Add a Model](docs/add_model.md) | Port a new architecture (AI-assisted) |
|
|
496
|
+
| [Test a Model](docs/test_model.md) | Validate model quality (AI-assisted) |
|
|
497
|
+
|
|
498
|
+
**Using Agents under xInfer backend:** [xbot](docs/xbot.md) · [OpenCode](docs/opencode.md) · [Kilo Code](docs/kilocode.md) · [Claude Code](docs/claude_code.md) · [Goose](docs/goose.md)
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## ⚙️ CLI Reference
|
|
503
|
+
|
|
504
|
+
| Flag | Description |
|
|
505
|
+
|---|---|
|
|
506
|
+
| `--m` | HuggingFace model ID (auto-download) |
|
|
507
|
+
| `--w` | Local Safetensors model path |
|
|
508
|
+
| `--f` | GGUF file path (or filename when `--m` is given) |
|
|
509
|
+
| `--d` | Device IDs (e.g. `--d 0,1`) |
|
|
510
|
+
| `--ui-server` | API server + built-in ChatGPT-style web UI |
|
|
511
|
+
| `--server` | API server only (no web UI) |
|
|
512
|
+
| `--i` | Interactive CLI chat |
|
|
513
|
+
| `--isq` | On-the-fly quantization: `q2k`, `q3k`, `q4k`, `q5k`, `q6k`, `q8_0` |
|
|
514
|
+
| `--kvcache-dtype` | KV cache quantization: `fp8`, `turbo8`, `turbo4`, `turbo3` |
|
|
515
|
+
| `--max-num-seqs` | Max concurrent requests (default: 32, macOS: 8) |
|
|
516
|
+
| `--max-tokens` | Max tokens per response (default: 16384) |
|
|
517
|
+
| `--kv-fraction` | GPU memory fraction for KV cache |
|
|
518
|
+
| `--cpu-mem-fold` | CPU swap memory ratio (default: 0.2) |
|
|
519
|
+
| `--pd-server` | Run as PD prefill server |
|
|
520
|
+
| `--pd-client` | Run as PD decode client |
|
|
521
|
+
| `--pd-url` | PD connection URL (`tcp://`, `http://`, `file://`) |
|
|
522
|
+
| `--disable-prefix-cache` | Disable prefix caching |
|
|
523
|
+
| `--prefix-cache-max-tokens` | Cap prefix cache size |
|
|
524
|
+
| `--disable-cuda-graph` | Disable CUDA graph capture |
|
|
525
|
+
| `--yarn-scaling-factor` | YARN RoPE context extension factor |
|
|
526
|
+
| `--temperature` | Sampling temperature (0–1) |
|
|
527
|
+
| `--top-k` / `--top-p` | Top-k / nucleus sampling |
|
|
528
|
+
| `--presence-penalty` | Penalize repeated tokens (−2 to 2) |
|
|
529
|
+
| `--frequency-penalty` | Penalize frequent tokens (−2 to 2) |
|
|
530
|
+
| `--mcp-config` | MCP servers JSON config |
|
|
531
|
+
| `--mcp-command` / `--mcp-args` | Single MCP server command + args |
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## 📽️ Demo
|
|
536
|
+
|
|
537
|
+
<video src="https://github.com/user-attachments/assets/7fc6aa0b-78ac-4323-923f-d761dd12857f" width="1000px"></video>
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## 🛠️ Roadmap
|
|
542
|
+
|
|
543
|
+
* [x] Batched inference (Metal)
|
|
544
|
+
* [x] GGUF format support
|
|
545
|
+
* [x] FlashAttention (CUDA)
|
|
546
|
+
* [x] CUDA Graph
|
|
547
|
+
* [x] OpenAI-compatible API (streaming support)
|
|
548
|
+
* [x] Continuous batching
|
|
549
|
+
* [x] Multi-gpu inference (Safetensors, GPTQ, AWQ, GGUF)
|
|
550
|
+
* [x] Speedup prompt processing on Metal/macOS
|
|
551
|
+
* [x] Chunked Prefill
|
|
552
|
+
* [x] Prefix cache (available on `CUDA` when `prefix-cache` enabled)
|
|
553
|
+
* [x] Model loading from hugginface hub
|
|
554
|
+
* [ ] Model loading from ModelScope (China)
|
|
555
|
+
* [x] Prefix cache for Metal/macOS
|
|
556
|
+
* [x] FP8 KV Cache (CUDA, all backends including FlashInfer on SM80+)
|
|
557
|
+
* [x] FP8 KV Cache (Metal)
|
|
558
|
+
* [x] FP8 KV Cache (with FlashInfer, SM80+)
|
|
559
|
+
* [x] TurboQuant KV Cache (2-4 bit compression with WHT rotation)
|
|
560
|
+
* [x] FP8 Models (CUDA: MoE, Dense; Metal: Dense)
|
|
561
|
+
* [ ] Additional model support (Kimi K2, GLM 5.1 etc.)
|
|
562
|
+
* [x] CPU KV Cache Offloading
|
|
563
|
+
* [x] Prefill-decode Disaggregation (CUDA)
|
|
564
|
+
* [x] Prefill-decode Disaggregation (Metal)
|
|
565
|
+
* [x] Built-in ChatGPT-like Web Server
|
|
566
|
+
* [x] Embedding API
|
|
567
|
+
* [x] Tokenize/Detokenize API
|
|
568
|
+
* [x] MCP Integration & Tool Calling
|
|
569
|
+
* [x] Prefix Caching
|
|
570
|
+
* [x] Claude/Anthropic-compatible API Server
|
|
571
|
+
* [x] Support CUDA 13
|
|
572
|
+
* [x] **Support FlashInfer backend**
|
|
573
|
+
* [x] **Support DeepGEMM backend (Hopper)**
|
|
574
|
+
* [x] **MXFP4/NVFP4 Model Support**
|
|
575
|
+
* [x] **Support Turboquant (4-bit, 3-bit) KvCache**
|
|
576
|
+
* [ ] TentorRT-LLM
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## 📚 References
|
|
581
|
+
|
|
582
|
+
- [Candle-vLLM](https://github.com/EricLBuehler/candle-vllm)
|
|
583
|
+
- Python nano-vllm
|
|
584
|
+
|
|
585
|
+
## Star History
|
|
586
|
+
|
|
587
|
+
<a href="https://www.star-history.com/?repos=guoqingbao%2Fxinfer&type=date&legend=top-left">
|
|
588
|
+
<picture>
|
|
589
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=guoqingbao/xinfer&type=date&theme=dark&legend=top-left" />
|
|
590
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=guoqingbao/xinfer&type=date&legend=top-left" />
|
|
591
|
+
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=guoqingbao/xinfer&type=date&legend=top-left" />
|
|
592
|
+
</picture>
|
|
593
|
+
</a>
|
|
594
|
+
|
|
595
|
+
**Like this project? Give it a ⭐ and contribute!**
|
package/bin/xinfer.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const { spawnSync } = require("child_process");
|
|
7
|
+
|
|
8
|
+
function targetTriple() {
|
|
9
|
+
const platform = process.platform;
|
|
10
|
+
const arch = process.arch;
|
|
11
|
+
if (
|
|
12
|
+
(platform !== "linux" && platform !== "darwin") ||
|
|
13
|
+
(arch !== "x64" && arch !== "arm64")
|
|
14
|
+
) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Unsupported platform: ${platform}-${arch}. Supported: linux/darwin x64/arm64.`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return `${platform}-${arch}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function findBinary() {
|
|
23
|
+
const target = targetTriple();
|
|
24
|
+
const root = path.resolve(__dirname, "..");
|
|
25
|
+
|
|
26
|
+
// Prefer arch-specific variant installed by postinstall
|
|
27
|
+
const variants = fs.readdirSync(path.join(root, "vendor")).filter((d) =>
|
|
28
|
+
d.startsWith(target)
|
|
29
|
+
);
|
|
30
|
+
if (variants.length > 0) {
|
|
31
|
+
variants.sort();
|
|
32
|
+
const best = variants[variants.length - 1];
|
|
33
|
+
const bin = path.join(root, "vendor", best, "xinfer");
|
|
34
|
+
if (fs.existsSync(bin)) return bin;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Fallback to plain target
|
|
38
|
+
const fallback = path.join(root, "vendor", target, "xinfer");
|
|
39
|
+
if (fs.existsSync(fallback)) return fallback;
|
|
40
|
+
|
|
41
|
+
throw new Error(
|
|
42
|
+
`xinfer native binary is missing for ${target}. Reinstall the package or set XINFER_INSTALL_BASE_URL for a custom release mirror.`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function main() {
|
|
47
|
+
const binary = findBinary();
|
|
48
|
+
const result = spawnSync(binary, process.argv.slice(2), {
|
|
49
|
+
stdio: "inherit",
|
|
50
|
+
env: process.env,
|
|
51
|
+
});
|
|
52
|
+
if (result.error) {
|
|
53
|
+
throw result.error;
|
|
54
|
+
}
|
|
55
|
+
if (result.signal) {
|
|
56
|
+
process.kill(process.pid, result.signal);
|
|
57
|
+
}
|
|
58
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
main();
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error(`xinfer: ${err.message}`);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|