跳转到内容

第 2 节 · 提示词与角色:Messages 协议

为什么同一个模型表现得像不同的"人"

你可能见过这种现象:同一个 LLM,有时候像严肃的技术助手,有时候像萌萌的猫娘——区别往往只在于一条高优先级提示词

python
# 正经模式
messages = [
    {"role": "system", "content": "你是一位专业的技术助手"},
    {"role": "user", "content": "你是谁?"}
]
# → "我是一个 AI 助手,可以帮你解决技术问题。"

# 猫娘模式
messages = [
    {"role": "system", "content": "你是一只猫娘,每句话以喵结尾"},
    {"role": "user", "content": "你是谁?"}
]
# → "我是一只可爱的猫娘喵~"

这是怎么做到的?答案是 messages 协议

Messages 协议

大多数 OpenAI-compatible Chat API 都使用类似的 messages 列表格式:

python
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 是身份说明书 / User 提问 / Assistant 回答

角色作用由谁写类比
system定义 AI 的身份、规则、约束开发者岗位说明书
user用户的输入用户客户的提问
assistantAI 的历史回复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

usertool 里可能包含不可信文本。比如网页内容写着"忽略之前所有规则",它只是网页数据,不应该变成新的系统指令。这就是后面 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),会包含:

python
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:

  1. 严谨学者:规范术语、配例子
  2. 5 岁小朋友的语言:简单比喻、短句
  3. 只能用 emoji:零文字

你会直观看到:改一行 system prompt = 改变整个输出风格。这就是后面所有 Agent 的基础——一个最小 Agent 可以理解为"高优先级 prompt + messages 历史 + 一组工具 + 一个循环"。

小结

概念一句话理解
Messages 协议把对话拆成一条条带角色的消息
system / developer开发者写的高优先级行为规则
user用户当前任务和输入
assistant模型过去的回复,用来保持上下文
tool外部工具返回的结果,后面 Agent Loop 会用到
角色优先级高优先级规则会覆盖低优先级请求
模型无状态模型不自动记忆,每次要传入必要上下文
Prompt Engineering不是咒语,而是清晰定义目标、约束、上下文和输出格式

下一节:聊了这么多,这些消息到底要花多少钱?Token 是什么?上下文窗口又是什么?

Released under the MIT License.