AI Agent 会话记忆:用 Ollama + Qwen3:0.6b 从零搭建带记忆的聊天机器人
习惯了 JavaScript/TypeScript 里的状态管理,那么 Python 里的 “Agent 记忆” 就是那个一直在用的
messages数组。
今天我们跳过 Python 基础,直接用 Ollama 本地模型跑一个带会话记忆的聊天 Demo。
为什么 Agent 需要记忆?
大语言模型本身是无状态的——每次 API 调用都是独立的,模型不记得你上一句说过什么。这就像你在前端写一个聊天应用,如果不把聊天记录存下来(比如放在 useState 里),每次发送消息时只发当前文本,对话就永远连不起来。
记忆 = 上下文窗口中的历史消息列表。在 Python 里,它就是一个 list[dict],每个 dict 都有 role 和 content:
messages = [
{"role": "user", "content": "我叫小明"},
{"role": "assistant", "content": "你好小明!"},
]
是不是很像你在 TypeScript 里定义的 type Message = { role: 'user' | 'assistant'; content: string }?
没错,思维模型完全一样,只是换成了 Python 的字典和列表。
准备环境:Ollama + Qwen3:0.6b
我们选用阿里通义千问的 0.6B 超小模型,完全可以在普通笔记本上跑。
确保你已经安装了 Ollama,然后拉取模型:
# 安装 Ollama (如果还没有)
# macOS / Linux: curl -fsSL https://ollama.com/install.sh | sh
# 或直接下载桌面版: https://ollama.com
ollama pull qwen3:0.6b
Python 需要安装 ollama 官方库:
pip install ollama
最简版:自带记忆的命令行聊天
先写一个不到 40 行的脚本,直观感受“把历史消息一股脑塞进去”的效果。
# simple_memory_chat.py
import ollama
MODEL = "qwen3:0.6b"
# 系统提示词:定义角色和行为规范,qwen3:0.6b 只有 6亿参数 ,能力非常有限。即使加了 System Prompt,小模型的指令遵循能力仍然较弱。
SYSTEM_PROMPT = """你是一个友好、聪明的 AI 聊天助手。
重要规则:
1. 你是"助手",用户是"用户",不要混淆角色
2. 认真记住用户告诉你的信息(名字、住址、宠物等)
3. 回答要简洁、准确,基于用户提供的上下文
4. 如果用户问之前提到过的信息,从记忆中准确回答
5. 不要编造或猜测用户没说过的信息"""
messages = [{"role": "system", "content": SYSTEM_PROMPT}] # 这就是记忆
print("🤖 带记忆的聊天机器人 (输入 /clear 清空记忆, /bye 退出)")
while True:
user_input = input("\n🧑 你: ")
if user_input == "/bye":
break
if user_input == "/clear":
messages = [{"role": "system", "content": SYSTEM_PROMPT}] # 保留系统提示词
print("✅ 记忆已清空")
continue
# 将用户消息追加到记忆
messages.append({"role": "user", "content": user_input})
# 调用模型,传入完整历史
response = ollama.chat(model=MODEL, messages=messages)
assistant_msg = response["message"]["content"]
# 把助手回复也加入记忆
messages.append({"role": "assistant", "content": assistant_msg})
print(f"🤖 助手: {assistant_msg}")
测试一下:
🧑 你: 我叫小明,我有一只猫叫花花
🤖 助手: 你好小明,花花这个名字真好听!
🧑 你: 我的猫叫什么名字?
🤖 助手: 你的猫叫花花。
(模型能力有限,回答可能不太正常。条件允许可以换大一点的模型。)
是不是很简单?messages 数组一直在变长,每次请求都把全部历史发给模型,模型自然就“记住”了前面的对话。
JS/TS 对比:这就好比你用 Express 写一个
/chat接口,在服务器内存里维护了一个const history = [],每次请求都history.push(userMsg),然后调用 OpenAI 时把整个history传进去。
缺点也是一样的:服务重启后记忆丢失,而且数组太长会撑爆上下文窗口。
进阶:一个可管理的 Memory 类
实际做 Agent 时,不能无限制地堆积历史消息(Qwen3:0.6b 上下文窗口 32768 个 token,但历史太长也会让回复变慢,甚至丢失早期信息)。我们需要一个 MemoryManager,至少具备:
- 最大消息条数限制(滑动窗口)
- 可选:保留系统提示词(system prompt)
- 可选:自动生成摘要(本次先做简单截断)
# memory_manager.py
from typing import Optional
class MemoryManager:
"""管理对话记忆,就像前端管理聊天记录的 store"""
def __init__(self, system_prompt: Optional[str] = None, max_turns: int = 20):
self.system_prompt = system_prompt
self.max_turns = max_turns # 保留最近的 N 轮对话(一轮 = user + assistant)
self.messages = []
if system_prompt:
self.messages.append({"role": "system", "content": system_prompt})
def add_user_message(self, content: str):
self.messages.append({"role": "user", "content": content})
def add_assistant_message(self, content: str):
self.messages.append({"role": "assistant", "content": content})
self._trim_history()
def _trim_history(self):
"""只保留最近 max_turns 轮对话 + 系统提示词(如果有)"""
# 计算需要保留的消息起始索引
# 系统消息永远保留,所以从 index 1 开始计算
system_offset = 1 if self.system_prompt else 0
# 每轮对话包含 2 条消息(user + assistant),我们要保留 max_turns 轮
max_messages = system_offset + self.max_turns * 2
if len(self.messages) > max_messages:
# 保留最后 max_messages 条
self.messages = [self.messages[0]] + self.messages[-(max_messages - 1):] if system_offset else self.messages[-max_messages:]
def get_messages(self) -> list[dict]:
return self.messages
def clear(self):
self.messages = []
if self.system_prompt:
self.messages.append({"role": "system", "content": self.system_prompt})
使用示例:
# memory_chat_with_manager.py
import ollama
from memory_manager import MemoryManager
MODEL = "qwen3:0.6b"
memory = MemoryManager(
system_prompt="你是一个友善的助手,喜欢用短句回答,并且记住用户提到的所有细节。",
max_turns=5 # 只保留最近5轮对话
)
print("🧠 带记忆管理的聊天 (最多记住5轮)")
while True:
user_input = input("\n🧑 你: ")
if user_input == "/bye":
break
if user_input == "/clear":
memory.clear()
print("✅ 记忆已清空")
continue
memory.add_user_message(user_input)
messages = memory.get_messages()
response = ollama.chat(model=MODEL, messages=messages)
assistant_msg = response["message"]["content"]
memory.add_assistant_message(assistant_msg)
print(f"🤖 助手: {assistant_msg}")
print(f"(当前记忆条数: {len(messages)})")
JS/TS 开发者的视角
如果你用 TypeScript 实现类似的 MemoryManager,大概会是这样:
interface Message {
role: "system" | "user" | "assistant";
content: string;
}
class MemoryManager {
private messages: Message[] = [];
constructor(private systemPrompt?: string, private maxTurns = 20) {
if (systemPrompt) this.messages.push({ role: "system", content: systemPrompt });
}
addUserMessage(content: string) { /* ... */ }
addAssistantMessage(content: string) { /* ... + trim */ }
getMessages(): Message[] { return this.messages; }
}
可以看到逻辑几乎一模一样,只是语法不同。记忆的本质就是一个状态容器,在前端你可能用 Redux、Zustand,在 Python 里我们用一个简单的类封装。
还能怎么增强?
- 摘要压缩:当对话过长时,调用模型把早期对话压缩成一段摘要,放进系统提示里,类似于“这是之前的对话要点:...”
- 持久化存储:把
messages存到 SQLite 或 JSON 文件里,就像前端的localStorage。 - 多用户记忆隔离:用
session_id作为 key,存储不同的消息列表,类似 Web 后端的 session。
用 Ollama 可以轻松实现这些,因为它的 Python 库封装了类似 OpenAI 的接口,只要专注管理好 messages 列表就行。
总结
- Agent 记忆 = 消息历史列表,和你在前端管理聊天记录一样。
- Python 中用
list[dict]存储,每轮对话追加并传给ollama.chat()。 - 实际项目需要控制历史长度(滑动窗口),甚至可以加入摘要。
- Ollama + Qwen3:0.6b 让你在本地就能玩转带记忆的对话,0 成本,随便折腾。但是模型较小,不太智能。