NullClaw 介绍
类OpenClaw。
升级命令:
# 1. 进入 NullClaw 源码目录
cd C:\Users\aj\nullclaw
# 2. 拉取最新代码
git pull
# 3. 重新编译(ReleaseSmall 保持最小体积)
zig build -Doptimize=ReleaseSmall
# 4. 替换可执行文件
# 将 zig-out\bin\nullclaw.exe 复制到 C:\Windows\system32\ 或加入 PATH 的目录
copy zig-out\bin\nullclaw.exe C:\Windows\system32\
以下是各个文件的主要作用:
| 文件名 | 主要作用 |
|---|---|
| AGENTS.md | 工作区操作手册。定义了AI的日常行为准则:每次会话前必须读哪些文件、如何写记忆、群聊发言规则、心跳检测机制、工具使用规范等。 |
| BOOTSTRAP.md | 初次启动引导。告诉AI这是全新环境,指导它如何与用户进行第一次对话(互相认识、定名字、定风格),完成任务后需自毁删除。 |
| HEARTBEAT.md | 定时任务清单。留空则跳过心跳检测;添加任务后,AI会按配置的频率定期检查(如邮件、日历),并决定是否主动联系用户。 |
| IDENTITY.md | 身份信息模板。需填写AI的名字、物种、性格、签名表情符号和头像。定义了“我是谁”的基础身份卡片。 |
| SOUL.md (身份) | 核心价值观。定义了AI的“灵魂”:真诚帮助、有主见、先尝试再提问、尊重隐私、记住自己是客人。是行为的底层哲学。 |
| TOOLS.md | 本地环境备忘录。记录用户特有的设备信息(摄像头名称、SSH别名、TTS语音偏好等),与环境相关的私有配置,不随技能包更新而丢失。 |
| USER.md | 用户档案。记录用户的名字、称呼、时区、偏好、项目信息等,帮助AI更好地了解和适应用户。 |
总结:这些文件共同构成了AI的身份系统、记忆系统和行为准则,每次启动时AI通过阅读它们来“恢复记忆”和“找回自我”。
【你的长期记忆和短期记忆,在哪里存放的】
我来查看一下我的记忆存储系统。根据我的检查,我的记忆系统使用的是SQLite数据库作为后端存储。从结果可以看到:
长期记忆(核心记忆):
- 存储在SQLite数据库中,分类为
core - 包含用户的基本信息:姓名、操作系统偏好等
- 这些记忆会持久保存,跨会话可用
短期记忆(会话记忆):
- 目前没有看到
daily或conversation类别的记忆 - 根据AGENTS.md的指导,短期记忆应该存放在
memory/YYYY-MM-DD.md文件中
让我检查一下是否有记忆目录和今天的记忆文件:
<tool_call>由于shell命令执行受策略限制,让我通过文件读取来检查记忆目录是否存在:
<tool_call>现在我可以清楚地回答你的问题了:
我的记忆存储系统
1. 长期记忆(核心记忆)
- 存储位置: SQLite数据库
- 访问方式: 通过
memory_store、memory_recall、memory_list、memory_forget工具 - 内容类型: 用户基本信息、偏好设置、重要决策等
- 特点: 持久化存储,跨会话可用
- 示例: 用户姓名、操作系统偏好、重要事件
2. 短期记忆(每日记忆)
- 存储位置:
memory/YYYY-MM-DD.md文件(如memory/2026-03-01.md) - 访问方式: 通过
file_read、file_write工具 - 内容类型: 每日对话记录、临时上下文、会话细节
- 特点: 按日期组织,便于回顾
- 示例: 今天的对话记录、临时任务、会话状态
3. 工作空间记忆
- 存储位置: 各种配置文件(
AGENTS.md、SOUL.md、USER.md、MEMORY.md等) - 内容类型: 身份定义、行为准则、用户偏好、长期总结
- 特点: 结构化存储,指导我的行为和决策
记忆管理流程:
- 每次会话开始: 读取
SOUL.md(身份)、USER.md(用户)、当日记忆文件 - 主会话中: 额外读取
MEMORY.md(长期总结) - 记忆更新:
- 重要信息 → 存入SQLite长期记忆
- 日常对话 → 写入当日记忆文件
- 重要总结 → 更新
MEMORY.md
这样的设计让我既能记住重要信息,又能保持会话间的连续性,同时避免记忆过载。
以下是图2中所有表及其字段的详细说明:
📦 记忆与对话数据库表结构
| 表名 | 作用 | 字段名 | 字段类型 | 字段中文名 | 说明 |
|---|---|---|---|---|---|
| memory_embeddings | 记忆向量存储 | key |
A-Z | 主键 | 向量记录唯一标识 |
memory_key |
A-Z | 关联记忆键 | 关联到 memories.key |
||
embedding |
向量数据 | 文本的向量表示(BLOB) | |||
updated_at |
A-Z | 更新时间 | 记录最后修改时间 | ||
| memories | 主记忆表 | id |
A-Z | 自增ID | 记忆唯一编号 |
key |
A-Z | 记忆键 | 快速查找特定记忆 | ||
content |
内容 | 记忆的文本内容 | |||
category |
A-Z | 分类 | 记忆类别(如 core(核心事实), daily(日常记录), conversation(对话上下文)) |
||
session_id |
A-Z | 会话ID | 所属会话标识 | ||
created_at |
A-Z | 创建时间 | 记录创建时间戳 | ||
updated_at |
A-Z | 更新时间 | 记录最后修改时间 | ||
| embedding_cache | 向量缓存表 | content_hash |
A-Z | 内容哈希 | 文本内容的哈希值(主键) |
embedding |
向量数据 | 缓存的向量表示 | |||
created_at |
A-Z | 创建时间 | 缓存生成时间 | ||
| kv | 键值存储表 | key |
A-Z | 键名 | 配置/状态键 |
value |
值 | 对应的值(文本/BLOB) | |||
| memories_fts | 全文搜索主表 | key |
A-Z | 记忆键 | 关联到 memories.key |
content |
内容 | 被索引的文本内容 | |||
memories_fts |
虚拟表 | FTS虚拟表特殊字段 | |||
rank |
相关度 | 搜索排序分值 | |||
| memories_fts_config | FTS配置表 | k |
A-Z | 配置键 | FTS内部配置项 |
v |
配置值 | 对应的配置值 | |||
| memories_fts_data | FTS数据表 | id |
123 | 数据块ID | FTS内部数据块编号 |
block |
0 | 数据块 | FTS内部数据块内容 | ||
| memories_fts_docsize | FTS文档长度表 | id |
123 | 文档ID | 对应文档的标识 |
sz |
0 | 文档大小 | 文档的长度信息 | ||
| memories_fts_idx | FTS索引表 | segid |
A-Z | 段ID | 索引段标识 |
term |
A-Z | 词项 | 索引的词条 | ||
pgno |
A-Z | 页号 | 索引位置信息 | ||
| messages | 消息记录表 | id |
123 | 消息ID | 消息唯一编号 |
session_id |
A-Z | 会话ID | 所属会话标识 | ||
role |
A-Z | 角色 | user/assistant/system | ||
content |
内容 | 消息文本内容 | |||
created_at |
A-Z | 创建时间 | 消息发送时间 | ||
updated_at |
A-Z | 更新时间 | 最后修改时间 | ||
| sessions | 会话记录表 | id |
A-Z | 会话ID | 会话唯一标识 |
provider |
A-Z | 提供商 | 使用的AI提供商 | ||
model |
A-Z | 模型 | 使用的具体模型 | ||
created_at |
A-Z | 创建时间 | 会话开始时间 | ||
updated_at |
A-Z | 更新时间 | 最后活动时间 |
🔍 关键关系说明
- 记忆核心链路:
memories→memory_embeddings(向量检索) +memories_fts(全文检索) - 对话记录:
sessions→messages(一对多) - 缓存优化:
embedding_cache避免重复计算向量 - 通用存储:
kv用于保存各类运行时状态
这套结构实现了混合检索(关键词+向量),让 NullClaw 在轻量级 SQLite 中具备完整的记忆管理能力。
这条日志信息是 NullClaw 在每次处理你的请求时,对其记忆检索策略的一次“自我汇报”。
简单来说,它在告诉你:“我刚刚决定只用最快的方式去查资料,没动用那些耗资源的复杂功能。”
结合你之前的技术背景,我们可以把这条日志拆解为以下几个关键决策点:
📋 日志逐项深度解读
| 字段 | 值 | 含义解读 (通俗版) | 含义解读 (技术版) |
|---|---|---|---|
| backend | sqlite |
仓库:我用的是本地 SQLite 数据库存记忆。 | 使用嵌入式 SQLite 作为持久化存储层,而非外部向量库(如 Chroma/Pinecone)。 |
| retrieval | keyword |
搜索方式:我用关键词匹配来找记忆。 | 启用 FTS5 (Full-Text Search) 进行布尔或排名搜索,速度快,资源占用极低。 |
| vector | none |
语义搜索:没开。我不做“意思相近”的搜索。 | **未启用向量嵌入 **(Embedding)。不会计算查询语句与历史记录的余弦相似度。这是省内存的关键。 |
| rollout | off |
多步推理:没开。我不做复杂的记忆推演。 | 禁用了基于记忆的链式思考或多步检索规划。 |
| hygiene | true |
清洁工:开了。我会清理无关噪音。 | 启用了记忆清洗机制,过滤掉低质量或过时的上下文片段。 |
| snapshot | false |
快照:没开。我不保存当前状态的完整镜像。 | 禁用会话状态快照,减少磁盘 I/O。 |
| cache | false |
缓存:没开。这次没命中通用缓存。 | 响应结果未写入通用缓存层(可能是首次查询或缓存策略未命中)。 |
| semantic_cache | false |
语义缓存:没开。没做“类似问题直接复用答案”的检查。 | 禁用基于语义相似度的答案缓存(这通常也需要向量计算)。 |
| summarizer | false |
总结器:没开。我没把旧对话压缩成摘要。 | 禁用后台摘要任务,不消耗 CPU 去生成历史对话的 Summary。 |
| sources | 1 |
来源数:找到了 1 条相关记忆。 | 检索模块从 SQLite FTS5 索引中返回了 1 个匹配文档。 |
💡 核心结论:这意味着什么?
【每次对话都有这: info(memory): memory plan resolved: backend=sqlite retrieval=keyword vector=none rollout=off hygiene=true snapshot=false cache=false semantic_cache=false summarizer=false sources=1 】
这条日志揭示了 NullClaw 的“极致轻量”设计哲学:
-
**速度优先 (Speed First):
它完全放弃了向量搜索 (Vector Search)。向量搜索虽然能理解“苹果”和“水果”的关系,但需要加载巨大的模型、计算矩阵乘法,非常吃内存和 CPU。NullClaw 选择只用关键词匹配 **(Keyword/FTS5),这使得它的检索速度极快(微秒级),且内存占用几乎可以忽略不计。 -
按需激活 (On-Demand):
注意vector=none,summarizer=false等。这说明 NullClaw 的架构是模块化的。默认配置下,它只开启最核心的功能。如果你需要更智能的语义记忆,可能需要修改配置文件(config.toml或启动参数)来显式开启这些功能(前提是你的硬件支持且配置了 Embedding 模型)。 -
当前的局限性:
- 死板:因为
vector=none,如果你问“上次聊的那个红色的水果是什么?”,而历史记录里只写了“苹果”,它可能找不到(因为它只匹配关键词“红色”或“水果”,而不理解语义关联)。 - 依赖精确措辞:你需要用和之前对话相似的词汇才能触发记忆。
- 死板:因为
🛠️ 如何改变这种行为?(如果你想让它更聪明)
如果你希望 NullClaw 像 OpenClaw 一样拥有语义记忆(即 vector=enabled),你需要:
- 配置 Embedding 模型:在配置文件中指定一个本地的轻量级 Embedding 模型(如
all-MiniLM-L6-v2的 ONNX 版本)或远程 API。 - 修改启动参数:NullClaw 通常允许通过 flag 或 config 文件开启向量支持。例如(具体需查阅最新文档):
nullclaw --enable-vector-search --embedding-model local:model-name - 权衡代价:一旦开启,内存占用可能会从 1MB 上升到 几十甚至几百 MB,启动速度也会变慢,这就失去了 NullClaw 最大的优势。
总结:
这条日志是在告诉你:“我现在处于‘极速模式’,只靠关键词匹配在干活,没动脑子做语义分析,所以我很轻、很快,但可能不够‘聪明’。”对于大多数简单的指令(如“打开文件”、“查一下昨天的日志”),这种模式完全够用且效率最高。
【长期记忆和短期记忆,你的使用策略是怎样的】
根据我的配置和工作空间文件,我的记忆使用策略如下:
记忆系统架构
1. 长期记忆 (Long-term Memory)
- 存储位置:
MEMORY.md文件 + SQLite 内存数据库 - 使用时机: 仅在主会话(与用户直接对话)中加载
- 内容类型:
- 用户的核心偏好和习惯(存储在
USER.md中) - 重要的学习经验、错误教训
- 关键决策和系统配置
- 需要长期记住的重要事件
- 用户的核心偏好和习惯(存储在
2. 短期记忆 (Short-term Memory)
- 存储位置:
memory/YYYY-MM-DD.md每日文件 - 使用时机: 每次会话都会读取当天和昨天的文件
- 内容类型:
- 当天的对话记录
- 临时的上下文信息
- 会话中的具体细节
- 需要记住但不必长期保存的信息
具体使用策略
启动流程
-
每次会话开始:
- 读取
SOUL.md(我的身份定义) - 读取
USER.md(用户偏好) - 读取当天和昨天的
memory/YYYY-MM-DD.md文件 - 如果是主会话: 额外读取
MEMORY.md
- 读取
-
记忆维护:
- 定期(每几天)使用心跳检查来整理记忆
- 从每日文件中提取重要信息更新到
MEMORY.md - 删除
MEMORY.md中过时的信息
记忆工具使用
- memory_store: 存储用户事实、偏好和重要决策
core类别:稳定的用户事实daily类别:会话笔记conversation类别:重要的对话上下文
- memory_recall: 搜索相关记忆
- memory_list: 列出最近的记忆记录
- memory_forget: 删除过时或敏感的记忆
安全策略
- 不共享原则: 在群聊或共享环境中不加载
MEMORY.md - 隐私保护: 不泄露私人数据,不存储每次聊天的常规问候
- 选择性记忆: 只存储真正重要的信息,避免记忆膨胀
最佳实践
- "写下来"原则: 如果想让某件事被记住,就写入文件
- "大脑笔记"无效: 不依赖"心理笔记",所有记忆都写入文件
- 定期整理: 使用心跳检查来维护记忆系统
- 安全第一: 不暴露内部记忆实现细节给用户
这样的设计让我既能保持会话连续性,又能保护用户隐私,同时避免记忆过载。
浙公网安备 33010602011771号