Tempo9

面向 Apple Silicon 的
服务器级本地推理引擎。

English · 中文

Apple Silicon 的硬件已经足以运行大型本地模型,但多数推理 软件仍主要面向单用户、单请求。Tempo9 把连续批处理、共享 KV 缓存、按需分页、 SSD 卸载和多请求调度带到 Mac,并让 GPU 与 Neural Engine 同时参与推理。

35B · 单流 · 工具调用 JSON104.9 tok/s24 GB M5 Pro · 系统默认设置
547 MB声明 128K 上下文时的启动内存
80 / 80四个 Agent 的测试轮次全部完成

使用手册 性能测量 发布状态

104.9 tok/s 来自生成 200 token 以上的工具调用 JSON,并启用 --speculation-k 4;默认设置下为 91.8 tok/s。完整测试方法与原始数据 已经公开。

多个 Agent 并发运行

Tempo9 当前以一套共享运行时承载多个 Agent:Continuous batching (连续批处理)将新请求动态加入正在执行的批次;Paged KV 按实际 token 分配缓存页;Prefix cache 让相同的 system prompt 与工具历史只计算、 保存一次;内存紧张时,冷 KV 页可直接在 GPU 可访问的统一内存与 SSD 之间 迁移。

这几项机制共同降低并发会话的等待时间和内存占用。在四个 coding Agent 共享 system prompt 的测试中,80 轮请求全部完成;无论共享前缀为 1.5K 还是 10K token,Tempo9 的首 token 延迟区间都低于对照引擎。下图给出各组测试的 完整范围。

四个 Agent · 数值越低越好

四组测试中,Tempo9 的最慢结果仍快于 llama.cpp 的最快结果

02467 秒
1.5K prompt · p50
Tempo90.56–0.89 秒
llama.cpp1.52–2.29 秒
1.5K prompt · p95
Tempo90.92–2.27 秒
llama.cpp4.94–6.52 秒
10K prompt · p50
Tempo90.94–0.95 秒
llama.cpp1.60 秒
10K prompt · p95
Tempo91.61–1.75 秒
llama.cpp6.32 秒

每项重复两至三轮,每轮 12 个请求。横轴表示首 token 延迟。

Qwen3.5-35B-A3B q3km · M5 Pro · 24 GB · 系统默认设置。 两个引擎读取同一 GGUF,并使用各自默认的前缀缓存。每组重复两至三次、每轮 12 个请求;这里只比较首 token 延迟,不比较尚未达到稳定复现条件的并发 decode 吞吐。测试方法与数据 →

长上下文不预分配

声明上下文长度只规定会话上限,不应立即占用对应容量。Tempo9 通过 Paged KV 按需分配缓存页,通过 Prefix cache 在会话之间共享公共页;冷页还可卸载到 SSD, 为正在运行的请求释放统一内存。

实测中,将声明上下文从 8K 提高到 128K,Tempo9 的启动占用始终约为 0.55 GB;写入更多 token 后,内存才随实际用量逐步增长。

KV + 工作内存 · 数值越低越好

上下文上限从 8K 增至 128K,启动占用基本不变

启动时,尚未填入上下文

刻度:0–4 GB

8K
Tempo9557 MB
llama.cpp505–573 MB
32K
Tempo9547–558 MB
llama.cpp981–1051 MB
64K
Tempo9536–558 MB
llama.cpp2034–2041 MB
128K
Tempo9547–557 MB
llama.cpp3.6 GB · OOM

填入 token 后的实际占用

刻度:0–2.2 GB

约 4K token
Tempo9约 550 MB
llama.cpp2.03 GB
23.4K token
Tempo9731 MB
llama.cpp2.08 GB
46.8K token
Tempo9927 MB
llama.cpp2.12 GB

左右两栏刻度不同。左栏是尚未填入上下文时的启动占用,右栏是填入 token 后的实际内存。

Prefix cache 也会减少重复计算:在一组 15K-token 共享前缀测试中,后续请求 命中 14,976 个缓存 token,prefill 时间由 10.3 秒缩短至 0.48 秒。

