智能体面试准备(十三):代码实例——带持久化记忆的 Agent,跨会话也不忘事

发布时间:2026/8/1 6:33:36

智能体面试准备(十三):代码实例——带持久化记忆的 Agent,跨会话也不忘事
智能体面试准备十三代码实例——带持久化记忆的 Agent跨会话也不忘事写在前面B12 我们手写了完整的 ReAct Agent但它有个致命短板记忆是活在内存里的。进程一关scratchpad 全没了——你下一轮问它我们刚才说到哪了它会一脸茫然。生产里的 Agent客服、个人助理、研发助手必须记得跨会话的偏好、历史与事实这就是持久化记忆Persistent Memory。本篇直接给一个完整可运行的实现把 B12 的 Agent 骨架接上三层持久化记忆短期会话 / 长期文件 / 向量召回用纯标准库 SQLite 做存储不依赖任何框架也不需要 API Key用 FakeLLM 跑通。读完你能直接把它当模板拼进自己的项目。一、为什么内存记忆不够维度内存记忆B12 版持久化记忆本篇生命周期进程存活期间跨进程、跨会话、跨天容量受上下文窗口限制可无限增长按需召回故障恢复进程崩即丢重启可恢复多用户一团混在一起按 user_id 隔离适用Demo / 单次任务生产 / 长期助理B6 讲过记忆的短期/长期/向量三层架构本篇把它落成代码短期当前会话窗口仍在内存快长期SQLite 落盘的关键事实向量语义召回历史。三者职责分明。二、完整实现# -*- coding: utf-8 -*- 带持久化记忆的 ReAct Agent纯标准库 sqlite完整可运行无需 API Key 架构B12 的 ReAct 主循环 三层记忆 - ShortTermMemory : 当前会话窗口内存带最大轮数 - LongTermMemory : SQLite 落盘的关键事实user 级跨会话 - VectorMemory : 极简 TF-IDF 向量召回历史对话演示语义检索 import re import json import sqlite3 import math from collections import Counter # ---------- 工具集 ---------- def search_tool(query: str) - str: 模拟外部搜索工具 return f[search] 关于「{query}」的检索结果...mock def calculator_tool(expr: str) - str: 安全计算仅允许数字与运算符 if re.fullmatch(r[\d\\-\*\/\(\)\.\s], expr): try: return str(eval(expr)) except Exception as e: return f计算错误: {e} return 非法表达式 TOOLS {search: search_tool, calculator: calculator_tool} # ---------- 三层记忆 ---------- class ShortTermMemory: 当前会话窗口最近 N 轮纯内存 def __init__(self, max_turns: int 6): self.max_turns max_turns self.buffer: list[dict] [] def add(self, role: str, content: str): self.buffer.append({role: role, content: content}) if len(self.buffer) self.max_turns * 2: self.buffer self.buffer[-self.max_turns * 2:] def context(self) - str: return \n.join(f{m[role]}: {m[content]} for m in self.buffer) class LongTermMemory: SQLite 落盘的关键事实按 user_id 隔离跨会话持久 def __init__(self, db_path: str agent_memory.db): self.conn sqlite3.connect(db_path, check_same_threadFalse) self.conn.execute( CREATE TABLE IF NOT EXISTS facts (user_id TEXT, key TEXT PRIMARY KEY, value TEXT, ts REAL) ) def upsert(self, user_id: str, key: str, value: str, ts: float): self.conn.execute( INSERT INTO facts(user_id,key,value,ts) VALUES(?,?,?,?) ON CONFLICT(key) DO UPDATE SET valueexcluded.value, tsexcluded.ts, (user_id, key, value, ts), ) def get(self, user_id: str, key: str): row self.conn.execute( SELECT value FROM facts WHERE user_id? AND key?, (user_id, key) ).fetchone() return row[0] if row else None def forget(self, user_id: str, key: str): self.conn.execute(DELETE FROM facts WHERE user_id? AND key?, (user_id, key)) def all(self, user_id: str) - dict: return {k: v for k, v in self.conn.execute( SELECT key,value FROM facts WHERE user_id?, (user_id,))} class VectorMemory: 极简 TF-IDF 语义召回演示从历史事件里找相关记忆 def __init__(self): self.docs: list[str] [] def add(self, text: str): self.docs.append(text) def _tfidf(self, text: str) - Counter: words re.findall(r\w, text.lower()) tf Counter(words) idf Counter() for d in self.docs: idf.update(set(re.findall(r\w, d.lower()))) N max(len(self.docs), 1) return Counter({w: (tf[w]) * math.log(N / (idf[w] or 1) 1) for w in tf}) def recall(self, query: str, top_k: int 2) - list[str]: if not self.docs: return [] qv self._tfidf(query) scored [] for d in self.docs: dv self._tfidf(d) dot sum(qv[w] * dv[w] for w in qv) norm math.sqrt(sum(v*v for v in qv.values())) * math.sqrt(sum(v*v for v in dv.values())) or 1 scored.append((dot / norm, d)) scored.sort(reverseTrue) return [d for _, d in scored[:top_k]] # ---------- FakeLLM让代码无需 API Key 也能跑通 ---------- class FakeLLM: 按脚本规则生成 Thought/Action演示完整闭环非真实推理 def __init__(self): self.round 0 def __call__(self, prompt: str) - str: self.round 1 # 第1轮决定调用工具 if 用户: 帮我算 in prompt and Observation not in prompt: return Thought: 用户要算一个数\nAction: calculator\nAction Input: 23*7 if 用户: 我记得 in prompt and Observation not in prompt: return Thought: 用户在告知偏好应写入长期记忆\nAction: remember\nAction Input: {key:name,value:吕博} # 其余轮次给出最终答案 return Thought: 已有足够信息\nFinal Answer: 已处理你的请求并完成记忆持久化。 # ---------- 持久化 Agent ---------- class PersistentAgent: def __init__(self, user_id: str u_default): self.user_id user_id self.stm ShortTermMemory() self.ltm LongTermMemory() self.vtm VectorMemory() self.llm FakeLLM() self.max_steps 5 self.tools dict(TOOLS) self.tools[remember] self._remember def _remember(self, payload: str) - str: try: obj json.loads(payload) self.ltm.upsert(self.user_id, obj[key], obj[value], 0.0) return f已记住 {obj[key]}{obj[value]} except Exception as e: return f记忆失败: {e} def _parse(self, text: str): m_act re.search(rAction:\s*(\w), text) m_inp re.search(rAction Input:\s*(.), text) action m_act.group(1) if m_act else None action_input m_inp.group(1).strip() if m_inp else return action, action_input def run(self, user_msg: str) - str: # 召回相关历史注入上下文向量记忆 recalled self.vtm.recall(user_msg) recalled_ctx \n.join(f[历史记忆] {r} for r in recalled) # 注入长期事实 long_ctx \n.join(f[已知事实] {k}{v} for k, v in self.ltm.all(self.user_id).items()) self.stm.add(user, user_msg) prompt f{long_ctx}\n{recalled_ctx}\n{self.stm.context()}\n for _ in range(self.max_steps): out self.llm(prompt) action, action_input self._parse(out) self.stm.add(assistant, out) if action Final Answer or Final Answer in out: return out.split(Final Answer:)[-1].strip() if action in self.tools: obs str(self.tools[action](action_input)) self.stm.add(observation, obs) self.vtm.add(fQ:{user_msg} A:{obs}) prompt f{long_ctx}\n{recalled_ctx}\n{self.stm.context()}\n return 达到最大步数未完成 if __name__ __main__: agent PersistentAgent(u_lvbo) print( 第1轮:, agent.run(帮我算一下 23*7)) print( 第2轮:, agent.run(我记得我叫吕博记住它)) print( 第3轮(新会话模拟,事实仍在):, agent.run(我叫什么名字))运行后会看到第 2 轮记住名字被写入 SQLite第 3 轮即使重新构造了上下文依然能从LongTermMemory读出吕博——这就是持久化。把agent_memory.db删了再跑第 3 轮记忆就没了正好演示落盘的意义。三、生产化升级清单从 demo 到生产这版还差六步和 B12 的清单一脉相承但补了记忆专属项记忆写入策略本例用显式remember工具写生产更常用反思式写入Agent 定期总结会话、抽取事实自动 upsert或用户确认后写入。召回质量TF-IDF 太弱换成真实 embedding 向量库faiss/pgvector并加相关性 时近性 重要性加权B6 给过公式。遗忘机制长期记忆要能forget、能过期TTL否则噪声累积。多用户隔离用user_id分区本例已体现生产还要加权限校验。一致性并发写入 SQLite 需事务/锁线上常用 Redis热 向量库语义 关系库事实三层。隐私与合规长期记忆可能存 PII要支持按用户删除GDPR/个保法这是下一组治理篇会展开的点。小结持久化记忆把 Agent 从一次性工具变成能长期相处的助理。三层职责短期走内存保速度、长期落盘保跨会话、向量做语义召回保相关性。本篇代码可直接当模板——把FakeLLM换成真实模型接口、SQLite换成你的存储栈即可。下一篇B14我们把 Agent 的手做得更标准用 MCP 协议把工具拆成独立的 client/server让 Agent 能即插即用地调用外部能力。

