本地大模型栈总览与阅读路线

本地大模型栈总览与阅读路线

「本系列第 1/17 章」

本系列共十七章,编号从 00 到 16。它不是四个仓库各自再写一遍目录,而是按「训练 → 转换 → 推理 → 检索增强」把一条可在本机复现的本地大模型栈串起来。本章先画边界,再给出阅读顺序;从下一章起进入 GGML 0.15.3 的张量与计算图。

一条栈,四段职责

本地栈不要理解成「把 Hugging Face、llama.cpp、LlamaIndex 塞进同一个进程」。四段产物不同、进程不同、出了问题的排查入口也不同:

  1. 训练:LLaMA-Factory 0.9.6.dev0 在 Hugging Face 权重上做监督微调与偏好对齐,磁盘产物仍是 SafeTensors / PyTorch,不是 GGUF。
  2. 转换与量化convert_hf_to_gguf.py 把 HF 模型写成 GGUF;llama-quantize 再压到生产常用的 Q4_K_M。IQ 系列必须带 imatrix,否则质量会塌。
  3. 推理:llama.cpp 用 GGML 建图并在 CPU / CUDA / Metal / Vulkan 上执行;对外由 llama-server 提供 OpenAI 兼容 HTTP。
  4. RAG:LlamaIndex 0.14.23 不读 GGUF,也不管理 KV cache。它只用 OpenAILike / OpenAILikeEmbedding 打到 llama-server
HF 数据集与基座LLaMA-Factory 0.9.6.dev0convert_hf_to_ggufllama-quantizellama.cpp / llama-serverLlamaIndex 0.14.23

边界必须守住。LLaMA-Factory 不懂 GGUF 的 32 字节对齐,也不懂 vec_dot。GGML 不懂 chat template,也不决定采样策略。LlamaIndex 看不见量化 block,更不会去改 n_gpu_layers。日志里一旦同时出现「训练 loss」「GGUF magic」「retriever 空结果」,先判断卡在哪一段,再往下翻对应章节。

GGML 在栈中的位置

GGML 0.15.3 是 llama.cpp 的张量引擎,不是应用框架。库拆成三层链接:ggml-base 放张量、图、量化、GGUF、Backend 接口、调度器与分配器;ggml 负责 Backend 发现与注册;ggml-cpuggml-cudaggml-metalggml-vulkan 是各硬件实现。llama.cpp 的 libllama 同时链这三层。

每个 ggml_tensornenbtypeopsrc 描述,维度上限 GGML_MAX_DIMS=4nb 是字节 stride,因此 permute / view / transpose 可以不拷贝数据。ggml_mul_matggml_ropeggml_rms_norm 这类 API 只连边,不会立刻算矩阵。图要等 ggml_build_forward_expand 做拓扑排序并填 use_counts,再走三条执行路径之一:

路径 API 典型场景
纯 CPU ggml_graph_compute 示例与调试
单 Backend ggml_backend_graph_compute 单卡、单设备
多 Backend 调度 ggml_backend_sched_graph_compute_async llama.cpp 生产路径

权重容器是 GGUF:magic 为 GGUF,当前 version 为 3,默认 alignment 为 32。llama.cpp 用 gguf_init_from_fileno_alloc=true:先解析 KV 与张量元数据,再用 Backend buffer 承接 data,而不是让 Context 自己 malloc 整份权重。

推理热路径是 Q4 权重 × Q8 激活vec_dot,不是先反量化成 F32 再做通用 GEMM。生产量化优先 Q4_K_M。IQ 系列依赖 codebook,且 ggml_quantize_requires_imatrix 为真,没有校准矩阵就不要当成品。

内存分两套。Context 的 bump allocator 只管张量与图的元数据;真正的 data 由 gallocr 配合 dyn_tallocr 按拓扑分配。中间结果在 n_children==1ggml_op_can_inplace 时可以原地复用。标了 GGML_TENSOR_FLAG_OUTPUT 的张量永不覆盖,否则 logits 会在下一次 decode 里被写坏。

Backend 是五层 vtable。静态注册顺序是 CUDA → Metal → … → CPU 最后,CPU 作兜底。调度器对图做三遍切分,n_copies=4 用来做跨设备 pipeline。CUDA 按形状走 mmvq / mmq / cublas;macOS 默认开 Metal;Vulkan 用 shader-gen 生成各量化类型的 SPIR-V。构建时最常碰到的开关是 GGML_CUDAGGML_CPU_REPACKGGML_CUDA_FA

这些机制分别在第 2 到第 4 章展开。总览只要求你记住:算子 API 不计算,GGUF 只提供自描述权重,真正落地的是 Backend 与调度器。

训练侧停在 Hugging Face

LLaMA-Factory 0.9.6.dev0 默认走 v0:扁平 YAML 经 HfArgumentParser 变成 dataclass,再按 stage 选 workflow,最后落到 Hugging Face Trainer。它能做 SFT、DPO 一类对齐、导出 adapter 或合并后的 HF 权重,也能拉起自己的 chat / API / Board。那是另一条「HF 或 vLLM 推理」路径,不是本系列后续要接的 GGUF 路径。

要把训练结果送进 llama.cpp,必须承认一次格式断裂:HF 侧的 config.json、tokenizer 文件、SafeTensors 分片,与 GGUF 的 general.architecturetokenizer.ggml.tokens、按 blk.{i} 命名的张量,不是同一套元数据。转换桥负责翻译,而不是「改个后缀」。

转换桥:HF 写成 GGUF,再压到 Q4_K_M

1
2
python convert_hf_to_gguf.py /path/to/hf --outfile model-f16.gguf --outtype f16
llama-quantize model-f16.gguf model-q4_k_m.gguf Q4_K_M

