前端转agent-第一周【python】-05 Ollama+Qwen3实战:会话记忆实战

AI Agent 会话记忆:用 Ollama + Qwen3:0.6b 从零搭建带记忆的聊天机器人

习惯了 JavaScript/TypeScript 里的状态管理,那么 Python 里的 "Agent 记忆" 就是那个一直在用的 messages 数组。

今天我们跳过 Python 基础,直接用 Ollama 本地模型跑一个带会话记忆的聊天 Demo。

为什么 Agent 需要记忆?

大语言模型本身是无状态 的------每次 API 调用都是独立的,模型不记得你上一句说过什么。这就像你在前端写一个聊天应用,如果不把聊天记录存下来(比如放在 useState 里),每次发送消息时只发当前文本,对话就永远连不起来。

记忆 = 上下文窗口中的历史消息列表 。在 Python 里,它就是一个 list[dict],每个 dict 都有 rolecontent

python 复制代码
messages = [
    {"role": "user", "content": "我叫小明"},
    {"role": "assistant", "content": "你好小明!"},
]

是不是很像你在 TypeScript 里定义的 type Message = { role: 'user' | 'assistant'; content: string }

没错,思维模型完全一样,只是换成了 Python 的字典和列表。

准备环境:Ollama + Qwen3:0.6b

我们选用阿里通义千问的 0.6B 超小模型,完全可以在普通笔记本上跑。

确保你已经安装了 Ollama,然后拉取模型:

bash 复制代码
# 安装 Ollama (如果还没有)
# macOS / Linux: curl -fsSL https://ollama.com/install.sh | sh
# 或直接下载桌面版: https://ollama.com

ollama pull qwen3:0.6b

Python 需要安装 ollama 官方库:

bash 复制代码
pip install ollama

最简版:自带记忆的命令行聊天

先写一个不到 40 行的脚本,直观感受"把历史消息一股脑塞进去"的效果。

python 复制代码
# 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)
  • 可选:自动生成摘要(本次先做简单截断)
python 复制代码
# 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})

使用示例:

python 复制代码
# 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,大概会是这样:

typescript 复制代码
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 里我们用一个简单的类封装。

还能怎么增强?

  1. 摘要压缩:当对话过长时,调用模型把早期对话压缩成一段摘要,放进系统提示里,类似于"这是之前的对话要点:..."
  2. 持久化存储 :把 messages 存到 SQLite 或 JSON 文件里,就像前端的 localStorage
  3. 多用户记忆隔离 :用 session_id 作为 key,存储不同的消息列表,类似 Web 后端的 session。

用 Ollama 可以轻松实现这些,因为它的 Python 库封装了类似 OpenAI 的接口,只要专注管理好 messages 列表就行。

总结

  • Agent 记忆 = 消息历史列表,和你在前端管理聊天记录一样。
  • Python 中用 list[dict] 存储,每轮对话追加并传给 ollama.chat()
  • 实际项目需要控制历史长度(滑动窗口),甚至可以加入摘要。
  • Ollama + Qwen3:0.6b 让你在本地就能玩转带记忆的对话,0 成本,随便折腾。但是模型较小,不太智能。
相关推荐
前端一小卒1 小时前
我用 TypeScript 从零手写了一个 Claude Code,然后发现它的核心只有 30 行
前端·agent
大圣编程3 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang3 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆3 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜4 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞5 小时前
异步HttpModule的实现方式
java·服务器·前端
丹宇码农8 小时前
把 HLS 字幕玩出花:zwPlayer 如何让 M3U8 视频支持全文搜索、翻译与码率自适应
前端·javascript·音视频·hls·视频播放器
2501_943782358 小时前
【共创季稿事节】猜数字游戏:二分法思维与交互式反馈
前端·游戏·microsoft·harmonyos·鸿蒙·鸿蒙系统
GV191rLvq8 小时前
基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
服务器·前端·asp.net