狗头军师memory_store.py实现原理详解:同意门禁、有界SQLite与撤销机制
【免费下载链接】goutoujunshi一个先接住情绪、再分析关系并给出可执行策略的 Codex 恋爱军师,内置心理、法律、社会、人文、哲学、婚姻家庭与性学知识库,支持多元关系。项目地址: https://gitcode.com/gh_mirrors/go/goutoujunshi
狗头军师是一款先接住情绪、再分析关系并给出可执行策略的 Codex AI 恋爱军师。它的本地长期记忆脚本memory_store.py用"同意门禁、有界 SQLite、撤销机制"三道防线,确保保存在本机的精简关系档案可控、可审阅、随时可删。本文用通俗的方式带你读懂这份 scripts/memory_store.py 的设计与实现原理。
为什么恋爱军师需要本地长期记忆 🧠
聊过几次之后,每次都要重新交代"我和对象 A 进展到哪了"很烦。狗头军师的解法不是把整段聊天记录塞进数据库,而是只保存精简字段 + 关键事件摘要(单条不超过 200 字),存到操作系统用户数据目录里的一份本地 SQLite 文件中——没有云端、没有账号、绝不写入仓库。
完整的记忆规则和使用分级见 references/practical/长期记忆与关系档案.md,整体架构定位见 documentation/architecture.md。
这套"本地有界记忆"由三道防线组成:
| 防线 | 解决什么问题 |
|---|---|
| 🚪 同意门禁 | 用户没明确同意,一个字节都不写 |
| 📦 有界 SQLite | 条数、字数、来源全部有硬上限,防止无限累积 |
| ↩️ 撤销机制 | 每次写入都留操作日志,可撤销、可暂停、可硬删除 |
第一道防线:同意门禁(Consent Gate)
没有enable,就没有写入
数据库里有一张settings表记录"是否已获同意"。所有写入和召回操作都会先执行 scripts/memory_store.py#L138-L142 中的require_enabled检查:
- 文件不存在 → 报错
NOT_INITIALIZED(尚未启用长期记忆) consent_enabled不为 true → 报错CONSENT_REQUIRED(尚未获得用户同意)paused为 true → 报错MEMORY_PAUSED(当前已暂停)
也就是说,apply(写入)和context(召回)在同意前都会被拦截;而status、show这类只读查询随时可用,方便用户先看看再说。
启用需要显式确认
启用命令必须带--confirm参数,表示"用户已明确同意":
python3 scripts/memory_store.py enable --confirm不带确认会直接收到CONFIRMATION_REQUIRED错误。同样的"确认锁"也被用在所有破坏性操作(删除对象档案、撤回同意、清空)上。
文件本身也上了权限锁
数据库落在哪个目录,由 scripts/memory_store.py#L50-L64 决定:macOS 用~/Library/Application Support/goutoujunshi,Windows 用%LOCALAPPDATA%\goutoujunshi,Linux 用 XDG 数据目录;也可用环境变量GOUTOUJUNSHI_MEMORY_DIR指定私密目录(变量说明见 documentation/variables.md)。
创建时目录权限设为0o700、数据库文件设为0o600,配合 SQLite 的 WAL 日志模式,把敏感的关系档案尽量锁在当前系统用户的范围内。权限边界的完整说明见 documentation/permissions.md。
第二道防线:有界 SQLite —— 三张表、三重限额 📦
三张表各司其职
连接逻辑在 scripts/memory_store.py#L71-L122,建表脚本一次性创建三张表:
| 表 | 作用 |
|---|---|
settings | 同意开关、暂停状态、策略版本 |
memories | 真正的记忆条目(scope + 对象 + 字段 + 值 + 来源 + 置信度) |
operations | 每次写入的 before/after 快照,支撑撤销 |
数字上限一览
所有硬性限额都集中在文件头部 scripts/memory_store.py#L17-L28:
| 限额项 | 上限 | 含义 |
|---|---|---|
| 单条值 | 200 字符 | 只存摘要,不存整段聊天 |
| 记忆总条数 | 200 条 | 全库兜底上限 |
user档案 | 30 条 | 用户稳定档案 |
object档案 | 15 条 | 单个对象事实 |
relationship快照 | 10 条 | 关系阶段与共识 |
event事件 | 20 条/对象 | 带时间的关键转折 |
hypothesis假设 | 5 条/对象 | 可被纠正的暂定解释 |
| 可撤销操作 | 最近 20 次 | 操作日志滚动保留 |
超限时的两种处理策略
prune_rows(scripts/memory_store.py#L227-L269)对不同类型采取不同策略:
- 档案类(user / object / relationship):拒绝写入。到达上限报
MEMORY_LIMIT_REACHED,提示"请先合并或删除旧字段"——档案必须经用户整理,系统不擅自丢弃稳定信息。 - 事件与假设类(event / hypothesis):自动淘汰。超限后按
updated_at从最旧开始删除,并计入本次操作日志,保证撤销时能还原。 - 全库兜底:总数超过 200 条时,优先从 event/hypothesis 中删最旧条目;仍超限时直接报错,要求用户归档或删除旧对象,而不是悄悄扩容。
来源门禁:谁说的话能写进哪一层
写入前validate_delta(scripts/memory_store.py#L164-L216)还做"来源-范围"匹配校验,核心规则是:越靠近稳定人格判断,来源要求越严格。
| 记忆范围 | 允许的来源 |
|---|---|
user(用户档案) | 仅用户明确陈述 |
object/relationship | 用户明确陈述或转述 |
event/hypothesis | 可接受 ChatLab、工具结果、模型推断 |
hypothesis(假设) | 模型推断唯一允许落脚的范围,且必须带置信度 |
违反规则会收到SOURCE_NOT_ELIGIBLE错误。这样模型"读心"出的解释只能落在带置信度的假设层,永远不会悄悄升级成"事实档案"。
上图是狗头军师跨学科知识库的 135 条参考资料总览;长期记忆与其互补:知识库回答"这类关系该怎么分析",有界 SQLite 记住"你这个人的具体档案"。
第三道防线:撤销机制 —— 每次操作都能悔棋 ↩️
操作日志:写入前先拍快照
每次apply都在一个BEGIN IMMEDIATE事务里完成"查找旧值 → 写入新值 → 淘汰超限行 → 记录操作"。旧值(before)和写入结果(after)都以 JSON 存入operations表,并只保留最近 20 条(scripts/memory_store.py#L219-L224)。
撤销:undo与undo --op-id
command_undo(scripts/memory_store.py#L445-L466)的逻辑很直接:
- 取出目标操作(默认最近一次,或用
--op-id指定); - 删掉本次操作影响到的全部记忆行;
- 按 before 快照把旧值原样还原;
- 移除该操作日志,防止"撤销的撤销"。
配合 references/practical/长期记忆与关系档案.md 中的约定,每次成功写入后军师都会附一行提示:"记忆更新:…… 撤销:告诉我'撤销刚才的记忆'",普通用户不需要记命令也能使用。
硬删除与撤回:后悔药之外的"遗忘权"
撤销只能回到最近 20 次操作,更彻底的控制权交给用户:
| 命令 | 效果 | 需要 |
|---|---|---|
forget-object <代号> --confirm | 永久删除该对象全部记忆,并清空撤销历史、执行VACUUM回收空间 | --confirm |
revoke --confirm | 撤回同意但保留现有资料(暂停状态) | --confirm |
revoke --delete --confirm | 撤回同意并物理删除数据库及 WAL/SHM 附属文件 | --confirm |
clear --confirm | 永久清空全部长期记忆 | --confirm |
相关实现见 scripts/memory_store.py#L517-L563。注意forget-object是不可逆的:它同时清掉撤销历史,所以命令要求先与用户核对准确代号再加--confirm。
三道防线如何协同工作:一次记忆的生命周期 🔄
把上面串起来,就是一次完整的记忆流转:
- 查状态:
status报告是否存在数据库、是否已同意、当前条数与可撤销次数; - 明确同意:
enable --confirm写入consent_at时间戳和策略版本; - 写入:
apply依次通过来源校验 → 同意门禁 → 事务写入 → 超限淘汰 → 记录操作日志; - 召回:
context --subject-id obj-a --max-chars 4000只返回当前对象需要的压缩上下文,且总长度超预算时自动裁掉最旧条目; - 退出:随时可
undo/pause/forget-object/revoke --delete。
任何一环失败,脚本都以结构化 JSON 输出{"ok": false, "error": {"code": ...}}(错误码如CONSENT_REQUIRED、MEMORY_LIMIT_REACHED、NOTHING_TO_UNDO),方便宿主程序判断和向用户说明。
延伸阅读
- 记忆规则与五类档案定义:references/practical/长期记忆与关系档案.md
- 系统架构与信任边界:documentation/architecture.md
- 权限矩阵与资源边界:documentation/permissions.md
- 行为内核中的长期记忆条款:SKILL.md
小结
memory_store.py用约 600 行 Python 回答了一个关键问题:AI 恋爱军师记住了你,你还能不能控制它?答案是——没有明确同意不写、超过限额不存、推断不冒充事实、每次写入可悔棋、想忘就真忘。同意门禁、有界 SQLite 与撤销机制三道防线,让"长期记忆"从营销词变成了可审计、可逆、有边界的本地工程实现。
【免费下载链接】goutoujunshi一个先接住情绪、再分析关系并给出可执行策略的 Codex 恋爱军师,内置心理、法律、社会、人文、哲学、婚姻家庭与性学知识库,支持多元关系。项目地址: https://gitcode.com/gh_mirrors/go/goutoujunshi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考