部署模型推理
安装huggingface_hub:
py -m pip install huggingface_hub
我们用hf下载 量化版本:FP16 -> JQ4(4-bit) 这个是社区重打包的,完全公开。
但下面这些情况需要hugging face token:
- 门控模型(gated model),比如原始的 google/gemma-2-2b-it 需要去 huggingface 点一下同意协议
- 私有模型、上传操作
hf download tjake/gemma-2-2b-it-JQ4 --local-dir D:\huggingface\gemma-2-2b-it-JQ4
量化版大小约2GB,是原始版1/3
本地springboot web,加jlama-core、jlama-native就可以把这个模型跑起来,其他配置:
jlama:
model:
# 已下载的 JQ4 量化模型路径
path: D:\huggingface\gemma-2-2b-it-JQ4
generation:
temperature: 0.3
max-tokens: 512
上下文记忆用内存里的Map,测试了一下基本能用,说实话 2B 参数就这么大,能正确记住上下文已经算及格了,偶尔兜不住是正常的。
实践心得总结
本地模型就是"聪明胶水"
上游确定性输出(订单号、用户意图、检索结果)
↓
本地小模型 ← 系统提示词 + RAG 上下文 + Tool Schema
↓
结构化输出 / 工具调用 / 最终回复
一般不用做开放式闲聊,而是做这些事:
- 意图识别、实体抽取、情感判断
- 把 RAG 召回的多段文本提炼成一个答案
- 根据语境选合适的工具并填参数
- 格式化输出(JSON、特定话术)
这类任务对模型不需要强创造力,需要的是指令遵循 + 格式稳定 + 低延迟。
不同量级模型的定位
┌───────────────────┬───────────────┬────────────────────────────────────────────┐
│ 参数量 │ 角色 │ 典型场景 │
├───────────────────┼───────────────┼────────────────────────────────────────────┤
│ 1B-3B(现在的) │ 胶水 / 筛选器 │ 单步分类、简单抽取、边缘端,不太稳 │
├───────────────────┼───────────────┼────────────────────────────────────────────┤
│ 7B-14B │ 本地主力 │ 意图路由、RAG 合成、Tool Calling,够用且快 │
├───────────────────┼───────────────┼────────────────────────────────────────────┤
│ 30B-70B │ 本地天花板 │ 复杂推理、多步 Agent,能打但吃显存 │
├───────────────────┼───────────────┼────────────────────────────────────────────┤
│ 70B-400B+ │ 云端满血 │ 全开放对话、深度推理、代码生成 │
└───────────────────┴───────────────┴────────────────────────────────────────────┘
本地部署的甜点在 7B-14B,日常"胶水"任务完全胜任,普通机器跑得动。
满血模型
云端闭源的都不公开参数了(Claude、GPT-5),开源的几个大玩家:
┌─────────────────┬──────┬────────────────┐
│ 模型 │ 参数 │ 架构 │
├─────────────────┼──────┼────────────────┤
│ DeepSeek-V3 │ 671B │ MoE,激活 ~37B │
├─────────────────┼──────┼────────────────┤
│ Llama 4 │ 405B │ Dense │
├─────────────────┼──────┼────────────────┤
│ Qwen 3 │ 235B │ MoE │
├─────────────────┼──────┼────────────────┤
│ Mistral Large 2 │ 123B │ Dense │
└─────────────────┴──────┴────────────────┘
所以 Gemma 2B 跑通链路没问题,但真要当"胶水"用,上个 7B 的模型体验会好很多(比如 Qwen2.5-7B-Instruct 对中文友好,JLama 也支持)。本地部署 7B 量化版大概 4-5GB 。
笔者的笔记本电脑配置比较低,开了jlama-native加速的情况下,一次chat也要10几秒,所以就只用了2B的模型。
下载下来的LLM文件说明
目录结构
gemma-2-2b-it-JQ4/
├── config.json # 模型架构定义
├── model.safetensors # 模型权重(JQ4 量化)
├── tokenizer.json # 分词器词表
├── tokenizer_config.json # 分词器配置
├── .gitattributes # Git LFS 元数据
├── README.md # 模型说明
└── .cache/ # huggingface-hub 下载缓存
config.json — 模型架构
{
"model_type": "gemma2", // JLama 靠这个字段决定用什么 Java 类加载
"hidden_size": 2304, // 隐藏层维度
"num_hidden_layers": 26, // Transformer 层数 → 2B 参数的来源
"num_attention_heads": 8, // 注意力头数
"num_key_value_heads": 4, // KV 头数(GQA 分组查询)
"vocab_size": 256000, // 词表大小
"torch_dtype": "bfloat16", // 原始精度(注:实际已被 JQ4 量化覆盖)
...
}
JLama 的 ModelSupport.loadModel() 就是读这个 json 判断走 Gemma2Model 还是 LlamaModel。
model.safetensors — 权重文件(2.3GB)
- SafeTensors 格式:比 pickle 安全,不含可执行代码,直接 mmap 加载
- JQ4 量化:原始 BF16(~5GB)被压缩到 Q4(4-bit),体积减半,精度损失很小
- 加载时 JLama 按需反量化到 F32 计算
tokenizer.json — 词表(16.7MB)
把文本切成 token 的映射表。256000 个 token,每个 token 有 id 和对应的字符串。比如"你好"可能被切成[token_12345, token_67890]。
tokenizer_config.json — 分词器配置
特殊 token 的定义:
{
"bos_token": "<bos>", // 序列开头
"eos_token": "<end_of_turn>", // 轮次结束
"chat_template": "..." // 对话格式模板
}
其中 chat_template 就是拼 <start_of_turn>user\n...<end_of_turn>\n<start_of_turn>model\n...<end_of_turn> 的规则,JLama 的 promptSupport().builder() 自动按这个模板格式化。
.cache/ — 下载缓存
huggingface-hub 的内部缓存,删掉无所谓,不影响模型使用。
model.safetensors 权重文件 = 智能的载体
文件里存储的是 26 层 Transformer 的全部参数,每层包含:
Layer_i:
├── Self-Attention 权重(Q、K、V 投影矩阵 + 输出投影)
├── MLP 权重(两个全连接层,9216 → 2304 → 9216)
└── RMSNorm 参数
加上词嵌入表(256000 × 2304)、输出投影、位置编码等。总共 ~2B 个浮点数,每个数字都是在海量语料上训练出来的结果。知识不是存在某个地方,而是分布在这些数字之间的数学关系里。
推理过程 = Transformer Decoder
就是典型的 自回归 Transformer Decoder 推理:
输入 "你好"
→ tokenizer → [token_123, token_456]
→ Embedding → 两个 2304 维向量
→ Layer 1:
Self-Attention: 当前位置对前文加权(Masked,只看左边)
MLP: 非线性变换
→ 输出 2304 维向量
→ Layer 2...26(同上)
→ LM Head: 2304 维向量 → 256000 维(词表大小)
→ Softmax → 概率分布
→ 采样 → 下一个 token "!"
→ 拼回去 "你好!" → 继续循环直到 <end_of_turn>
我们常所说的"矩阵运算"就是每一层里 Q×K^T、Softmax × V、全连接层的 W×x + b 这些。JLama 做的就是连续 26 层的矩阵乘法和激活函数运算,参数来自 model.safetensors,一次跑出一个 token,每次拼回输入继续跑,直到生出完整回复。