内存系统
LibreFang 的内存系统提供持久化存储、语义搜索和知识图谱功能。
目录
概述
LibreFang 内存系统包含:
- SQLite 持久化 - 结构化 KV 存储
- 向量嵌入 - 语义搜索能力
- 知识图谱 - 实体和关系
- 会话管理 - 跨通道记忆
- 会话压缩 - 当单个会话体量过大时自动收缩
- 梦境模式(Auto-Dream) - 可选的后台整固机制,让加入的 agent 定期反思并整理自己的长期记忆,详见 后台整固(梦境模式)
- 使用追踪 - 成本和使用统计
提示: 内存数据默认存储在 ~/.librefang/data/librefang.db,可配置存储路径。
架构
┌─────────────────────────────────────────┐
│ Agent Loop │
└─────────────────┬───────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Memory Subsystem │
├─────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Session │ │ Vector │ │Knowledge│ │
│ │ Store │ │ Search │ │ Graph │ │
│ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────┤
│ SQLite Database │
└─────────────────────────────────────────┘
配置
基本配置
[memory]
decay_rate = 0.05
sqlite_path = "~/.librefang/data/librefang.db"
高级配置
[memory]
decay_rate = 0.05
sqlite_path = "~/.librefang/data/librefang.db"
vector_dimension = 1536
max_memory_items = 10000
auto_compact = true
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
decay_rate | Float | 0.05 | 记忆置信度衰减率 |
sqlite_path | String | ~/.librefang/data/librefang.db | 数据库路径 |
vector_dimension | Integer | 1536 | 向量维度 |
max_memory_items | Integer | 10000 | 最大记忆条目 |
auto_compact | Boolean | true | 自动压缩 |
会话管理
创建会话
# 创建新会话
librefang session create --name "research-project"
列出会话
# 列出所有会话
librefang session list
会话操作
# 查看会话详情
librefang session info <session-id>
# 删除会话
librefang session delete <session-id>
# 压缩会话
librefang session compact <session-id>
# 导出会话
librefang session export <session-id> --format json
记忆操作
存储记忆
# 存储简单键值(位置参数:agent key value)
librefang memory store <agent> "user:preference:theme" "dark"
# 示例:为 coder agent 存储版本信息
librefang memory store coder "project:version" "1.0"
# 等价形式:使用 set 子命令
librefang memory set coder "note:1" "Important note"
搜索记忆
# 关键词搜索
librefang memory search "project"
# 向量搜索 (语义搜索)
librefang memory search --vector "find information about AI agents"
# 带过滤的搜索
librefang memory search "meeting" --tags "work" --limit 10
记忆操作
# 读取记忆
librefang memory get <key>
# 更新记忆
librefang memory update <key> --value "new value"
# 删除记忆
librefang memory delete <key>
# 列出所有记忆
librefang memory list --prefix "project:"
向量搜索
语义搜索
LibreFang 支持向量嵌入的语义搜索:
# 语义搜索示例
librefang memory search --vector "machine learning techniques for text classification"
相似度阈值
[memory]
similarity_threshold = 0.75
API 端点
# 语义搜索 API(GET 请求,使用查询参数)
curl "http://127.0.0.1:4545/api/memory/search?q=find+information+about+AI&limit=10&threshold=0.8"
知识图谱
实体管理
# 添加实体
librefang kg add-entity --type "person" --name "John Doe" --properties '{"role": "developer"}'
# 列出实体
librefang kg list-entities --type "person"
# 搜索实体
librefang kg search-entities "John"
关系管理
# 添加关系
librefang kg add-relation \
--from "person:john" \
--relation "works_at" \
--to "company:acme"
# 列出关系
librefang kg list-relations --entity "person:john"
# 查询关系
librefang kg query --from "person:john" --relation "works_at"
图谱查询
# 查询路径
librefang kg path --from "person:alice" --to "company:acme"
# 查询子图
librefang kg subgraph --entity "person:bob" --depth 2
会话压缩
自动压缩
当会话消息数量达到阈值时自动压缩。压缩参数由 runtime 内部管理,不在 config.toml 中暴露。默认阈值为 80 条消息,保留最近 20 条原文,其余进行摘要压缩。
手动压缩
# 压缩会话
librefang session compact <session-id>
# 压缩所有会话
librefang session compact-all
# 查看压缩状态
librefang session compaction-status
压缩算法
- 保留最近 N 条消息
- 提取关键信息
- 生成摘要
- 保留工具调用历史
后台整固(梦境模式)
会话压缩只处理 单个会话 不溢出。梦境模式是更长时间尺度上的互补机制:定期唤醒已加入的 agent,把一份四阶段提示词(定位 / 收集 / 整固 / 修剪)交给它,让它自己跨会话地整理长期记忆 —— 通过 memory_store 写入持久见解、修剪过时条目。
默认关闭。 梦境模式会按计划消耗真实 token,因此全局开关和每个 agent 的加入开关默认都是 false,必须显式开启。完整参考见 [auto_dream]。
开启方式
两个开关必须同时为 true:
# ~/.librefang/config.toml
[auto_dream]
enabled = true
min_hours = 24 # 同一 agent 再次梦境的最短间隔
min_sessions = 5 # 上次梦境之后至少触及这么多会话才会触发
# agent manifest (.toml)
auto_dream_enabled = true
# 可选:用 per-agent 覆盖全局阈值
auto_dream_min_hours = 168 # 每周一次,适合低频 agent
auto_dream_min_sessions = 1 # 每个会话之后都触发,适合高频 agent
一次梦境的流程
- 主触发路径是
AgentLoopEnd钩子 —— agent 每完成一次 turn,kernel 立刻依次检查四道闸门:全局启用 → 时间间隔 → 会话活跃数 → 文件锁。任一不通过即跳过。另有稀疏的兜底调度器(默认check_interval_secs = 86400,即每天一次)覆盖从不 turn 的 agent(例如等待外部触发的 channel bot)。 - 闸门通过后,agent 以 fork turn 方式从 canonical session 派生调用(
kernel.run_forked_agent_streaming)—— system prompt、tools、消息前缀和父 turn 字节级一致,命中 Anthropic prompt cache。Fork turn 不会把消息写回 canonical session,所以用户对话历史不会被梦境过程污染。工具白名单(memory_store/memory_recall/memory_list)在 execute 阶段强制,不在 request 构造阶段过滤 —— 这样请求 schema 仍然和父 turn 对齐,cache 才能命中。被 prompt 注入的梦境即使试图调用非 memory 工具,也只会拿到合成的错误结果。 - 流式进度(phase、工具调用次数、涉及的记忆条目、最近一 turn 预览、token / 费用)存入每 agent 的进度注册表,通过状态端点对外暴露。
- 成功后锁的 mtime 前进到 "现在"(作为时间闸门的基准);失败或中止后会回滚 mtime,下次 tick 会重试。
使用入口
- Web Dashboard — 设置页 → 梦境模式卡片,每个 agent 一行:加入开关、运行中/完成/失败 badge、"立即梦境" / "中止" 按钮、运行中时的进度预览。
- TUI —
librefang→ Dashboard tab 顶部会出现 DREAMS 条,每 agent 一行状态字符;未发生过梦境时自动隐藏。 - HTTP API —
GET /api/auto-dream/status、POST /api/auto-dream/agents/{id}/trigger、POST /api/auto-dream/agents/{id}/abort、PUT /api/auto-dream/agents/{id}/enabled。 - 审计日志 — 每次梦境都会发出一条
DreamConsolidation审计事件,附带 phase、token 使用量和美元成本。
手动控制
POST /api/auto-dream/agents/{id}/trigger绕过时间和会话闸门(仍需满足文件锁和加入开关)。POST /api/auto-dream/agents/{id}/abort中止手动触发的梦境,并回滚 mtime 让时间闸门重新打开。- 调度器触发的梦境是顺序串行执行,不支持单独中止 —— 只能等它完成或命中
timeout_secs(默认 600 秒)。
完整字段、默认值、manifest 覆盖和 runtime 工具白名单的强制逻辑见 [auto_dream]。
内存提供者插件 API
MemoryProvider trait 允许把外部记忆后端(向量数据库、知识图谱、远程存储服务等)和 LibreFang 内置的 SQLite 内存并排接入。
架构
- 永远存在 一个内置 provider(默认的 SQLite 后端存储)。它不能被移除。
- 同时最多注册 一个外部 provider。外部 provider 只是补充内置存储,不替换它。
- 外部 provider 失败时,内置 provider 继续正常工作。外部 provider 的错误会被捕获、以
WARN级别记录,不会传播到 agent loop。
Trait 接口
#[async_trait]
pub trait MemoryProvider: Send + Sync {
/// A short, unique name for this provider (e.g. "pinecone", "weaviate").
fn name(&self) -> &str;
/// Returns `true` for the built-in provider, `false` for all external providers.
fn is_builtin(&self) -> bool;
/// Returns a text block to inject into the agent system prompt at session start,
/// or `None` if there is nothing to inject for this session.
async fn system_prompt_block(&self, session_id: &str) -> Option<String>;
/// Fetches relevant context for the given query string before an LLM call.
/// The returned string is appended to the context window.
async fn prefetch(&self, query: &str, session_id: &str) -> Result<String, MemoryError>;
/// Called after each agent turn completes. Use this hook to index new content,
/// synchronize state, or flush write buffers to the external backend.
async fn on_turn_complete(&self, session_id: &str, turn_summary: &str) -> Result<(), MemoryError>;
}
注册外部 provider
在初始化阶段把你的实现传给 kernel 的内存子系统:
use librefang_memory::{MemoryManager, MemoryProvider};
// Build your custom provider
let my_provider: Arc<dyn MemoryProvider> = Arc::new(MyVectorDbProvider::new(config));
// Register it with the memory manager
memory_manager.set_external_provider(my_provider).await;
同时只能注册一个外部 provider。再次调用 set_external_provider 会替换之前注册的 provider。
用 prefetch_all 聚合上下文
内存管理器暴露 prefetch_all(query, session_id),它会调用每个已注册 provider 的 prefetch 并把结果拼接:
// Called internally by the agent loop before each LLM request
let context = memory_manager.prefetch_all(&user_query, &session_id).await;
各 provider 的结果之间用空行分隔,并带上 provider 名作为标签前缀。任一 provider 返回错误时,该 provider 的结果会被跳过(同时打 WARN 日志),其余 provider 继续被查询。
错误隔离
外部 provider 的错误从不向 agent 或用户暴露:
prefetch错误 → 打WARN日志,该 provider 的贡献用空字符串代替。on_turn_complete错误 → 打WARN日志,静默丢弃。system_prompt_block错误(panic)→ 在调用点捕获,返回None。
这种设计确保配错的或暂时不可用的外部后端无法干扰 agent loop。
使用追踪
追踪操作
# 查看使用统计
librefang usage
# 查看 Agent 使用
librefang usage --agent <agent-id>
# 查看提供商使用
librefang usage --provider
成本追踪
# 查看成本
librefang cost
# 按时间范围查看成本
librefang cost --from 2025-01-01 --to 2025-01-31
# 导出报告
librefang cost export --format csv
API 端点
KV 内存操作
| 端点 | 方法 | 说明 |
|---|---|---|
/api/memory/search | GET | 搜索记忆(查询参数:q、limit、threshold) |
/api/memory | POST | 存储记忆条目 |
/api/memory/{id} | GET | 获取指定记忆条目 |
/api/memory/{id} | DELETE | 删除记忆条目 |
会话操作
| 端点 | 方法 | 说明 |
|---|---|---|
/api/memory/sessions | GET | 列出会话 |
/api/memory/sessions/{id} | GET | 获取会话详情 |
/api/memory/sessions/{id}/compact | POST | 压缩会话 |
知识图谱
知识图谱是 per-agent 的,不是全局 REST 接口。用 per-agent 端点:
| 端点 | 方法 | 说明 |
|---|---|---|
/api/memory/agents/{id}/relations | GET | 查询该 agent 的知识图谱(实体 + 关系) |
/api/memory/agents/{id}/relations | POST | 给该 agent 的图谱存新关系 |
Agent 也可以从循环里直接用 knowledge_add_entity / knowledge_add_relation / knowledge_query 工具 构建图谱。早期文档列的 /api/memory/kg/* 端点从未发布过 —— 调那些路径会 404。
主动记忆(Proactive Memory)
主动记忆让 agent 自主浮现、整合、召回长期知识,不用显式工具调用。每条记忆同时存三份 —— 语义存储(文本 + embedding)、结构化 KV(memory:{id})、知识图谱(抽取的 entity / relation 三元组) —— 所以 agent 可以按相似度、按 ID、或从已知 entity 沿图谱遍历来召回。
条目 schema
| 字段 | 类型 | 用途 |
|---|---|---|
id | UUID | 唯一记忆 ID |
agent_id | UUID | 所有 agent —— 条目严格按 agent 隔离,不会跨 agent 泄漏 |
content | text | 记忆文本 / 事实 |
source | enum | 来源:auto_memorize、manual_add 等 |
scope | enum | 级别:user_memory、session_memory、agent_memory |
confidence | f64(0.0–1.0) | 相关度分数;随时间衰减 |
metadata | JSON | 自由 KV;含 category(见下) |
created_at | RFC3339 时间戳 | 创建时间 |
accessed_at | RFC3339 时间戳 | 最近访问 —— 驱动衰减 |
access_count | int | 被召回的次数 |
deleted | bool | 软删除标志 |
embedding | vector(独立表) | 余弦相似度搜索用 |
作用域(Scope)
| 作用域 | 生命期 | 用途 |
|---|---|---|
user_memory | 跨 session 持久化 | 用户级事实和偏好(可在该用户的多个 agent 间共享)。 |
session_memory | session_ttl_hours(默认 24)后自动删除 | 当前对话的工作笔记。 |
agent_memory | per-agent 持久化 | Agent 学到的行为和技能,严格隔离。 |
类别(Category)
类别住在 metadata.category。auto_memorize 默认抽取的有:communication_style、preference、expertise、work_style、project_context、personal_detail、frustration。类别列表可配置。
自动整合
每个 agent 每 10 次 auto_memorize 自动触发一次(无需显式 cron / 用户操作)。整合器:
- 用分级相似度梯队找重复或近似条目:
- 子串包含(完全 / 超集 / 子集)
- 向量余弦(存了 embedding 时)
- Jaccard 词重叠(回退)
- 每个重复簇里保留最近创建的那条。
- 软删除其余,记日志方便审计。
整合器只扫最近 100 条,以让 dedup 循环在热路径上保持 O(n²)-安全。要扫完整历史,手动调 POST /api/memory/agents/{id}/consolidate。
衰减
未访问超过 1 天的记忆:
decayed_conf = original_conf × e^(-decay_rate × days_since_access)
final_conf = min(decayed_conf × (1 + log2(access_count)), 1.0)
衰减扫描每小时最多一次(在 auto_retrieve 顶部检查)。默认值:confidence_decay_rate = 0.01(很慢 —— 大约 70 天减半)、session_ttl_hours = 24。一条记忆"过期"的条件是:(a)超过一天没访问,或 (b)scope 是 session_memory 且 TTL 到了。
per-agent vs 跨 agent
除 user_memory 外,所有条目严格按 agent 隔离。Search、consolidate、eviction 都按 agent_id 过滤 —— 一个 agent 没有路径读到另一个 agent 的 agent_memory 或 session_memory。Per-agent 上限默认 1000 条;超过时按"最旧 / 最低 confidence"逐出。
API 端点
主动记忆端点分两类 —— 全局和 per-agent。(KV memory 在 /api/memory/agents/{id}/kv/*,是另一个子系统,不在此列。)
全局 / 跨 agent:
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /api/memory | 列出所有主动记忆(分页,可选 ?category=) |
| POST | /api/memory | 新增记忆条目 |
| GET | /api/memory/search?q=&limit= | 跨所有条目语义搜索 |
| GET | /api/memory/stats | 全局统计 |
| GET | /api/memory/config | 获取记忆配置 |
| PATCH | /api/memory/config | 更新记忆配置 |
| POST | /api/memory/cleanup | 手动跑 session-TTL 清理 |
| POST | /api/memory/decay | 手动跑 confidence 衰减 |
| POST | /api/memory/bulk-delete | 批量删除 |
| PUT | /api/memory/items/{id} | 更新单条记忆 |
| DELETE | /api/memory/items/{id} | 删除单条记忆 |
| GET | /api/memory/items/{id}/history | 记忆编辑历史 |
| GET | /api/memory/user/{user_id} | 该用户跨所有 agent 的 user-level 记忆 |
Per-agent:
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /api/memory/agents/{id} | 列出该 agent 的记忆 |
| DELETE | /api/memory/agents/{id} | 重置(清空)该 agent 的全部记忆 |
| GET | /api/memory/agents/{id}/search?q= | 限制在此 agent 范围的语义搜索 |
| GET | /api/memory/agents/{id}/stats | 该 agent 的统计 |
| DELETE | /api/memory/agents/{id}/level/{level} | 按 scope 清(session、agent、user) |
| GET | /api/memory/agents/{id}/duplicates | 找近似条目但不删 |
| POST | /api/memory/agents/{id}/consolidate | 对完整历史触发整合 |
| GET | /api/memory/agents/{id}/count | 记忆数量 |
| GET | /api/memory/agents/{id}/relations | 查询该 agent 的知识图谱 |
| POST | /api/memory/agents/{id}/relations | 存关系 |
| GET | /api/memory/agents/{id}/export | 导出该 agent 的记忆(JSON) |
| POST | /api/memory/agents/{id}/import | 导入记忆(JSON) |
之前的 /api/memory/proactive/* 命名空间是一个从未发布的草稿端点 —— 用上面这套。如果客户端还在调旧路径,会得到 404。
最佳实践
- 定期压缩 - 防止会话过大
- 使用标签 - 便于组织和搜索
- 设置衰减率 - 控制记忆置信度
- 监控使用 - 跟踪成本和使用量
故障排除
内存搜索慢
# 重建向量索引
librefang memory reindex
# 检查索引状态
librefang memory index-status
数据库膨胀
# 清理旧数据
librefang memory cleanup --older-than 30d
# 压缩数据库
librefang memory vacuum
记忆丢失
# 检查数据库完整性
librefang doctor
# 恢复备份
librefang memory restore --backup <path>