全栈串联:训练、GGUF、推理服务与 RAG
「本系列第 16/17 章」,也是最后一章。请先通读第 00–15 章:00–11 分别对应 LLaMA Factory、llama.cpp / GGML 与本地服务细节,12–15 对应 LlamaIndex
0.14.23的骨架、摄取、合成与 Agent。本章只做串联,不发明新 API,也不把某一段的默认值说成全栈唯一标准。命令能跑,仍然要以 00–15 章核对过的对象边界为准,不要在串联时“顺便”改回旧接口。
1. 为什么要先读 00–15
全栈最常见的失败不是“哪一条命令敲错”,而是把四个系统的职责叠在一起。Factory 负责权重怎么训、怎么导出成 HuggingFace 目录;llama.cpp 负责把目录变成 GGUF、量化、用 llama-server 提供 OpenAI 兼容 HTTP;LlamaIndex 负责文档怎么切、怎么检索、怎么合成。GGML 是推理后端的张量与量化基础,应用代码通常碰不到它,但你要理解:量化发生在 C++ 工具里,不发生在 Settings.llm 里。
第 00–11 章已经用各自仓库的真实入口说明了这些边界,例如 Factory 的 llamafactory-cli train / export、llama.cpp 的 convert_hf_to_gguf.py、llama-quantize、llama-server。第 12–15 章则固定了 0.14.23 里不能再靠印象拼的事实:元包只带 core、OpenAI 与 nltk;Document(Node(BaseNode));Settings 是模块单例;ServiceContext 直接抛错;两条摄取路径不要叠用;UPSERTS 是 Pipeline 默认策略;stores_text 决定拓扑;ChatMode.REACT / OPENAI 已删除;记忆用 Memory.from_defaults;图用 PropertyGraphIndex;本地只走 OpenAILike / OpenAILikeEmbedding。本章把它们按一次落地的顺序接起来。
若某一跳报错,回到对应章节核对,而不是在全栈脚本上继续打补丁。训练导出对不上,查 Factory;GGUF 架构不支持,查转换脚本;HTTP 404 或模板回显,查 server 与 is_chat_model;检索来源不对,查摄取与 stores_text;答案慢,先数合成的 K 和对话是否改写追问。
2. 一条可以照着敲的路径
目标:用 Factory 做 LoRA SFT 并导出 HuggingFace 目录,转成 GGUF、量化,用两个 llama-server 分别提供 chat 与 embedding,再让 LlamaIndex 持久化索引并查询。路径里的示例文件名来自本系列已经核对过的 Factory / llama.cpp 章节,本机目录按实际替换。
1 | # 1) SFT(在 LLaMA Factory 仓库根目录) |
先 curl http://127.0.0.1:8080/v1/models 与 :8081/v1/models,确认模型 ID 再写入客户端。chat 与 embedding 必须分进程:一个权重既做生成又做向量,模板、批处理和 -c 都会互相干扰。然后在 Python 里只走 HTTP,不混用进程内 LlamaCPP。
1 | from llama_index.core import ( |
这是一次性建库。需要增量时改走 IngestionPipeline,默认 UPSERTS,transformations 显式写成切分器加 embed model,不要再叠一次 from_documents()。需要工具时接 ReActAgent + AgentWorkflow,不要开已经删除的 ChatMode.REACT。多轮对话用 Memory.from_defaults,不要新写 ChatMemoryBuffer。
导出阶段记住 Factory 的硬约束:合并 adapter 时不要带 quantization_bit;量化模型上不能再合并 adapter。量化留给 llama-quantize。convert_hf_to_gguf.py 读的是导出目录,不是 adapter 文件夹本身。
3. 每一跳在守什么
把命令看成契约,而不是脚本彩排:
| 步骤 | 守住的不变量 |
|---|---|
train → export |
得到可被转换脚本识别的 HF 目录;示例输出在 saves/qwen3_sft_merged |
F16 GGUF → llama-quantize |
推理侧的体积与精度在这一跳决定,LlamaIndex 看不见 GGUF |
两个 llama-server |
:8080 聊天、:8081 向量;-c 与客户端 context_window 对齐 |
from_documents / persist |
文档向量已写入 simple store,加载不再向 :8081 重算;查询仍要嵌入问题 |
is_function_calling_model=False |
本地默认走 ReAct,而不是假想中的原生 tools |
换 embedding 模型或维数,必须新建 persist 目录。stores_text 为假的外部库不能走 from_vector_store()。合成模式按第 14 章的 K 估算调用次数:compact 在 repack 后仍可能多次 refine;condense_plus_context 有历史时还多一次改写。把这些次数加在 llama-server 的并发槽位上,才能解释“为什么一个用户问题打满了 GPU”。
健康检查失败时,先看端口和 /v1 前缀,再看模型 ID,最后才怀疑 LlamaIndex。输出像 prompt 回显,优先查 is_chat_model 和 instruct 模板。上下文溢出要同时核对 server -c、客户端窗口、chunk、top-k、历史和 max_tokens。客户端把 context_window 写成更大的数字,不会扩大服务端 KV。
4. 如何选路径
不必每次都走完整链条。按你缺的那一层裁剪,这是本系列作为课本而不是清单的原因:
- 只验证数据格式、模板和损失是否有限: Factory 的短跑
train、chat或 Board 即可,不必转 GGUF。 - 只验证本地吞吐、槽位和 chat template:
llama-server+curl,不必上 LlamaIndex。 - 已有云端模型和托管向量库、只要 RAG: 跳过上面 1–5 步,直接安装 core 与对应集成;仍然遵守第 12–13 章的对象和摄取边界。
- 本机闭环、要引用私有文档: 走本章命令,查询用
compact,多轮用Memory.from_defaults。 - 要工具、增量更新或属性图: 第 15 章的
AgentWorkflow与PropertyGraphIndex,摄取用 Pipeline 的UPSERTS,不要开已废弃的KnowledgeGraphIndex。 - 要多租户服务: 不要在请求里改
Settings;按租户注入 engine 与 Memory。这是第 12、15 章的工程结论,与是否本地推理无关。
选型时回到具体章节核对事实,而不是凭印象拼接 0.10 时代的教程:ServiceContext 已抛错,ChatMemoryBuffer 已 deprecated,ChatMode.REACT 已删除,pip install llama-index 不会装齐约 620 个集成。版本数字变了,先重读对应章的“会抛错 / 已删除 / 默认值”,再改自己的仓库。
若你带团队分工,也可以按章节切开责任:训练同学读 00–11 的 Factory 与导出约束;推理同学读 llama-server 与量化;应用同学读 12–15,只把 :8080 / :8081 当成两个 OpenAI 兼容端点。全栈负责人的工作是守住本章这张表,防止有人在应用进程里再拉起一份进程内 LlamaCPP,或在 Pipeline 之后又 from_documents 一次。
系列结束
第 00–16 章合在一起,是一条可复查的全栈课本:训练导出、GGUF 量化、HTTP 推理、RAG 编排。从哪一章切入,取决于你缺的是权重、服务还是检索质量。选定一条路径后,用该章已经出现过的命令和对象边界做最小验证,再向外扩存储、权限与 Agent。不要同时换模型、换切分、换合成模式和换 Agent,否则你无法判断是哪一跳坏了。
复习时不必按文件名从 00 扫到 16。可以倒着问三个问题:用户问题经过了几次 LLM 调用、文档向量是在哪一次写入的、生成请求打到了哪一个端口。答得出,全栈就接上了;答不出,就回到第 14 章数 K、第 13 章看摄取、第 12 章看 Settings,或回到 00–11 查导出与 server。正向阅读建立地图,反向提问用来验收。
落地验收建议只做三件事,且一次只动一件。第一,固定提示问 llama-server 的 chat 端口,确认模板与中文指令遵循。第二,对同一批文档建索引后立刻 persist、重启进程再 load_index_from_storage,确认查询不再重算文档向量、但问题向量仍会打到 :8081。第三,把同一句带代词的追问分别交给 as_query_engine 与 condense_plus_context,数清 LLM 调用次数是否符合第 14 章。三件事都稳定,再打开 Agent 或外部向量库。
本系列到此结束。若只记住一句话:先固定“权重在哪推理、向量在哪存储、嵌入发生在哪一步”,再谈 Prompt 与工具。三者未定,后面的技巧都是噪音。选路时宁肯裁掉整段链条,也不要同时开两条互相嵌入的摄取路径,或同时开 HTTP 与进程内两套本地推理。读完 00–15 再改生产配置,比对着搜索引擎拼旧参数更安全。旧博客里的类名可以当索引,不能当本版本的行为说明。
正在加载留言…