首次运行会先下载模型,需保证网络与磁盘空间;Python 包安装需把 替换为实际发布版本并指定 releases 源;HTTP 服务默认绑定 127.0.0.1:11434,需在配置中声明要 serve 的模型。
qvac
tethertoApache-2.0活跃维护开源本地 AI SDK,无需云端和 API Key 即可在设备端跑 GGUF 模型,集成 RAG、图像音乐视频生成、语音转写和 P2P 推理,覆盖桌面与移动端。
Open-source local AI SDK - run AI on-device with no cloud, no API keys. Supports GGUF, RAG, image, music, and video generation, speech-to-text, P2P inference, and more. Cross-platform: Linux, macOS, Windows, Android, iOS.
npm i @qvac/sdk
pip install tetherto-qvac-sdk -f https://github.com/tetherto/qvac/releases/expanded_assets/sdk-v<version>
npm install -g @qvac/cliREADME 未给出具体显存或 GPU 型号要求,仅说明针对消费级硬件与嵌入式系统优化,并覆盖 Linux、macOS、Windows、Android、iOS;部分能力(如音乐生成)标注为桌面端。
开源本地 AI SDK,无需云端和 API Key,在设备端跑 LLM、语音、视觉与生成模型
开源本地 AI SDK,无需云端和 API Key 即可在设备端跑 GGUF 模型,集成 RAG、图像音乐视频生成、语音转写和 P2P 推理,覆盖桌面与移动端。
核心能力
- 提供 JS/TS 与 Python SDK 统一调用多种本地 AI 能力
- 内置 OpenAI 兼容 HTTP 服务,可接入 OpenCode 等工具
- 支持 GGUF 模型加载与流式 token 输出
- 覆盖文本、嵌入、RAG、LoRA 微调与多模态推理
- 支持图像、视频、音乐生成及语音转写与合成
容易踩的坑
- sdk-v0.23.0QVAC SDK v0.23.0最新正式版2026-11-02 · 2026-11-02 12:57 UTC
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.23.0
QVAC SDK 0.23.0 sits on
@qvac/[email protected]. It adds reranking withrerank()and allamacpp-rerankmodel type, speculative decoding, prompt priming withprefill, finer prompt-cache control, TranscribePsy transcription, and Qwen-Image-2.1 generation and reference editing. Native addons move onto fabric 0.24, which changes the RPC protocol to 112, and bundling moves to bare-pack 3. The model fit runs inside the worker on every platform, and completions now allow parallel tool calls by default. The Python client gainsassess_model_fitandmodel_fit_policywrappers and pinsbare-rpcbelow 0.1. A new Kotlin client brings the SDK to Android apps; this release ships it as Maven archives attached below (see Kotlin client).It depends on
@qvac/inference^0.23.0, andtetherto-qvac-sdkand the Kotlin client publish at the same version.Table of Contents
- Kotlin client
- Breaking Changes
- Fabric 0.24 addon set
- Bundling with bare-pack 3
- An explicit BCI
backendsDiris scanned as given - Rank pooling is gone from embedding configs
- The model fit runs inside the worker
- Parallel tool calls are on by default
executeToolSearchno longer repeats loaded schemas- A missing registry model has its own error
- One image or video generation at a time per model
- Python client
- New APIs
- Features
- Bug Fixes
- Model Changes
Kotlin client
New from 0.23.0:
io.tether:qvac-sdk-kotlin, a Kotlin client that drives the same worker as the JS/TS and Python clients.- Use it for: on-device AI in Android apps (
arm64-v8a, API 29+). Desktop JVM is experimental. - What's different: Kotlin data classes and coroutine
Flowstreams, with a self-contained runtime hosted in an isolated Android service. - Install: At the moment, using the QVAC Kotlin SDK is possible via the Maven repository archive for your runtime profile from this release's assets and pointing Gradle at it.
- Learn more: Kotlin SDK docs
Breaking Changes
Fabric 0.24 addon set
The SDK now ships the fabric 0.24 addon set. It installs these addons itself; an app that also pins any of them must move to the same floor:
Package 0.22.0 floor 0.23.0 floor @qvac/inference^0.22.0^0.23.0@qvac/asr-ggml^0.10.0^0.11.1@qvac/audiogen-ggml^0.8.0^0.9.0@qvac/bci-whispercpp - sdk-v0.22.0QVAC SDK v0.22.02026-10-19 · 2026-10-19 11:31 UTC
查看更新说明
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.22.0
QVAC SDK 0.22.0 sits on
@qvac/[email protected].assessModelFitnow asks each engine's fitter instead of a shared coefficient table, a load can setmodelFitPolicyfor itself, and completions can issue parallel tool calls with nested JSON Schema still intact. MiniMax-H3 can start a video from a still,decide()answers typed Laya questions, and the catalog adds MOSS speech, Laya decisions, and Nemotron diarization. Native addons move onto fabric 0.22. Bundling needs Node^22.21.0 || >=24.9.0.The committed range is
^0.22.0.tetherto-qvac-sdkpublishes at the same version.Table of Contents
- Breaking Changes
- Node version for
qvac bundle/ bare-pack assessModelFituses engine fitters- Per-load
modelFitPolicy - Catalog constant names
- Split addons resolve
#host-addonfrom the consumer manifest - Cached turns send the full conversation
- Mobile addons need bare-link 4
- GPU backend selection on generated VLA configs
- Fabric 0.22 addon set
- Node version for
- New APIs
- Features
- Bug Fixes
- Model Changes
Breaking Changes
Node version for
qvac bundle/ bare-packbare-pack needs Node
^22.21.0 || >=24.9.0. Earlier 22.x (including 22.20.0) crashes the lexer.qvac doctorandqvac bundle sdkrefuse those versions instead of native-crashing.Before:
"engines": { "node": ">=18.0.0" }After:
"engines": { "node": "^22.21.0 || >=24.9.0" }assessModelFituses engine fittersEvery candidate is assessed by the engine that would run it. The
'calibration'evidence class is gone, and so isestimateon the result and on each model. Under'computed-only',floorBytesis the bound. A candidate the engine itself calls a fit can still come backlikely-too-large: theinteractive-v1reserve applies on top of the engine's own headroom.Before:
const result = await assessModelFit({ models }) result.evidence // 'calibration' | 'computed-only' | 'native-fit' result.estimate // { lowerBoundBytes, upperBoundBytes } result.models[0].estimate // sameAfter:
const result = await assessModelFit({ models }) result.evidence // 'computed-only' | 'native-fit' result.floorBytes // bound under 'computed-only'Per-load
modelFitPolicySkipping the fit probe was process-wide (
QVAC_ADVISORY_MODEL_FIT=0) and also disabled the engine verdict forassessModelFit. The probe is now per load.'log'(default) still runs it and never blocks.'off'skips it for that load only.'refuse'fails a load the engine projects will not fit.Before:
// Skipping the fit probe was process-wide, and also disa - Breaking Changes
- sdk-v0.21.1QVAC SDK v0.21.12026-10-16 · 2026-10-16 16:55 UTC
查看更新说明
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.21.1
Update native add-ons to include the latest fixes and allow compatible patch updates.
Update your app lockfile and rebuild native bundles to apply the fixes.
- sdk-v0.21.0QVAC SDK v0.21.02026-10-04 · 2026-10-04 16:06 UTC
查看更新说明
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.21.0
QVAC SDK 0.21.0 sits on
@qvac/[email protected]. A model can split across machines through llama.cpp's RPC backend, Ternary Bonsai 2 27B runs in QVAC's engine, tools can defer their schemas behindtool_search, and TTS/ASR pick up MOSS plus Parakeet Core ML on Apple. Mobile bundles can auto-install addon platform packages, andverifyBundlechecksengines.bareagainst the Bare runtime each host actually runs. Catalog constant names for BitNet, Llama tool-calling, and Indic Parakeet change.assessModelFitnow takesloadModelfields instead of a separate workload object, infersmodelTypefrommodelSrcwhen omitted, and the load-time fit probe runs on every engine that ships a fitter.The committed range is
^0.21.0.tetherto-qvac-sdkpublishes at the same version.Table of Contents
Breaking Changes
assessModelFituses loadModel parametersCandidates are described the same way as a load:
modelSrc,modelType, andmodelConfig. The oldmodel/workload/artifactsobject is rejected.Before:
await assessModelFit({ models: [ { model: LLAMA_3_2_1B, workload: { kind: 'llm', contextTokens: 4096 }, artifacts: [MMPROJ_F16] } ] })After:
await assessModelFit({ models: [ { modelSrc: LLAMA_3_2_1B, modelType: 'llamacpp-completion', modelConfig: { ctx_size: 4096, projectionModelSrc: MMPROJ_F16 } } ] })modelTypeis optional and inferred frommodelSrcwhen omitted, the same wayloadModelinfers it. Required only where the source names no engine. A load whose sources are all config fields may omitmodelSrc. Audioworkload.windowMsbecomesmodelConfig.duration_ms.workload.batchhas no equivalent and is gone.Flattened fit-probe projection
getLoadedModelInfo().fitProbe.projectionis a flat byte breakdown.projection.devicesandNativeProbeDeviceare gone. Totals are summed across devices;deviceNamenames the first.Before:
info.fitProbe?.projection?.devicesAfter:
info.fitProbe?.projection?.deviceBytes info.fitProbe?.projection?.hostBytes info.fitProbe?.projection?.weightsBytes info.fitProbe?.projection?.contextBytes info.fitProbe?.projection?.computeBytes info.fitProbe?.projection?.deviceNameCatalog constant names
BitNet instructed TQ2_0 exports are retagged as base. Llama tool-calling 1B moves from
Q4_KtoQ4_K_M. Indic Parakeet Conformer CTC constants are replaced by the 600M GGUFs.Before:
import { BITNET_0_7B_INST_TQ2_0 } from '@qvac/sdk' import { LLAMA_TOOL_CALLING_1B_INST_Q4_K } from '@qvac/sdk' import { PARAKEET_INDIC_CONFORMER_CTC_Q4_0 } from '@qvac/sdk'After:
import { BITNET_0_7B_BASE_TQ2_0 } from '@qvac/sdk' import { LLAMA_TOOL_CALLING_1B_INST_Q4_K_M } from '@qvac/sdk' import { PARAKEET_INDIC_CONFORMER - sdk-v0.20.1QVAC SDK v0.20.12026-09-28 · 2026-09-28 09:52 UTC
查看更新说明
📦 NPM: https://www.npmjs.com/package/@qvac/sdk/v/0.20.1
QVAC SDK 0.20.1 is a patch on 0.20.0. It exposes the remaining llama.cpp load-time placement, MoE, fit, and image-token fields, and
assessModelFitnow runs the engine fitter on a registry fit stub instead of coefficients alone. Mobile hosts that usereact-native-bare-kitare tested against^0.15.5(Bare 1.33), which matches the addon graph this release installs.Install
@qvac/sdkand@qvac/inferencetogether at 0.20.1.Table of Contents
New APIs
llama.cpp placement, MoE, fit, and image-token load fields
loadModelforllamacpp-completionaccepts the rest of the llama.cpp load config that 0.20.0 left off the schema: CPU placement (threads,threads-batch,cpu-mask,override-tensor), MoE offload (cpu-moe,n-cpu-moe,n-cpu-ffn,moe-cache-mib), batch sizes, KV offload, weight prefetch, tensor-read laziness,fit/fit-target/fit-ctx, and image token caps.loadModel({ modelSrc, modelType: 'llamacpp-completion', modelConfig: { threads: 8, 'threads-batch': 16, 'cpu-mask': 'ff', 'override-tensor': 'blk\\.(1[0-9])\\.ffn_(up|down|gate)_exps=CPU', 'cpu-moe': true, 'n-cpu-moe': 2, 'n-cpu-ffn': 4, 'moe-cache-mib': 2048, 'batch-size': 1024, 'ubatch-size': 256, 'kv-offload': false, 'prefetch-weights': 'auto', 'tensor-read-lazy': 'on', fit: true, 'fit-target': '1024,512', 'fit-ctx': 8192, 'image-max-tokens': 512, 'image-min-tokens': 64 } })assessModelFituses the engine fitterWhen the registry has published a fit description for a model,
assessModelFitruns the engine fitter on that stub and returnsevidence: 'native-fit'. Coefficient-only projection remains the fallback when no stub is available.const { verdict, evidence } = await assessModelFit({ models: [{ model: SOME_CATALOG_CONSTANT, workload: { kind: 'llm', contextTokens: 8192 } }] }) // evidence === 'native-fit' when the registry published a description for itThe engine depends on
@qvac/registry-client^0.7.0sofitBlobBindingon those stubs decodes.@qvac/sdkno longer depends on@qvac/registry-client.Bug Fixes
Mobile Bare-kit host
react-native-bare-kit^0.15.5is the mobile host this release is tested against. It embeds Bare 1.33, which current Bare addons require. Other kit versions still install; the addon graph must match the Bare runtime that kit embeds.
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
QVAC lets you run a comprehensive range of AI workloads locally using open models across Linux, macOS, Windows, Android, and iOS.
QVAC provides:
- SDK for building local-first AI applications and systems in JavaScript/TypeScript and Python.
- HTTP server for using QVAC as a local model provider. Its OpenAI-compatible API lets you connect AI tools such as OpenCode and OpenClaw, or any other compatible tool.
Why QVAC
- Local-first: run AI offline with inference optimized for commodity hardware, from consumer apps and embedded systems to on-premises deployments.
- Privacy and control: keep data local, own the AI system. No cloud or third-party APIs required.
- One SDK, all of AI: a comprehensive range of AI capabilities through one interface.
- Cross-platform: one codebase for Linux, macOS, Windows, Android, and iOS, using JavaScript/TypeScript or Python.
- Peer-to-peer: fetch AI models directly between peers and build unstoppable internet systems, like BitTorrent or IPFS, but for AI.
Quickstart
Load a model and run inference locally in a few steps. Pick your path.
Run your first example using the JS/TS SDK.
- Create the examples workspace:
mkdir qvac-examples
cd qvac-examples
npm init -y && npm pkg set type=module
- Install the SDK:
npm i @qvac/sdk
- Create
qvac.config.jsonto enable client and server logs during the run:
{
"loggerConsoleOutput": true,
"loggerLevel": "info"
}
- Create the
quickstart.jsscript:
import { loadModel, LLAMA_3_2_1B_INST_Q4_0, completion, unloadModel } from '@qvac/sdk';
try {
const modelId = await loadModel({
modelSrc: LLAMA_3_2_1B_INST_Q4_0,
onProgress: (p) => {
const mb = (n) => (n / 1e6).toFixed(1);
const line = `▸ Downloading ${p.percentage.toFixed(0)}% (${mb(p.downloaded)}/${mb(p.total)} MB)`;
process.stderr.write(process.stderr.isTTY ? `\r${line}` : `${line}\n`);
if (p.percentage >= 100) process.stderr.write('\n');
},
});
const history = [{ role: 'user', content: 'Explain quantum computing in one sentence' }];
const result = completion({ modelId, history, stream: true });
for await (const token of result.tokenStream) {
process.stdout.write(token);
}
await unloadModel({ modelId });
} catch (error) {
console.error('✖', error);
process.exit(1);
}
- Run the quickstart script:
QVAC_CONFIG_PATH=./qvac.config.json node quickstart.js
You'll see the model download first. Then QVAC will stream the response tokens and print them to the terminal.
Run your first example using the Python SDK.
- Create the examples workspace:
mkdir qvac-examples-py
cd qvac-examples-py
python -m venv .venv
source .venv/bin/activate
- Install the package (self-contained — bundles the QVAC worker and Bare runtime, no Node.js required):
# Replace <version> with the release you want, e.g. sdk-v0.17.0:
pip install tetherto-qvac-sdk \
-f https://github.com/tetherto/qvac/releases/expanded_assets/sdk-v<version>
- Create the
quickstart.pyscript:
import asyncio
import sys
from tetherto.qvac_sdk import Client, completion, load_model, unload_model
from tetherto.qvac_sdk.models import LLAMA_3_2_1B_INST_Q4_0
def print_progress(p):
line = f"▸ Downloading {p.percentage:.0f}% ({p.downloaded / 1e6:.1f}/{p.total / 1e6:.1f} MB)"
print(line, end="\r" if sys.stderr.isatty() else "\n", file=sys.stderr)
if p.percentage >= 100:
print(file=sys.stderr)
async def main():
async with Client() as client:
t = client.transport
try:
model_id = await load_model(
t, model_src=LLAMA_3_2_1B_INST_Q4_0, on_progress=print_progress
)
run = completion(
t,
model_id=model_id,
history=[
{"role": "user", "content": "Explain quantum computing in one sentence"},
],
)
async for event in run.events:
if event.type == "contentDelta":
sys.stdout.write(event.text)
sys.stdout.flush()
print()
await unload_model(t, model_id)
except Exception as error:
print(f"✖ {error}", file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
sys.exit(asyncio.run(main()))
- Run the quickstart script:
python quickstart.py
You'll see the model download first. Then QVAC will stream the response tokens and print them to the terminal.
Launch the server with the CLI, then use QVAC as model provider for OpenAI-compatible tools like OpenCode and OpenClaw.
- Install the CLI globally (this also installs
@qvac/sdkas a transitive dependency):
npm install -g @qvac/cli
- Create the examples workspace:
mkdir qvac-server
cd qvac-server
- Create the
qvac.config.jsondeclaring one model to serve:
{
"serve": {
"models": {
"my-llm": {
"model": "QWEN3_600M_INST_Q4",
"default": true,
"config": { "ctx_size": 8192 }
}
}
}
}
- Start the server (bound to
127.0.0.1:11434by default):
qvac serve openai
The model downloads on first start and is preloaded into memory. You'll see progress in the server output.
- From another terminal, hit it with any OpenAI-compatible client. A minimal
curl:
curl http://localhost:11434/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "my-llm",
"messages": [{"role": "user", "content": "Explain quantum computing in one sentence"}]
}'
The response comes back as a single JSON payload with the model's answer. Add "stream": true to the body to get an SSE stream instead.
- Point your AI tool at the server: open its model provider settings and add a new OpenAI-compatible provider with base URL
http://localhost:11434/v1, any string as the API key, andmy-llmas the model name.
[!IMPORTANT] Setup varies by tool, and we ship dedicated plugins for some of them (like OpenCode and OpenClaw) that run the server for you. See Connect AI tools to QVAC for details.
⭐ If QVAC saves you from shipping yet another cloud dependency, give it a star, it helps other developers find the project!
AI capabilities
| Task | Description |
|---|---|
| Text generation | LLM inference for text generation and chat via Fabric LLM. |
| Text embeddings | Vector embedding generation for semantic search, clustering, and retrieval. |
| RAG | Out-of-the-box retrieval-augmented generation workflow. |
| Fine-tuning | Adapting LLMs to domain-specific tasks via LoRA. |
| Multimodal | LLM inference over text, images, and other media in one context. |
| Image generation | Text-to-image and image-to-image generation via a Diffusion backend. |
| Video generation | Text-to-video and image-to-video generation via a Diffusion backend. |
| Music generation | Generate music from text, lyrics, and musical controls via ACE-Step or MiniMax-Music3 (desktop). The AudioGen addon exposes independent ACE-Step backend selection, opt-in WebGPU, Apple Core ML sidecars, and memory preflight for the selected placement. Native dependency versions are declared in the AudioGen manifest. |
| Transcription | Speech-to-text via a Whisper backend, NVIDIA Parakeet, TranscribePsy EU and EU-sub (full 25-language EU with CAFE adapters and language routing, or the eight-language EU-sub), or MOSS-Transcribe-Diarize (speaker-labelled transcripts with hotwords, fused CPU encoder attention and metadata-only memory fit via assessFit). |
| Speaker diarization | Whisper tinydiarize speaker turns, four-speaker Sortformer, up to eight-speaker Nemotron 3 Diarization, Parakeet text per speaker turn with a separate diarizer, and speaker-labelled MOSS-Transcribe-Diarize transcripts through @qvac/asr-ggml. The addon exposes native Parakeet backend selection and streaming token IDs, finality and event timing, delivering transcript chunks before their end-of-turn boundary. |
| Audio decoding | FFmpeg audio decoder with streaming PCM output and a default 64 MiB decoded-output limit. |
| Text-to-Speech | Speech synthesis with selective MOSS Delay text projection on Metal and single-reference MOSS-TTSD preparation, incremental Audio8 PCM streaming, speech-to-speech replies and text-to-sound-effects generation via a GGML backend, with memory preflight for MOSS-SoundEffect, LavaSR denoising on Android Mali GPUs with explicit Core ML denoiser/enhancer options on Apple, and Pocket TTS (CPU, Metal, CUDA, Vulkan and OpenCL through the addon). Native engine controls expose MOSS sampling/budgets, Supertonic precision/warm-up, Parler Core ML selection and CosyVoice token replay. Exact native dependency versions are declared in the package manifest. Chatterbox and CosyVoice3 Core ML sidecars are optional on Apple platforms. Re-export existing CosyVoice3 LM sidecars after upgrading. |
| Translation | Neural machine translation, via Fabric LLM and Bergamot. |
| BCI | Brain–computer interface transcription via a Whisper backend. |
| VLA | Vision-language-action for robot control via a GGML backend. |
| OCR | Extract text from images via ONNX Runtime or GGML backends. See OCR GPU selection (main-gpu) to select a GGML GPU by registry index or device class. |
| Image classification and embeddings | Classify images with MobileNet or generate MegaLoc descriptors for image retrieval via a GGML/Fabric backend. |
Peer-to-peer
QVAC's built-in P2P capabilities let you build unstoppable internet systems without depending on centralized infrastructure:
- Fetch models: download AI models directly from peers through a distributed model registry, removing the need for centralized model hosting and distribution. The registry also serves weightless descriptions of models, their settings and tensor list without the weights, so whether a model fits in memory can be assessed before it is downloaded.
- Blind relays: route traffic through relay peers when devices cannot connect directly across NATs and firewalls, keeping the network connected without centralized infrastructure.
Resources
Explore and use QVAC:
| Resource | Description |
|---|---|
| Docs | Comprehensive QVAC documentation. |
| Examples | Sample apps and PoCs built with QVAC SDK. |
| Local model provider | Use QVAC as a local model provider connected to your favorite AI tools. |
| QV.AC | Get to know our local AI assistant. |
| Support and community | We gather on Discord and Keet. Ask for help, give feedback, and discuss QVAC. |
| Blog | Tutorials, deep dives, engineering notes, and announcements. |
| Ecosystem | Discover the broader QVAC ecosystem. |
| Research | Papers, datasets, and models optimized for edge devices. |
| Our vision | Learn why Tether built QVAC. |
Contributing
We welcome contributions! Feel free to open a pull request, report bugs, or share ideas through issues.
See CONTRIBUTING for details.
Banners and badges
Built something with QVAC? Add a badge to your README to show it and help others discover QVAC:
[](https://github.com/tetherto/qvac)
The full set of banners and light/dark and inline badge variants, with copy-paste snippets, lives in BADGES.md.