内存系统

LibreFang 的内存系统提供持久化存储、语义搜索和知识图谱功能。


目录


概述

LibreFang 内存系统包含:

  • SQLite 持久化 - 结构化 KV 存储
  • 向量嵌入 - 语义搜索能力
  • 知识图谱 - 实体和关系
  • 会话管理 - 跨通道记忆
  • 会话压缩 - 当单个会话体量过大时自动收缩
  • 梦境模式(Auto-Dream) - 可选的后台整固机制,让加入的 agent 定期反思并整理自己的长期记忆,详见 后台整固(梦境模式)
  • 使用追踪 - 成本和使用统计

架构

┌─────────────────────────────────────────┐
              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_rateFloat0.05记忆置信度衰减率
sqlite_pathString~/.librefang/data/librefang.db数据库路径
vector_dimensionInteger1536向量维度
max_memory_itemsInteger10000最大记忆条目
auto_compactBooleantrue自动压缩

会话管理

创建会话

# 创建新会话
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

压缩算法

  1. 保留最近 N 条消息
  2. 提取关键信息
  3. 生成摘要
  4. 保留工具调用历史

后台整固(梦境模式)

会话压缩只处理 单个会话 不溢出。梦境模式是更长时间尺度上的互补机制:定期唤醒已加入的 agent,把一份四阶段提示词(定位 / 收集 / 整固 / 修剪)交给它,让它自己跨会话地整理长期记忆 —— 通过 memory_store 写入持久见解、修剪过时条目。

开启方式

两个开关必须同时为 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

一次梦境的流程

  1. 主触发路径是 AgentLoopEnd 钩子 —— agent 每完成一次 turn,kernel 立刻依次检查四道闸门:全局启用 → 时间间隔 → 会话活跃数 → 文件锁。任一不通过即跳过。另有稀疏的兜底调度器(默认 check_interval_secs = 86400,即每天一次)覆盖从不 turn 的 agent(例如等待外部触发的 channel bot)。
  2. 闸门通过后,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 工具,也只会拿到合成的错误结果。
  3. 流式进度(phase、工具调用次数、涉及的记忆条目、最近一 turn 预览、token / 费用)存入每 agent 的进度注册表,通过状态端点对外暴露。
  4. 成功后锁的 mtime 前进到 "现在"(作为时间闸门的基准);失败或中止后会回滚 mtime,下次 tick 会重试。

使用入口

  • Web Dashboard — 设置页 → 梦境模式卡片,每个 agent 一行:加入开关、运行中/完成/失败 badge、"立即梦境" / "中止" 按钮、运行中时的进度预览。
  • TUIlibrefang → Dashboard tab 顶部会出现 DREAMS 条,每 agent 一行状态字符;未发生过梦境时自动隐藏。
  • HTTP APIGET /api/auto-dream/statusPOST /api/auto-dream/agents/{id}/triggerPOST /api/auto-dream/agents/{id}/abortPUT /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 或用户暴露:

  1. prefetch 错误 → 打 WARN 日志,该 provider 的贡献用空字符串代替。
  2. on_turn_complete 错误 → 打 WARN 日志,静默丢弃。
  3. 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/searchGET搜索记忆(查询参数:qlimitthreshold
/api/memoryPOST存储记忆条目
/api/memory/{id}GET获取指定记忆条目
/api/memory/{id}DELETE删除记忆条目

会话操作

端点方法说明
/api/memory/sessionsGET列出会话
/api/memory/sessions/{id}GET获取会话详情
/api/memory/sessions/{id}/compactPOST压缩会话

知识图谱

知识图谱是 per-agent 的,不是全局 REST 接口。用 per-agent 端点:

端点方法说明
/api/memory/agents/{id}/relationsGET查询该 agent 的知识图谱(实体 + 关系)
/api/memory/agents/{id}/relationsPOST给该 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

字段类型用途
idUUID唯一记忆 ID
agent_idUUID所有 agent —— 条目严格按 agent 隔离,不会跨 agent 泄漏
contenttext记忆文本 / 事实
sourceenum来源:auto_memorizemanual_add
scopeenum级别:user_memorysession_memoryagent_memory
confidencef64(0.0–1.0)相关度分数;随时间衰减
metadataJSON自由 KV;含 category(见下)
created_atRFC3339 时间戳创建时间
accessed_atRFC3339 时间戳最近访问 —— 驱动衰减
access_countint被召回的次数
deletedbool软删除标志
embeddingvector(独立表)余弦相似度搜索用

作用域(Scope)

作用域生命期用途
user_memory跨 session 持久化用户级事实和偏好(可在该用户的多个 agent 间共享)。
session_memorysession_ttl_hours(默认 24)后自动删除当前对话的工作笔记。
agent_memoryper-agent 持久化Agent 学到的行为和技能,严格隔离。

类别(Category)

类别住在 metadata.categoryauto_memorize 默认抽取的有:communication_stylepreferenceexpertisework_styleproject_contextpersonal_detailfrustration。类别列表可配置。

自动整合

每个 agent 每 10auto_memorize 自动触发一次(无需显式 cron / 用户操作)。整合器:

  1. 用分级相似度梯队找重复或近似条目:
    • 子串包含(完全 / 超集 / 子集)
    • 向量余弦(存了 embedding 时)
    • Jaccard 词重叠(回退)
  2. 每个重复簇里保留最近创建的那条。
  3. 软删除其余,记日志方便审计。

整合器只扫最近 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_memorysession_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 清(sessionagentuser)
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。


最佳实践

  1. 定期压缩 - 防止会话过大
  2. 使用标签 - 便于组织和搜索
  3. 设置衰减率 - 控制记忆置信度
  4. 监控使用 - 跟踪成本和使用量

故障排除

内存搜索慢

# 重建向量索引
librefang memory reindex

# 检查索引状态
librefang memory index-status

数据库膨胀

# 清理旧数据
librefang memory cleanup --older-than 30d

# 压缩数据库
librefang memory vacuum

记忆丢失

# 检查数据库完整性
librefang doctor

# 恢复备份
librefang memory restore --backup <path>