你写了一条很长的 user message,把角色(“你是一名资深工程师”)、全局规则(“始终返回 JSON、不用 emoji”)、任务(“重写下面这个函数”)和输入代码全捆在一起。模型有时遵守规则,有时无视。聊到第 5 轮,规则就完全消失了——因为它们和任务挤在同一条通道里,被更新的输入埋掉。模型没坏,是你把持久规则放进了单轮通道。System 指令、project / custom instructions、单轮 user message 的生命周期各不相同,混在一起就会把模型依赖的优先级层级拍平。
最快的修法: 把所有应该每轮生效的规则(角色、输出格式、语气)从 user message 里拿出来,放进持久通道——API 里的 system 参数,或聊天 UI 里的 Custom Instructions / Project instructions。user message 里只留本轮任务和输入。这一步通常就能让整段对话的行为重新稳定下来。
本文讲清楚为什么有这种分层、截至 2026 年 6 月各主流平台把持久通道叫什么,以及怎么把 prompt 各部分路由到对的地方。
你属于哪一类?
| 症状 | 可能原因 | 跳到 |
|---|---|---|
一条 user message 里装着规则 + 任务 | 全挤在一条通道 | Step 1、Step 2 |
| 每轮都重打同样的规则 | 没用持久通道 | Step 2 |
| 规则撑 2-3 轮就开始跑偏 | 被新轮次埋掉 | Step 2、Step 3 |
| 输出语气 / 格式随机乱跳 | system 和 user 矛盾 | Step 6 |
Claude messages[] 里的 role: "system" 被忽略 | Anthropic 用错了通道 | Step 2(Anthropic 注意事项) |
| 工具被当建议而非合约 | 工具定义写在 prose 里 | Step 5 |
常见原因
1. 全塞进一条 user message
你写了一条长 message,没用 system prompt,于是规则和任务在同一通道里争注意力。
如何判断:API 调用里只有一条 role 为 user 的消息,或聊天 UI 里所有规则都打在输入框里。
2. 完全没用持久通道
很多平台把持久通道藏在 “Custom Instructions""Project instructions” 或 “Saved info” 这类名字后面,不少用户根本不知道它存在。
如何判断:你有想每轮都生效的规则,却每次都重打一遍。
3. 每条 user message 都重申全局规则
你发现模型会忘,于是每轮都重贴。这能工作,但浪费 token、脆弱,而且其中一些重贴的规则会和你之前设过的 system prompt 静默冲突。
如何判断:每条 user message 开头都是同样的 5 行 preamble。
4. system prompt 和 user message 矛盾
你昨天写的 system prompt 说 “be formal”,今天又打 “keep it casual”。模型拿到两个方向相反的权威来源,结果就摇摆。
如何判断:你已经记不清 system prompt 里写了什么。
5. tools / functions 配置在 user message 里
Agent 工作流里,工具定义应该有自己的槽位。塞进 user message 能被解析,但模型会把它当成软建议,而不是带 schema 验证的合约。
如何判断:工具描述写在 user prose 里,而不在 tools 参数里。
动手前先确认
- 列出当前 prompt 的每一行。
- 给每行分类:system(持久)、user(单轮)、tool(能力)、assistant(历史)。
- 标出哪些每轮会变、哪些是持久的。
- 查清你平台到底支持什么——聊天 UI 和原始 API 暴露通道的方式不一样。
- 计划好每部分放哪里。
手头有的话再收集:完整发送的 prompt、你当前的 system / project instructions、对话历史、那条无视规则的输出,以及确切的模型和平台。
最短修复路径
Step 1:分清持久 vs 单轮
持久(system / custom instructions):
- 角色:"You are a senior backend engineer."
- 输出格式:"Return only valid JSON matching schema X."
- 语气规则:"No emoji. No exclamation marks."
单轮(user message):
- "把下面这个函数加上指数退避的重试逻辑。"
- <粘代码>
分开之后两半都更清爽,也更好调试。
Step 2:把持久规则挪到持久通道
OpenAI API。 对 GPT-5.5 以及 o1 之后的每个模型,承载指令的角色名叫 developer,不再是 system。旧的 system 角色仍然能用(它被当作别名映射到 developer),但 developer 是现在的叫法;平台强制固定的权威顺序 platform > developer > user,所以 developer 指令压过用户输入的任何东西。
messages = [
{"role": "developer", "content": "<所有持久规则>"},
{"role": "user", "content": "<仅本轮任务>"}
]
Anthropic(Claude)API。 Claude 不使用 role: "system" 的消息。System prompt 是请求上的顶层 system 参数,独立于 messages 数组。把 {"role": "system", ...} 放进 messages 是常见错误——很多 Anthropic 兼容端点会拒绝或忽略它。
import anthropic
client = anthropic.Anthropic()
client.messages.create(
model="claude-opus-4-7",
max_tokens=1024,
system="<所有持久规则>", # 顶层参数,不是 message
messages=[{"role": "user", "content": "<仅本轮任务>"}],
)
聊天 UI(截至 2026 年 6 月):
- ChatGPT — 点头像,再进
Settings->Personalization->Custom instructions。打开 customization 开关,把持久规则放进去(长文本框每个上限约 1500 字符)。常做的活儿可以建一个 Project,它的指令会对里面每个对话生效。 - Claude — 在
Settings->Profile里设持久规则(那个对所有对话生效的 “personal preferences” 框),或者更好的做法是建一个 Project,用它的Project instructions/ custom instructions,让规则自动套用到该 Project 里每个对话。 - Gemini — 用
Saved info(用 Gemini Gems 的话还有 Gem 自己的指令)把规则带到各个对话。 - Cursor — 项目级规则放
.cursor/rules(老配置用顶层.cursorrules文件)。 - Claude Code — 项目级规则放仓库根目录的
CLAUDE.md。
Step 3:user message 只聚焦本轮任务
单轮 message 只放新请求、新输入、以及会变的东西。任何每轮通用的都不要放。
差: "记住:返回 JSON、不用 emoji、你是资深工程师。
现在:重写这个函数。"
好: "重写这个函数:"
<代码>
Step 4:API 里持久通道放最前
对 OpenAI,developer(或 system)消息放数组第一条。对 Claude,system 是顶层参数,所以 messages 内部的顺序对它不适用。
messages = [
{"role": "developer", "content": "..."}, # OpenAI 放第一条
{"role": "user", "content": "..."},
{"role": "assistant", "content": "..."},
{"role": "user", "content": "..."}
]
在 OpenAI 上,如果承载指令的消息出现在对话中间,行为会更难预测——把持久规则留在第一条指令消息里。
Step 5:能力用 tools / functions
Agent 工作流里,把工具定义在 API 的 tools 参数里,不要写在 prose。模型会把声明出来的工具当成带 schema 验证的合约,而不是埋在文字里的软建议。
tools = [{
"type": "function",
"function": {
"name": "search_codebase",
"description": "...",
"parameters": {"type": "object", "properties": {}}
}
}]
(在 Anthropic API 上,对应结构里每个工具用 name、description、input_schema。)
Step 6:审矛盾、做取舍
打印你的 system / developer 指令,再打印最新的 user message,找冲突。持久通道一般压过 user message;如果你想让 user message 在某一点上赢,就显式说明:“本轮覆盖 system prompt 中关于 X 的规则。“
怎么确认已经修好
- 同一批规则跨 10 轮以上都成立,不需要任何重贴。
- user message 短而聚焦任务。
- 删掉某条 user message 里的旧 preamble,行为不变——规则在持久通道里活着。
- 不同轮次任务输出不同,但语气、格式、角色一致。
- 单轮 token 用量明显下降(你不再每轮重发 preamble 了)。
如果还是没修好
- 你的平台可能没暴露真正的持久通道——查文档里有没有 “custom instructions” 或 “system prompt” 支持。
- 有些平台会截断过长的持久指令(ChatGPT 的 custom-instruction 框每个上限约 1500 字符)——精简并排优先级。
- 模型可能不严格 system 优先于 user。故意写一条矛盾的 user message 测一下,看哪条赢。
- 在 Claude 上,再确认你用的是顶层
system参数,而不是messages[]里的role: "system"消息。 - 聊天 UI 如果没有持久通道,就切到 API,那里的通道分离由请求 schema 强制。
常见问答
system prompt 和 user message 有什么区别? system / developer 通道承载持久指令——角色、输出格式、语气、硬规则——对每轮都生效。user message 是单轮的:具体请求和它的输入。持久规则放进 user message 会被后续轮次埋掉、丢失优先级。
OpenAI:2026 年 6 月该用 system 角色还是 developer 角色?
用 developer。对 o1 之后的每个模型(含 GPT-5.5),developer 是承载指令角色的现行名字。旧的 system 角色仍被接受并映射到 developer,所以老代码还能跑,但新代码应该用 developer。
为什么我 Claude 的 role: "system" 消息被忽略了?
因为 Claude API 不接受 messages[] 里的 system 消息。它接受请求上的顶层 system 参数。把规则挪到和 messages 并列的 system="...",别放进数组。
ChatGPT 现在的 Custom Instructions 在哪?
头像菜单 -> Settings -> Personalization -> Custom instructions(打开 customization 开关)。Project 也会对里面每个对话带上它自己的指令。
把规则贴进每条 user message 行不行? 基本行,但既浪费又脆弱:你每轮都要为 preamble 付 token,而且贴进去的规则可能和你之前设过的 system prompt 静默矛盾。不如在持久通道里设一次。
system 规则一定压过 user message 吗?
通常会,但不是绝对。OpenAI 强制 platform > developer > user,所以 developer 指令压过用户。强弱因模型而异,所以关键规则务必用一条矛盾的 user message 测,并把规则留在持久通道里。
预防建议
- 默认:持久规则放 system / project / custom-instructions 通道;user message 只放本轮任务。
- 新对话发第一条 user message 之前,先设好持久通道。
- 定期审 project / custom instructions——过期规则会悄悄污染新任务。
- 团队工作流把 system prompt 和代码一起版本化。
- 想在 user message 里重打某条规则时,先反问:“这是不是该放进持久通道?”
- API agent 工作流里,把能力声明成 tools/functions,而不是 prose。