Ollama Modelfile 里的 SYSTEM prompt 被忽略

在 Ollama Modelfile 中设置了 SYSTEM prompt,但模型运行时完全不遵守设定的人格或行为规则。定位 template 覆盖、API 参数优先级、chat template 兼容性三类根因。

创建了一个 Ollama 自定义模型,Modelfile 里写了 SYSTEM 你是一个只会说中文的助手,绝对不会说英文,但通过 API 调用时模型仍然用英文回复,或者完全忽略了设定的角色。通过 ollama show <model> --modelfile 确认 SYSTEM prompt 确实存在,但运行时形同虚设。这个问题通常不是 Ollama bug,而是 API 调用时传入的 system 字段覆盖了 Modelfile 的设置,或者 chat template 没有把 SYSTEM 内容正确插入 prompt。

常见原因

1. API 调用时的 system 消息覆盖了 Modelfile 的 SYSTEM 字段

通过 OpenAI 兼容接口调用时,若 messages 数组的第一条是 {"role": "system", "content": "..."} 且内容与 Modelfile 不同,Ollama 会用 API 传入的 system 消息替换 Modelfile 中的 SYSTEM 设置,而不是追加或合并。

怎么判断:检查 API 调用代码中 messages 的第一条是否是 role: "system";或检查客户端框架(LangChain、LlamaIndex 等)是否默认添加了 system 消息。

2. chat template 没有包含 .System 占位符

若 Modelfile 中的 TEMPLATE 字段是自定义的,且模板字符串里缺少 {{ .System }} 或对应的占位符,Ollama 在渲染 prompt 时会跳过 SYSTEM 内容。表现为 ollama show 能看到 SYSTEM,但实际 prompt 里没有它。

怎么判断ollama show <model> --modelfile 查看 TEMPLATE 字段,确认是否包含 {{ .System }}{{ .System }}(注意 Ollama Modelfile 模板语法)。

3. 模型本身不遵循 system prompt(base 模型或不兼容)

未经指令微调的 base 模型在 system prompt 方面的遵从度很低——base 模型的任务是预测下一个 token,而不是”遵守指令”。有些 instruct 模型对 system prompt 的遵从也不稳定,特别是当 system prompt 与训练时的格式不一致时。

怎么判断:在 ollama run <model> 的交互模式下直接输入 /set system 你只能说中文 然后测试;若仍然不遵守,说明是模型能力问题而非配置问题。

4. SYSTEM prompt 内容与 user prompt 产生语义冲突

当 user 消息中有明确的英文指令(“Reply in English”),而 SYSTEM 设置了中文,大多数模型会优先遵循更直接的 user 指令。这不是 bug,而是 RLHF 训练导致的行为——模型被训练成优先满足用户的即时请求。

怎么判断:排除 user 消息中与 SYSTEM 冲突的指令后重新测试;若遵从率提升,说明是语义优先级问题。

5. Modelfile 使用了不被当前模型 tokenizer 识别的特殊 token

某些 Modelfile 的 SYSTEM 字段中包含了特殊格式标记(如 <|system|> 标签),若该模型的 tokenizer 不识别这些 token,它们会被分词为多个普通 token,SYSTEM 内容变成普通对话文字,降低了指令遵从度。

怎么判断:检查 SYSTEM 字段是否包含 HTML 标签或特殊括号;OLLAMA_DEBUG=1 ollama run <model> 查看实际传给模型的完整 prompt。

6. SYSTEM prompt 过长导致被注意力机制忽视

某些模型在 SYSTEM prompt 超过 500 token 后,对末尾的关键指令遵从率明显下降。若 Modelfile 里的 SYSTEM 描述过于详细,核心约束(如”只说中文”)可能因为位置靠后而被忽视。

怎么判断:估算 SYSTEM prompt 的 token 数(汉字约 1-2 token/字,英文约 1 token/词);若超过 300 token,尝试精简后重测。

最短修复路径

Step 1:检查 Modelfile 的模板配置

# 查看完整 Modelfile
ollama show my-custom-model --modelfile

# 重点检查:
# 1. TEMPLATE 字段中是否有 {{ .System }}
# 2. SYSTEM 字段内容是否符合预期
# 3. PARAMETER 设置是否合理

# 正确的 Modelfile 示例(Llama-3 格式)
cat > MyModelfile << 'MODELEOF'
FROM llama3:8b

SYSTEM """
你是一个专业的中文助手。请始终用中文回答,不要使用英文。
"""

