本文整理一套已经存在于 Apple Silicon 48GB 统一内存机器上的本地大模型服务:使用 MLX 运行 4-bit 量化的 27B 生成模型,并用独立 FastAPI 服务提供 Embedding 和 Rerank。

文章重点不是宣称本地模型可以完全替代云端,而是说明以下工程问题:

  1. 三个模型如何分工;
  2. OpenAI SDK 兼容接口覆盖到什么程度;
  3. 混合注意力架构下为什么不能直接套传统 KV Cache 公式;
  4. 本地服务需要补哪些网络安全配置;
  5. 如何比较本地总成本与 API 按量计费。

1. 环境与模型

适用环境:Apple Silicon、48GB 统一内存、Python 虚拟环境、MLX/MLX LM、FastAPI 和 uvicorn。

现有模型目录核查结果如下:

模型 磁盘占用 作用
Qwen3.8-27B-OptiQ-4bit 约19GB Chat/Completion 生成
Qwen3-Embedding-8B-4bit-DWQ 约4.0GB 4096维文本向量
Qwen3-Reranker-4B-mxfp8 约3.9GB Query/Document 相关性重排

合计约 27GB。生成模型包含 4 个 safetensors 分片,其中 3 个约 5.0GB,1 个约 3.2GB。部署前应按本地实际文件计算空间,不要只引用模型参数量推测磁盘占用。

基础依赖可在虚拟环境中安装:

python -m venv .venv
source .venv/bin/activate
pip install mlx-lm mlx-embeddings fastapi uvicorn openai modelscope

使用 ModelScope 下载时,可以为每个模型指定独立目录:

modelscope download \
  --model mlx-community/Qwen3.8-27B-OptiQ-4bit \
  --local_dir ./Qwen3.8-27B-OptiQ-4bit

modelscope download \
  --model Qwen3-Embedding-8B-4bit-DWQ \
  --local_dir ./Qwen3-Embedding-8B-4bit-DWQ

modelscope download \
  --model Qwen3-Reranker-4B-mxfp8 \
  --local_dir ./Qwen3-Reranker-4B-mxfp8

模型 ID 和访问权限可能随仓库发布状态变化,执行前应在 ModelScope 模型页核对完整 ID。

2. 服务拆分与接口

在这里插入图片描述

当前实现拆成两个进程:

端口 路由 模型
8002 GET /v1/models 27B生成模型
8002 POST /v1/chat/completions 27B生成模型
8002 POST /v1/completions 27B生成模型
8002 POST /v1/responses 27B生成模型
8001 POST /v1/embeddings Embedding 8B
8001 POST /v1/rerank Reranker 4B

启动方式:

python llm_service.py
python embedding_service.py

生成服务支持流式输出、工具调用解析,并支持通过环境变量或单次请求调整 KV Cache 配置。配置优先级为:请求字段、环境变量、代码默认值。

LLM_KV_BITS=8 LLM_MAX_KV_SIZE=65536 python llm_service.py

单次请求覆盖示例:

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:8002/v1",
    api_key="local-only",
)

response = client.chat.completions.create(
    model="qwen3.8",
    messages=[{"role": "user", "content": "分析这段代码的并发风险"}],
    max_tokens=512,
    extra_body={"kv_bits": 8, "max_kv_size": 65536},
)

兼容性边界

这套实现是“OpenAI SDK 兼容子集”,不等同于完整的 OpenAI API 实现。

  • 常见 Chat Completions 和 SSE 流式调用可沿用 OpenAI SDK;
  • Responses API 的部分输入字段会被接受,但未完整实现对应行为;
  • Batch prompt 不支持;
  • seed 字段可以被请求模型接收,但底层不支持确定性种子;
  • Tool Call 结果依赖本地 tokenizer、chat template 和解析器;
  • /v1/rerank 属于 Cohere/Jina 风格接口,不是 OpenAI 标准路由。

迁移已有应用时,应针对实际使用的每个字段建立接口回归测试。

3. RAG链路

RAG 的调用顺序为:

文档 -> Embedding -> 向量库
问题 -> Embedding -> Top-K召回 -> Reranker -> 27B生成模型

Embedding 请求示例:

curl http://127.0.0.1:8001/v1/embeddings \
  -H 'Content-Type: application/json' \
  -d '{"model":"Qwen3-Embedding-8B-4bit-DWQ","input":"Apple Silicon上的MLX部署"}'

Rerank 请求示例:

