创建了一个 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 是否有更新。
相关阅读
- Chat template 不匹配导致输出全是乱码
- 本地模型不遵守 tool calling 格式
- Ollama 下载模型卡在某个百分比
- Ollama pull 成功但 list 看不到
- 本地模型输出在 token 中间被截断
标签: #local-llm #ollama #排查