主题:第19部分 基于SQLite的智能体记忆
难度等级:中级
预计学习时间:6-8小时(理论2小时,实践4-6小时)
前置知识: SQL和SQLite基础知识(创建表、索引、简单查询)
理解Qwen Code架构和钩子系统(课程第1-4部分)
具备命令行和Python脚本工作经验
熟悉SDD(规范驱动开发)概念
对LLM和上下文窗口有基本理解
学习目标: 独立部署完整的基于SQLite的智能体记忆系统,包含events和memories表,包括架构设计、钩子和上下文注入机制
批判性评估哪些数据应存入智能体记忆、哪些绝对不可存入,并在实践中应用隐私和安全规则
实现和配置记忆的后台摘要(类似/dream),通过dream_sqlite.py脚本调用LLM API,并控制其运行
区分智能体工作记忆与持久性规范之间的界限,将稳定规则从memories迁移至specs/、QWEN.md或技能中
优化请求上下文,应用"少即是多"原则:按标签过滤相关记录、限制注入块数量、防止"上下文退化"
概述:本部分课程致力于创建基于SQLite的本地、透明且完全可控的智能体开发记忆层。Qwen Code内置的记忆(QWEN.md、/remember、/forget、/dream)足以满足大多数项目需求,但在需要审计、跨环境迁移或自定义清理规则时,开发者可以构建自己的系统。核心思想:智能体会话中的事件通过钩子记录到events表,然后通过后台摘要压缩为memories表的紧凑备忘,再注入到新会话的上下文中。最重要的限制——记忆补充但不替代规范:稳定规则必须迁移到specs/或QWEN.md中。课程涵盖数据库架构、两个关键钩子(log_event.py和inject_memory.py)、Qwen Code连接、摘要自动化、隐私以及防止"上下文退化"的上下文节约原则。
核心概念: 双层记忆架构(events + memories):原始事件存储在events表中——这是智能体操作的完整日志:请求、工具调用、结果。从这些事件中得出的持久性结论被压缩到memories表中——紧凑、结构化的笔记。这种分离至关重要:events提供审计和摘要的原始材料,memories为新会话提供快速相关的上下文。没有这种分离,上下文会因非结构化数据而迅速膨胀。
Qwen Code钩子(log_event.py、inject_memory.py):钩子是在会话生命周期关键点调用的可执行脚本。log_event.py连接到UserPromptSubmit(发送请求)、PostToolUse(使用工具后)和Stop(会话结束)事件——它将元数据记录到events中。inject_memory.py连接到SessionStart和UserPromptSubmit——它从memories中读取相关记录并添加到当前会话的上下文中。两个脚本都必须是可执行的,并在settings.json中正确配置。
后台摘要(SQLite版/dream):将原始事件整合为持久性备忘的周期性过程。与内置/dream不同,SQLite版本离线工作:dream_sqlite.py脚本读取一段时间内的events(例如--since 24h),通过API(DashScope/Bailian)调用LLM进行摘要,并将结果写入memories。通过cron、手动或在项目阶段后启动。关键优势:完全透明——人可以查看原始事件和压缩笔记。
上下文卫生与"上下文退化":大量不相关上下文降低模型回答质量的现象,其程度超过简短精确上下文。研究表明:300个相关token比30,000个不相关token更有效。实践结论:注入不超过3-5个记忆块,按标签/类别过滤,删除过时内容而非"细化",将常用记录作为规则转移到QWEN.md中。
记忆与规范的界限:智能体记忆——用于发现模式、偏好和错误的操作层。规范(specs/、QWEN.md、技能)——产品必须遵守的规则。当后台摘要发现稳定规则时(例如"合并前始终更新CHANGELOG.md"),它必须从memories迁移到相应规范中。记忆帮助发现,规范确保强制性。
记忆隐私与安全:记忆很容易变成敏感数据的仓库。强制规则:不记录环境变量、截断工具响应、不存储秘密和个人数据、限制上下文为3-5个块、定期清理过时内容、不提交.db文件(仅提交架构和脚本)。课程中提供了.gitignore示例。
SQLite全文搜索(FTS):memory_fts表提供对备忘内容的快速搜索。使用snippet()函数显示找到匹配的上下文。允许在注入上下文或手动审计时通过关键词查找相关记录。
实践练习: 标题:部署基础架构和第一个钩子
问题:创建目录.qwen/memory,从教程复制schema.sql,初始化SQLite数据库agent-memory.db。然后创建.qwen/hooks,复制log_event.py,设为可执行。在settings.json中配置钩子连接到UserPromptSubmit和PostToolUse事件。使用Qwen Code进行一次测试会话,发送简单请求(例如"创建hello.py")。验证事件是否已记录到数据库中。
解决方案:1. mkdir -p .qwen/hooks .qwen/memory
- cp "$TUTORIAL_DIR/examples/sqlite-memory/schema.sql" .qwen/memory/schema.sql
- sqlite3 .qwen/memory/agent-memory.db < .qwen/memory/schema.sql
- cp "$TUTORIAL_DIR/examples/sqlite-memory/hooks/log_event.py" .qwen/hooks/
- chmod +x .qwen/hooks/log_event.py
- 将settings-hooks.example.json中的配置合并到您的settings.json中(不要覆盖模型和授权配置)
- 启动Qwen Code,执行请求
- 验证:sqlite3 .qwen/memory/agent-memory.db "select event_name, tool_name, substr(prompt,1,80), timestamp from events order by id desc limit 5;"
预期结果:可见UserPromptSubmit和PostToolUse类型的记录。
难度:初级
标题:向会话注入相关记忆
问题:将inject_memory.py连接到SessionStart和UserPromptSubmit事件。手动在memories表中创建2-3条测试记录,设置不同类别(preferences、workflow、project)。启动新的Qwen Code会话,发送与其中某个类别相关的请求。通过日志或修改inject_memory.py输出到stderr来验证正确的记录已添加到上下文中。
解决方案:1. cp "$TUTORIAL_DIR/examples/sqlite-memory/hooks/inject_memory.py" .qwen/hooks/
- chmod +x .qwen/hooks/inject_memory.py
- 在settings.json中添加钩子
- 通过SQL手动创建记录或复制manual-memory-example.sql
- 临时修改inject_memory.py:添加print(f"[DEBUG] Injecting: {path}", file=sys.stderr)
- 启动与您的类别相关的请求会话
- 检查输出:您应该看到带有正确路径的[DEBUG] Injecting:
- 确认不相关记录未被注入
难度:中级
标题:带dry-run的后台摘要
问题:将dream_sqlite_qwen_example.py安装为dream_sqlite.py。确保已配置BAILIAN_API_KEY环境变量。以dry-run模式运行最近24小时的摘要。分析输出:选择了哪些事件,建议了哪些备忘。然后不带dry-run运行并验证memories表中的结果。
解决方案:1. cp "$TUTORIAL_DIR/examples/sqlite-memory/dream_sqlite_qwen_example.py" .qwen/memory/dream_sqlite.py
- export BAILIAN_API_KEY=your_key
- python .qwen/memory/dream_sqlite.py --since 24h --dry-run
- 研究stdout:将显示计划——选择了哪些events,生成了哪些summaries
- 如果结果满意:python .qwen/memory/dream_sqlite.py --since 24h
- 验证:sqlite3 .qwen/memory/agent-memory.db "select path, substr(content,1,100), updated_at from memories order by updated_at desc;"
- 预期结果:memories中出现新的紧凑记录,反映events中的模式
难度:中级
标题:将规则从记忆迁移到规范
问题:经过几次会话后,您发现智能体系统性地忘记更新CHANGELOG.md。该模式在memories中记录为workflow/sdd-validation.md备忘。您的任务:评估这是否已成为稳定规则,并将其正确转移到项目规范中,从memories中删除或标记为已转移。
解决方案:1. 查找记录:sqlite3 .qwen/memory/agent-memory.db "select path, content from memories where path like '%validation%';"
- 分析频率:错误重复了多少次,用户是否确认修复
- 如果规则稳定(≥3次确认,对产品关键):
- 创建或更新specs/workflow/changelog.md,或在QWEN.md中添加章节
- 表述为强制规则:"功能分支合并到main前,使用Unreleased章节更新CHANGELOG.md"
- 在memories中标记:UPDATE memories SET content = content || '\n\n[TRANSFERRED TO specs/workflow/changelog.md 2024-XX-XX]' WHERE path = 'workflow/sdd-validation.md';
或如果确定重复则删除
- 在新会话中验证:智能体应遵循规范中的规则,无需依赖记忆
难度:高级
标题:审计和清理敏感数据
问题:检查数据库时,您发现events中prompt字段意外包含API密钥字符串(用户为测试将其粘贴到请求中)。此外memories中有包含测试人员个人邮箱的记录。执行审计,找到所有敏感记录,清理它们,并实施防止再次发生的保护措施。
解决方案:1. 审计events:sqlite3 .qwen/memory/agent-memory.db "select id, substr(prompt,1,200) from events where prompt like '%sk-%' or prompt like '%Bearer%' or prompt like '%@%.%';"
- 审计memories:对content进行类似查询
- 删除找到的记录:DELETE FROM events WHERE id IN (...); DELETE FROM memories WHERE path = '...';
- 检查FTS:DELETE FROM memory_fts WHERE docid IN (SELECT id FROM memories WHERE ...);
- 加强log_event.py:添加过滤——记录前用正则表达式检查prompt中的秘密,替换为[REDACTED]
- 添加到.gitignore:.qwen/memory/agent-memory.db和任何.db-journal、.db-wal
- 在项目README中记录规则:"切勿在提示中插入秘密"
难度:高级
案例研究: 标题:AgentClinic:从操作笔记到产品规范
场景:初创公司开发AgentClinic服务——AI智能体的讽刺评论公共平台。4人开发团队使用带自定义SQLite记忆的Qwen Code进行协调。3个月内积累了15,000个事件和200条memories备忘。
挑战:问题1:由于未过滤注入所有memories,新会话上下文膨胀到8,000个token——模型开始"迷失"并忽略QWEN.md中的关键指令。问题2:关于评论语气的产品约定("公开且讽刺,非私人沟通")仅存在于memories中,不同开发者有不同理解。问题3:新开发者无法理解某些决策为何做出——memories未版本控制且未提交。
解决方案:团队在inject_memory.py中引入严格过滤:仅注入与当前任务标签相关的记录(通过请求关键词确定),最多4个块,每个200个token。对于产品约定,建立"memory triage"流程——高级开发者每周审查新memories,将稳定规则转移到specs/中。具体语气约定迁移到specs/mission.md,表述为"AgentClinic中所有记录默认公开;讽刺语气为强制要求,禁止私人沟通"。架构和脚本提取到独立版本控制仓库,.db文件添加到.gitignore——每位开发者保存本地副本,必要时通过导出/导入memories的SQL转储进行同步。
结果:平均会话上下文从8,000减少到1,200个token,同时指令遵循准确率(通过50次会话手动评估测量)从64%提升至91%。产品约定在团队中实现统一。新开发者通过阅读specs/可在2小时内理解规则,而非花费2天挖掘记忆。"memory triage"时间——每周30分钟——通过减少解释错误得到回报。
经验教训: 未过滤注入所有memories比没有记忆更糟——上下文退化真实且可测量
产品规则应尽快迁移到specs/;memories仅是孵化器
架构和脚本版本控制至关重要,但.db文件不应提交——这是个人数据和操作层
定期手动记忆审计(memory triage)是必要的,完全自动化的摘要可能固化错误模式
相关概念: 上下文卫生与"上下文退化"
记忆与规范的界限
记忆隐私与安全
后台摘要(SQLite版/dream)
标题:金融科技初创:智能体记忆中的客户数据隐私
场景:拥有12名开发者的金融科技公司使用带SQLite记忆的Qwen Code开发支付处理系统。记忆帮助跟踪复杂业务规则和银行API集成的常见错误。
挑战:安全审计中发现,log_event.py将银行API的完整响应记录到events表中,包括掩码卡号、交易金额和客户内部标识符。此外memories中积累了调试SMS通知使用的测试人员邮箱和电话。agent-memory.db在紧急修复时意外被提交。
解决方案:立即响应:撤销提交、轮换所有可能泄露的密钥、按程序通知监管机构(数据已掩码,但泄露事实存在风险)。结构性变更:重写log_event.py,强制过滤——PAN(即使掩码)、金额、邮箱、电话的正则表达式;API响应截断为仅保留状态码和message,不含payload。实施pre-commit钩子,阻止任何.db文件提交。通过带审计操作日志的SQL脚本清理memories。在memory triage中增设"privacy reviewer"角色。
结果:事件得到控制,由于快速响应和数据掩码,未产生罚款。新过滤系统在6个月内阻止了340次潜在泄露(通过正则表达式触发次数测量)。开发者配置过滤时间——4小时——在第一周即收回成本。"privacy by design"文化融入智能体记忆流程。
经验教训: "掩码"数据仍然敏感——监管机构和伦理要求将其排除在任何日志之外
技术措施(.gitignore)若无pre-commit钩子不足够——匆忙时人为因素不可避免
过滤必须在log_event.py中实现,不要依赖"开发者会小心"
记忆审计应像代码审计一样定期——数据在不知不觉中积累
相关概念: 记忆隐私与安全
双层记忆架构(events + memories)
Qwen Code钩子(log_event.py、inject_memory.py)
学习建议: 从手动走完整个链条开始:创建架构、运行一个钩子、通过sqlite3 CLI手动检查数据库——这样您会在自动化之前"感受"数据流
在单独文件中维护"实验日志":记录执行了哪些SQL查询、期望什么、得到什么——这能培养SQLite记忆的调试直觉
对dream_sqlite.py践行"先dry-run,后现实"原则:在写入前检查摘要的习惯可防止垃圾污染memories
为规则创建自己的"成熟度量表":1次——笔记,2次——验证,3次——规范候选。这简化了迁移决策
使用人类记忆类比:events是"您今天看到的一切",memories是"日记中的记录",specs/是"签署的合同"。合同具有法律效力,日记是操作辅助
视觉风格:在纸上绘制从事件到注入的数据流图,标记可能发生泄露或上下文膨胀的位置——这能激活空间思维
配对学习:如可能,一人配置log_event.py,另一人配置inject_memory.py,然后交换角色并在对方实现中寻找bug——发现边界案例的最佳方式
学习期间定期在Qwen Code中执行/clear——这训练有意识的上下文工作方式,而非无差别积累
补充资源: 课程原始示例(schema.sql、钩子、dream sqlite):sdd-qwen-code-ru/examples/sqlite-memory/仓库——所有脚本的原始来源,从此处复制,不要从头重写
SQLite FTS5文档:https://www.sqlite.org/fts5.html——深入理解memory_fts表的全文搜索
VentureBeat关于Anthropic智能体记忆的文章:课程中提及;搜索关键词'Anthropic agent memory sessions patterns'——后台摘要的概念基础
课程第14部分(上下文卫生):part-14-build-your-own-workflow.md——理解为何/clear和角色分离有效的必读补充
课程第4部分(DashScope/Bailian API配置):用于在dream_sqlite_qwen_example.py中正确配置BAILIAN_API_KEY
OWASP日志安全速查表:https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html——扩展智能体记忆的隐私规则
'Lost in the Middle'研究(斯坦福,2023):上下文退化现象的关键科学依据;搜索标题以理解为何信息在上下文中的位置至关重要
总结:基于SQLite的智能体记忆是补充Qwen Code内置记忆的本地、透明且完全可控的层。关键原则:原始事件(events)与持久备忘(memories)的分离、用于记录和注入的钩子、通过dream_sqlite.py的离线后台摘要、工作记忆与强制规范之间的严格界限。主要风险——过量注入导致的上下文退化和敏感数据泄露。解决方案:按相关性过滤、限制3-5个块、定期审计、钩子中过滤秘密、不提交.db文件。成功实现需要纪律:记忆帮助发现规则,但规范使其成为强制要求。