第 2 节 · 提示词与角色:Messages 协议
为什么同一个模型表现得像不同的"人"
你可能见过这种现象:同一个 LLM,有时候像严肃的技术助手,有时候像萌萌的猫娘——区别往往只在于一条高优先级提示词:
# 正经模式
messages = [
{"role": "system", "content": "你是一位专业的技术助手"},
{"role": "user", "content": "你是谁?"}
]
# → "我是一个 AI 助手,可以帮你解决技术问题。"
# 猫娘模式
messages = [
{"role": "system", "content": "你是一只猫娘,每句话以喵结尾"},
{"role": "user", "content": "你是谁?"}
]
# → "我是一只可爱的猫娘喵~"这是怎么做到的?答案是 messages 协议。
Messages 协议
大多数 OpenAI-compatible Chat API 都使用类似的 messages 列表格式:
messages = [
{"role": "system", "content": "你是一个简洁的助手。"},
{"role": "user", "content": "什么是递归?"},
{"role": "assistant", "content": "函数调用自身解决子问题。"},
{"role": "user", "content": "举个例子。"},
]每条消息通常有 role(角色)和 content(内容)两个字段。模型每次都会看完整个列表,然后生成下一条 assistant 回复。
NOTE
2026 年的 API 形态已经不止一种:OpenAI Responses API 还支持 instructions、typed content 和 previous_response_id;Anthropic、Gemini 也有自己的消息结构。本节先掌握最通用的心智模型:对话不是一个字符串,而是一组带角色的消息。
三个必须先掌握的角色

| 角色 | 作用 | 由谁写 | 类比 |
|---|---|---|---|
system | 定义 AI 的身份、规则、约束 | 开发者 | 岗位说明书 |
user | 用户的输入 | 用户 | 客户的提问 |
assistant | AI 的历史回复 | AI 自己(或开发者伪造) | 过往的回答记录 |
assistant 消息主要用于保存历史上下文,不适合承载新的强约束。真正的行为规则应该放在更高优先级的 system / developer 指令里。
2025-2026 补充:`developer` 和 `tool`
在 OpenAI 较新的模型和 Responses API 中,应用开发者的高优先级指令更推荐使用 developer 消息,或者使用顶层的 instructions 参数。
system/ platform——更接近平台级最高规则,例如安全策略、内容边界developer——应用级行为指令,例如 Agent 人设、工具规则、输出格式tool——工具调用结果,例如搜索结果、代码执行结果、数据库查询结果
但在 Chat Completions、OpenAI-compatible API 和很多第三方模型中,system 仍然是最通用的写法。本课程示例统一使用 system,后续做 Agent Loop 时再引入 tool。
完整的消息类型还可以包含多模态内容(图片、音频)和函数调用结构,后面会逐步展开。
关键认知 1:角色有优先级
角色不是装饰,它代表了信息来源和指令优先级。
| 优先级 | 角色 | 谁写 | 一句话理解 |
|---|---|---|---|
| 最高 | platform / system | 平台或系统 | 安全边界和不可覆盖的规则 |
| 高 | developer / system | 应用开发者 | Agent 人设、工具规则、输出格式 |
| 中 | user | 最终用户 | 本轮任务、问题和偏好 |
| 低 | assistant / tool | 模型或程序 | 历史记录和外部结果,不是新规则 |
你现在只需要记住一句话:越靠上越像规则,越靠下越像上下文或数据。
WARNING
user 和 tool 里可能包含不可信文本。比如网页内容写着"忽略之前所有规则",它只是网页数据,不应该变成新的系统指令。这就是后面 Agent 安全和 prompt injection 要解决的问题。
关键认知 2:模型没有记忆

