所有文章

llama.cpp 报错 “System message must be at the beginning”:3 种实测解法(2026)

“System message must be at the beginning” 是模型聊天模板拒绝了请求:system 消息不在第一条,或有两条。实测三种解法:合并成一条放最前面、用 --chat-template chatml 启动、改一份模板副本。

llama.cpp system 消息报错:黏土对话气泡顺序错乱,旁边是带红色警告三角的黏土服务器

先说结论:这个报错不是 llama.cpp 引擎的问题,而是模型文件里自带的聊天模板(chat template)在拒绝你的请求。模板规定“system 消息只能放在第一条”,而你的客户端把它放在了别处,或者发了两条。最干净的办法是在客户端把所有 system 内容合并成第 0 位的一条 system 消息。改不了客户端的话,就用更宽松的模板启动服务,比如 --chat-template chatml。我在 llama.cpp 构建 11963 上复现了这个报错,下面三种解法都实测过。

“System message must be at the beginning”是什么意思

llama-server 返回的完整报错长这样(中间我省略了一段):

{"error":{"code":400,"message":"Unable to generate parser for this template. Automatic parser generation failed: ... Error: Jinja Exception: System message must be at the beginning.","type":"invalid_request_error"}}

新版 llama-server 会读取 GGUF 文件里存的 Jinja 聊天模板,每个请求都跑一遍(按 llama.cpp server README,--jinja 默认开启)。有些模板里写了一道检查。比如 Hugging Face 上 Qwen/Qwen3.5-35B-A3B 的 chat_template.jinja 就有这一行:raise_exception('System message must be at the beginning.')。检查触发时,llama.cpp 返回 HTTP 400 和上面那段话。

所以有三件事同时成立:模型权重没坏,内存也没问题,是请求被模板拒绝了。

我是怎么复现的(实测)

我没有跑 Qwen3.5 本体。为了测试够小,我用了 Hugging Face 上 ggml-org 仓库里 1.19 MB 的测试模型 stories260K.gguf,再给服务器一个带同样检查的模板文件(system 不在第一条就 raise_exception)。服务器是 Linux 上的 llama.cpp 构建 11963,纯 CPU:

llama-server -m stories260K.gguf --jinja --chat-template-file tpl.jinja --port 18091 -c 512

然后往 /v1/chat/completions 发了四种请求:

发送的消息顺序结果
user,然后 systemHTTP 400,“System message must be at the beginning.”
system、system、userHTTP 400,同样的报错(第二条 system 不是第一条)
system、user、assistant、system、userHTTP 400,同样的报错
合并成一条 system,然后 user正常,模型有回答

第二行最容易让人意外:不用有“晚到”的消息,连续两条 system 就够触发。

你也可以看服务器加载了哪个模板:curl localhost:8080/props 会返回 chat_template 字段,里面就是模板文本(我在构建 11963 上确认了这个字段存在)。

解法一:只发一条 system,放在最前面(改客户端)

这是最干净的办法。把所有指令合并成一条消息,放第一位:

{"messages":[
 {"role":"system","content":"规则 A。\n\n规则 B。"},
 {"role":"user","content":"hi"}
]}

我的测试里这个请求通过了。如果某个工具或插件会在对话中途加一条“system 提醒”,去找有没有“合并 system 提示词”的设置,或者关掉这个功能。具体有没有这个设置取决于客户端,请看它自己的文档。

解法二:用不做检查的模板启动服务

改不了客户端,就换掉模型自带的模板。llama.cpp README 列出了内置模板,chatml 就是其中之一。README 的工具调用部分也把 --chat-template chatml 列为“最坏情况下可能有效”的选项,所以这是已知的退路:

llama-server -m model.gguf --jinja --chat-template chatml

我的测试里,同样的“坏请求”(先 user 后 system)在内置 chatml 模板下得到了正常回答。两点提醒:

  • 内置模板不一定和模型训练时的格式一致,回答质量可能略差,请用自己的提示词试一下。
  • 如果你要用工具调用,README 说可能需要支持工具的 --chat-template-file,这时别盲目换模板。

解法三:改一份模型自带模板的副本

从模型的 Hugging Face 页面下载 chat_template.jinja,删掉或放宽 raise_exception('System message must be at the beginning.') 这个分支,再加载:

llama-server -m model.gguf --jinja --chat-template-file my-template.jinja

这样保留了模型自己的格式,但位置奇怪的消息可能被渲染到模型没见过的位置。把它当作临时办法,并留好原文件方便对照。

它不是什么

更多 llama.cpp 和 Ollama 报错汇总在 Ollama 与 llama.cpp 报错清单。还在选模型的话,看 本地大模型推荐。

常见问题

这个报错是不是说明我的模型文件坏了?

不是。文件加载成功,服务也启动了,只是请求被模板的检查拒绝。

为什么有的模型会出现,有的不会?

只有部分模板写了这道检查。Qwen3.5 的模板有;我查的 Qwen3-8B 的 tokenizer 配置里没找到这句话,其他模型我没有逐个查。

--no-jinja 能解决吗?

我没有测。README 说 --jinja 默认开启,而且工具调用需要它,所以关掉它不适合作为第一步。先合并 system 消息。

--chat-template 和 --chat-template-file 有什么区别?

前者接收模板名称或模板文本,后者接收文件路径。两者都会替换模型里存的模板。

来源与测试说明

  • llama.cpp server README(选项、内置模板、工具调用说明):github.com/ggml-org/llama.cpp 的 tools/server/README.md。
  • Hugging Face 上 Qwen3.5-35B-A3B 的 chat_template.jinja(包含这句报错原文)。
  • 自己实测:llama.cpp 构建 11963,Linux 纯 CPU,stories260K.gguf 加我自己写的带检查的模板。没测:真正的 Qwen3.5 权重、工具调用、--no-jinja。

留下你的想法

你的邮箱不会公开。