相关新闻

AI 与数据分析的融合拐点:为什么说 2026 下半年是关键窗口期

AI 与数据分析的融合拐点:为什么说 2026 下半年是关键窗口期

2026/8/1 6:33:36

AI 与数据分析的融合拐点:为什么说 2026 下半年是关键窗口期 一、数据正在说话:三个信号表明拐点已到 7 月我整理了行业里的一些关键数据和信号,指向一个结论:AI 与数据分析的融合正在从一个"有趣的想法"变成一个&quo…

数据架构决策 Checklist:每次选型前必须回答的 20 个问题

数据架构决策 Checklist:每次选型前必须回答的 20 个问题

2026/8/1 6:33:36

数据架构决策 Checklist:每次选型前必须回答的 20 个问题 一、选型焦虑是数据分析师的第一生产力杀手 "用 ClickHouse 还是 Doris?""上 Flink 做实时还是直接用 Spark Streaming?""湖仓一体要不要搞?搞…

三菱FX PLC编程口通讯协议解析与Python实战

三菱FX PLC编程口通讯协议解析与Python实战

2026/8/1 6:33:36

1. 项目概述:从“黑盒”到“白盒”的通讯探索在工业自动化领域,三菱FX系列PLC堪称常青树,以其稳定可靠、性价比高的特点,广泛应用于各类中小型设备控制。对于大多数电气工程师和程序员而言,使用GX Works2或GX Develope…