curl http://127.0.0.1:8001/v1/rerank \
  -H 'Content-Type: application/json' \
  -d '{
    "model":"Qwen3-Reranker-4B-mxfp8",
    "query":"MLX如何限制KV Cache",
    "documents":["使用max_kv_size限制缓存长度", "FastAPI用于定义HTTP路由"]
  }'

现有测试脚本展示了 Embedding 归一化和 Reranker 打分的验证方式,但没有保留可审计的测试输出。因此不应发布“相关文档 0.99+、无关文档 0.01”之类的结果。若要对外给出指标,应保存测试集、运行命令、依赖版本和原始输出。

4. 混合架构下的KV Cache边界

在这里插入图片描述

生成模型的本地 config.json 包含以下关键配置:

model_type: qwen3_5_text
num_hidden_layers: 64
full_attention_interval: 4
num_key_value_heads: 4
head_dim: 256
max_position_embeddings: 262144

其层类型按“3 层 linear attention + 1 层 full attention”重复,64 层中只有 16 层是 full attention。

因此,下面这种传统 KV Cache 估算不能直接使用:

2 × KV heads × head_dim × 64层 × bytes × token数

它默认所有 64 层都按标准 full-attention K/V 缓存工作,没有覆盖 MLX 对混合架构缓存的具体实现。仅根据该公式推导 128K 上下文占用,会得到误导性的精确数字。

当前服务中的两个参数仍然有明确用途:

  • kv_bits 控制支持量化的 KV Cache 位宽;
  • max_kv_size 限制缓存长度,避免缓存无限增长。

但它们不能保证总进程内存,也不能证明 128K 上下文在 48GB 机器上稳定可用。总内存还包括权重、激活、临时张量、Python 进程、系统和其他应用。

推荐按以下顺序验证:

  1. 固定模型、提示词和生成长度;
  2. 从 4K/8K 上下文开始记录峰值内存与首 Token 延迟;
  3. 分别测试 kv_bits=4kv_bits=8
  4. 对代码、数学和长文问答建立质量样本;
  5. 逐级增加 max_kv_size,不要直接以模型声明的最大位置长度作为可用容量。

5. 网络与安全

现有服务使用:

uvicorn.run(app, host="0.0.0.0", port=8002)

Embedding 服务也监听 0.0.0.0。同时,CORS 允许任意来源,API Key 没有服务端验证。

如果服务仅供本机客户端使用,应改为:

uvicorn.run(app, host="127.0.0.1", port=8002)

若需要局域网或远程访问,至少增加:

  • 服务端 Token 或 mTLS 鉴权;
  • 防火墙和来源网段限制;
  • Nginx/Caddy 反向代理与 TLS;
  • 请求大小、并发和超时限制;
  • 脱敏访问日志与依赖审计。

本地推理减少了向第三方模型 API 发送数据,但不自动消除应用层和运维层的合规风险。

6. 成本计算边界

在这里插入图片描述

以每月 3000 万未缓存输入 Token、750 万输出 Token 为场景,并全部按 DeepSeek V4 Pro 高峰价计算:

输入成本 = 30 × 9 = 270元
输出成本 = 7.5 × 27 = 202.5元
月成本 = 472.5元

该数字不是实际节省,只是给定 Token 构成和计费口径的计算。实际云端成本还取决于缓存命中、峰谷时段、模型选择和输出长度。

本地成本可以按下面的方式估算:

月电量(kWh) = 平均功耗(W) / 1000 × 每日运行小时 × 30
月电费 = 月电量 × 当地电价
本地月总成本 = 电费 + 硬件折旧/机会成本 + 存储 + 维护时间

例如平均功耗 100W、每天 24 小时运行,月电量为 72kWh,而不是“几元电费”。至于是否更省,要代入当地电价、设备是否已有、调用量和维护时间后判断。

7. 选型结论

适合本地部署:

  • 已有 48GB Apple Silicon 设备;
  • 存在稳定、高频、可排队的摘要、分类、抽取和 RAG 任务;
  • 希望减少内容默认发送给第三方模型 API;
  • 能维护依赖、模型、鉴权和质量回归。

更适合云端 API:

  • 调用量低或波动很大;
  • 需要旗舰模型能力与托管可用性;
  • 有高并发、多用户或严格 SLA;
  • 不希望维护本地推理服务。

工程上更合理的目标通常不是“100% 本地替代”,而是建立混合路由:稳定重复任务优先走本地,复杂和突发任务回退云端。这样既能控制 Token 成本,也不会把模型能力和运维风险压在一台机器上。

参考资料

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