Qwen3.5-35B-A3B q3km · M5 Pro · 24 GB · 系统默认设置。 图中统计 KV 缓存与工作内存,不含文件映射的模型权重;两栏刻度不同。 测试方法与数据 →

经过精度验证的工具调用服务链

Tempo9 验证的不只是模型输出,而是从兼容 API 接收请求、解析工具定义、 生成参数到返回调用结果的完整服务链。BFCL v4 的 3,641 个单轮样本均经由 Agent 实际使用的 OpenAI API 兼容端点发送,没有绕过服务层。

同一服务端点已经与 CodexClaude CodeOpenClaw 及其他 支持本地模型的 Agent 框架完成兼容性验证。现有 Agent 无需更换,只需将推理 端点指向 Tempo9。

85.19%Non-Live AST
76.61%Live AST
分类明细
BFCL v4 分类Tempo9
simple (Python)95.25%
multiple94.50%
parallel89.00%
parallel multiple83.50%
Non-Live irrelevance84.17%

Qwen3.5-35B-A3B q3km · M5 Pro · 24 GB。使用官方 BFCL v4 evaluator;本页报告已运行的 single_turn 分组,不将未运行的 multi-turn、web search 和 memory 计入 overall。

基于 XGrammar 的结构化生成

Tempo9 可依据 JSON Schema 在解码阶段约束可生成的 token,使 JSON 与工具 参数在生成过程中保持结构有效。语法约束负责输出格式,BFCL 则进一步验证工具 选择和参数内容是否正确。

结构化输出也更适合投机解码

在 JSON 与工具调用负载中,模型自身 MTP head 的草稿接受率达到 0.724; 启用 --speculation-k 4 后,单流 decode 从 91.8 提高到 104.9 tok/s。2,501 个 BFCL 配对样本未显示显著精度差异。该功能目前仍 默认关闭,因为不同投机深度尚不能保证生成结果逐字节一致。

Qwen3.5-35B-A3B q3km · M5 Pro · 24 GB。单流,生成 200 token 以上的工具调用 JSON,decode 吞吐不含 TTFT。 测试方法与数据 →

从 LLM 到 VLM

VLM:视觉编码与语言模型并行

当负载从纯文本 LLM 变为视觉语言模型(VLM)时,图像编码会引入一条新的 计算链。Tempo9 将视觉 Transformer(ViT)部署在 Neural Engine,将语言 模型部署在 GPU;两者可以并行执行,图像编码不再占用正在生成文本的 GPU。

同一张图片 · 同一模型视觉计算部署位置决定 GPU 能否持续解码。
2.8×LLM 解码
基线 · 视觉计算部署在 GPU9.4 tok/s
NPU
空闲
GPU
解码 NViT N+1恢复解码

视觉编码与语言模型竞争同一个处理器。

视觉计算部署在 NPU25.9 tok/s
NPU
ViT N+1
GPU
解码 N · 持续运行

NPU 编码 N+1 时,GPU 持续解码 N。

不带图片的纯文本参考值为 73.6 tok/s。2.8 倍对比采用同一张图片和同一语言模型负载,仅改变 ViT 的执行位置。

并发负载下的执行过程

预处理CPU + NPU串行请求 N+1分词ViT · NPU请求 N+2分词ViT · NPU请求 N+3分词ViT · NPU引擎GPU连续批处理prefill N+1prefill N+2prefill N+3解码 N解码 N+1解码 N+2解码 N+3批次 N加入 N+1加入 N+2加入 N+3同一时刻:NPU 预处理 N+3 · GPU 持续解码 N、N+1、N+2后续请求加入时,GPU 解码循环保持连续运行。下一请求的 NPU 预处理与当前批次的 GPU 解码并行执行。调度与异构计算由同一运行时协调。示意图:模块宽度与对齐关系不表示实测时长。时间

上述两项为 Tempo9 内部对照,仅改变 ViT 的执行设备。相同的分页机制还使 更大的视觉语言模型能够在 24 GB 设备上运行:

Tempo9正常运行 · 回答正确
llama.cpp mtmdMetal OOM