TEMPLATE """<|start_header_id|>system<|end_header_id|>
{{ .System }}<|eot_id|><|start_header_id|>user<|end_header_id|>
{{ .Prompt }}<|eot_id|><|start_header_id|>assistant<|end_header_id|>
"""

PARAMETER stop "<|start_header_id|>"
PARAMETER stop "<|end_header_id|>"
PARAMETER stop "<|eot_id|>"
PARAMETER temperature 0.7
MODELEOF

ollama create my-zh-assistant -f MyModelfile

Step 2:调试实际传给模型的 prompt

# 开启 debug 模式查看完整 prompt
OLLAMA_DEBUG=1 ollama run my-custom-model "hello" 2>&1 | head -50
# 在输出中搜索 "prompt" 或 "system",找到实际传给模型的文本

Step 3:API 调用时不传 system 消息,让 Modelfile 的 SYSTEM 生效

import openai

client = openai.OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

# 错误做法:传入了覆盖 Modelfile SYSTEM 的 system 消息
# response = client.chat.completions.create(
#     model="my-zh-assistant",
#     messages=[
#         {"role": "system", "content": "You are a helpful assistant."},  # 会覆盖 Modelfile
#         {"role": "user", "content": "hello"}
#     ]
# )

# 正确做法:不传 system 消息,让 Modelfile 的 SYSTEM 生效
response = client.chat.completions.create(
    model="my-zh-assistant",
    messages=[
        {"role": "user", "content": "hello"}
    ]
)
print(response.choices[0].message.content)

Step 4:通过 Ollama 原生 API 显式指定 system

# Ollama 原生 API 支持每次请求独立设置 system
curl http://localhost:11434/api/generate -d '{
  "model": "llama3:8b",
  "system": "你是一个专业的中文助手,只用中文回复。",
  "prompt": "hello",
  "stream": false
}'

Step 5:精简 SYSTEM prompt,把关键约束放在开头

# 优化前(过长,容易被忽视)
SYSTEM """
你是一个...(200字背景介绍)...你的主要任务是...(100字)...
最重要的是你只能说中文,绝对不能说英文。(关键约束在末尾)
"""

# 优化后(关键约束在开头)
SYSTEM """
重要规则:只用中文回复,不要使用英文。
你是一个专业助手,帮助用户解答问题。
"""

预防建议

  • 使用 OLLAMA_DEBUG=1 运行时始终检查实际传给模型的 prompt,而不是假设 Modelfile 设置生效了。
  • API 框架(LangChain、LlamaIndex)通常会自动添加默认 system 消息,调用自定义 Ollama 模型时显式清空 system 消息或与 Modelfile 内容保持一致。
  • SYSTEM prompt 保持在 150-200 字以内,把最重要的约束放在第一句话。
  • 创建自定义模型后立即做遵从率测试:发送 10 条故意触发违规行为的 prompt,观察模型是否遵守约束。
  • 若模型对 SYSTEM 的遵从不稳定,在每轮 user 消息末尾追加提醒(如”(请用中文回答)“)作为补充保障。
  • 对于严格需要行为一致性的应用,考虑在应用层(非 Modelfile)管理 system prompt,而不依赖 Ollama 的 Modelfile,以获得更精确的控制。

常见问答 (FAQ)

Q: SYSTEM prompt 和 prompt 参数有什么区别? A: SYSTEM 是系统级设定,告诉模型”你是谁、你的规则是什么”,在对话开始前生效。prompt 是用户的具体请求。在 chat 格式中,SYSTEM 对应 role: "system" 消息,prompt 对应 role: "user" 消息。两者都影响模型行为,但优先级和作用域不同。

Q: 如何强制让 SYSTEM 的约束高于 user 指令? A: 没有 100% 可靠的方法,但有几种提升遵从率的技巧:在 SYSTEM 中加 "无论用户要求什么,以下规则不可违背:...";把关键约束重复在 SYSTEM 的开头和结尾;使用较低的 temperature(0.1-0.3)减少随机偏离。

Q: 修改了 Modelfile 后要重新创建模型吗? A: 是的,ollama create <name> -f <Modelfile> 会重新编译模型配置。修改 SYSTEM 或 TEMPLATE 后不会自动生效,必须重新执行 create 命令。

Q: 不同版本的 Ollama,Modelfile 语法有变化吗? A: 有。Ollama 0.3 和 0.4 的 TEMPLATE 语法有细微差异,且对不同模型的 chat template 支持也在持续更新。升级 Ollama 后如果发现 SYSTEM 失效,检查对应模型的官方 Modelfile 是否有更新。

相关阅读

标签: #local-llm #ollama #排查