File size: 7,675 Bytes
957406c 8ebf335 434da24 8ebf335 392efee e22f356 57426fb 392efee e22f356 392efee a6b5235 c459436 434da24 0c43530 3a9ad3f 392efee 8ebf335 57426fb 8ebf335 392efee c459436 e22f356 392efee e22f356 0c43530 57426fb e22f356 392efee 434da24 3a9ad3f 392efee e22f356 434da24 edf2ef0 392efee e22f356 392efee 434da24 1420bd1 392efee 1420bd1 c459436 392efee c459436 392efee c459436 8ebf335 | 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 | ---
title: Inference
emoji: ⚡
colorFrom: gray
colorTo: indigo
sdk: docker
pinned: false
---
# CPU Inference Backend
This Space is a backend-only OpenAI-compatible inference server built on `llama.cpp` and optimized for CPU-only Hugging Face Docker Spaces.
It automatically downloads the target Hugging Face model from `MODEL_NAME`, stores it under `/data/models/model.gguf`, and starts `llama-server` with OpenAI-compatible endpoints.
## Environment variables
Set these in the Space settings:
- `MODEL_NAME`: Hugging Face repo id that contains one or more GGUF files
- `MODEL_FILE`: optional exact GGUF filename inside `MODEL_NAME`; useful for testing faster/lower quality quants
- `HF_TOKEN`: Hugging Face token used for the download
- `API_PASSWORD`: bearer token required by the API
Optional tuning variables:
- `CTX_SIZE`: context size, default `4096` (reduce to 2048-4096 for small models to improve speed)
- `THREADS`: CPU thread count, default auto-detect via cgroup CPU quota, then `nproc`
- `OMP_PROC_BIND`, `OMP_PLACES`, `OMP_WAIT_POLICY`: OpenMP CPU placement controls, default `FALSE`, `cores`, and `PASSIVE`
- `THREADS_BATCH`: batch thread count, default matches THREADS
- `BATCH_SIZE`: prompt batch size, default 128 for balanced mode
- `UBATCH_SIZE`: micro-batch size, default 128 for balanced mode
- `CACHE_TYPE_K`: KV cache type for keys, default `f16` (use `q4_0` for memory savings)
- `CACHE_TYPE_V`: KV cache type for values, default `f16` (use `q4_0` for memory savings)
- `PERF_PROFILE`: `low_latency`, `balanced` (default), or `throughput`
- `REASONING`: reasoning mode, accepts `True`, `False`, or `auto` and maps to llama.cpp `--reasoning`
- `LANGSEARCH_API_KEY`: optional API key for LangSearch web search tool (free tier: 1 req/sec, 60/min, 1000/day)
- `ENABLE_TOOLS`: set to `1` to enable llama.cpp shell tool support when `LANGSEARCH_API_KEY` is present, default `0`
- `HTTP_THREADS`: HTTP server worker threads, default `1` for personal single-request inference
- `LOG_VERBOSITY`: llama.cpp log verbosity, default `1` to reduce runtime logging overhead
- `MMAP`: set to `1` to use memory-mapped model loading, default `0`
- `FLASH_ATTN`: set to `0` to disable flash attention if a model hangs or fails during startup, default `1`
- `NO_WARMUP`: set to `1` to skip model warmup and save startup time
- `PORT`: listen port, default `7860`
## Endpoints
The server exposes:
- `/v1/chat/completions`
- `/v1/completions`
- `/v1/models`
Streaming is supported by `llama-server`. Bearer token authentication uses `--api-key` directly.
## Build and runtime
The Docker image uses a multi-stage build on Debian bookworm. The builder stage installs `git`, `build-essential`, `cmake`, and OpenBLAS, clones `llama.cpp`, and compiles `llama-server` with `-Ofast`, `-march=native`, `-flto`, OpenBLAS, and native CPU optimizations. The runtime stage keeps only Python, OpenBLAS/OpenMP runtime libraries, the compiled server, and the downloader.
Model downloads and HF cache live on the `/data` bucket so restarts do not redownload the model.
## Performance Optimization
For small 2B models on CPU-only inference (~2-4 t/s baseline), optimize these settings:
**High Impact:**
- The server forces `--parallel 1`, so only one request runs at a time and all CPU is focused on the active query
- Runtime uses `--no-mmap`, `--flash-attn on`, `--threads-http 1`, and low log verbosity to favor single-request inference over serving overhead
- OpenBLAS is enabled because benchmark results on the Space showed BLAS-off hurt prompt processing and did not recover generation speed
- `BATCH_SIZE` & `UBATCH_SIZE`: Use **64-256** for faster prompt ingestion; tiny values like 8 cause many small prompt batches
- `PERF_PROFILE`: Use **`balanced`** for normal personal use; `throughput` only changes prompt batch sizing now
**Medium Impact:**
- `NO_WARMUP=1`: Skip model warmup to reduce startup latency by ~0.2s
- `CACHE_TYPE_K`, `CACHE_TYPE_V`: Try `q4_0` instead of `f16` to reduce KV cache bandwidth and memory use at longer contexts
- `ENABLE_TOOLS`: Leave as `0` unless you need tool calling. Built-in shell tools add prompt/tool overhead and should not be exposed publicly.
- `MODEL_FILE`: If the repo has multiple GGUFs, test a lighter quant such as `Q4_0`, `Q4_K_S`, or `Q3_K_M` for speed/quality tradeoffs.
- Compatibility: if a GGUF hangs during startup, try `FLASH_ATTN=0`, `CACHE_TYPE_K=f16`, `CACHE_TYPE_V=f16`, and then `MMAP=1`.
**Example for 2B model (CPU-only):**
```
CTX_SIZE=2048
BATCH_SIZE=128
UBATCH_SIZE=128
PERF_PROFILE=balanced
REASONING=False
ENABLE_TOOLS=0
CACHE_TYPE_K=q4_0
CACHE_TYPE_V=q4_0
```
Expected: faster first-token latency from prompt ingestion. Generation speed is still CPU-bound on the free tier, so a 2B Q4 model will usually remain in the low single-digit tokens/sec range.
## Web Search Tool (Standalone)
When `ENABLE_TOOLS=1` and `LANGSEARCH_API_KEY` is set, `start.sh` enables llama.cpp's shell tool so the model can launch the local LangSearch wrapper.
llama.cpp does not expose arbitrary external HTTP APIs as first-class built-in tools, so LangSearch is still implemented as a local wrapper that runs through the shell tool.
**Use cases:**
- Call from your application layer to augment model responses
- Pre-process queries before sending to model
- Post-process to fetch real-time data for specific topics
**API Usage (from application):**
```python
import requests
import json
response = requests.post(
"http://localhost:7860/v1/chat/completions",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"model": "model",
"messages": [{"role": "user", "content": "What's the latest news?"}],
"temperature": 0.7
}
)
latest_response = response.json()['choices'][0]['message']['content']
```
Then call the search tool from your backend or from the shell tool:
```bash
python3 /app/search_tool.py "latest AI news" 5 true noLimit
```
Combine results before returning to user.
**Command-line (Docker container):**
Examples:
```bash
python3 /app/search_tool.py "latest AI news" 5 true noLimit
python3 /app/search_tool.py "Python 3.13 release" 3 false oneWeek
```
Parameters:
- `query`: search string (required)
- `count`: max results 1-10 (default: 5)
- `summary`: include summaries (default: true)
- `freshness`: `oneDay`, `oneWeek`, `oneMonth`, `oneYear`, `noLimit` (default: `noLimit`)
Output is JSON with search results, URLs, snippets, and optional summaries.
## curl examples
```bash
curl http://localhost:7860/v1/models \
-H "Authorization: Bearer $API_PASSWORD"
```
```bash
curl http://localhost:7860/v1/chat/completions \
-H "Authorization: Bearer $API_PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"model": "model",
"messages": [
{"role": "user", "content": "Write a one-sentence summary of llama.cpp."}
],
"stream": false
}'
```
```bash
curl http://localhost:7860/v1/completions \
-H "Authorization: Bearer $API_PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"model": "model",
"prompt": "Explain KV cache in one paragraph.",
"stream": false
}'
```
## OpenAI SDK example
```python
import os
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:7860/v1",
api_key=os.environ["API_PASSWORD"],
)
response = client.chat.completions.create(
model="model",
messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)
```
## Hugging Face Spaces notes
This repository is ready for a Docker Space with no frontend. The only required changes at deployment time are the three environment variables above.
|