llama.cpp:llama-server 与生产部署
「本系列第 8/17 章」。前两章已经说明:llama_model 只读可共享,llama_context 不能跨线程乱调,llama_decode 按 ubatch 推进。llama-server 并不另造一套推理引擎,它只是把这些约束做成可并发的 HTTP 服务。源码在 tools/server/,HTTP 用 cpp-httplib,JSON 用 nlohmann/json。
1. 请求怎么走进 decode
服务端主路径可以看成四段:
1 | server-http.cpp → server-queue.cpp → server-context.cpp (slots) → server-chat.cpp |
server-http 负责路由与协议。请求进入 queue 后排队、合并、调度。真正算 token 的是 context slots:每个 slot 对应一份推理会话,内部仍是上一章的 memory 与 llama_decode。server-chat.cpp 把 OpenAI 风格的 messages 收成模型能吃的 token 序列(Jinja chat template 在 common/chat.cpp),再把采样结果写回响应。Function calling 在 server-tools.cpp,多模型路由在 server-models.cpp。
--parallel 控制 slot 数量。slot 不是「开几个线程就安全」,而是「同时能挂起几路会话」。上一章写过 context 非线程安全:服务端用 slot 把并发请求隔开,再在调度器里决定哪些序列可以放进同一次 batch。slot 太少,请求在 queue 里等;slot 太多,每路都要占一份 KV,内存会先于 CPU 撑满。
2. 连续批处理与 SSE
生产环境很少「一个人 prefill 完再独占整段 decode」。连续批处理(--cont-batching,默认打开)允许不同请求处于不同阶段:有的还在灌 prompt,有的已经在逐 token 生成,调度器把它们合成一次 decode。新请求可中途加入,完成的序列立刻释放 slot。吞吐来自「同一张图里塞进更多活着的序列」,而不是无限加进程。slot 还可以 seq_cp fork、保存 / 恢复。
流式输出走 SSE。客户端把 stream: true 打开后,每个新 token 以 data: {"choices":[{"delta":{"content":"..."}}]} 推送,最后 data: [DONE]。这与 decode 循环一一对应:每成功一步 llama_decode 并采样,就多写一帧。不要把 SSE 理解成另一个推理后端。
投机解码用 -md draft.gguf --draft-max 16:draft 模型先吐若干 token,target 模型一次性验证。多模型目录用 --models-dir。这些都建立在同一套 slot / ubatch 之上。
3. 先认这些端点
| 端点 | 用途 |
|---|---|
GET /health |
健康检查,部署探活 |
GET /props |
当前服务属性 |
GET /v1/models |
模型列表,LlamaIndex 先对这个 |
POST /v1/chat/completions |
Chat 补全,可 SSE |
POST /v1/completions |
文本补全 |
POST /v1/embeddings |
向量,embedding 进程才开 |
POST /tokenize /detokenize /apply-template |
排词表与模板 |
GET /metrics |
需要 --metrics |
探活用 /health,确认加载用 /v1/models,对话走 /v1/chat/completions。模板或词表异常时,先打 /tokenize 看 token 是否符合预期。还有 Anthropic 风格的 /v1/messages、以及 /infill、/slots,不是最小闭环必需。
关键旋钮:-c 上下文、-b / -ub batch、-ngl 卸层、-fa Flash Attention、--host / --port。环境变量 LLAMA_ARG_THREADS、LLAMA_ARG_CTX_SIZE、LLAMA_ARG_N_GPU_LAYERS、LLAMA_ARG_HOST / PORT 可以少写命令行。默认 --host 是 127.0.0.1,局域网访问必须改成 0.0.0.0。
4. 冒烟部署
编译与 GGUF 仍沿用第 5 章:静态链接、GGML_NATIVE=OFF,需要界面时备好 tools/ui/dist。模型继续用 Qwen2.5-0.5B-Instruct-GGUF 的 q4_k_m,先证明链路,再换大模型。
1 | ./build/bin/llama-server \ |
必须等到 HTTP server is listening。先打 /health,再发一条最短的 /v1/chat/completions。slot 不够会排队,KV 满会从 llama_decode 返回 1 一路冒到请求失败——这时应回到上一章检查 n_ctx 与 memory,而不是先改 HTTP 框架。集成测试在 tools/server/tests/,用 pytest 打 chat / tool / vision / slot。
llama-server 是调度壳,不是新的模型格式。权重仍是 GGUF,计算仍是 libggml,会话仍是一份份 context。推理这一段到此闭环。下一章《LLaMA Factory:环境、双架构与调用链》转回训练侧:在 Hugging Face 权重上做微调,再经第 5 章那条转换链回到 GGUF。
正在加载留言…