摘要 :智能体要在多轮对话中保持连贯、在跨会话中记住用户偏好与关键信息,离不开记忆管理 。本章围绕一个完整的「中介留学咨询智能办理」案例展开,刻意不依赖任何 LangGraph Memory 模块 ,而是用最普通的工程手段------history 参数、SQLite 数据库和本地 Markdown 文件------来实现一套与 OpenClaw Memory 思路高度相似的三层记忆体系:短期记忆:当前会话的对话历史与槽位状态;中期记忆:按日记录的槽位变更日志;长期记忆:机构规则与经验沉淀在 MEMORY.md 中,并在前端可视化编辑。在后文中,我们还会引入 OpenClaw 的 Memory 设计(Short-Term / Daily Logs / MEMORY.md + Hybrid Search),并给出与本章实现的结构映射与差异对照,帮助你在自建项目时,既理解 LangGraph 的 State + Checkpointer / Store 方案,又能借鉴 OpenClaw 在记忆运营与维护上的最佳实践。
关键词:记忆管理;短期记忆;长期记忆;SQLite;三层记忆;每日日志;MEMORY.md;OpenClaw;Hybrid Search
1 为什么智能体需要记忆?
想象一位助手:若每次见面都像第一次见面,你需要反复介绍自己、重复偏好、重复项目背景,体验会非常糟糕。智能体同样如此:若没有记忆,每次请求都从零开始,无法维持对话连贯性,也无法在多次交互中学习与个性化。
记忆管理要解决两类需求:
- 当前会话内的连贯:刚说过的话、上一条回复、本轮的中间结果,都要在「当前这一条对话线」里可用。
- 跨会话的持久与召回:用户偏好、历史决策、项目关键信息等,要在不同会话、甚至不同线程间被检索并注入当前上下文。
前者对应短期(上下文)记忆 ,后者对应长期(持久)记忆。二者结合,智能体才能既「记得本轮在聊什么」,又「记得用户是谁、以前做过什么决定」。
💡 理解要点 :记忆 = 短期(会话内 state + 持久化) + 长期(跨会话、可检索的存储) ;LangGraph 用 checkpointer 管短期、用 Store 管长期。
2 短期记忆与长期记忆的区分
| 维度 | 短期记忆(上下文记忆) | 长期记忆(持久记忆) |
|---|---|---|
| 作用范围 | 单一线程/会话内 | 跨会话、跨线程,可按用户/应用组织 |
| 典型内容 | 当前对话消息、本轮的中间状态 | 用户画像、偏好、历史决策、事实与经验 |
| 容量与限制 | 受 LLM 上下文窗口限制,需做裁剪/摘要 | 外部存储,容量大,通过检索按需注入 |
| 在本章 Demo 中 | Gradio 传入的 history + SQLite 中的 slots_info_dict |
本地 Markdown 文件(MEMORY.md + 每日日志),按需人工或程序检索 |
在「纯工程实现」里,短期记忆本质上就是「当前会话可见的状态」:通常包括前端传入的 history(上一轮对话消息列表)和后端从数据库中恢复的结构化槽位。我们可以在进入 LLM 之前对 history 做截断(例如只保留最近 N 轮),再把当前轮用户输入 append 上去,构造出这一轮调用所需的上下文。\n\n长期记忆则往往存放在图外部的可检索存储 里:可以是关系型数据库、KV 存储,或像本章一样直接用 Markdown 文件(MEMORY.md)承载规则和经验;真正「记忆」的是这些持久文件或表,而在对话中只是在需要时读出来,拼进 prompt 再调用模型。
🔍 实际例子:用户在第一轮说「请记住我喜欢用暗色主题」;短期记忆里会有这条消息和助手的回复;若同时把「用户偏好:暗色主题」写入 Store 的长期记忆,下一周在新会话里问「根据我的偏好推荐一个 IDE 设置」,智能体可以从 Store 检索到该偏好并回答。
3 本章 Demo 项目:中介留学咨询智能办理
本章使用的 Demo 项目是一个中介留学咨询售前机器人,目标是在官网/小程序中自动完成「售前接待 + 信息引导收集」,替代人工客服,降低运营成本。典型业务场景是:
- 家长或学生发来一句自然语言问题(如「想去英国读博士」);
- 机器人主动引导,围绕 六大主题 有序地收集关键信息:
- 留学目标与意向(目标院校、学位类型);
- 学业背景(当前学校、GPA);
- 专业与职业规划(目标专业、留学目的);
- 经济与预算(学费预算、生活费预算);
- 奖学金需求;
- 用户补充说明。
在产品体验上有三个要求:
- 主动引导:机器人能根据缺失信息自动追问,而不是被动回答;
- 按主题推进:每次围绕一个主题的所有子问题展开,收集完再总结并开启下一主题;
- 灵活对话:用户可以一次说多个主题的信息(如院校 + 学位 + 当前学校 + GPA),系统也能正确抽取并更新槽位。
核心方案:一次 LLM + 策略编排。这个 Demo 的核心设计是:
-
一次 LLM 调用完成槽位抽取:
- 每一轮仅调用一次大模型,使用 Function Calling 把用户输入中的信息抽到预定义的槽位结构中(如
intention_school、academic_degree等); - 是否继续追问、追问哪些槽位、如何总结当前主题,都不再让 LLM 来"自由发挥",而是由纯逻辑和模版控制。
- 每一轮仅调用一次大模型,使用 Function Calling 把用户输入中的信息抽到预定义的槽位结构中(如
-
策略编排层负责「总结 + 追问」:
- 使用
get_next_message_by_slots遍历当前filled_slots,找出第一个还有缺失槽位的主题,并返回:next_collect_slot_list:下一轮要收集的槽位列表;is_all_field_missing:当前主题是否一个槽位都没填;theme:当前主题函数名(如get_academic_info)。
- 根据缺失情况决定:
- 若当前主题完全没填 → 使用
main_question_schema[theme]里的整句标准话术发问; - 若部分已填 → 使用
params_schema中的中文槽位名拼出「还缺哪些信息」的追问话术; - 若当前主题已填完且还有下一个主题 → 调用
FunctionCallSummaryConfig对本主题做总结,并开启下一个主题; - 若全部主题都填满 → 用
final_message_template生成结束语。
- 若当前主题完全没填 → 使用
- 使用
-
槽位持久化与跨会话恢复:
- 所有槽位信息以 JSON 字符串的形式保存在本地 SQLite 数据库
consult.db的slot_info_table中,键为group_id; - 用户再次进入时,只要带上同一个
group_id,系统就能从数据库中读出上次的槽位进度,继续推进后续主题。
- 所有槽位信息以 JSON 字符串的形式保存在本地 SQLite 数据库
这套架构的优势是:
- 高效:每轮只调用一次 LLM,不做「总结 + 追问」的第二次调用;
- 可控:总结与追问完全由模板和逻辑驱动,避免 LLM 临场发挥导致流程跑飞;
- 稳定:槽位持久化在 SQLite 中,跨会话连续性和一致性有保障。
4 基于案例的三层记忆设计
在中介留学咨询这个业务场景中,我们希望不仅能在一轮对话内保持连贯 ,还能按天回看发生了什么 ,并逐渐沉淀出一份跨会话可复用的"经验库"。为此,本章在原方案上叠加了一套三层记忆 + 文件为源的设计,与 LangGraph 的「state + checkpointer / store」形成互补。
4.1 三层结构与对应代码
| 层级 | 对应物 | 持久化与范围 | 主要代码位置 |
|---|---|---|---|
| 短期 | 当前会话对话 + 槽位状态 | 单次会话,受上下文窗口限制 | chat_process_client.py / main.py / memory_file_utils.py |
| 中期 | 每日日志(每日槽位变更摘要) | memory_files/memory/YYYY-MM-DD.md |
memory_file_utils.append_daily_log |
| 长期 | 精选记忆(规则、经验、画像等) | memory_files/MEMORY.md |
memory_file_utils.load_memory_md/save_memory_md |
下面分别说明三层记忆在代码中的具体实现方式。
4.2 短期记忆:当前会话上下文 + 槽位状态
短期记忆的来源有三部分:
-
LLM 调用上下文(传给大模型的 history)
在
chat_process_client.chat_round中,函数签名为:pythonasync def chat_round( current_message: str, history: List[Dict[str, str]], group_id: str = "12", slot_info_out: Optional[Dict[str, Any]] = None, ) -> AsyncGenerator[str, None]:history是上一轮 Gradio 传入的消息列表,元素形如:
{"role": "user"|"assistant", "content": "..."};- 为避免上下文过长,只保留最近
MAX_SHORT_TERM_ROUNDS轮问答:
pythonMAX_SHORT_TERM_ROUNDS = 5 trimmed_history = history[-2 * MAX_SHORT_TERM_ROUNDS :] \ if len(history) > 2 * MAX_SHORT_TERM_ROUNDS else list(history) new_history_list: List[Dict[str, str]] = [] new_history_list.append({"role": "system", "content": SYSTEM_PROMPT}) new_history_list.extend(trimmed_history) new_history_list.append({"role": "user", "content": current_message})- 这部分就是传给 DeepSeek 模型的短期上下文。
-
槽位状态(结构化短期记忆)
-
每次进入
chat_round,都会从 SQLite 中读取当前group_id的槽位:pythonpast_records = await Read_SlotInfo(db_client, table_name=config.slot_table_name, group_id=group_id) if past_records: all_filled_slots = copy.deepcopy(json.loads(past_record["slots_info_dict"])) all_filled_slots = sort_nested_dict(input_dict=all_filled_slots) else: all_filled_slots = copy.deepcopy(tool_config_instance.slot_dict) # 首次对话时插入空槽位记录 await insert_SlotInfo(...) -
all_filled_slots的结构大致为:python{ "get_academic_info": {"intention_school": "英国", "academic_degree": "博士"}, "get_major_info": {"current_school": "某大学", "gpa_point": "3.5"}, ... } -
chat_round会把最新的all_filled_slots写入slot_info_out["slots"],供前端展示:pythondef _emit_slots() -> None: if slot_info_out is not None: slot_info_out["slots"] = copy.deepcopy(all_filled_slots) -
前端
main.py中的slot_display使用_format_slots_as_markdown(all_filled_slots)将其渲染为 Markdown 表格,作为短期记忆的结构化视图。
-
-
短期记忆快照文件(人类可读)
-
为了方便调试与教学,本项目还会将当前会话的完整 history 写入 Markdown 文件:
pythonfrom memory_file_utils import save_short_term_history # 在 chat_round 读取完 all_filled_slots 后调用 save_short_term_history(group_id=group_id, history=history) -
在
memory_file_utils.py中:pythondef save_short_term_history(group_id: str, history: List[Dict[str, str]]) -> str: path = _SHORT_TERM_DIR / f"{group_id}.md" lines = [f"# 短期记忆快照(group_id: {group_id})\n"] for msg in history or []: role = msg.get("role", "") content = str(msg.get("content", "") or "").strip() ... if role == "user": lines.append(f"**[用户]** {content}\n") elif role == "assistant": lines.append(f"**[助手]** {content}\n") path.write_text("\n".join(lines), encoding="utf-8") -
这些文件保存在
memory_files/short_term/{group_id}.md,在 Gradio 的「记忆可视化」Tab 中以只读形式展示。
-
⚠️ 注意 :真正传给 LLM 的短期记忆是 trimmed_history + current_message,而 short_term/*.md 更偏向「人类审计」用途。
4.3 中期记忆:每日日志(Daily Logs)
中期记忆用来回答「这几天我们都聊了什么、填了哪些信息」,在代码中通过 memory_files/memory/YYYY-MM-DD.md 实现。
-
写入时机:槽位有实质更新后
在
chat_round中,当 Function Calling 导致某些槽位发生变化时,会设置is_slot_changed = True并更新all_filled_slots。更新完成、写回 SQLite 后,会调用:pythonif is_slot_changed: summary_for_log = whole_function_response.strip() or current_round_slots_info.strip() append_daily_log(group_id=group_id, slots=all_filled_slots, summary=summary_for_log)whole_function_response:本轮函数调用的自然语言总结(如「目标院校:UCLA 攻读学位:博士生」);current_round_slots_info:本轮新增或更改的槽位信息。
-
具体写入逻辑
memory_file_utils.append_daily_log的实现如下:pythondef append_daily_log(group_id: str, slots: Dict[str, Dict[str, str]], summary: str) -> str: today = date.today() path = _DAILY_DIR / f"{today.isoformat()}.md" if not path.exists(): path.write_text(f"# {today.isoformat()}\n\n", encoding="utf-8") with path.open("a", encoding="utf-8") as f: ts = datetime.now().strftime("%H:%M") f.write(f"## {ts} - group_id: {group_id}\n") if summary.strip(): f.write(f"槽位摘要:{summary.strip()}\n") slots_json = json.dumps(slots, ensure_ascii=False) f.write(f"原始槽位:`{slots_json}`\n\n") return str(path)- 每天一个文件,例如
memory_files/memory/2026-03-16.md; - 每次槽位更新会追加一个小节,包含时间戳、group_id、本轮摘要、完整槽位 JSON。
- 每天一个文件,例如
-
前端展示
-
在「记忆可视化(三层)」Tab 中,
mid_term_display会调用:pythonmid_term_display = gr.Markdown(value=load_daily_logs(), label="最近几天的每日日志") -
load_daily_logs(days=3)会合并最近 3 天的 daily log,以 Markdown 形式展示所有条目。
-
4.4 长期记忆:MEMORY.md(语义知识与经验)
长期记忆使用 memory_files/MEMORY.md 承载,更偏向于规则 / 经验 / 机构画像,而不是具体对话细节。
-
文件结构与代码接口
-
文件路径:
demo_codes/memory_files/MEMORY.md; -
在
memory_file_utils.py中:pythondef load_memory_md() -> str: _ensure_dirs() return _MEMORY_MD.read_text(encoding="utf-8") if _MEMORY_MD.exists() else "" def save_memory_md(content: str) -> str: _ensure_dirs() _MEMORY_MD.write_text((content or "").strip() + "\n", encoding="utf-8") return str(_MEMORY_MD) -
_ensure_dirs()会在首次运行时创建memory_files/目录,并写入一份默认的 MEMORY.md 模板。
-
-
前端编辑与刷新
在「记忆可视化(三层)」Tab 中:
pythonlong_term_box = gr.Textbox( value="", label="MEMORY.md(长期精选记忆)", lines=14, max_lines=30, ) save_btn.click( fn=_on_save_long_term, # 内部调用 save_memory_md inputs=[long_term_box], outputs=[save_status, long_term_box], ) refresh_lt_btn.click( fn=load_memory_md, inputs=[], outputs=[long_term_box], ) # 页面加载时自动从磁盘读取最新 MEMORY.md demo.load( fn=load_memory_md, inputs=[], outputs=[long_term_box], )- 用户可以在前端直接编辑 MEMORY.md,并点击「保存到长期记忆」覆盖写入文件;
- 点击「刷新显示」或刷新浏览器页面时,会再次从磁盘读取最新内容,保证前后端一致。
-
使用长期记忆增强 LLM(可选)
当前 Demo 中,MEMORY.md 主要用于展示和教学。实际项目中,可以在调用 LLM 前增加一步:
- 用
MEMORY.md做关键词或向量检索,选出与当前问题相关的若干段落; - 将这些段落拼接到 system prompt 或 context 中,让模型在回答时能利用长期知识;
- 这样可以实现「记得机构规则与经验」的留学顾问,而不必把所有规则硬塞进 prompt。
- 用
5 参考体系:OpenClaw Memory 与本章三层记忆对比
本节简要介绍 OpenClaw 的 Memory 体系(基于官方文档
https://learnopenclaw.com/core-concepts/memory),并对照本章的三层记忆设计,帮助你把「平台级记忆框架」和「单项目工程实现」放在一起理解。
5.1 OpenClaw Memory 的整体设计(更详细版)
按照 OpenClaw 官方文档,Memory 分为三层,并配套若干 hook + 搜索策略 + 运维 ritual,组成一个「既能记、又能管、还能定期清洗」的完整体系。
注意,在 OpenClaw 语境里,hook 指的是:当系统运行到某个固定时机(例如会话结束、会话启动、执行命令后),就会自动触发一段预先定义好的流程来做事(比如写 daily log、加载 MEMORY.md、记录命令)。开发者只需要在 openclaw.json 里开关 + 配置参数,不需要自己在代码里到处插入文件读写逻辑。
5.1.1 三层结构与职责边界
-
Layer 1:Short-Term(Conversation Context)
- 载体:当前会话的上下文窗口(历史消息列表);
- 生命周期:仅限本次对话,会话结束即失效;
- 限制:受模型上下文长度约束,对超长会话会自动「遗忘」早期内容;
- 工程上不额外持久化,由 LLM / 对话框架自然承担。
-
Layer 2:Medium-Term(Daily Logs)
- 载体:按日期划分的 Markdown 文件,例如:
memory/daily/2026-02-16.md- 每个文件中按时间分小节(09:15 / 11:30 / ...),记录当天多个会话的摘要;
- 生成方式:由
session-memoryhook 在每次会话结束时 自动触发:- 对本次会话做摘要(可调「短 / 中 / 长」三档,是否包含 actions);
- 以时间戳 + 主题 title 形式 append 到当日文件;
- 角色:作为「预压缩前的原材料」,后续从中抽取值得进入长期记忆的条目。
- 载体:按日期划分的 Markdown 文件,例如:
-
Layer 3:Long-Term(MEMORY.md)
- 载体:单一的
MEMORY.md文件,结构推荐类似:## Active Projects/## Key Decisions Made/## Ongoing Preferences/## People & Context等分区;
- 内容:仅保留长期稳定、跨会话都重要的事实与偏好,例如:
- 正在进行的项目、上线节奏;
- 做过的重要决策及日期与依据;
- 长期偏好(写作风格、作息、沟通偏好等);
- 加载方式:通过
boot-mdhook,在每次新对话「启动阶段」自动读入,成为 agent 的默认背景。
- 载体:单一的
5.1.2 关键 hooks:如何写入 / 加载记忆
OpenClaw 把记忆操作抽象为若干 hook,开发者只需在 openclaw.json 中配置,不必自己写 IO 逻辑:
-
session-memoryhook:负责"写日记"json{ "hooks": { "session-memory": { "enabled": true, "summaryLength": "medium", "includeActions": true, "dailyLogPath": "./memory/daily/" } } }summaryLength:short/medium/long,控制 daily log 中摘要的粒度;includeActions:是否记录 agent 执行的命令、修改文件等操作;dailyLogPath:daily logs 的根目录;- 触发时机:每次对话结束;若会话异常中止(crash / timeout)则可能不会写入。
-
boot-mdhook:负责"上电就读配置"json{ "hooks": { "boot-md": { "enabled": true, "files": [ "SOUL.md", "IDENTITY.md", "USER.md", "MEMORY.md" ] } } }- 作用:每次新建会话前,自动把上述文件内容读入模型上下文;
- 影响:这些文件越长,占用的上下文预算越多,留给「当前任务」的空间越少,因此文档中强烈建议控制 MEMORY.md 长度(例如 < 200 行)。
-
command-loggerhook:负责"记录动作轨迹"json{ "hooks": { "command-logger": { "enabled": true, "logPath": "./memory/commands/", "includeOutput": false } } }- 记录 agent 实际执行过的命令、文件修改、API 调用;
- 主要用于「审计 + 调试」,有需要时再结合 daily logs 与 MEMORY.md 一起分析。
5.1.3 Hybrid Search:如何从记忆中检索
当 agent 需要「想起」某些信息时,OpenClaw 对 MEMORY / daily logs 使用 Hybrid Search:
-
70% 语义向量搜索:
- 把段落 embedding 进向量索引,找出语义上最相关的若干条;
- 适合问题表达和记忆条目用词不完全一致的情况(如「课程定价策略」 vs 「Course pricing」)。
-
30% BM25 关键词搜索:
- 对具体名称、日期、项目ID 等做精确匹配;
- 保证关键字不会被语义距离「平均掉」。
因此,OpenClaw 文档特别强调写 MEMORY.md 的时候要:
- 使用自然语言完整句子,给向量搜索足够语义上下文;
- 同时保留关键名词和术语,保证 BM25 能抓到;
- 将相关信息按段落分块,避免一个段落塞太多不相关事实。
5.1.4 记忆"运营":预压缩、每周回顾与陈旧记忆
OpenClaw 不是只解决「怎么写入」,还很强调「怎么清理和重构」:
-
Pre-Compaction(预压缩)流程:
- 定期(比如每周)回看最近 7--14 天的 daily logs;
- 抽取真正长期有价值的信息(新项目、关键决策、稳定偏好);
- 将其写入 / 更新
MEMORY.md中相应板块; - 已经抽取完毕的 old daily logs 可以归档或删除。
-
Weekly Memory Review(每周记忆回顾):
-
官方给的 checklist 包括:
-
推荐用 cron 自动提醒:
json{ "crons": [ { "label": "Weekly Memory Review", "schedule": "0 18 * * 0", "prompt": "It's time for the weekly memory review. Summarize the daily logs from this past week and suggest updates to MEMORY.md. Show me the proposed changes before making them." } ] }
-
-
Stale Memory(陈旧记忆)问题与诊断:
5.2 与本章三层记忆的结构映射
如果把本章的实现与 OpenClaw 的三层结构对照,大致对应关系如下:
| OpenClaw 层级 | OpenClaw 载体 | 本章对应层级 | 本章载体 |
|---|---|---|---|
| Short-Term | 当前会话上下文(模型上下文窗口) | 短期记忆 | trimmed_history + current_message + SQLite 中的 all_filled_slots |
| Medium-Term | Daily Logs(memory/daily/2026-02-16.md 等) |
中期记忆 | memory_files/memory/YYYY-MM-DD.md,记录时间、group_id、本轮槽位摘要与完整槽位 JSON |
| Long-Term | MEMORY.md(通过 boot-md hook 加载) |
长期记忆 | memory_files/MEMORY.md,可在前端直接编辑与刷新 |
可以看到,两者在分层思想和持久化载体(Markdown 文件)上是高度一致的:
- 都用对话上下文做短期记忆;
- 都通过按日 Markdown 日志承载中期记忆;
- 都用单一
MEMORY.md文件来保存长期精选记忆。
不同的是,本章出于教学与业务 Demo 的目的,对中期层加上了更多结构化槽位信息 与 group_id 维度,对长期层则提供了一个简单可视化编辑界面,更贴近「单个业务项目」的实际接入形态。
5.3 差异与互补点:平台级框架 vs. 项目级实现
从工程视角看,两套方案可以理解为「同一理念的两个落点」:
-
OpenClaw 更像是"平台级记忆基础设施":
- 通过
session-memory/boot-md/command-logger等 hook,把「写日记、加载长期记忆、记录命令」统一封装; - 提供 Hybrid Search 与「Weekly Memory Review」等运维建议,关注记忆的长期健康与陈旧问题;
- 上层应用不必关心具体文件结构,只通过框架能力使用记忆。
- 通过
-
本章 demo 更像是"单项目的工程化实现模板":
- 把 Short-Term / Daily Logs / MEMORY.md 三层记忆全部用显式代码实现(SQLite + Markdown + Gradio UI),便于在任何框架下复用;
- 中期层紧贴业务槽位(留学咨询六大主题),方便运营同学按
group_id回看具体填数过程; - 长期层
MEMORY.md目前主要展示/人工编辑,未来可以再叠加「预压缩」与「混合检索」逻辑,向 OpenClaw 的实践看齐。
换句话说:OpenClaw 给了一个「怎么运营记忆」的宏观实践,本章给了一个「如何在你自己的 Python 项目里抄一套类似架构」的最小可行代码实现。你可以同时参考两者:
- 架构上沿用本章的三层结构与 SQLite + Markdown 方案;
- 流程与治理上借鉴 OpenClaw:定期从 daily logs 抽取/更新
MEMORY.md,控制文件长度,避免陈旧记忆。
6 本仓库示例一览与运行方式
| 文件/目录 | 说明 |
|---|---|
| demo_codes/README.md | 环境、依赖、两种运行方式(LangGraph 记忆图 / 文件型记忆)及步骤说明 |
| demo_codes/requirements.txt | Python 依赖(langgraph、langchain-*、python-dotenv 等) |
| demo_codes/config_parser.py | 从 .env 读取 API Key 等配置 |
| demo_codes/memory_graph.py | LangGraph 图:短期记忆(MemorySaver + thread_id)+ 长期记忆(InMemoryStore + namespace),节点内 search/put |
| demo_codes/file_style_memory.py | 文件型记忆:MEMORY.md + memory/YYYY-MM-DD.md 文件结构、混合检索(关键词 + 可选向量)、预压缩前刷新模拟,对应 OpenClaw 三层记忆的项目级实现版本 |
| demo_codes/main.py | 入口:运行 LangGraph 记忆示例,或运行文件型记忆示例(见 README) |
在 demo_codes 目录下执行:
bash
pip install -r requirements.txt
# 配置 .env 中的 OPENAI_API_KEY(或 DASHSCOPE_API_KEY 等)
python main.py # LangGraph 短期+长期记忆示例
python main.py --file-style # 文件型记忆(MEMORY.md + 每日日志 + 混合检索)示例
详见 demo_codes/README.md。
7 小结
- 短期记忆 :LangGraph 用 State(如 messages)+ Checkpointer 按 thread 持久化,实现多轮对话不丢上下文;在本章的非 LangGraph 版中,用
history+ SQLite 槽位实现同等能力,对标 OpenClaw 的 Short-Term 会话上下文。 - 长期记忆 :用 Store (namespace + put/get/search),在节点内通过 Runtime 注入;在文件型实现中则落地为
MEMORY.md+ 每日日志 + 混合检索,对标 OpenClaw 的 MEMORY.md 与 Daily Logs。 - 基于文件的记忆设计 :三层(对话 / 每日日志 / MEMORY.md)、文件为源、混合检索、预压缩前刷新;本仓库在 demo_codes/file_style_memory.py 中提供了可复现的简化实现,你可以将其视为「OpenClaw Memory 思想在单一 Python 项目中的最小实现模板」,再在下一章对比 LangGraph 的官方 Memory 方案。
参考