让大模型在本地持续进化:YoungAi 如何用 Sidecar 和后训练重新思考本地 AI
项目地址: github.com/fodelf/Youn...
当我们讨论本地部署大模型时,大多数人的关注点都集中在三个问题上:
- 模型能不能装进本地内存?
- 推理速度能不能满足实际需求?
- 部署成本能不能接受?
这些问题当然重要。但如果本地部署的终点只是让模型在自己的机器上运行,那么我们可能忽略了更值得探索的方向。
模型部署完成之后,能不能继续利用自己的业务数据改进模型?
例如,一个企业内部的代码 Agent,每天都会接触新的代码、评审意见和执行反馈。如果每次能力调整都需要重新训练、量化并部署整个模型,迭代成本就会很高。
如果业务数据又不能随意上传到外部服务,那么模型应该如何持续适应真实业务?
这正是我开发 YoungAi 时希望探索的问题。
YoungAi 是一个面向 DeepSeek V4.1 Flash 的原生 C/CUDA 本地推理引擎和离线优化工具链。它不仅尝试解决大模型在有限内存中的部署问题,还进一步探索了领域 Sidecar 和独立后训练文件的实现方式。
本文不准备简单罗列项目功能,而是从几个核心设计问题出发,解释为什么采用这套架构、底层实现有哪些技术取舍,以及目前还存在哪些挑战。
一、为什么把大模型部署到本地,还只是第一步?
先看模型本身。
根据项目文档,YoungAi 面向的 DeepSeek V4.1 Flash 原始权重规模约为 510GB,而目标设备 NVIDIA DGX Spark 只有 128GB 统一内存。
原始模型无法直接完整装入这块内存,因此必须对权重进行压缩。
最直接的方式是量化:用更紧凑的数值表示权重,减少模型占用的存储空间。
但量化解决的是模型的存储问题,并不自动解决业务能力问题。
1. 模型能运行,不等于模型适合业务
假设我们需要将一个通用大模型用于企业内部的代码分析。
原始模型能够理解代码,但量化之后,它在部分输入上的预测可能发生变化。
这属于量化误差。
另一方面,即使完全恢复原始模型的输出,它也不一定能正确处理企业内部的特殊规范、工作流程或业务约束。
这属于模型本身的能力边界。
两者需要不同的解决方案:
- 对于量化误差,需要改进权重表示、校准方式或误差修正方法。
- 对于业务能力不足,需要研究领域适配、后训练以及更完整的业务反馈机制。
如果把这两个问题混在一起,就容易走向一个成本很高的方案:每次需要适应新的领域,就重新调整甚至重建整套模型。
YoungAi 选择了一条不同的路线:尽可能保持通用基座稳定,将领域适配和后续更新拆分成独立的参数制品。
2. 为什么不直接使用领域数据校准整个模型?
一种直观的方法是,使用金融语料校准金融模型,使用代码语料校准代码模型。
但这样做可能使通用基座的量化结果受到特定领域数据的影响。
YoungAi 的实验记录显示,在特定金融测试设置中,使用金融语料加权校准没有改善对应测试指标,通用文本指标反而下降了约 2.4 个百分点。
这并不意味着领域校准在所有场景中都无效,而是说明:在这个项目的实验条件下,把领域数据直接用于基座量化,并没有得到预期收益。
因此,YoungAi 将问题拆分成两个独立目标:
- 通用基座尽可能保留原始模型的行为。
- 特定领域需要的修正,由独立的 Sidecar 完成。
这就是整个架构的第一个关键选择。
二、为什么选择 Sidecar,而不是每个领域部署一套完整模型?
Sidecar 可以理解为附加在主模型旁边的独立参数文件。
在 YoungAi 中,它并不是另一套完整的大模型,而是通过特定的参数修正机制,对已有模型的计算结果进行调整。
整体架构可以简化为:
yaml
离线构建
|
+---------+---------+
| |
模型权重 领域数据
| |
v v
权重量化 参数求解
| |
v v
通用量化基座 Domain Sidecar
约 113.6 GB 约 40 MB
| |
+---------+---------+
|
v
本地推理引擎
|
v
业务请求
这里的模型与 Sidecar 体积来自项目文档记录,实际结果取决于具体模型、配置和构建版本。
1. Sidecar 修改的是已有专家的计算结果
DeepSeek V4.1 Flash 使用混合专家架构,也就是 MoE。
在这种架构中,模型会根据输入选择部分专家参与计算。
可以用下面的简化表达理解某个专家的计算:
专家输出 = 专家权重 × 输入
YoungAi 的 Sidecar 可以通过逐通道乘性增益,调整已有专家的输出。
用伪代码表达就是:
ini
for (int i = 0; i < hidden_size; i++) {
output[i] = gain[i] * expert_output[i];
}
这段代码只是解释计算方式的示意,不是仓库中对应函数的原样摘录。
这里有三个重要概念:
expert_output:原有专家产生的输出。gain:侧车提供的逐通道增益。output:经过增益修正后的结果。
除此之外,Sidecar 还可以调整路由器的专家选择分数,让模型在特定领域的输入上更接近原始模型的路由行为。
因此,Sidecar 并不是重新构建一套模型,而是在已有计算路径上增加轻量级的修正。
2. 为什么选择乘性修正?
对于一个已经产生的向量,最直观的修正方式是直接增加一个偏移量:
修正输出 = 原始输出 + 偏移量
但偏移量本身不一定能够适应不同输入产生的不同激活结果。
YoungAi 的实验记录中,低秩加性修正在部分局部测试中有所改善,但端到端结果并不理想。
因此,项目转向了逐专家的乘性增益和路由偏置。
乘性修正可以理解为:
css
修正输出[i] = 原始输出[i] * 增益[i]
这种方式直接作用于已有专家输出,而不是单独构造一个额外的输出向量。
需要强调的是,这不意味着乘性修正在所有模型上都优于 LoRA。它是 YoungAi 根据当前模型结构和实验结果作出的技术选择。
3. 一个很小的 Sidecar,能带来什么变化?
项目记录了多个领域的量化保真度测试:
| 领域 | 基座 Top-1 一致率 | 加入 Sidecar 后 |
|---|---|---|
| 编程 | 78.61% | 82.26% |
| 法律 | 72.90% | 76.36% |
| 医疗 | 69.08% | 72.82% |
| 科研 | 71.65% | 74.93% |
这些数据衡量的是量化模型与原始模型在测试位置上是否选择相同的最高概率 Token。
它们不是代码正确率、医疗诊断准确率,也不是金融预测准确率。
因此,这组结果可以支持一个相对明确的结论:在项目测试条件下,小型 Sidecar 能够改善量化模型对原始模型输出的保真度。
它不能直接证明模型在所有真实业务中都变得更准确。
但对于本地推理引擎来说,这依然是值得探索的方向:恢复部分模型行为,不一定只能通过增加整套模型的权重存储量来完成。
三、为什么本地部署的长期价值,在于后训练?
这是我认为 YoungAi 最值得关注的部分。
Sidecar 主要解决领域适配问题,而后训练文件进一步探索的是:模型部署之后,如何根据新的业务反馈进行更新。
1. 企业需要的不是一个永远不变的模型
假设企业已经部署了一个本地 Agent。
它每天都会接触新的请求、人工审核意见、执行结果和业务反馈。
如果每次能力调整都需要重新训练、量化并部署整个模型,迭代成本会非常高。
如果模型永远不更新,它又无法充分利用这些真实业务反馈。
如果业务数据不能离开本地环境,传统依赖外部训练服务的工作流也可能不符合要求。
于是,一个值得探索的方案出现了:
yaml
本地业务请求
|
v
本地模型推理
|
v
收集经过审核的反馈
|
v
本地后训练求解
|
v
生成新的参数文件
|
v
独立评估与回归测试
|
v
通过验证后切换版本
这条链路的意义在于,业务反馈可以进入模型的迭代流程,而不必每次都重建整个模型制品。
当然,模型是否真正变好,需要独立测试来证明,而不能仅凭参数文件成功生成就下结论。
2. YoungAi 的后训练实现了什么?
可以从项目的 ds4_posttrain.c 开始阅读:
该文件包含与权重行缩放相关的计算逻辑。
为了理解它的作用,我们先看一个简化问题。
假设有一行权重,需要用更简单的符号表示来近似原始权重。
原始权重中的每个元素记为 w[i],符号量化后的值记为 b[i]:
css
b[i] = w[i] < 0 ? -1 : 1;
原始权重可以包含不同大小的数值,而符号表示只保留正负方向。
因此,我们还需要一个缩放系数,让量化后的权重输出尽可能接近原始输出。
对于一组输入激活,可以定义:
原始输出 = 原始权重与输入激活的点积
量化输出 = 符号权重与输入激活的点积
目标是找到一个合适的缩放系数,使量化输出与原始输出之间的平方误差尽可能小。
对应的核心优化问题可以写成:
markdown
最小化:
所有样本的 (原始输出 - 缩放系数 × 量化输出)^2 之和
当分母不为零时,对这个单变量最小二乘问题求解,就可以得到对应的最优缩放系数。
从工程角度看,这个计算并不复杂。真正重要的是,它直接围绕项目采用的权重表示方式进行优化,而不是把所有问题都交给一个通用训练框架。
需要注意,行级缩放函数只是后训练相关计算的一部分。完整的后训练流程还涉及参数求解、文件生成、依赖关系和效果评估,不能把一个缩放函数等同于完整的持续学习系统。
3. 为什么把后训练结果保存成独立文件?
因为更新参数与重建模型是两种不同的工程操作。
如果所有参数都保存在同一个模型文件中,那么一次小范围更新也可能导致整个模型制品需要重新生成、分发和验证。
如果后训练结果独立保存,就可以采用更灵活的版本管理方式:
lua
base.gguf
|
+-- domain_sidecar/
| |
| +-- 当前领域参数
|
+-- posttrain/
|
+-- 后训练版本 A
+-- 后训练版本 B
+-- 后训练版本 C
这里展示的是概念结构,不代表仓库规定必须采用这样的实际目录。
独立文件可以带来几个好处:
- 后训练更新不必直接覆盖基座。
- 新版本可以先验证,再决定是否启用。
- 发现效果退化时,可以回滚到之前的版本。
- 不同领域的参数可以独立管理。
项目还为后训练文件记录了所依赖的 Sidecar 指纹。如果依赖关系不匹配,引擎会拒绝加载。
这是一项重要的工程约束。
后训练参数并不是可以随意组合的通用文件。它们是在特定模型和参数配置下产生的,必须确保依赖关系正确。
4. 本地后训练为什么比单纯本地推理更值得关注?
本地推理让数据可以在自己的计算环境中处理。
本地后训练则进一步探索:能否让这些经过筛选的业务反馈参与模型更新。
例如:
- 代码 Agent 可以利用内部代码评审反馈。
- 企业工作流可以利用人工审核结果调整某些输出倾向。
- 本地分析系统可以利用经过确认的业务错误生成候选参数文件。
但这里有一个重要边界:
本地后训练不等于模型必然越用越好。
如果反馈数据存在偏差,参数更新可能让模型在某个测试集上变好,却在其他任务上退化。
因此,后训练流程必须包含独立评估、版本管理和回滚机制。
本地部署也不自动等于数据安全。日志、缓存、文件权限和备份仍然需要单独管理。
四、如何把模型压缩到 113.6GB?关键在于向量量化
接下来回到底层实现。
YoungAi 针对 MoE 专家权重采用了八维向量量化,也就是 Vector Quantization,简称 VQ。
它与简单地把每个权重独立映射为低位宽数值有所不同。
1. 从单个权重转向一组权重
假设连续八个权重组成一个向量:
ini
w = [w1, w2, w3, w4, w5, w6, w7, w8]
向量量化会从一个共享码本中选择最合适的八维码字。
yaml
原始权重向量
|
v
寻找最接近的码本向量
|
v
保存码本索引
|
v
结合缩放系数还原近似权重
因此,存储时不必独立保存八个完整权重,而是保存一个索引,再通过共享码本和缩放参数恢复近似表示。
这种设计可以大幅降低专家权重的存储成本,但实际效果取决于码本质量、权重分布和额外参数开销。
2. 为什么使用 12 bit 和 13 bit 两种索引?
根据项目文档,码本采用两种配置:
- 12 bit 索引,对应 4096 个码字。
- 13 bit 索引,对应 8192 个码字。
每个索引对应八个权重,因此索引本身的平均存储开销为:
ini
12 / 8 = 1.5 bit/weight
13 / 8 = 1.625 bit/weight
注意,这里只计算码本索引,不包含行级增益和其他辅助数据。
因此,不能把它直接理解为整个模型的平均位宽。
YoungAi 的设计并不是让所有权重都采用完全相同的格式,而是根据不同部分的特点选择合适的表示方式。
3. 为什么同一层的专家要共享码本?
MoE 模型包含大量专家。
如果每个专家都拥有自己的码本,那么码本本身就会产生大量重复存储。
YoungAi 在实验中采用了同一层多个专家共享码本的策略。
根据项目记录,这种设计省去了 15,744 份码本,减少约 3.09GB 的存储开销。
节省出来的空间还可以用于提升部分层的量化精度。
例如,项目将最浅的 14 层从 12 bit 提升到 13 bit,并记录了相关量化误差约 16.1% 的下降。
这背后的工程思想是:
不要只盯着某一个权重需要多少位,而要从整个模型的存储结构出发,减少重复开销,再将资源分配给更重要的部分。
当然,这些结论来自项目特定模型和测试条件,并不意味着所有 MoE 模型都应该采用完全相同的码本共享策略。
五、为什么量化格式必须和 CUDA Kernel 一起设计?
模型压缩到内存能够容纳的规模,只解决了部署的第一步。
实际推理速度还取决于权重如何被读取、解码和参与计算。
尤其是在逐 Token 解码阶段,GPU 每生成一个新 Token,都需要执行大量计算,并读取相关权重。
如果内存带宽成为瓶颈,即使计算单元还有余量,推理速度也不一定能够继续提升。
1. 解码阶段的内存带宽问题
假设某个解码步骤需要读取约 6GB 数据,实际有效内存带宽为 235GB/s。
仅从数据搬运估算,理想情况下的时间下界约为:
bash
6 GB / 235 GB/s ≈ 25.5 ms
这只是简化估算,不代表完整的端到端延迟。
真实执行还会受到计算、同步、调度和其他内存访问的影响。
因此,推理性能优化不仅是提高算力,还需要减少不必要的数据搬运,并让压缩格式适合硬件的访问方式。
2. 为什么需要专门的量化内核?
通用矩阵计算路径不一定能够充分利用自定义量化格式。
例如,VQ 权重需要先读取码本索引,再恢复相应的权重表示。如果这一过程产生大量额外的数据搬运,量化节省下来的空间就不一定能够转化为速度优势。
YoungAi 针对量化权重设计了专门的 CUDA 执行路径,涉及码本读取、索引解码、专家计算和不同执行阶段的优化。
此外,Prefill 与 Decode 的计算特点不同:
- Prefill 一次处理多个输入 Token,更适合批量矩阵计算。
- Decode 则反复生成单个 Token,更容易受到内存带宽和调度开销的影响。
因此,不能假设一种内核在所有执行阶段都拥有相同的效率。
3. CUDA Graph 与投机解码
除了内核本身,YoungAi 还针对推理流程进行优化。
CUDA Graph 可以将一组 GPU 操作捕获为可重复执行的计算图,减少重复提交操作的主机端开销。
投机解码则让草稿模型先提出多个候选 Token,再由主模型验证。
其基本流程是:
yaml
草稿模型生成候选
|
v
主模型批量验证
|
v
接受符合验证规则的候选
|
v
继续生成下一个 Token
在实现正确的前提下,投机解码可以减少主模型逐 Token 执行的次数,同时保持目标模型要求的输出行为。
YoungAi 的项目记录包含相关的贪心与采样投机解码实验。评估这类优化时,除了速度,还需要验证输出正确性。
根据仓库记录,项目在 NVIDIA DGX Spark 上取得过以下性能:
| 测试场景 | 项目记录的性能 |
|---|---|
| 12.5k Token 提示的 Prefill | 1,055 Token/s |
| 14.1k Token 的真实 Agent 请求 Prefill | 940 Token/s |
| 短上下文普通贪心解码 | 约 30.7 Token/s |
| 真实 Agent 请求投机解码 | 约 43 Token/s |
| 未用于调参的请求投机解码 | 约 40 Token/s |
这些数字是项目特定测试条件下的结果,不应直接视为其他硬件上的性能承诺。
六、如何判断模型优化真的有效?
对于量化推理引擎,能够启动、能够生成文本、能够跑出较高的 Token/s,并不足以证明模型优化成功。
至少需要分别评估三个问题:
- 系统是否能够稳定运行?
- 量化模型与原始模型的行为差异有多大?
- 模型在目标业务中是否真正有用?
这三个问题需要不同的评估方法。
1. Top-1 一致率的局限
Top-1 一致率衡量的是原始模型与量化模型在相同位置上,是否选择了相同的最高概率 Token。
但两个模型即使选择相同的 Token,其完整概率分布也可能有明显差异。
例如:
ini
原始模型:
A = 0.51
B = 0.48
C = 0.01
量化模型:
A = 0.90
B = 0.05
C = 0.05
两者都会选择 A,但它们对其他候选的判断并不相同。
因此,Top-1 一致率只能描述部分行为保真度。
2. 概率分布重叠度
为了进一步比较原始模型与量化模型的输出分布,可以使用概率重叠度。
用普通文字描述,它的计算方式是:
对词表中的每个 Token:
取原始模型概率与量化模型概率中的较小值
最后将所有 Token 的较小概率相加
该指标介于 0 和 1 之间,数值越高,表示两个概率分布的重叠程度越高。
项目还使用 KL 散度等指标评估模型输出分布的差异。
这些指标可以帮助判断量化误差是否得到改善,但仍然不能代替真实业务评估。
3. 为什么后训练必须使用独立留出集?
假设一个后训练求解器能够将某个训练样本上的错误决策修正过来。
这只能说明它对该样本产生了预期影响,并不能说明它对新的业务请求也有效。
因此,需要将用于生成参数的数据与用于评估的数据分开。
对于真实业务,还应考虑:
- 新请求与训练样本之间的差异。
- 不同时间段的数据分布变化。
- 后训练对其他任务的影响。
- 模型更新前后的回归结果。
YoungAi 的项目记录明确指出,后训练机制已经跑通,但跨交易日泛化仍然是待解决的问题。
这意味着,当前成果主要证明了相关参数更新机制的可行性,还不能将其视为已经实现稳定的持续学习。
七、YoungAi 目前还面临哪些挑战?
我认为,一个技术项目真正值得讨论的,不仅是它已经做到了什么,还包括它没有解决什么。
1. 局部修正不等于完整任务能力提升
如果只修正某个位置的 Token 决策,后续生成仍然可能受到上下文影响,重新回到原来的判断。
因此,局部决策修正不能直接等同于完整推理链的改善。
要证明后训练有效,还需要在完整业务任务上进行评估。
2. 金融场景尤其需要谨慎
YoungAi 使用交易 Agent 流水线进行了实验,也记录了部分不理想的市场判断结果。
这些记录说明,即使模型能够在本地运行、量化保真度得到改善、特定决策可以被修正,也不能由此推导出它已经具备可靠的金融预测能力。
金融任务仍然需要独立的时间外验证、基线比较、风险控制和人工复核。
3. 本地后训练仍然需要完整的工程闭环
如果要将这套机制用于生产环境,还需要回答更多问题:
- 如何筛选可信的业务反馈?
- 如何避免错误标签和异常数据污染更新?
- 如何识别后训练导致的能力退化?
- 如何验证新版本在其他领域的表现?
- 如何安全地管理参数文件、日志和业务数据?
这些问题并不会因为模型部署在本地而自动消失。
相反,它们是本地 AI 系统从实验走向生产必须解决的问题。
八、如何阅读 YoungAi 的源码?
项目地址:
建议从以下文件开始:
| 文件 | 阅读重点 |
|---|---|
| README.zh-CN.md | 项目架构、部署要求和实验结果 |
| ds4_posttrain.c | 后训练相关的行级缩放与量化计算 |
| ds4_zchain.c | 领域侧车相关实现 |
| ds4_cuda.cu | CUDA 后端与 GPU 计算路径 |
| vq_fmt.h | 向量量化格式定义 |
项目的完整验证环境以 NVIDIA DGX Spark 为主,涉及 GB10 芯片、128GB 统一内存和 CUDA 运行环境。
如果准备运行,应以仓库当前版本的安装文档为准,确认硬件、依赖、驱动和模型文件符合要求。
九、总结:本地 AI 的下一步,是让模型能够持续适应业务
YoungAi 的设计可以归纳为三个层次。
第一层:量化基座。
通过向量量化、码本共享和专用 CUDA 计算路径,解决大模型在有限内存中的部署问题。
第二层:领域 Sidecar。
通过独立的领域参数文件,探索如何以较小的存储成本改善量化模型在特定领域中的输出保真度。
第三层:后训练文件。
通过独立的参数更新、验证和回滚机制,探索如何根据本地业务反馈修正模型行为,而不必每次都重新部署整套模型。
这三个层次解决的是不同的问题。
量化让模型能够运行,Sidecar 让领域适配更轻量,而后训练为模型上线后的持续改进提供了一条可以继续探索的工程路径。
目前,这套方案仍然需要在更广泛的业务任务中验证其泛化能力。尤其是局部决策修正能否稳定改善完整任务,以及连续更新是否会造成其他能力退化,都需要进一步研究。
但我认为,这个方向值得继续投入。
本地部署不应该只是把云端模型搬到自己的机器上,而应该让模型、业务数据和迭代流程在一个可控的环境中协同工作。
当模型已经能够在本地运行之后,下一个值得解决的问题,就是如何让它根据真实业务持续改进,同时保留可验证、可回滚和可维护的工程边界。
这也是 YoungAi 正在探索的方向。
项目地址:
欢迎交流,也欢迎直接阅读源码、复现实验,并提出建议。