对于两个引擎都能运行的视觉模型,使用同一张图片和同一个问题进行测试:

Gemma 4 12B,单图Tempo9llama.cpp
图像编码28 ms131 ms
回答解码28.2 tok/s33.9 tok/s

Qwen3-VL-30B-A3B 与 Gemma 4 12B · M5 Pro · 24 GB。 2.8× 比较同一图像负载下 NPU 与 GPU 两种 ViT 部署方式,不比较两种处理器的 孤立峰值性能。Gemma 4 每项重复三次,两个引擎读取相同的 GGUF 与 mmproj测试方法与数据 →

两种使用方式

命令行服务

使用 GGUF 模型文件启动本地服务,再将客户端的服务地址指向 Tempo9。

tempo9 --gguf <model.gguf> --port 11435

# OpenAI 客户端      base_url = http://127.0.0.1:11435/v1
# Anthropic 客户端   base_url = http://127.0.0.1:11435     (/v1/messages)

端点:/v1/chat/completions · /v1/messages · /v1/responses · /v1/models。 支持 OpenAI、Anthropic 和 Ollama 风格的 API。默认端口是 11435,紧邻 Ollama 的 11434,两个服务可以同时运行。

macOS SDK

Tempo9 也提供可嵌入 macOS 应用的原生 SDK。运行时与模型加载位于应用进程 内,无需安装或管理独立的本地服务进程;依赖可随应用一并签名,便于按照 Mac App Store 的沙盒与审核要求完成集成。

面向本地 Agent 与 VLM 的完整运行时

Continuous batching、Paged KV、Prefix cache 与 SSD offload 共同解决多个 长上下文 Agent 的调度和内存问题;Neural Engine 与 GPU 的并行执行,则让本地 VLM 在处理图像时仍能持续生成文本。这些能力组合在一起,使一台 Mac 可以承担 原本依赖服务器运行时的多会话与多模态负载。

本地部署也是这一架构的直接结果:模型权重、上下文和工具调用数据均由本机 进程处理,不需要云端账户或遥测服务。

已经实际验证的模型架构

目前验证了九种架构、十六个 GGUF 模型文件。架构名称采用模型 config.json 中的 Transformers 标准类名;清单由模型实际加载、问答 和长上下文测试生成,不根据代码路径推测支持范围。

纯文本语言模型

架构模型系列已验证示例
Qwen3ForCausalLMQwen3Qwen3 0.6B
LlamaForCausalLMLlamaLlama 3.1 8B、Llama 3.2 1B、TinyLlama 1.1B
MistralForCausalLMMistral、MinistralMistral 7B v0.3、Ministral 3B
GptOssForCausalLMGPT-OSSGPT-OSS 20B(MXFP4)

多模态语言模型

架构模型系列已验证示例
Qwen3_5ForConditionalGenerationQwen3.5、Qwen3.8Qwen3.5 0.8B / 4B / 9B、Qwen3.8 27B
Qwen3_5MoeForConditionalGenerationQwen3.5 MoEQwen3.5 35B-A3B
Qwen3VLForConditionalGenerationQwen3-VLQwen3-VL 4B
Qwen3VLMoeForConditionalGenerationQwen3-VL MoEQwen3-VL 30B-A3B
Gemma4UnifiedForConditionalGenerationGemma 4 UnifiedGemma 4 12B

表中模型均在同一台 24 GB M5 Pro 上运行。每个模型完成加载与 常规问答,并在模型上下文上限允许时完成 10K-token 测试;多模态架构已有代表 模型完成真实图片输入测试。完整矩阵同时记录未测试和失败项目。

需要支持其他模型

模型支持按实际需求安排优先级。可以通过 GitHub issue 提交模型名称和量化 格式,进入后续支持清单。

提交模型支持申请 →

示例与开发文档

从一个可运行的示例开始,再根据集成方式查阅完整接口。

示例

开发手册

首个公开版本准备中

使用手册和测量数据已经公开;签名二进制与 Homebrew tap 仍在准备中。

使用手册 发布状态