第一行写出接近全精度的 GGUF,第二行用 ggml-quants.c 的参考实现做量化。量化工具不走 CUDA mmq,也不走 Metal shader。Q4_K_M 使用 K-quant 的 256 元素 super-block,体积与质量之间最稳,适合作为默认生产格式。若改 IQ,先用校准数据生成 imatrix,再交给 llama-quantize;否则 codebook 选点没有列重要性,生成会明显变差。

转换脚本还要写入架构 KV、词表和特殊 token。漏掉 bos / eos 或架构名写错,后面 llama.cpp 能打开文件,但建图会对不上层数或头数。分片 GGUF 用 split.count / split.no 描述,加载器会合成一张权重表。

推理侧:llama.cpp 建图,llama-server 对外

llama.cpp 读 GGUF,按架构建 ggml_mul_mat / ggml_rope / ggml_flash_attn_ext 等节点,管理 KV cache 与采样,经 ggml_backend_sched_graph_compute_async 执行。llama-server 把同一套能力暴露为 /v1/chat/completions/v1/embeddings。上下文长度、GPU offload、并发 slot、chat template 都在这个进程里,不在 RAG 框架里。

因此「模型很慢」首先看 Backend 是否真的注册到 CUDA / Metal,以及调度器有没有把 MUL_MAT 切到 GPU;「接口 404」才去看 server 路由。不要在 LlamaIndex 里找 ggml_type

应用侧:LlamaIndex 只认 HTTP

LlamaIndex 0.14.23 的规范接法是进程外 HTTP:生成模型一个 llama-server,embedding 模型另一个,LlamaIndex 用 OpenAILikeOpenAILikeEmbedding 访问。它负责切分文档、建索引、检索与响应合成。GGUF 路径、量化类型、n_copies 对它不可见。

不要把进程内的 LlamaCPP 绑定与这条 OpenAILike 路径混配。前者把推理塞进 Python 进程,后者把推理留给 C++ server。本系列后续只沿 HTTP 这条线讲 RAG,以免配置项对不上。

十七章怎么读

按依赖读,不要跳过 GGML 三章直接抄 server 命令。编号 00 到 16 对应阅读顺序:

编号 主题 读完应能回答
00 本栈总览 四段职责如何切开
01 GGML 张量与惰性图 为何 mul_mat 当时不算数
02 内存、量化、GGUF 权重如何进 buffer,Q4×Q8 如何算
03 Backend 与调度 图如何切到 CUDA / Metal / CPU
04 llama.cpp 加载与建图 GGUF 如何变成可执行图
05 Decode 与 KV Cache 逐 token 如何复用图
06 Batch 与采样 连续批处理停在哪一层
07 llama-server OpenAI 兼容 HTTP 如何落地
08 LLaMA-Factory 入口与配置 v0 训练如何启动
09 数据、模板与模型 样本如何变成 HF batch
10 训练与对齐流水线 SFT / 偏好阶段如何走
11 导出与转换桥 HF 如何变成 Q4_K_M
12 LlamaIndex 架构 Document 如何变成 Node
13 索引、检索与合成 查询如何拼出 prompt
14 OpenAILike 对接 如何接到 llama-server
15 端到端联调 训练到问答的检查点
16 性能、硬件与排错 如何选 Backend、看峰值

建议先读 00 到 03,把「惰性图 + 量化权重 + 可插拔 Backend」变成默认心智模型;再读 04 到 07,看 llama.cpp 如何把图变成服务;然后 08 到 11 把训练产物接进 GGUF;最后 12 到 16 做成可查询系统。

后文只写源码里能对上的 API 与常量,不编造一层「更友好」的封装。遇到「这个函数会立刻算出结果」的直觉,先回到张量与计算图那一章。遇到 OOM 或 logits 被覆盖,先回到内存分配与 OUTPUT 标志。遇到「明明编译了 CUDA 却在 CPU 上算」,先回到注册顺序与三遍调度。

读系列时要带着的三张检查表

第一张表问数据格式。训练完成时磁盘上应是 HF 目录。转换完成后应能用文件头四个字节 GGUF 认出容器,version 为 3。量化完成后 general.file_type 应指向 Q4_K_M 或你明确选择的类型;若是 IQ,旁边必须有 imatrix 来源。RAG 联调时,LlamaIndex 进程里不应出现 GGUF 路径,只应出现 http://127.0.0.1:8080 这类 base URL。

第二张表问进程边界。LLaMA-Factory 的 Trainer、convert_hf_to_gguf 的 Python 解释器、llama-quantize 的 C++ 工具、llama-server、LlamaIndex 应用,默认是五个进程、五份日志。把它们焊进一个 notebook 单元格,出了错无法判断是建图失败还是检索为空。本系列允许你在同一台机器上跑完全流程,但不鼓励把五段合成一个「一键脚本」再去调试。

第三张表问计算发生的位置。训练算力在 PyTorch。量化算力在 ggml-quants.c 参考实现,通常是 CPU。推理算力在 GGML Backend:CPU 的 vec_dot、CUDA 的 mmvq/mmq/cublas、macOS 的 Metal、跨平台的 Vulkan shader。RAG 侧几乎不占模型算力,它只拼 prompt、打 HTTP、写向量库。显存被占满时,先看 llama-server 而不是 LlamaIndex。

把三张表当作阅读锚点,十七章就不会读成互不相干的手册。你随时可以停下来问:此刻改的是格式、进程,还是计算位置?答案会直接指向后面某一章,而不是让你回到七十篇旧笔记里翻文件名。

下一章进入 GGML 的张量模型、计算图与惰性执行。

文章互动

阅读 --

留言

0 条留言

正在加载留言…