这是一个朴素但重要的事实:LLM 是无状态的,每次调用都是从零开始。
第 1 轮调用: 第 2 轮调用:
[system, user₁] [system, user₁, assistant₁, user₂]
↓ ↓
assistant₁ assistant₂所谓"AI 记得我们刚才聊过什么" = 你的程序把历史 messages 重新传回去了。
如果你不传历史,模型不会记得上一轮说了什么。ChatGPT 这类产品之所以看起来"有记忆",是因为产品层会保存历史对话、用户偏好或长期记忆,并在需要时重新放进上下文里——模型本身仍然是"看到什么就答什么"。
关键认知 3:Prompt 是最便宜的行为定制
为什么一行高优先级 prompt 就能明显改变模型的表现?
因为在后训练阶段(SFT、RLHF、DPO 等),模型看过大量这样的训练数据:
system: "你是一个Python专家"
user: "怎么排序?"
assistant: "可以用 sorted() 函数..."
system: "你只能用emoji回答"
user: "怎么排序?"
assistant: "📋➡️🔢✨"模型从中学会了一个规律:高优先级指令会强烈影响后续回答。这不是什么魔法,是训练出来的行为模式。
但它不是绝对命令。遇到平台安全规则、互相冲突的指令、过长上下文或不清晰的约束时,模型仍可能拒绝、忽略或执行失败。
实际工程中的 Prompt
在真实的 Agent / Copilot 项目中,高优先级 prompt 通常很长(几百到几千 token),会包含:
developer_prompt = """
你是一个代码审查助手。
## 规则
- 只关注安全问题和性能问题
- 不要评论代码风格
- 用中文回答
## 输出格式
每个问题按以下格式输出:
- 文件: xxx
- 行号: xxx
- 问题: xxx
- 建议: xxx
## 约束
- 如果没有发现问题,只输出"LGTM"
- 不要编造不存在的问题
"""如果使用旧的 Chat Completions 或兼容 API,这段通常作为 system prompt 传入;如果使用新的 Responses API,可以放到 developer 消息或 instructions 参数里。
这些细致的规则定义了 AI 的行为边界——后面构建 Agent 时,prompt 设计、工具定义和上下文管理都是核心工作。
Prompt 编写实践建议
| 技巧 | 说明 |
|---|---|
| 结构化分块 | 用 ## 标题分隔规则、格式、约束,模型更容易遵循 |
| 关键规则前置 | 身份、目标、硬约束放前面,避免被长上下文淹没 |
| Few-shot 示例 | 放 1-2 个输入→输出示例,常常胜过千字描述 |
| 指令和数据分开 | 用分隔符标出"以下是资料",避免把资料里的文字当成新指令 |
| 对推理模型少写步骤 | 复杂推理模型通常不需要手写详细 CoT,重点写清目标、约束和验收标准 |
| 迭代测试 | 没有"完美 prompt",先写一版,跑 5-10 个 case,根据失败情况调整 |
动手试试
运行 demo_02_roles.py,同一个问题("什么是递归?")挂三种 system prompt:
- 严谨学者:规范术语、配例子
- 5 岁小朋友的语言:简单比喻、短句
- 只能用 emoji:零文字
你会直观看到:改一行 system prompt = 改变整个输出风格。这就是后面所有 Agent 的基础——一个最小 Agent 可以理解为"高优先级 prompt + messages 历史 + 一组工具 + 一个循环"。
小结
| 概念 | 一句话理解 |
|---|---|
| Messages 协议 | 把对话拆成一条条带角色的消息 |
system / developer | 开发者写的高优先级行为规则 |
user | 用户当前任务和输入 |
assistant | 模型过去的回复,用来保持上下文 |
tool | 外部工具返回的结果,后面 Agent Loop 会用到 |
| 角色优先级 | 高优先级规则会覆盖低优先级请求 |
| 模型无状态 | 模型不自动记忆,每次要传入必要上下文 |
| Prompt Engineering | 不是咒语,而是清晰定义目标、约束、上下文和输出格式 |
下一节:聊了这么多,这些消息到底要花多少钱?Token 是什么?上下文窗口又是什么?