在构建智能对话系统(Chatbot)、RAG(检索增强生成)或 Agent(智能体) 时,上下文记忆(Context Memory)
是核心能力之一。模型本身是无状态的,它不知道您上一句说了什么,除非您显式地将历史对话记录传递给它们。
OpenAI 兼容接口(如阿里云 DashScope)的
messages参数设计得非常巧妙,它是一个列表(List),天然支持传入多条历史消息。本文将演示如何通过维护这个列表,实现具备"记忆力"的多轮对话。
🧠 为什么需要历史消息?
大语言模型(LLM)本质上是基于概率预测下一个 token 的。如果没有历史信息,每一次请求对模型来说都是"初次见面"。
通过传入历史消息,我们可以实现:
- 指代消解:用户说"它多少钱?",模型知道"它"指的是上一轮提到的商品。
- 逻辑推理:用户先说"A有2个苹果",后说"B有3个苹果",最后问"一共几个?",模型能结合前文计算。
- 风格一致性:保持对话的人设和语气贯穿始终。
💡 核心机制:Messages 列表结构
messages 参数是一个字典列表,每个字典代表一条消息,包含 role(角色)和 content(内容)。
三种关键角色
| 角色 (Role) | 作用 | 示例场景 |
|---|---|---|
| system | 系统指令 。设定助手的行为准则、人设、回答风格。通常放在列表最开头,权重最高。 | "你是一个数学专家,回答要简洁。" |
| user | 用户输入。代表用户的提问、指令或提供的信息。 | "小明有2条狗。" |
| assistant | 助手回复。代表模型之前的回答。将其回填到列表中,相当于告诉模型:"刚才我是这么回答的"。 | "好的,记住了。" |
📌 关键点 :要实现多轮对话,只需将之前的
user提问和assistant回答按时间顺序依次加入messages列表即可。
📝 完整代码示例:多轮对话与逻辑推理
以下代码演示了一个经典的"累加推理"场景。我们将多轮对话历史硬编码在列表中,观察模型如何结合上下文回答问题。
python
import os
from openai import OpenAI
# 1. 初始化客户端
# 建议将 API Key 放入环境变量,避免硬编码在代码中
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 2. 构建包含历史上下文的 messages 列表
# 注意:这里模拟了三轮对话的历史记录
messages_history = [
# 第一轮:设定人设
{"role": "system", "content": "你是AI助理,回答很简洁。"},
# 第二轮:用户陈述事实 A
{"role": "user", "content": "小明有2条宠物狗"},
{"role": "assistant", "content": "好的"},
# 第三轮:用户陈述事实 B
{"role": "user", "content": "小红有3条宠物猫"},
{"role": "assistant", "content": "好的"},
# 第四轮:基于前文的事实进行提问
{"role": "user", "content": "共有多少条宠物狗?"}
# ⚠️ 注意:这里问的是"狗",模型需要忽略"猫"的信息
]
print("🤖 正在结合上下文思考...\n")
# 3. 调用模型 (开启流式输出以获得更好体验)
response = client.chat.completions.create(
model="qwen-plus", # 使用 qwen-plus 模型
messages=messages_history, # 传入完整的对话历史
stream=True # 开启流式输出
)
# 4. 处理流式结果
try:
for chunk in response:
# 提取增量内容并打印
if chunk.choices and len(chunk.choices) > 0 and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
print("\n\n✅ 回答结束")
except Exception as e:
print(f"\n❌ 发生错误:{e}")

🔍 代码运行逻辑解析
- System Prompt:首先告诉模型"回答要简洁",这会影响后续所有输出的风格。
- History Injection :
- 用户说"小明有2条狗" -> 模型回"好的"。
- 用户说"小红有3条猫" -> 模型回"好的"。
- 关键点 :我们将这两组问答都放入了
messages列表。
- Final Query :最后用户问"共有多少条宠物狗 ?"。
- 模型会扫描整个列表。
- 它发现第一条信息提到"2条狗"。
- 它发现第二条信息提到"3条猫"(与问题无关,忽略)。
- 结论:模型会回答"2条"。
🎯 测试建议:您可以尝试修改最后一句提问为"共有多少只宠物?",模型应该会回答"5只"(2狗+3猫),证明它真正理解了上下文。
🔄 进阶:如何在程序中动态维护历史消息?
上面的例子是静态的(写死的列表)。在实际的聊天机器人应用中,我们需要动态地往列表里添加消息。
简易聊天循环示例
python
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 初始化历史列表,只包含 System Prompt
conversation_history = [
{"role": "system", "content": "你是一个乐于助人的AI助手。"}
]
print("💬 开始聊天 (输入 'quit' 退出):")
while True:
# 1. 获取用户输入
user_input = input("👤 你: ")
if user_input.lower() == 'quit':
break
# 2. 将用户输入加入历史记录
conversation_history.append({"role": "user", "content": user_input})
# 3. 调用模型
try:
response = client.chat.completions.create(
model="qwen-plus",
messages=conversation_history, # 发送包含最新问题的完整历史
stream=True
)
print("🤖 AI: ", end="", flush=True)
full_response = ""
# 4. 流式接收并打印
for chunk in response:
if chunk.choices and len(chunk.choices) > 0 and chunk.choices[0].delta.content:
content = chunk.choices[0].delta.content
print(content, end="", flush=True)
full_response += content
print("\n") # 换行
# 5. 【重要】将模型的回答也加入历史记录,以便下一轮对话能引用
conversation_history.append({"role": "assistant", "content": full_response})
except Exception as e:
print(f"\n❌ 出错啦:{e}")
动态维护的关键点
- Append User : 每次用户说话后,立即
history.append({"role": "user", ...})。 - Call Model : 发送整个
history列表。 - Append Assistant : 收到模型回复后,必须
history.append({"role": "assistant", ...})。如果不做这一步,模型就会"失忆",不知道刚才自己说了什么。
⚠️ 注意事项与最佳实践
1. Token 长度限制
messages 列表不能无限增长。每个模型都有最大上下文窗口(Context Window),例如 8k, 32k, 128k tokens。
- 风险:如果列表太长,超过限制,API 会报错。
- 对策 :当对话过长时,需要实施滑动窗口策略 (只保留最近 N 轮对话)或摘要策略(用模型总结之前的对话)。
2. System Prompt 的位置
虽然大多数模型对位置不敏感,但最佳实践是将 system 角色始终放在列表的第一个位置,以确保指令的全局有效性。
3. 数据清洗
在将用户输入加入 messages 之前,最好进行简单的清洗(如去除多余空白、过滤敏感词),以保证上下文质量。
🚀 总结
通过灵活运用 messages 列表,我们可以赋予无状态的大模型以"记忆"。
- 基础用法 :按顺序填入
system,user,assistant消息。 - 核心价值:实现指代理解、逻辑推理和人设保持。
- 工程落地 :在代码中使用列表
append操作动态维护对话历史。
掌握这一技术,是开发 RAG 系统和自主 Agent 的基石。下一步,您可以尝试结合向量数据库,将外部知识库作为"长期记忆"注入到 messages 中!