国庆节10月1日
--


大模型本身没有记忆,靠"会话历史滚雪球"实现多轮对话:messages 累积、*解包展开与上下文顺序

与 AI 大模型的交互本质是无状态的,每一次请求响应都是相互独立的,AI 大模型本身没有真正的会话记忆能力。
课程里的例子很直观:先问”12 个苹果,3 个人怎么均分”,得到”每人 4 个”;接着问”那 2 个人呢?“,模型却反问”你是指哪两个人呢?”
原因:第二次请求里只有”那 2 个人呢?”这一句话,服务端根本不知道前文。
1"messages": [2 { "role": "system", "content": "你是一名可爱的AI助手……" },3 { "role": "user", "content": "那2个人呢?" }4]把之前所有对话都塞进 messages 一起发过去,模型就”看起来记得”了。
1"messages": [2 { "role": "system", "content": "你是一名可爱的AI助手……" },3 { "role": "user", "content": "12个苹果,3个人怎么均分?" },4 { "role": "assistant", "content": "嘻嘻,12个苹果分给3个人,每个人可以分到 **4个苹果** 哦~" },5 { "role": "user", "content": "那2个人呢?" }6]这样模型就能正确回答”每人 6 个苹果”。每多聊一轮,这个列表就长一截,所以叫”滚雪球”。
1# 保存用户输入的提示词2st.session_state.messages.append({"role": "user", "content": prompt})3...4# 保存大模型返回的结果5st.session_state.messages.append({"role": "assistant", "content": full_response})必须把 assistant 的回复也存下来。只存用户的问题是不行的:模型看到的是”我问了 3 个问题”,却看不到自己答过什么,前后逻辑会断裂。
1response = client.chat.completions.create(2 model="deepseek-chat",3 messages=[4 {"role": "system", "content": system_prompt},5 *st.session_state.messages # 把历史消息一条条"摊开"接到后面6 ],7 stream=True8)| 写法 | 含义 |
|---|---|
[A, *B] | 列表解包:把 B 里的元素逐个展开,和 A 拼成一个新列表 |
| 结果 | [system消息, 历史user, 历史assistant, ..., 本轮user] |
system 消息必须放在最前面,且只放一条。它负责设定身份和行为准则,位置错了模型的行为约束会失效。
1messages[0] system 设定身份2messages[1] user 第1轮提问3messages[2] assistant 第1轮回答4messages[3] user 第2轮提问5...6最后一条 user 本轮提问(在调用前已经 append 进去)调用前先 append 用户的问题,所以列表最后一条正好是本轮提问,不用再单独拼一次。
| 问题 | 说明 |
|---|---|
| Token 越来越贵 | 每轮都要重发全部历史,Token 消耗随对话轮数增长 |
| 超出模型上下文上限 | 历史太长会超过模型的最大上下文长度,需要截断 |
常见的优化方向(超出本章范围,知道有这回事即可):只保留最近 N 轮对话、或者让模型把早期对话压缩成一段摘要。
这也解释了为什么”会话记忆”这件事必须由客户端负责:模型是无状态的,记忆只能由调用方保存并在每次请求时重新提交。本章后面的 会话管理 就是把这份历史存到文件里,实现”关掉网页也能接着聊”。
messages=[{"role": "system", ...}, *st.session_state.messages]*,作用是把列表里的元素逐个展开system 消息必须放在最前面,而且只放一条 2-1 模拟”滚雪球”
不接大模型:写一个函数 add(role, content) 往列表追加消息,然后模拟三轮对话(用户问 → 假设的 AI 答 → 用户再问),每一轮都把”这次要发给模型的完整消息列表”打印出来,亲眼看到历史是怎么累积的。
一级 · 思路:发出去的是”system + 全部历史 + 本轮提问”,历史就是那个越来越长的列表
二级 · 方法:列表 append + 列表拼接([system消息] + 历史列表)
三级 · 骨架:messages = [{"role": "system", "content": "……"}, ____history]
1history = []2
3def add(role, content):4 """往历史里追加一条消息"""5 history.append({"role": role, "content": content})6
7def messages_for(question):8 """本轮要发给模型的完整 messages:system 在最前,后面接全部历史 + 本轮提问"""9 return [{"role": "system", "content": "你是小甜甜"}] + history + [{"role": "user", "content": question}]10
11# 第一轮12print(messages_for("12个苹果,3个人怎么均分?"))13add("user", "12个苹果,3个人怎么均分?")14add("assistant", "每个人可以分到 4 个苹果")15
16# 第二轮:历史已经攒了 2 条17msgs = messages_for("那2个人呢?")18print(f"\n第二轮要发 {len(msgs)} 条:")19for m in msgs:20 print(" ", m["role"], ":", m["content"])21
22# 观察结论:同一个问题,轮次越靠后,发出去的消息条数越多 —— 这就是"滚雪球"2-2 给聊天页加上记忆 把基本交互那版改成带记忆的版本:每轮把用户问的和 AI 答的都存进消息列表,发请求时带上全部历史;然后测两轮有前后关系的问题,验证 AI 能接上话。
一级 · 思路:界面渲染用这份列表,发给模型也用这份列表——同一份数据
二级 · 方法:st.session_state.messages.append(...) 两次(user 一次、assistant 一次)
三级 · 骨架:messages=[{"role": "system", "content": system_prompt}, *st.session_state.messages]
1import os2import streamlit as st3from openai import OpenAI4
5st.set_page_config(page_title="AI智能伴侣", page_icon="🤖", layout="wide")6st.title("AI智能伴侣")7
8system_prompt = "你是一名非常可爱的AI助理, 你的名字叫小甜甜, 请你使用温柔可爱的语气回答用户的问题"9
10if "messages" not in st.session_state:11 st.session_state.messages = []12
13for message in st.session_state.messages:14 st.chat_message(message["role"]).write(message["content"])15
16client = OpenAI(api_key=os.environ.get("DEEPSEEK_API_KEY"), base_url="https://api.deepseek.com")17
18prompt = st.chat_input("请输入您要问的问题")19if prompt:20 st.chat_message("user").write(prompt)21 st.session_state.messages.append({"role": "user", "content": prompt})22
23 response = client.chat.completions.create(24 model="deepseek-chat",25 messages=[26 {"role": "system", "content": system_prompt},27 *st.session_state.messages, # 关键:把历史一条条摊开接在后面28 ],29 stream=False,30 )31 reply = response.choices[0].message.content32 st.chat_message("assistant").write(reply)33 st.session_state.messages.append({"role": "assistant", "content": reply})34
35# 验证:先问"12个苹果,3个人怎么均分",再问"那2个人呢" —— 这次 AI 能答对了如果你喜欢,那么欢迎来到我的世界!
了解更多暂未播放



"生活不是等待暴风雨过去,而是学会在雨中跳舞。"—— 塞维涅夫人


