改个 base_url 就能用:Edge0 本地 35B 秒变 OpenAI 兼容服务
【免费下载链接】Edge0-35B-A3B-preview项目地址: https://ai.gitcode.com/hf_mirrors/Edge0/Edge0-35B-A3B-preview
本地跑大模型,最大的痛点从来不是"能不能跑",而是"跑起来之后怎么用"。大多数端侧推理方案都止步于一个命令行交互窗口,想接进自己写的应用、接进已经成熟的工具链,还得自己写胶水层。Edge0 的做法是直接把模型目录变成一个 OpenAI 兼容的 HTTP 服务:一条edge0 serve命令起服务,/v1/chat/completions端点、SSE 流式输出、请求参数透传全套就位,任何按 OpenAI API 写的应用,改一行base_url就能把请求打到这台"本地 35B 模型服务器"上——不需要 GPU 集群、不需要 Docker、不需要改业务代码。
这篇文章基于 Edge0-35B-A3B-preview 模型仓库(README.md)与 edge0 框架服务层源码,拆解"一键起服务"的完整链路:从启动姿势、接口验证,到 SDK 接入实操,最后讲清楚服务层单槽 FIFO 队列这个设计取舍——它决定了这台"本地 OpenAI 服务"的并发边界,也恰恰是它在 3GB 内存跑 35B 模型时能保持稳定的原因。
一、一键起服务的启动姿势
Edge0 的定位是"模型 + 框架一体":本仓库就是一个完整的、可直接运行的模型目录,基模 checkpoint 和训练好的适配器放在同一个目录里,一次下载即开箱即用。目录结构里可以看到这套"开箱即用"的布局:
- config.json:模型架构声明(
Qwen3_5MoeForConditionalGeneration,40 层,256 个专家,hidden size 2048),并带完整的 4-bit affine 量化配置(group_size 64,所有层 4-bit,各层 gate 与共享专家 gate 用 8-bit 保住路由精度); model-00001-of-00004.safetensors~model-00004-of-00004.safetensors:4-bit 权重分片,索引文件 model.safetensors.index.json 记录的权重总量约 20.4 GB(配合 README 中"完整 4-bit checkpoint 约 23GB"的口径);- lora_edge0_35b.safetensors 与 prerouter_edge0_35b.safetensors:Recover-LoRA 适配器和 prerouter 路由预测头,与基模同目录,edge0 自动加载,无需手动 merge;
- chat_template.jinja:带 thinking 模式(
<think>推理块)与工具调用格式的对话模板; - generation_config.json:默认采样参数(temperature 1.0、top_k 20、top_p 0.95)。
对应的启动流程只有三步。先装框架,再下载模型(本仓库即下载产物),最后起服务:
# 1. 安装 edge0 框架(Apple Silicon Mac) pip install -e 'git+https://github.com/Edge0-AI/edge0.git#egg=edge0[fetch]' # 2. 下载模型到本地目录(本仓库即该下载的产物) huggingface-cli download Edge0/Edge0-35b-a3b-preview --local-dir ./Edge0-35b-a3b-preview # 3. 指定模型目录并起 OpenAI 兼容服务 export EDGE0_35B_MODEL=$PWD/Edge0-35b-a3b-preview edge0 serve --name edge0-35b --port 8085服务默认监听127.0.0.1:8000,--port可改。也可以完全不设环境变量,直接传目录,框架会从 checkpoint 的config.json自动识别档位:edge0 serve models/edge0-35b。
值得强调的是"自动加载"背后的机制:edge0 在推理时把专家权重从 SSD 按需 mmap 流式读取(SSD expert offload),内存只装当前激活的专家集,峰值 active 内存压到 2.9 GiB;prerouter 用训练好的路由预测头提前一步预取专家,让磁盘读取与前向计算重叠,解码速度实测 14.9–17.7 tok/s、长 prompt prefill 吞吐 113/140 tok/s(冷/热)。也就是说,这个服务的内存画像接近一台"内存占用 3GB 量级的本地模型服务",而不是"35B 参数全量常驻内存"的庞然大物。
二、/chat/completions 与 SSE 流式响应的验证
服务起来后,先别急着接 SDK,用 curl 把协议面探一遍。edge0 服务层暴露的路由是标准的 OpenAI 形状:
| 路由 | 方法 | 行为 |
|---|---|---|
/healthz | GET | 健康检查,返回{"status":"ok","model":"edge0-35b"} |
/v1/models | GET | 模型列表,返回{"object":"list","data":[{id, object, owned_by}]} |
/v1/chat/completions | POST | 对话补全,stream=true时走 SSE |
/v1/completions | POST | 显式返回 400(文本补全不支持,引导使用 chat 端点) |
非流式请求直接验证:
curl http://127.0.0.1:8000/v1/chat/completions \ -H 'Content-Type: application/json' \ -d '{ "model": "edge0-35b", "messages": [{"role": "user", "content": "Hello!"}], "max_tokens": 32 }'响应体是标准chat.completion结构:choices[0].message携带role/content,并附usage(prompt_tokens / completion_tokens / total_tokens)。
流式请求把stream置为 true,服务端返回text/event-stream,每个 token 一个chat.completion.chunk事件:
curl -N http://127.0.0.1:8000/v1/chat/completions \ -H 'Content-Type: application/json' \ -d '{ "model": "edge0-35b", "messages": [{"role": "user", "content": "用一句话解释流式推理"}], "stream": true, "max_tokens": 64 }'流式输出形如data: {…"choices":[{"delta":{"content":"推理"}}]…},每个 chunk 只带增量 delta,以data: [DONE]收尾——这与 OpenAI 官方流式协议逐字节对齐,客户端无需任何适配。
服务层的参数透传也相当完整。请求里的temperature、top_p、top_k、max_tokens、seed会被逐一映射到生成配置(未显式传参时回落到 generation_config.json 的默认值);enable_thinking控制是否开启思考模式——开启时服务端会把<think>推理块拆进reasoning_content字段,正文则进content,二者分离返回;tools/tool_choice则透传给 chat_template.jinja 渲染工具调用格式,模型输出的<tool_call>块会被服务端解析成标准的message.tool_calls结构。换言之,这不仅是"接口长得像 OpenAI",连 thinking 与 function calling 这两个高阶能力也对齐了协议。
三、接入任意 OpenAI SDK 应用的操作步骤
协议面验证通过后,接入存量应用就是纯改配置的活。核心只有两处:
base_url指向本机服务:http://127.0.0.1:8000/v1;model填edge0-35b(以/v1/models返回的id为准,--name可自定义)。
以 Python 生态最常用的openai官方 SDK 为例,非流式:
from openai import OpenAI client = OpenAI( base_url="http://127.0.0.1:8000/v1", # 只改这一行 api_key="edge0-local", # 本地服务不校验,占位即可 ) resp = client.chat.completions.create( model="edge0-35b", messages=[{"role": "user", "content": "帮我写一个 Python 快速排序"}], max_tokens=256, ) print(resp.choices[0].message.content)流式(SSE 增量):
stream = client.chat.completions.create( model="edge0-35b", messages=[{"role": "user", "content": "讲一个冷笑话"}], stream=True, ) for chunk in stream: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="", flush=True)只要是按 OpenAI 协议写的应用——ChatGPT-Next-Web 一类的聊天前端、LangChain / LlamaIndex 一类的 Agent 框架、各类 IDE AI 插件——把服务地址换成这个本地端点即可,业务代码零改动。SDK 层面唯一需要留意的差异是:本地服务没有 key 校验与计费逻辑,api_key字段传任意非空值即可满足 SDK 的参数要求。
配合 thinking 模式,代码里还能这样消费"思考过程":
resp = client.chat.completions.create( model="edge0-35b", messages=[{"role": "user", "content": "鸡兔同笼,35 个头 94 只脚,各几只?"}], enable_thinking=True, ) msg = resp.choices[0].message print("推理过程:", msg.reasoning_content) print("最终回答:", msg.content)这套接入能力背后的"质量底气"来自模型本身:edge0 的 int4 + Recover-LoRA + prerouter 管线相对 fp16 基座平均只掉 3.9 分(AIME 2026 86.6 vs 92.7、HumanEval 90.9 vs 95.1、MMLU-Pro 81.0 vs 84.6),也就是说你接到本地服务的这个 35B,不是"阉割版",而是量化损失已被 LoRA 蒸馏基本补偿回的可推理模型。
四、单槽 FIFO 队列:并发边界与取舍
把服务跑起来、把应用接进去之后,就该聊聊这台"本地 OpenAI 服务"的并发画像了——这是它和云端服务最大的不同,也是 edge0 服务层最刻意的设计。
edge0 服务层(python/src/edge0/server/)的QueueServer是一个明确的单槽模型:所有请求通过一把线程锁串行化,chat()方法内部是with self._lock:的互斥区。服务层注释把设计动机写得很直白:引擎在同一时刻只服务一个请求——单个 MLX 进程流式生成一个序列没有问题,但并发请求会反复搅动专家缓存(thrash the expert cache);请求在锁上排队,每个生成任务通过 SSE 逐 token 流式输出,队列按 FIFO 顺序消费。
这个取舍要结合推理架构来理解。Edge0 的内存优势(峰值 2.9 GiB 跑 35B)建立在"专家权重按需从 SSD 流式加载 + 页缓存驻留"之上:不同请求会激活不同的专家子集,如果两个生成并发推进,各自需要换入的专家集合互相驱逐,SSD 随机读放大、页缓存命中率崩坏,最终两个请求都会变慢,吞吐反而不如串行。单槽 FIFO 牺牲了并发度,换来的是:内存占用有硬边界、每个请求的吞吐可预期、SSD 读取模式线性化。
作为交换,代价是明确的排队延迟。以 35B 档 15–18 tok/s 的解码速度估算,一个 200 token 的生成大约耗时 11–13 秒,第 N 个排队请求的等待时间约等于前面 N−1 个请求的生成时长之和。所以这个服务形态的适用边界很清晰:
- 个人/小团队私有网关:给 IDE 插件、聊天前端、脚本任务提供统一入口,同一时刻通常只有一个人在对话,体验完全无感;
- 单机 batch serving:README 明确给出的用例之一——一份只读基模服务多套 LoRA 适配器,适合离线批量任务按 FIFO 逐个消化;
- 不适合高并发在线服务:多用户同时密集调用时,排队延迟会线性增长,需要并发能力请走云端或 GPU 集群方案。
对使用者来说,正确的姿势是把"并发"的预期对齐到"排队"上:把服务当作一台单用户的私有推理机,而不是多租户 API。如果你在 SDK 接入后遇到响应变慢,先检查是否有多处调用在同时挤这一个槽——这是单槽 FIFO 设计下唯一需要调优的变量。
小结
从edge0 serve一条命令,到 curl 验证、SDK 接入、并发边界评估,Edge0 把"本地 35B 模型"真正做成了一个可消费的软件形态:内存占用 3GB 量级、解码 15–18 tok/s、int4 质量只掉 3.9 分,对外却是一个协议完备的 OpenAI 兼容服务。对开发者而言,它意味着本地私有模型第一次可以像调用云端 API 一样被接入任意工具链——改一行base_url,35B 模型即刻上岗。当然也要记住它的边界:MLX 后端目前面向 Apple Silicon,服务层是单槽 FIFO,定位是"个人与单机的私有推理服务"。它的下一个里程碑(统一推理框架、CUDA 后端)已经在路线图上,届时这套 OpenAI 兼容接入方式大概率会原样继承——协议一旦对齐,迁移成本就只剩换一个地址而已。
【免费下载链接】Edge0-35B-A3B-preview项目地址: https://ai.gitcode.com/hf_mirrors/Edge0/Edge0-35B-A3B-preview
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考