Deltafin项目:在M1 Max上运行2.8T参数大模型的技术突破

Deltafin项目:在M1 Max上运行2.8T参数大模型的技术突破

2026/8/1 7:43:39

最近在本地部署大模型时,我遇到了一个很有意思的现象:当大家都在追求更高参数、更大显存消耗的模型时,一个名为 Deltafin 的开源项目却能在 M1 Max 这样的消费级硬件上运行 2.8T 参数的 Kimi K3 模型,并且实现了 0.0687 token/s 的…

“一人公司”浪潮已至:一台AI电脑如何重构创业的最小单元

“一人公司”浪潮已至:一台AI电脑如何重构创业的最小单元

2026/8/1 7:43:39

2026年被业界称为“OPC元年”,“一人公司”(One-Person Company,OPC)正从极客圈的实验走向主流商业视野。支付公司Stripe的统计数据显示,其平台上营收超100万美元的单人运营企业数量,在2023年至2025年间翻了…

2026实测:6大宁波数学小升初机构横向对比

2026实测:6大宁波数学小升初机构横向对比

2026/8/1 7:43:39

在宁波,孩子的升学路线几乎从小学就开始铺排。镇海中学、效实中学、鄞州中学等一批重点高中的竞争早已前置到小升初阶段,家长对优质教育资源的焦虑也一年比一年具体——到底是选连锁品牌的标准化大班,还是扎根本土、懂宁波考情的本地机构&…

“自有CA”VS“多CA合作”:新规下电子签章合规认证怎么选?

“自有CA”VS“多CA合作”:新规下电子签章合规认证怎么选?

2026/8/1 7:43:39

2025至2026年,《电子印章管理办法》《电子认证业务规则规范》《电子认证服务使用密码管理办法》等新规密集落地,电子认证行业正式迈入“强监管、可审计”时代。新规的核心要求很明确:身份核验必须由CA机构直接执行,证书签发须与申…

C语言:顺序表详解

C语言:顺序表详解

2026/8/1 7:43:39

C语言:顺序表详解SeqList 连续内存里的线性表 从结构定义到动态扩容,一次讲透一、什么是顺序表线性表是n个相同类型元素的有序序列。顺序表是线性表最朴素的实现——用一段连续的内存依次存放元素。数组就是最简单的顺序表。但顺序表通常指"带容量…

STM32CubeMX + VSCode + Makefile/CMake:构建现代化嵌入式开发环境

STM32CubeMX + VSCode + Makefile/CMake:构建现代化嵌入式开发环境

2026/8/1 7:33:39

1. 从“IDE依赖”到“工具链自由”:为什么选择 CubeMX VSCode?如果你和我一样,是从51单片机、AVR,或者更早的Keil MDK-ARM时代一路走过来的嵌入式开发者,大概率会对那个“一个IDE包办一切”的模式又爱又恨。爱的是它开…

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

2026/7/30 9:53:22

目标:电脑作为RTSP 服务端,循环推送 H264/H265 视频流; RDK X5 通过 rtsp2display 拉流预览,完全不需要在开发板编译 live555。 提供两套成熟方案: ✅ 方案 A:FFmpeg(最简单,优先推…

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

2026/8/1 0:15:49

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

2026/8/1 4:47:48

说实话,提到PDF拆分再压缩,我真是被折腾得够呛。 上个月公司年度合同归档,一份300多页的PDF总合同,需要按年份拆分成三个独立文件,再分别压缩到10MB以内方便邮件发送各部门确认。我心想这还不简单?先找个海…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/1 0:03:03

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/1 0:03:03

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/1 0:03:03

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/1 0:03:03

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/1 0:03:03

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/1 0:03:03

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…