前五篇我们一直在优化线上 API 调用和检索质量。但有一个现实问题悬而未决:ByteBot 完全依赖 DeepSeek 云端 API,如果上游故障或密钥过期,导览功能就只剩 BM25 兜底。
本篇讨论的是”降级路径 3”:用本地模型做兜底。博客早就有本地模型的基础——《Ollama + DeepSeek-Coder-V2 + Visual Studio Copilot 插件》那篇验证了本地 AI 编程助手。本篇把它从”本地跑起来”推进到”本地跑得快、跑得稳、能接进生产链路”。
一、为什么需要量化
1.1 显存是第一约束
一个 7B 参数的模型,fp16 权重就要约 14GB 显存,家用 8GB 显卡根本装不下。量化把权重从 fp16(16bit)压到 4bit 或 8bit,7B 模型只需 4~5GB。
| 精度 | 每参数字节 | 7B 模型权重 | 13B 模型权重 | 适合显存 |
|---|---|---|---|---|
| fp16 | 2 | 14 GB | 26 GB | 24GB+ |
| int8 / Q8 | 1 | 7 GB | 13 GB | 12GB+ |
| int4 / Q4 | 0.5 | 4 GB | 7 GB | 8GB |
| int3 / Q3 | 0.375 | 3 GB | 5 GB | 6GB |
1.2 量化不是”精度换体积”这么简单
现代量化(GGUF 的 GPTQ/AWQ 路线)不只是把浮点砍成整数,关键技术在三点:
- 按块缩放(Group Quantization):权重按小块(如 128 个一组)分别算缩放因子和零点的偏移,把信息损失控制在块内。
- 校准(Calibration):用一批代表数据(校准集)微调量化参数,让量化后的模型在”你实际会用到的数据分布”上损失最小。
- 混合精度:敏感层(通常是 attention 的 QKV 投影)保留更高精度。
对应用开发者来说,不需要自己写量化器——直接用 HuggingFace 上别人量化好的 GGUF 文件,或者用 llama.cpp / mlx 工具自己转。
二、量化等级实测对比
用一份统一的测试集(中文问答 + 代码生成 + 摘要),在同一个 7B 模型(以 Qwen2.5-7B-Instruct 为例)的不同量化等级下对比。以下数字为典型值,实际应在本机复测:
| 量化 | 文件大小 | 首 token 延迟(8GB) | 输出速度 | 中文问答质量 | 适用 |
|---|---|---|---|---|---|
| Q2_K | ~2.9 GB | 低 | 快 | 明显下降 | 不推荐 |
| Q4_K_M | ~4.4 GB | 低 | 快 | 可接受 | 内存小、日常用 |
| Q5_K_M | ~5.1 GB | 中 | 中 | 接近原始 | 质量优先 |
| Q8_0 | ~7.2 GB | 高 | 慢 | 几乎无损 | 显存够用 |
工程结论:
- Q4_K_M 是性价比甜点:质量损失在可接受范围内,显存要求低,速度最快。
- Q5_K_M 是质量优先选择:如果显存允许(12GB),值得多花 1GB 换质量。
- 不要用 Q2:语言质量崩塌,省的那点内存没有意义。
- 注意:量化主要影响”复杂度任务”的表现。ByteBot 的导览型任务(推荐文章、简单问答)对量化不敏感,Q4 完全够用;但让它写代码或做复杂推理会明显变差——所以本地兜底只承担降级导览,不强求全能。
2.1 实测方法
1 | # 用 llama-bench 量化前先测基线 |
更科学的做法是接进第 05 篇的评测集,把量化模型跑一遍 RAGAS——Faithfulness 下降幅度就是量化的真实代价。
三、推理引擎对比:Ollama vs vLLM
3.1 定位差异
| 维度 | Ollama | vLLM |
|---|---|---|
| 定位 | 本地一键部署,开发者友好 | 生产级推理服务器,面向高并发 |
| 底层 | llama.cpp | 自研 PagedAttention |
| 并发 | 串行为主(支持并发但有限) | 高并发 + 连续批处理 |
| 内存复用 | KV cache 固定 | PagedAttention 按页分配,碎片少 |
| 部署成本 | 极低,一条命令 | 较高,需 Python 环境 + GPU |
| OpenAI 兼容 API | 原生支持 | 原生支持 |
3.2 并发与吞吐的真相
本地推理的吞吐瓶颈在 prefill(处理输入)与 decode(逐 token 生成)的争抢。vLLM 的核心创新 PagedAttention 把 KV cache 切成固定大小页,支持连续批处理(Continuous Batching)——新请求不用等当前批次结束就能插入。这让 vLLM 在并发场景下的吞吐远超 Ollama/llama.cpp。
对 ByteBot 的实测建议:
- 单用户、低并发(博客场景):Ollama 足够。一次一个请求,Ollama 的优势(部署简单、内存占用可控)完胜。
- 多用户并发(比如评论系统接 AI、多 Agent 并行):vLLM。第 10 篇的多 Agent 流水线如果本地化,必须上 vLLM。
一个量化对比表(7B 模型,8GB 显存):
| 引擎 | 并发 1 时吞吐 | 并发 8 时吞吐 | 退化幅度 |
|---|---|---|---|
| Ollama (llama.cpp) | 22 tok/s | 9 tok/s | -59% |
| vLLM | 21 tok/s | 38 tok/s(批处理) | +81% |
(示例值,需本机复测。核心结论:Ollama 单并发不输,多并发被 vLLM 反超。)
四、本地模型接入 ByteBot 的降级链路
目标架构:
1 | POST /api/chat |
api/chat.js 里的实现思路:
1 | async function callWithFallback(outboundMessages, stream) { |
三个工程细节:
- 本地模型超时给足:本地 CPU/小显卡推理慢,30 秒可能不够,单独给 60 秒。
- 降级要打标:回答里或响应头加
x-llm-source: local,第 11 篇观测能统计”降级发生频率”,反哺到评估和成本。 - 本地兜底只跑导览任务:降级时 system prompt 应切到”最简导览模式”(去掉复杂指令),因为量化小模型吃不下长指令。
五、落地清单与小结
| 优先级 | 改造 | 收益 |
|---|---|---|
| P0 | 本机量化对比实验(Q4 vs Q5) | 明确本地模型质量边界 |
| P0 | Ollama 部署 + OpenAI 兼容 API | 本地链路就绪 |
| P1 | 降级链路接入 chat.js + 打标 | DeepSeek 挂时仍有 AI 回答 |
| P2 | vLLM 部署(并发场景才需要) | 多 Agent 本地化时用 |
| P2 | 量化模型跑 RAGAS 评测 | 量化代价有数据 |
| P3 | 模型路由:重任务仍走云端 | 质量与成本平衡 |
核心结论:
- 量化是本地推理的前提,Q4_K_M 是性价比甜点,Q5 质量优先;Q2 不要用。
- 量化对小模型的语言能力影响主要体现在复杂任务,导览型降级任务影响可控。
- 单并发用 Ollama,多并发用 vLLM;PagedAttention + 连续批处理让 vLLM 在并发场景吞吐反超。
- 本地兜底要有明确的职责边界(只做导览),且必须打标可观测。
- 降级链路分三层:云端 → 本地 → BM25,逐层兜底,可用性最大化。
下一篇进入编排层:LangGraph 源码剖析。我会深入 LangGraph 的状态图核心,逐行拆解节点执行、检查点持久化、流式执行原理,并演示一个”文章分析 Agent”工作流。
本系列持续更新中,每周一篇。