6.2 本地服务与 API


6.2 本地服务与 API

本节摘要:命令行问答不是交付,服务才是。本节用 llama-server 把 GGUF 变成本地 HTTP 服务:它暴露 OpenAI 风格的 chat completions 接口——任何为 OpenAI API 写的客户端与 SDK,把地址指向 localhost 即可复用(2.3 的蒸馏脚本同款接口形态)。内容包括启动参数示意(模型路径、监听地址、GPU 卸载层数)、启动自检两条、一个维护多轮 messages 历史的最小 Python 对话客户端(写法示意),以及部署侧四症状排查表——腰斩、永不停、开头乱码、太慢,分别对应终止符错配、模板不一致、词表漂移或量化过狠、档位与硬件错配。本节的 API 地址就是第 7 章语音回路里"对话腿"的插头。

学习目标

阅读完本节,你应当能够:

  1. 用 llama-server 起一个本地 OpenAI 兼容服务并完成启动自检。
  2. 写一个维护多轮 messages 历史的最小对话客户端。
  3. 按四症状表定位部署侧故障,知道何时回 4.3、何时回 6.1。

一、为什么是 llama-server

自建推理服务要管三件事:模型加载、请求并发、接口协议。llama-server 把三件全包:加载 GGUF、起 HTTP 服务、讲 OpenAI 方言(chat completions 一类端点,具体以官方 README 为准)。方言统一带来的直接红利:本书 2.3 的蒸馏脚本、5.2 的裁判脚本、任何 OpenAI SDK 生态工具,把 base_url 指到本地端口就能复用——你的模型在自己的机器上冒充了一个"OpenAI 服务"

# serve_llama.sh —— 启动本地对话服务(写法示意,以 llama.cpp 官方仓库 README 为准) ./llama-server -m chat_model/sft_124m_q8_0.gguf --host 127.0.0.1 --port 8080 # 可选加速:把前 N 层卸载到 GPU(参数名以 README 为准,CPU 机器不用管)

启动自检两条:日志里确认加载的模型与档位无误;发一条固定消息("你是谁?"),确认会停、身份正常、无标记泄漏——这一步就是 4.1 的 assert 纪律在服务侧的人肉版。

💡 为什么从 llama.cpp 起步:对 124M 这种小模型与 CPU 场景,它是最省事的一站式起点(转换、量化、服务同生态)。将来吞吐要求上来了再换 vLLM 一类专用推理服务——它们讲的也是 OpenAI 方言,本章客户端原样可用。

💡 服务化还有一个隐性收益:5.2 的回归题库跑分脚本把 base_url 指向本地服务,评测从此不依赖训练机——分数台账的"部署版"与"训练版"由同一个端口统一。

二、最小对话客户端

# chat_client.py —— 最小多轮对话客户端(写法示意,接口以 llama.cpp 官方 README 为准) import requests URL = "http://127.0.0.1:8080/v1/chat/completions" SYSTEM = "你是一个简洁的中文助手。" history = [{"role": "system", "content": SYSTEM}] def ask(history: list[dict]) -> str: r = requests.post(URL, json={ "model": "sft_124m", # 本地服务通常不校验模型名,字段按协议带上 "messages": history, "temperature": 0.7, # 4.2 默认组 "max_tokens": 200, }, timeout=60) r.raise_for_status() return r.json()["choices"][0]["message"]["content"] if __name__ == "__main__": print("输入空行退出。") while True: q = input("你:").strip() if not q: break history.append({"role": "user", "content": q}) a = ask(history) history.append({"role": "assistant", "content": a}) print(f"助手:{a}")

客户端的分工要点:客户端只发 messages,不拼模板——序列化由服务端按 GGUF 元数据里那份模板执行(4.3 的单一事实源原则:模板只在 6.1 转换时定义一次)。客户端唯一的格式责任是维护完整历史(含 assistant 旧答),多轮指代才接得住。

服务侧的采样参数也可以由客户端逐请求覆盖(如上例的 temperature 与 max_tokens)——4.2 的场景参数组(客服低温、创作高温)在这里按请求生效,不必为不同场景起多个服务。

💡 历史过长怎么办:把最早的轮次成对裁掉(user/assistant 成对裁、system 常驻),不要从中间腰斩一轮——半轮对话是训练分布里没有的序列形态(4.3 错位一的温和版)。

三、部署侧四症状排查表

症状 首要病因 处置
回答被腰斩 部署侧停止条件提前触发(终止符或 max_tokens 配错)——4.3 错位三部署版 对齐训练侧终止符 id(4.3 三板斧之二);检查 max_tokens
永不停(回答后接乱码) 终止符 id 没配或配错 同上;确认 GGUF 元数据与训练同源(6.1 校验一)
开头乱码/冒出标记 模板不一致或词表漂移(4.3 错位一/三);量化过狠也会偶发 回 4.3 三板斧;重做 6.1 回环校验;升 Q8_0 排除量化因素
太慢 档位与硬件错配 升量化档(6.1 表);开 GPU 卸载;确认没在 CPU 上跑 f16

排查次序:先模板(4.3)后量化(6.1)——模板病是全灭(所有回答都坏),量化病是概率性劣化(偶发措辞破绽),先治全灭的。

排查的通用入口:先绕开客户端,直接向服务发一条最小请求(工具与参数以官方 README 为准),看原始响应里的停止原因与生成文本——问题在服务端还是客户端,一问便知;再按表回 4.3 或 6.1。

⚠️ 腰斩先查 max_tokens 再查终止符:客户端给小了同样表现为"话说一半就停",与终止符错配的症状几乎一样。排查表第一行的两个嫌疑,成本低的先查。

本节要点回顾

  1. llama-server = 模型加载 + HTTP 服务 + OpenAI 方言;生态工具改个 base_url 就能复用你的模型。
  2. 客户端只管 messages,模板由 GGUF 元数据定义——单一事实源在 6.1 转换时定格,启动自检两条必做。
  3. 四症状表:腰斩/不停是终止符病,乱码是模板/词表病(偶发则是量化病),慢是档位病;先模板后量化。

文字对话通了,第 7 章给这台服务接上耳朵和嘴——Whisper 进、语音出。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U