多智能体记忆系统
为 AI Agent 提供跨会话持久化记忆、团队知识沉淀与语义检索能力 | Memory System API v3.0.2
1. 项目概述
1.1 背景与定位
在多智能体协作场景中,AI Agent 面临以下核心痛点:
- 无状态困境:Agent 每次对话都是从零开始,之前的交互经验无法积累
- 会话间记忆丢失:对话结束后,上下文和决策依据全部消失
- 团队知识孤岛:多个 Agent 各自独立工作,无法共享已学到的知识和经验
- 检索效率低下:当记忆积累到一定规模,关键词匹配无法满足语义级别的回忆需求
- 记忆无限膨胀:缺少自动化的清理和压缩机制,存储成本持续增长
- 知识结构化不足:原始记忆是自由文本,缺少事实提取、场景聚合和画像生成等智能化处理能力
多智能体记忆系统正是为解决这些问题而设计的。它为 AI Agent 提供了一套双层次(工作记忆 + 长期记忆)、LLM 驱动的智能生命周期管理、多团队隔离、语义检索的记忆基础设施,让 Agent 能够像人类一样"记住"、"回忆"、"总结"和"遗忘"。
1.2 核心能力
💾 持久化记忆
跨会话、跨部署的记忆存储。Agent 重启后依然能回忆之前学到的知识和经验。
🔍 语义检索
基于 BGE 向量模型的语义搜索,无需精确关键词匹配,用自然语言即可找到相关记忆。
👥 多团队隔离
团队间数据完全隔离,互不可见。每个团队拥有独立的记忆空间和 API Key。
🔄 生命周期管理
工作记忆自动过期、长期记忆智能压缩与清理。让记忆保持精简有价值。
📝 知识共享
团队级共享记忆,一个 Agent 的发现可以被整个团队复用,避免重复劳动。
⚡ 高性能架构
MySQL 持久化 + Redis 缓存 + BGE 向量检索,写入 P99 < 20ms,读取 P99 < 30ms。
🧠 智能生命周期
LLM 驱动的原子事实提取、场景聚合和用户画像生成,配合 Pipeline 自动化引擎实现记忆全生命周期管理。
🤖 Pipeline 自动化
可配置的自动压缩、清理规则和暖机机制。写入工作记忆时自动检查阈值,无需手动触发。
1.3 记忆层次说明
系统采用双层次记忆模型,模拟人类的短期记忆与长期记忆,同时支持基于 LLM 的场景聚合和用户画像层:
| 维度 | 工作记忆 (Working Memory) | 长期记忆 (Long-term Memory) |
|---|---|---|
| 存储介质 | Redis | MySQL + BGE 向量 |
| 生命周期 | 72 小时 TTL(可配置),或手动压缩后删除 | 永久保存,直到被清理策略移除 |
| 检索方式 | 按时间顺序获取最近条目 | 语义向量检索(余弦相似度) |
| 数据结构 | 有序列表(Redis List) | 结构化记录 + 512 维向量 |
| 适用场景 | 当前会话上下文、临时笔记、待处理任务 | 经验总结、用户偏好、代码规范、决策记录 |
| 容量特点 | 轻量、快速、自动过期 | 大容量、可检索、支持重要性评分 |
| 持久化 | 纯内存,服务重启丢失 | 磁盘持久化,不怕重启 |
扩展数据类型
| 数据类型 | 说明 | 生成方式 | 持久化 |
|---|---|---|---|
| 场景块 (Scenarios) | 按主题聚合的记忆块,含摘要和关联记忆 ID 列表 | /lifecycle/aggregate-scenes(LLM 聚合) | MySQL 持久化 |
| 用户画像 (Persona) | 结构化画像:偏好、习惯、擅长领域、沟通风格 | /lifecycle/generate-persona(LLM 提取) | MySQL 持久化 |
| 原子事实 (Facts) | 从工作记忆提取的独立结构化事实,存为长期记忆 | /lifecycle/extract-facts(LLM 提取) | MySQL 持久化(metadata 标记来源) |
| Pipeline 配置 | 自动压缩、清理和暖机规则 | /lifecycle/auto-config | MySQL 持久化 |
记忆流转路径
工作记忆 →(压缩/事实提取)→ 长期记忆 →(场景聚合/画像生成)→ 场景块/用户画像
长期记忆 →(清理)→ 归档/删除
- 写入阶段:Agent 将当前交互的关键信息写入工作记忆(Redis),速度快、不阻塞
- 沉淀阶段:通过
/lifecycle/compress将工作记忆压缩为摘要,或通过/lifecycle/extract-facts提取结构化原子事实,写入长期记忆(MySQL) - 聚合阶段:通过
/lifecycle/aggregate-scenes将相关记忆聚合为场景块,通过/lifecycle/generate-persona生成用户画像 - 检索阶段:Agent 需要回忆时,通过语义搜索从长期记忆中找到相关条目
- 清理阶段:通过
/lifecycle/cleanup或/lifecycle/auto-config配置的自动规则清理过期记忆
1.4 架构流程图
graph LR
subgraph Client["客户端"]
A[AI Agent
OpenClaw / Hermes / Claude Code / Codex]
end
subgraph Gateway["接入层"]
B[Nginx
HTTPS + SSL]
C[Auth Middleware
HMAC-SHA256 签名验证]
end
subgraph Core["核心服务 (Flask)"]
D[API Routes]
E[Memory System
业务逻辑]
F[Lifecycle Manager]
F1[Fact Extractor
原子事实提取]
F2[Scenario Aggregator
场景聚合]
F3[Persona Generator
画像生成]
F4[Pipeline Engine
自动化引擎]
end
subgraph Storage["存储层"]
G[(MySQL
长期记忆 + 向量)]
H[(Redis
工作记忆缓存)]
I[BGE Embedding
512 维向量化]
end
A -->|"HTTPS 请求
+ HMAC 签名"| B
B --> C
C -->|"认证通过"| D
C -.->|"认证失败 → 401"| A
D --> E
E -->|"写入记忆"| G
E -->|"缓存工作记忆"| H
E -->|"文本→向量"| I
E -->|"语义搜索"| G
F -->|"压缩: 工作→长期"| E
F -->|"清理: 过期记忆"| G
F1 -->|"提取事实→长期记忆"| E
F2 -->|"聚合场景"| G
F3 -->|"生成画像"| G
F4 -->|"自动触发"| F
F4 -->|"自动触发"| F1
style Client fill:#1a1f2e,stroke:#58a6ff,color:#c9d1d9
style Gateway fill:#1a1f2e,stroke:#d29922,color:#c9d1d9
style Core fill:#1a1f2e,stroke:#3fb950,color:#c9d1d9
style Storage fill:#1a1f2e,stroke:#f85149,color:#c9d1d9
数据流说明
| 流程 | 路径 | 说明 |
|---|---|---|
| 写入记忆 | Agent → Nginx → Auth → Routes → Memory System → MySQL + BGE向量 | 文本经 BGE 模型向量化后,连同元数据一起持久化到 MySQL |
| 语义检索 | Agent → Nginx → Auth → Routes → Memory System → BGE向量 → MySQL向量比对 | 查询文本向量化后,与存储向量计算余弦相似度,返回 Top-K 结果 |
| 工作记忆 | Agent → Nginx → Auth → Routes → Memory System → Redis List | 写入 Redis List(TTL 自动过期),读取时按时间倒序返回 |
| 压缩 | Lifecycle → 读取工作记忆 → 调用 LLM 摘要 → 写入长期记忆 → 删除工作记忆 | 将多条工作记忆压缩为一条长期记忆摘要 |
| 事实提取 | Lifecycle → 读取工作记忆 → LLM 提取结构化事实 → 每条事实存为独立长期记忆 | 从工作记忆中提取独立的、可检索的原子事实 |
| 场景聚合 | Lifecycle → 读取个人记忆 → LLM 按主题聚合 → 存储场景块 | 将相关记忆聚合为场景块并生成摘要 |
| 画像生成 | Lifecycle → 读取记忆+场景 → LLM 分析 → 输出结构化画像 | 从历史记忆中提取用户偏好、习惯、擅长领域 |
| Pipeline | Lifecycle → 每次写入工作记忆 → 检查阈值 → 自动触发压缩/清理 | 可配置的自动压缩、清理和暖机规则 |
| 清理 | Lifecycle → 查询过期记忆 → 删除低重要性条目 | 基于 last_accessed + importance 双维度清理 |
1.5 适用场景
🤖 多智能体协作开发
多个 AI Agent 协同编写代码,共享编码规范、设计决策和技术栈知识,避免重复踩坑。
💬 客服系统
客服 Agent 记住用户历史问题和偏好,提供个性化服务。团队共享常见问题解决方案。
🔬 研究团队
研究 Agent 积累文献笔记、实验结论和方法论,团队成员可互相检索和引用。
📊 个人助理
个人 Agent 记住你的偏好、习惯和待办事项,跨会话提供连续的个性化体验。
📈 量化策略
策略 Agent 积累回测经验、参数调优记录和市场观察,形成可检索的策略知识库。
🏗️ 项目管理
PM Agent 记录会议决策、进度更新和风险点,团队成员随时回顾项目上下文。
2. 快速开始
2.1 前置条件
| 条件 | 说明 |
|---|---|
| HTTP 客户端 | curl / Python requests / 任何支持 HTTP 的语言 |
| API Key + Secret | 由管理员签发,每个团队一对 |
| 时钟同步 | 客户端时钟偏差需在 ±5 分钟以内(NTP 同步即可) |
2.2 获取 API Key
API Key 由管理员统一分配。请联系系统管理员获取:
X-API-Key:API 访问密钥,用于标识团队身份Secret:签名密钥,用于计算 HMAC-SHA256 签名。仅在创建时展示一次,请妥善保管
2.3 第一个请求
获取 API Key 后,先调用 /health 验证连通性(无需认证):
curl -s https://memory.lsz.name/health
# {"ok": true, "data": {"status": "ok"}}
然后用认证接口验证 Key 是否正常:
import hashlib, hmac, time, json, requests
API_KEY = "your_api_key_here"
SECRET = "your_secret_here"
BASE = "https://memory.lsz.name"
ts = int(time.time())
sig = hmac.new(SECRET.encode(), str(ts).encode(), hashlib.sha256).hexdigest()
r = requests.get(f"{BASE}/stats", headers={
"X-API-Key": API_KEY,
"X-Timestamp": str(ts),
"X-Signature": sig
})
print(r.json())
# {"ok": true, "data": {"personal_memories": 0, "team_memories": 0, "agents": 0, ...}}
2.4 Python SDK(MemoryClient)
推荐使用封装好的客户端类,所有签名细节自动处理:
import hashlib, hmac, time, json, requests
class MemoryClient:
"""Memory System API 客户端 — 自动处理 HMAC 签名"""
def __init__(self, api_key, secret, base_url="https://memory.lsz.name"):
self.api_key = api_key
self.secret = secret
self.base_url = base_url
def _sign(self, method, ts, body=None):
if method == "GET" or body is None:
msg = str(ts).encode() # GET: body = b""
else:
msg = str(ts).encode() + json.dumps(body, ensure_ascii=True).encode()
return hmac.new(self.secret.encode(), msg, hashlib.sha256).hexdigest()
def _headers(self, method, ts, body=None):
return {
"X-API-Key": self.api_key,
"X-Timestamp": str(ts),
"X-Signature": self._sign(method, ts, body),
}
def get(self, path, params=None):
ts = int(time.time())
return requests.get(f"{self.base_url}{path}",
headers=self._headers("GET", ts), params=params)
def post(self, path, body):
ts = int(time.time())
return requests.post(f"{self.base_url}{path}",
json=body, headers=self._headers("POST", ts, body))
def put(self, path, body):
ts = int(time.time())
return requests.put(f"{self.base_url}{path}",
json=body, headers=self._headers("PUT", ts, body))
def delete(self, path):
ts = int(time.time())
return requests.delete(f"{self.base_url}{path}",
headers=self._headers("DELETE", ts))
# ---- 便捷方法 ----
def write_memory(self, agent_id, content, importance=0.5):
return self.post("/memories/personal",
{"agent_id": agent_id, "content": content, "importance": importance})
def search(self, agent_id, query, limit=10, min_score=0.3, max_chars_per_memory=0, max_total_chars=0):
body = {"agent_id": agent_id, "query": query, "limit": limit, "min_score": min_score}
if max_chars_per_memory:
body["max_chars_per_memory"] = max_chars_per_memory
if max_total_chars:
body["max_total_chars"] = max_total_chars
return self.post("/memories/personal/search", body)
def get_recent(self, agent_id, limit=10):
return self.get(f"/memories/personal/recent/{agent_id}", params={"limit": limit})
def get_stats(self):
return self.get("/stats")
# ---- 生命周期方法 ----
def extract_facts(self, agent_id, max_memories=20, delete_after=False):
从工作记忆提取原子事实
return self.post("/lifecycle/extract-facts",
{"agent_id": agent_id, "max_memories": max_memories, "delete_after": delete_after})
def aggregate_scenarios(self, agent_id, max_memories=50):
将记忆按主题聚合为场景块
return self.post("/lifecycle/aggregate-scenes",
{"agent_id": agent_id, "max_memories": max_memories})
def get_scenarios(self, agent_id):
获取已存储的场景块
return self.get(f"/lifecycle/scenarios/{agent_id}")
def generate_persona(self, agent_id, max_items=30):
从记忆和场景中生成用户画像
return self.post("/lifecycle/generate-persona",
{"agent_id": agent_id, "max_items": max_items})
def get_persona(self, agent_id):
获取最新用户画像
return self.get(f"/lifecycle/persona/{agent_id}")
def set_pipeline_config(self, **kwargs):
设置 Pipeline 自动化配置
return self.post("/lifecycle/auto-config", kwargs)
def get_pipeline_config(self):
获取 Pipeline 自动化配置
return self.get("/lifecycle/auto-config")
def compress(self, agent_id, target_count=5):
压缩工作记忆为长期记忆
return self.post("/lifecycle/compress",
{"agent_id": agent_id, "target_count": target_count})
# 使用示例
client = MemoryClient("your_api_key_here", "your_secret_here")
r = client.write_memory("assistant", "用户偏好简洁回复", importance=0.8)
print(r.json())
3. 认证机制
3.1 API Key 与签名
除 /health 外,所有接口均需认证。认证方式为 API Key + HMAC-SHA256 签名。
认证模型
- 每个团队分配唯一的 API Key + Secret,Key 绑定到对应
team_id - 同团队下多个 Agent 共用同一个 Key
- 跨团队数据隔离由系统强制保证
请求头
| Header | 说明 |
|---|---|
X-API-Key | API 访问密钥 |
X-Timestamp | UTC Unix 时间戳(秒),误差范围 ±5 分钟 |
X-Signature | HMAC-SHA256 签名(十六进制) |
3.2 签名算法详解
签名公式
GET 请求: HMAC-SHA256(secret, str(timestamp)) # body 为空字节 b""
POST 请求: HMAC-SHA256(secret, str(timestamp) + raw_body) # body 为原始 JSON 字节
签名要点
- GET 请求使用空 body
b""进行签名(不是b"{}") - POST / PUT 请求使用实际发送的原始 JSON 字节。Python
requests.post(url, json=body)默认ensure_ascii=True,中文字符会被转义(如\u7b56\u7565),签名必须使用相同的序列化方式 - 时间戳过期后不可直接重试:必须用新的当前时间戳重新计算签名
- 时钟同步:客户端与服务器时钟偏差需在 ±5 分钟以内
3.3 错误码说明
认证失败时返回 {"ok": false, "error": "...", "code": "..."} 格式:
认证错误码
| HTTP | code | 说明 |
|---|---|---|
| 401 | AUTH_MISSING_HEADERS | 缺少 X-API-Key / X-Timestamp / X-Signature |
| 401 | AUTH_INVALID_TIMESTAMP | 时间戳格式错误(非数字) |
| 401 | AUTH_TIMESTAMP_EXPIRED | 时间戳过期(超出 ±5 分钟窗口) |
| 401 | AUTH_INVALID_KEY | API Key 不存在 |
| 401 | AUTH_KEY_DISABLED | API Key 已被禁用 |
| 401 | AUTH_INVALID_SIGNATURE | 签名不匹配 |
通用错误码
| HTTP | code | 说明 |
|---|---|---|
| 400 | VALIDATION_ERROR | 缺少必填参数或参数格式错误 |
| 403 | FORBIDDEN_CROSS_TEAM | 无权访问其他团队的数据 |
| 404 | TEAM_NOT_FOUND | 团队不存在 |
| 404 | AGENT_NOT_FOUND | Agent 不存在 |
| 404 | NOT_FOUND | 资源不存在 |
3.4 跨语言签名示例
Python
import hashlib, hmac, time
def sign(secret, timestamp, body=None):
"""body=None 表示 GET 请求,使用空字节"""
if body is None:
msg = str(timestamp).encode()
else:
msg = str(timestamp).encode() + body # body 已经是 bytes
return hmac.new(secret.encode(), msg, hashlib.sha256).hexdigest()
ts = int(time.time())
sig = sign("your_secret_here", ts) # GET 请求
Node.js
const crypto = require('crypto');
function sign(secret, timestamp, body = null) {
const msg = body
? Buffer.concat([Buffer.from(String(timestamp)), body])
: Buffer.from(String(timestamp));
return crypto.createHmac('sha256', secret).update(msg).digest('hex');
}
const ts = Math.floor(Date.now() / 1000);
const sig = sign('your_secret_here', ts); // GET 请求
Go
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"strconv"
)
func sign(secret string, timestamp int64, body []byte) string {
msg := strconv.FormatInt(timestamp, 10)
if body != nil {
msg += string(body)
}
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(msg))
return hex.EncodeToString(mac.Sum(nil))
}
ts := time.Now().Unix()
sig := sign("your_secret_here", ts, nil) // GET 请求
4. API 端点
4.1 系统
curl -s https://memory.lsz.name/health
# {"ok": true, "data": {"status": "ok"}}
curl -X GET "https://memory.lsz.name/stats" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Signature: <signature>"
# {"ok": true, "data": {
# "personal_memories": 11,
# "team_memories": 4,
# "agents": 4,
# "redis_ok": true,
# "embedding_ok": true
# }}
# 响应字段:
# personal_memories int 个人记忆条数
# team_memories int 团队共享记忆条数
# agents int Agent 数量
# redis_ok bool Redis 连接状态
# embedding_ok bool Embedding 服务状态
4.2 团队管理
curl -X POST https://memory.lsz.name/teams \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"team_id": "my_team", "name": "My Team", "description": "团队描述"}'
# {"ok": true, "data": {"id": "my_team", "name": "My Team", ...}}
# 参数:
# team_id string 必填 团队唯一标识
# name string 必填 团队名称
# description string 可选 描述
# config object 可选 配置(JSON)
curl -X GET "https://memory.lsz.name/teams/my_team" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": {"id": "my_team", "name": "My Team", ...}}
curl -X DELETE "https://memory.lsz.name/teams/my_team" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": null}
4.3 Agent 管理
curl -X POST https://memory.lsz.name/agents \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"agent_id": "researcher", "name": "研究员", "role": "research"}'
# {"ok": true, "data": {"id": "researcher", "team_id": "my_team", "name": "研究员", ...}}
# 参数:
# agent_id string 必填 Agent 唯一标识(团队内唯一)
# name string 必填 显示名称
# role string 可选 角色描述
# config object 可选 配置(JSON)
curl -X GET "https://memory.lsz.name/agents/my_team/researcher" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": {"id": "researcher", "team_id": "my_team", ...}}
curl -X GET "https://memory.lsz.name/agents/my_team" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": [{"id": "researcher", ...}, {"id": "coder", ...}]}
curl -X DELETE "https://memory.lsz.name/agents/my_team/researcher" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": null}
4.4 个人长期记忆
curl -X POST https://memory.lsz.name/memories/personal \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"agent_id": "researcher", "content": "用户偏好简洁回复,不喜欢冗长解释", "importance": 0.8}'
# {"ok": true, "data": {"id": 42, "content": "用户偏好简洁回复...", "importance": 0.8, ...}}
# 参数:
# agent_id string 必填 Agent 标识
# content string 必填 记忆内容
# importance float 可选 重要性评分 0.0~1.0(默认 0.5)
# metadata object 可选 元数据(JSON)
# enable_dedup bool 可选 是否启用去重(默认 true)
# dedup_threshold float 可选 去重相似度阈值 0.0~1.0(默认 0.85)
#
# 去重行为: 当 enable_dedup=true 时,系统会将新记忆与已有记忆做向量相似度
# 比较。若存在相似度 >= dedup_threshold 的已有记忆,则跳过写入并返回该已有
# 记忆(响应中包含 dedup_skipped=true 和 dedup_score 字段)。
last_accessed。提示:query 为空时,自动 fallback 为返回最近的记忆列表(等同于
GET /memories/personal/recent/{agent_id})。curl -X POST https://memory.lsz.name/memories/personal/search \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"agent_id": "researcher", "query": "用户的沟通偏好", "limit": 5, "min_score": 0.3}'
# {"ok": true, "data": [
# {"id": 42, "content": "用户偏好简洁回复...", "importance": 0.8, "score": 0.75,
# "metadata": {"source": "compression", "source_items": [...]}, ...},
# ...
# ]}
# 参数:
# agent_id string 必填 Agent 标识
# query string 可选 查询文本(自然语言),为空时返回最近记忆
# limit int 可选 返回条数(默认 10,最大 50)
# min_score float 可选 最低相似度阈值 0.0~1.0(默认 0.3)
# max_chars_per_memory int 可选 单条记忆最大字符数(0=不限制)
# max_total_chars int 可选 所有返回记忆的总字符预算(0=不限制)
#
# 字符限制: max_chars_per_memory 会截断超长单条记忆(末尾追加 "...")。
# max_total_chars 在累计达到预算后停止返回更多结果。两者可组合使用。
last_accessed。curl -X GET "https://memory.lsz.name/memories/personal/recent/researcher?limit=10" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": [{"id": 42, "content": "...", "importance": 0.8, ...}, ...]}
# 查询参数:
# limit int 可选 返回条数(默认 20,最大 100)
last_accessed。curl -X PUT https://memory.lsz.name/memories/personal/42 \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"content": "用户偏好简洁回复,重要结论需要给出论据", "importance": 0.9}'
# {"ok": true, "data": {"id": 42, "content": "...", "importance": 0.9, ...}}
curl -X DELETE "https://memory.lsz.name/memories/personal/42" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": null}
4.5 团队共享记忆
curl -X POST https://memory.lsz.name/memories/team \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"content": "代码规范:所有接口返回 ResultBean 统一格式", "importance": 0.9}'
# {"ok": true, "data": {"id": 5, "content": "代码规范:...", "importance": 0.9, ...}}
# 参数:
# content string 必填 记忆内容
# importance float 可选 重要性评分 0.0~1.0(默认 0.5)
# category string 可选 分类标签(默认 "general")
# metadata object 可选 元数据(JSON)
# enable_dedup bool 可选 是否启用去重(默认 true)
# dedup_threshold float 可选 去重相似度阈值 0.0~1.0(默认 0.85)
GET /memories/team/recent)。curl -X POST https://memory.lsz.name/memories/team/search \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"query": "接口规范", "limit": 5, "min_score": 0.3}'
# {"ok": true, "data": [{"id": 5, "content": "代码规范:...", "score": 0.82, ...}, ...]}
# 参数:
# query string 可选 查询文本,为空时返回最近记忆
# limit int 可选 返回条数(默认 10,最大 50)
# min_score float 可选 最低相似度阈值(默认 0.3)
# max_chars_per_memory int 可选 单条记忆最大字符数(0=不限制)
# max_total_chars int 可选 所有返回记忆的总字符预算(0=不限制)
curl -X GET "https://memory.lsz.name/memories/team/recent?limit=10" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": [{"id": 5, "content": "...", ...}, ...]}
curl -X PUT https://memory.lsz.name/memories/team/5 \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"content": "代码规范:所有接口返回 ResultBean,含 ok/data/error/code 字段"}'
# {"ok": true, "data": {"id": 5, "content": "...", ...}}
curl -X DELETE "https://memory.lsz.name/memories/team/5" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": null}
4.6 工作记忆
curl -X POST https://memory.lsz.name/memories/working \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"agent_id": "researcher", "content": "当前正在处理用户关于量化策略的查询"}'
# {"ok": true, "data": {"agent_id": "researcher", "content": "..."}}
# 参数:
# agent_id string 必填 Agent 标识
# content string 必填 工作记忆内容
# ttl int 可选 TTL 秒数(默认 259200,即 72 小时)
curl -X GET "https://memory.lsz.name/memories/working/researcher?limit=20" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": [{"content": "...", "created_at": "..."}, ...]}
# 查询参数:
# limit int 可选 返回条数(默认 50)
curl -X DELETE "https://memory.lsz.name/memories/working/researcher" \
-H "X-API-Key: your_api_key_here" \
-H "X-Timestamp: <unix-ts>" \
-H "X-Signature: <signature>"
# {"ok": true, "data": {"cleared": 5}}
4.7 生命周期管理
curl -X POST https://memory.lsz.name/lifecycle/compress \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"agent_id": "researcher", "target_count": 5}'
# {"ok": true, "data": {
# "compressed": 12,
# "remaining": 3,
# "total_before": 15,
# "target_count": 5,
# "summary": "用户主要关注量化策略优化..."
# }}
# 参数:
# agent_id string 必填 Agent 标识
# target_count int 可选 压缩后保留的目标条数(默认 5)
# 响应字段:
# compressed int 已压缩的条目数
# remaining int 压缩后剩余的工作记忆条目数
# total_before int 压缩前的工作记忆总条目数
# target_count int 请求的目标压缩条数
# summary string 生成的摘要文本(可为 null)
last_accessed(或回退到 created_at)和 importance 双维度筛选。curl -X POST https://memory.lsz.name/lifecycle/cleanup \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"max_age_days": 90, "min_importance": 0.2}'
# {"ok": true, "data": {"cleaned": 3, "remaining": 8}}
# 参数:
# max_age_days int 可选 最大未访问天数(默认 90)
# min_importance float 可选 重要性阈值 0.0~1.0(默认 0.2)
# 仅清理 importance < min_importance
# 且 last_accessed > max_age_days 的记忆
curl -X POST https://memory.lsz.name/lifecycle/extract-facts \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"agent_id": "researcher", "max_memories": 20, "delete_after": false}'
# {"ok": true, "data": {
# "facts": [
# {"id": "abc123", "content": "...", "importance": 0.8, "category": "..."},
# ...
# ],
# "count": 4
# }}
# 参数:
# agent_id string 必填 Agent 标识
# max_memories int 可选 分析的最大工作记忆条数(默认 20)
# delete_after bool 可选 提取后是否清空工作记忆(默认 false)
# 响应字段:
# facts array 提取的事实列表,每条含 id/content/importance/category
# count int 提取的事实数量
curl -X POST https://memory.lsz.name/lifecycle/aggregate-scenes \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"agent_id": "researcher", "max_memories": 50}'
# {"ok": true, "data": {
# "scenarios": [
# {"id": "sc001", "name": "...", "summary": "...", "memory_ids": ["m1","m2"]},
# ...
# ],
# "count": 3
# }}
# 参数:
# agent_id string 必填 Agent 标识
# max_memories int 可选 分析的最大记忆条数(默认 50)
# 响应字段:
# scenarios array 场景列表,每条含 id/name/summary/memory_ids
# count int 场景数量
curl https://memory.lsz.name/lifecycle/scenarios/researcher \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>'
# {"ok": true, "data": [
# {"id": "sc001", "name": "...", "summary": "...", "memory_ids": [...], "created_at": "..."},
# ...
# ]}
curl -X DELETE https://memory.lsz.name/lifecycle/scenarios/sc001 \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>'
# {"ok": true, "data": {"deleted": "sc001"}}
curl -X POST https://memory.lsz.name/lifecycle/generate-persona \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{"agent_id": "researcher", "max_items": 30}'
# {"ok": true, "data": {
# "persona": {
# "id": "p001",
# "preferences": ["...", "..."],
# "habits": ["...", "..."],
# "expertise": ["...", "..."],
# "communication_style": "...",
# "summary": "..."
# }
# }}
# 参数:
# agent_id string 必填 Agent 标识
# max_items int 可选 分析的最大记忆+场景条数(默认 30)
# 响应字段:
# persona.preferences array 用户偏好列表
# persona.habits array 用户习惯列表
# persona.expertise array 擅长领域列表
# persona.communication_style string 沟通风格描述
# persona.summary string 画像摘要
curl https://memory.lsz.name/lifecycle/persona/researcher \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>'
# {"ok": true, "data": {
# "id": "p001", "agent_id": "researcher", "preferences": [...], ...
# }}
curl -X DELETE https://memory.lsz.name/lifecycle/persona/p001 \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>'
# {"ok": true, "data": {"deleted": "p001"}}
curl https://memory.lsz.name/lifecycle/auto-config \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>'
# {"ok": true, "data": {
# "team_id": "hermes1",
# "compress_every_n": 10,
# "compress_target_count": 5,
# "cleanup_idle_days": 30,
# "cleanup_min_importance": 0.2,
# "enabled": true,
# "warmup_max_memories": 5,
# "warmup_compress_every_n": 2
# }}
curl -X POST https://memory.lsz.name/lifecycle/auto-config \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{
"compress_every_n": 10,
"compress_target_count": 5,
"cleanup_idle_days": 30,
"cleanup_min_importance": 0.2,
"enabled": true,
"warmup_max_memories": 5,
"warmup_compress_every_n": 2
}'
# {"ok": true, "data": {...}}
# 参数:
# compress_every_n int 可选 工作记忆达到 N 条时自动压缩(0=禁用)
# compress_target_count int 可选 压缩后保留的目标条数(默认 5)
# cleanup_idle_days int 可选 自动清理未访问天数(0=禁用)
# cleanup_min_importance float 可选 清理的重要性阈值(默认 0.2)
# enabled bool 可选 是否启用自动规则(默认 true)
# warmup_max_memories int 可选 暖机阈值:个人记忆少于 N 条时进入暖机模式(0=禁用)
# warmup_compress_every_n int 可选 暖机模式下的压缩阈值(默认 1)
curl -X POST https://memory.lsz.name/lifecycle/auto-run \
-H 'Content-Type: application/json' \
-H 'X-API-Key: your_api_key_here' \
-H 'X-Timestamp: <unix-ts>' \
-H 'X-Signature: <signature>' \
-d '{}'
# {"ok": true, "data": {"results": [...]}}
last_accessed 字段维护说明
系统在以下操作时自动更新记忆的 last_accessed 时间戳:
- 语义检索命中:
POST /memories/personal/search、POST /memories/team/search - 读取最近记忆:
GET /memories/personal/recent/{id}、GET /memories/team/recent - 更新记忆内容:
PUT /memories/personal/{id}、PUT /memories/team/{id}
新创建的记忆 last_accessed 初始为 NULL,cleanup 时回退到 created_at。因此从未被访问过的记忆也会被纳入清理范围。
5. 对接示例
以下示例均使用前文的 MemoryClient 类。请将 API_KEY 和 SECRET 替换为实际值。
5.1 OpenClaw 对接
场景:AI 助手 OpenClaw 记住用户偏好和团队知识。
from memory_client import MemoryClient # 假设已封装为模块
client = MemoryClient("your_api_key_here", "your_secret_here")
# --- 1. 创建团队和 Agent ---
client.post("/teams", {"team_id": "openclaw_team", "name": "OpenClaw 团队"})
client.post("/agents", {"agent_id": "assistant", "name": "AI 助手", "role": "assistant"})
# --- 2. 写入个人记忆(用户偏好)---
client.post("/memories/personal", {
"agent_id": "assistant",
"content": "用户偏好简洁直接的回复,不喜欢冗长的解释",
"importance": 0.9
})
client.post("/memories/personal", {
"agent_id": "assistant",
"content": "用户的技术栈:Java 后端 + WSL2 + 腾讯云新加坡",
"importance": 0.7
})
# --- 3. 写入团队记忆(编码规范)---
client.post("/memories/team", {
"content": "Java 接口规范:ResultBean 统一返回格式,@ControllerAdvice 全局异常处理",
"importance": 0.8
})
client.post("/memories/team", {
"content": "部署规范:代码变更后必须三同步——代码逻辑、内部文档、公网文档",
"importance": 0.95
})
# --- 4. 语义检索(个人记忆)---
r = client.post("/memories/personal/search", {
"agent_id": "assistant",
"query": "用户的沟通风格偏好",
"limit": 3,
"min_score": 0.3
})
results = r.json()["data"]
for m in results:
print(f"[{m['score']:.2f}] {m['content']}")
# 输出:
# [0.75] 用户偏好简洁直接的回复,不喜欢冗长的解释
# [0.52] 用户的技术栈:Java 后端 + WSL2 + 腾讯云新加坡
# --- 5. 语义检索(团队记忆)---
r = client.post("/memories/team/search", {
"query": "接口返回格式规范",
"limit": 3,
"min_score": 0.3
})
for m in r.json()["data"]:
print(f"[{m['score']:.2f}] {m['content']}")
# [0.82] Java 接口规范:ResultBean 统一返回格式...
5.2 Hermes 对接
场景:量化策略系统 Hermes 的多个 Agent 积累策略研究知识。
from memory_client import MemoryClient
client = MemoryClient("your_api_key_here", "your_secret_here")
# --- 1. 创建团队和 Agent ---
client.post("/teams", {"team_id": "hermes", "name": "Hermes 策略研究部"})
client.post("/agents", {"agent_id": "cloud_strategist", "name": "云策", "role": "决策调度"})
client.post("/agents", {"agent_id": "backtest_engineer", "name": "弈回", "role": "回测工程师"})
client.post("/agents", {"agent_id": "review_analyst", "name": "弈析", "role": "复盘分析"})
# --- 2. 多 Agent 写入记忆 ---
client.post("/memories/personal", {
"agent_id": "cloud_strategist",
"content": "趋势策略在震荡行情中表现不佳,需要增加行情识别层",
"importance": 0.9
})
client.post("/memories/personal", {
"agent_id": "backtest_engineer",
"content": "回测数据源:Binance USDT 永续合约,1h K线,2024-01 至今",
"importance": 0.7
})
client.post("/memories/personal", {
"agent_id": "review_analyst",
"content": "2025-06 策略复盘:最大回撤 12%,主要损失来自 6/3 闪崩",
"importance": 0.85
})
client.post("/memories/team", {
"content": "风控规则:单策略最大仓位 30%,总杠杆不超过 3x",
"importance": 0.95
})
# --- 3. 查看统计 ---
r = client.get("/stats")
stats = r.json()["data"]
print(f"个人记忆: {stats['personal_memories']} 条")
print(f"团队记忆: {stats['team_memories']} 条")
print(f"Agent 数: {stats['agents']}")
print(f"Redis: {'OK' if stats['redis_ok'] else 'DOWN'}")
print(f"Embedding: {'OK' if stats['embedding_ok'] else 'DOWN'}")
# 个人记忆: 3 条
# 团队记忆: 1 条
# Agent 数: 3
# Redis: OK
# Embedding: OK
# --- 4. 获取最近记忆 ---
r = client.get("/memories/personal/recent/cloud_strategist", params={"limit": 5})
for m in r.json()["data"]:
print(f"[{m['importance']:.1f}] {m['content'][:50]}...")
# [0.9] 趋势策略在震荡行情中表现不佳,需要增加行情识别层...
5.3 Claude Code 对接
场景:Claude Code 使用工作记忆记录当前编码上下文,任务完成后压缩为长期记忆。
from memory_client import MemoryClient
client = MemoryClient("your_api_key_here", "your_secret_here")
# --- 1. 创建团队和 Agent ---
client.post("/teams", {"team_id": "claude_code", "name": "Claude Code 团队"})
client.post("/agents", {"agent_id": "coder", "name": "编码助手", "role": "developer"})
# --- 2. 写入工作记忆(当前任务上下文)---
working_items = [
"正在重构 memory_system.py 中的 compress 方法",
"目标:将返回值从 {summary: string} 改为结构化 dict",
"需要同步更新:routes.py, docs/index.html, README_INTERNAL.html",
"测试方法:E2E curl 验证响应格式",
]
for item in working_items:
client.post("/memories/working", {
"agent_id": "coder",
"content": item
})
# --- 3. 查看工作记忆 ---
r = client.get("/memories/working/coder")
print(f"工作记忆: {len(r.json()['data'])} 条")
# 工作记忆: 4 条
# --- 4. 任务完成后,压缩为长期记忆 ---
r = client.post("/lifecycle/compress", {
"agent_id": "coder",
"target_count": 1
})
result = r.json()["data"]
print(f"压缩: {result['compressed']} 条 → {result['remaining']} 条")
print(f"摘要: {result['summary']}")
# 压缩: 4 条 → 1 条
# 摘要: 重构 memory_system.py 的 compress 方法,将返回值改为结构化 dict...
# --- 5. 验证:语义检索 ---
r = client.post("/memories/personal/search", {
"agent_id": "coder",
"query": "compress 方法重构",
"limit": 3,
"min_score": 0.3
})
for m in r.json()["data"]:
print(f"[{m['score']:.2f}] {m['content'][:60]}...")
# [0.71] 重构 memory_system.py 的 compress 方法...
5.4 Codex 对接
场景:Codex Agent 记忆管理 + 验证跨团队隔离。
from memory_client import MemoryClient
client = MemoryClient("your_api_key_here", "your_secret_here")
# --- 1. 创建团队和 Agent ---
client.post("/teams", {"team_id": "codex_team", "name": "Codex 团队"})
client.post("/agents", {"agent_id": "codex_agent", "name": "Codex 助手", "role": "coder"})
# --- 2. 写入记忆 ---
client.post("/memories/personal", {
"agent_id": "codex_agent",
"content": "Codex 默认使用 gpt-4 模型,CLI 支持 --model 参数切换",
"importance": 0.7
})
client.post("/memories/personal", {
"agent_id": "codex_agent",
"content": "Codex 配置文件位于 ~/.codex/config.toml",
"importance": 0.6
})
# --- 3. 验证隔离:用当前 Key 查询其他团队 ---
# 尝试访问不存在的团队(预期:403)
r = client.get("/teams/other_team")
print(f"跨团队查询: {r.status_code} - {r.json().get('code')}")
# 跨团队查询: 403 - FORBIDDEN_CROSS_TEAM
# 尝试查询其他团队的 Agent(预期:403)
r = client.get("/agents/other_team/some_agent")
print(f"跨团队Agent: {r.status_code} - {r.json().get('code')}")
# 跨团队Agent: 403 - FORBIDDEN_CROSS_TEAM
5.5 跨团队隔离验证
验证不同团队之间的数据完全隔离:
from memory_client import MemoryClient
# 两个不同团队的客户端
team_a = MemoryClient("team_a_api_key", "team_a_secret")
team_b = MemoryClient("team_b_api_key", "team_b_secret")
# --- Team A 写入记忆 ---
team_a.post("/teams", {"team_id": "team_a", "name": "Team Alpha"})
team_a.post("/agents", {"agent_id": "agent_1", "name": "Agent 1"})
team_a.post("/memories/personal", {
"agent_id": "agent_1",
"content": "这是 Team A 的私密记忆",
"importance": 0.9
})
# --- Team B 写入记忆 ---
team_b.post("/teams", {"team_id": "team_b", "name": "Team Beta"})
team_b.post("/agents", {"agent_id": "agent_1", "name": "Agent B1"})
team_b.post("/memories/personal", {
"agent_id": "agent_1",
"content": "这是 Team B 的私密记忆",
"importance": 0.8
})
# --- 验证隔离 ---
# Team A 搜索自己的记忆
r = team_a.post("/memories/personal/search", {
"agent_id": "agent_1", "query": "私密记忆", "limit": 10
})
a_results = [m["content"] for m in r.json()["data"]]
print(f"Team A sees: {a_results}")
# Team A sees: ["这是 Team A 的私密记忆"] ← 看不到 Team B 的
# Team A 搜索团队记忆(也看不到 Team B 的)
r = team_a.post("/memories/team/search", {
"query": "私密", "limit": 10
})
print(f"Team A team search: {len(r.json()['data'])} 条")
# Team A team search: 0 条 ← Team B 的团队记忆不可见
# Team A 的 Stats 只包含自己的数据
r = team_a.get("/stats")
stats = r.json()["data"]
print(f"Team A stats: {stats['personal_memories']} personal, {stats['team_memories']} team")
# Team A stats: 1 personal, 0 team ← 只看到自己的
print("\n✅ 跨团队隔离验证通过")
5.6 记忆生命周期完整示例
场景:完整的记忆生命周期 —— 从工作记忆写入,到原子事实提取、场景聚合、画像生成,最后配置自动化 Pipeline。
from memory_client import MemoryClient
client = MemoryClient("your_api_key_here", "your_secret_here")
# --- 1. 创建团队和 Agent ---
client.post("/teams", {"team_id": "research_lab", "name": "研究实验室"})
client.post("/agents", {"agent_id": "researcher", "name": "研究员", "role": "研究分析"})
# --- 2. 写入工作记忆(模拟日常交互)---
wm_items = [
"今天决定把量化策略的回测周期从 3 个月改为 6 个月,因为短期数据噪声太大",
"发现 DeepSeek V4 在代码生成任务上比 MiMo 快约 40%,但中文理解稍弱",
"用户偏好简洁直接的回复风格,不喜欢冗长的解释",
"Redis 缓存命中率从 75% 提升到 92% 后,API 响应时间从 120ms 降到 45ms",
"下周一需要和团队讨论 Q3 的风控模型升级方案",
]
for item in wm_items:
client.post("/memories/working", {"agent_id": "researcher", "content": item})
print(f"工作记忆: {len(wm_items)} 条")
# --- 3. 原子事实提取 ---
# 从工作记忆中提取结构化事实,每条事实存为独立的长期记忆
r = client.extract_facts("researcher", max_memories=20, delete_after=False)
facts = r.json()["data"]["facts"]
print(f"\n提取了 {len(facts)} 条原子事实:")
for f in facts:
print(f" [{f['importance']:.1f}] [{f['category']}] {f['content'][:60]}...")
# --- 4. 场景聚合 ---
# 将长期记忆按主题聚合为场景块
r = client.post("/memories/personal", {
"agent_id": "researcher",
"content": "2025-06 策略复盘:最大回撤 12%,主要损失来自 6/3 闪崩",
"importance": 0.85
})
r = client.post("/memories/personal", {
"agent_id": "researcher",
"content": "回测数据源:Binance USDT 永续合约,1h K线,2024-01 至今",
"importance": 0.7
})
r = client.post("/memories/team", {
"content": "风控规则:单策略最大仓位 30%,总杠杆不超过 3x",
"importance": 0.95
})
r = client.aggregate_scenarios("researcher", max_memories=50)
scenarios = r.json()["data"]["scenarios"]
print(f"\n聚合了 {len(scenarios)} 个场景:")
for s in scenarios:
print(f" [{s['name']}] {s['summary'][:60]}... (关联 {len(s['memory_ids'])} 条记忆)")
# --- 5. 查看已存储场景 ---
r = client.get_scenarios("researcher")
print(f"\n已存储场景: {len(r.json()['data'])} 个")
# --- 6. 用户画像生成 ---
# 从记忆和场景中提取用户画像
r = client.generate_persona("researcher", max_items=30)
persona = r.json()["data"]["persona"]
print(f"\n用户画像:")
print(f" 偏好: {persona.get('preferences', [])}")
print(f" 习惯: {persona.get('habits', [])}")
print(f" 擅长: {persona.get('expertise', [])}")
print(f" 沟通风格: {persona.get('communication_style', '')}")
print(f" 摘要: {persona.get('summary', '')[:80]}...")
# --- 7. 查看用户画像 ---
r = client.get_persona("researcher")
print(f"\n画像已存储, ID: {r.json()['data'].get('id')}")
# --- 8. 配置 Pipeline 自动化 ---
# 设置自动压缩:每 10 条工作记忆自动压缩
# 设置自动清理:60 天未访问且重要性 < 0.2 的记忆自动清理
# 设置暖机:新 Agent 前 5 条记忆使用更频繁的压缩
r = client.set_pipeline_config(
compress_every_n=10,
compress_target_count=5,
cleanup_idle_days=60,
cleanup_min_importance=0.2,
enabled=True,
warmup_max_memories=5,
warmup_compress_every_n=2
)
print(f"\nPipeline 配置: {r.json()['data']}")
# --- 9. 查看 Pipeline 配置 ---
r = client.get_pipeline_config()
config = r.json()["data"]
print(f"自动压缩: 每 {config.get('compress_every_n')} 条触发")
print(f"自动清理: {config.get('cleanup_idle_days')} 天未访问, 重要性 < {config.get('cleanup_min_importance')}")
print(f"暖机模式: 前 {config.get('warmup_max_memories')} 条记忆启用")
# --- 10. 语义检索(验证所有数据可检索)---
r = client.post("/memories/personal/search", {
"agent_id": "researcher",
"query": "策略回测",
"limit": 5,
"min_score": 0.3
})
print(f"\n搜索 '策略回测': {len(r.json()['data'])} 条结果")
for m in r.json()["data"]:
src = m.get("metadata", {}).get("source", "normal")
print(f" [{m['score']:.2f}] [{src}] {m['content'][:60]}...")
print("\n✅ 记忆生命周期完整示例结束")
6. 数据管理
6.1 数据持久化说明
| 数据类型 | 存储介质 | 持久化 | 说明 |
|---|---|---|---|
| 个人长期记忆 | MySQL (InnoDB) | 磁盘持久化 | 含内容、向量(BLOB)、重要性、元数据 |
| 团队共享记忆 | MySQL (InnoDB) | 磁盘持久化 | 同上,团队内所有 Agent 可检索 |
| 工作记忆 | Redis | 纯内存 | TTL 自动过期,服务重启可能丢失 |
| API Key 元数据 | MySQL | 磁盘持久化 | Key、Secret Hash、状态等 |
| Agent / Team 元数据 | MySQL | 磁盘持久化 | 名称、角色、配置等 |
| 场景块 (Scenarios) | MySQL | 磁盘持久化 | 场景名、摘要、关联记忆 ID 列表(JSON) |
| 用户画像 (Persona) | MySQL | 磁盘持久化 | 偏好、习惯、擅长、沟通风格(JSON) |
| Pipeline 配置 | MySQL | 磁盘持久化 | 自动压缩/清理/暖机规则(per-team) |
/lifecycle/compress 及时转为长期记忆。6.2 记忆清理与压缩策略
工作记忆压缩(/lifecycle/compress)
将 Redis 中的工作记忆压缩为 MySQL 长期记忆:
- 从 Redis 读取指定 Agent 的全部工作记忆
- 调用 LLM 生成摘要
- 摘要写入 MySQL 长期记忆
- 原始工作记忆从 Redis 删除
长期记忆清理(/lifecycle/cleanup)
基于双维度清理过期的长期记忆:
- 时间维度:
max_age_days— 清理超过指定天数未访问的记忆 - 重要性维度:
min_importance— 仅清理重要性评分低于阈值的记忆
两个条件同时满足才会被清理:即 低重要性 + 长期未访问 的记忆才会被移除。高重要性的记忆即使长期未访问也不会被清理。
推荐清理策略
| 场景 | max_age_days | min_importance | 说明 |
|---|---|---|---|
| 保守清理 | 180 | 0.1 | 仅清理半年未访问的极低重要性记忆 |
| 常规清理 | 90 | 0.2 | 清理 3 个月未访问的低重要性记忆(推荐) |
| 积极清理 | 30 | 0.3 | 清理 1 个月未访问的中低重要性记忆 |
6.3 智能生命周期策略
原子事实提取(/lifecycle/extract-facts)
替代简单压缩,从工作记忆中提取独立的结构化事实:
- LLM 分析工作记忆内容,识别独立的、长期有价值的观察、决策和知识
- 每条事实作为独立的长期记忆存储,便于精确检索
- 适合需要精确回忆的场景(如技术决策、用户偏好、关键数据)
- 相比压缩,事实提取保留了信息的独立性和可检索性
- 系统对 LLM 返回结果和工作记忆条目均有类型安全校验,非标准格式数据会被自动跳过并记录警告日志
场景聚合(/lifecycle/aggregate-scenes)
将相关的长期记忆按主题聚合为场景块:
- LLM 分析多条记忆,识别共同主题并生成场景摘要
- 场景块保留原始记忆 ID 列表,支持溯源
- 适合将碎片化的记忆整合为完整的上下文(如项目进展、研究发现)
用户画像生成(/lifecycle/generate-persona)
从记忆和场景中提取结构化用户画像:
- 输出:偏好列表、习惯列表、擅长领域、沟通风格、综合摘要
- 适合为 Agent 提供长期的用户/上下文理解
- 建议定期更新(如每周或每月),画像会随记忆积累而丰富
Pipeline 自动化(/lifecycle/auto-config)
配置自动化的记忆管理规则,无需手动触发:
| 规则 | 配置项 | 说明 |
|---|---|---|
| 自动压缩 | compress_every_n | 工作记忆达到 N 条时自动触发压缩(0=禁用) |
| 自动清理 | cleanup_idle_days | 超过 N 天未访问且低重要性的记忆自动清理(0=禁用) |
| 暖机模式 | warmup_max_memories | 新 Agent 个人记忆少于 N 条时,使用更低的压缩阈值(更频繁压缩) |
| 暖机压缩 | warmup_compress_every_n | 暖机模式下的压缩触发条数(默认 1) |
Pipeline 在每次写入工作记忆时自动检查是否达到压缩阈值,无需手动调用。
6.4 last_accessed 字段维护
系统自动维护每条长期记忆的 last_accessed 时间戳,确保清理策略基于"最近使用时间"而非"创建时间":
| 操作 | 更新 last_accessed | 说明 |
|---|---|---|
| 语义检索命中 | ✅ | POST /memories/personal/search 和 POST /memories/team/search 返回的结果自动 touch |
| 读取最近列表 | ✅ | GET /memories/personal/recent/{id} 和 GET /memories/team/recent 返回的结果自动 touch |
| 更新记忆内容 | ✅ | PUT /memories/personal/{id} 和 PUT /memories/team/{id} 自动 touch |
| 写入新记忆 | — | 新记忆 last_accessed 初始为 NULL,cleanup 时回退到 created_at |
7. 常见问题
Q: 一个 Key 可以跨多个团队吗?
A: 不能。每个 Key 绑定一个 team_id,只能操作该团队的数据。跨团队访问返回 403 FORBIDDEN_CROSS_TEAM。
Q: 不存在的 agent_id 会报错吗?
A: 查询类接口(GET 列表、搜索)返回空列表 [];写入类接口返回 AGENT_NOT_FOUND 错误。
Q: BGE 为什么输出 512 维?
A: BGE-small-zh-v1.5 的 PyTorch 模型输出 384 维。本系统使用 Xenova 社区预转换的 ONNX 量化版 (model_quantized.onnx),输出 512 维。这是 ONNX 转换差异,不影响语义检索质量。
Q: TTL 过期后工作记忆能恢复吗?
A: 不能。Redis 到期自动删除整个 List。请在过期前使用 /lifecycle/compress 将重要记忆转为长期记忆。
Q: 语义搜索的最低相似度阈值是多少?
A: 默认 min_score=0.3。值域为 [0.0, 1.0],越高越严格。建议从 0.3 开始,根据实际效果调整。
Q: 如何监控服务健康状态?
A: 定期调用 GET /health(无需认证)检查服务存活。调用 GET /stats(需认证)查看记忆条数、Agent 数量、Redis 和 Embedding 服务状态。
Q: 原子事实提取和压缩有什么区别?
A: 压缩将多条工作记忆合并为一条摘要,丢失了原始信息的独立性。事实提取将工作记忆分解为独立的结构化事实,每条事实作为独立的长期记忆存储,保留了精确的可检索性。建议:对于需要精确回忆的场景(如技术决策、用户偏好),使用事实提取;对于需要概括性总结的场景,使用压缩。
Q: Pipeline 自动化如何工作?
A: 通过 POST /lifecycle/auto-config 配置自动规则后,系统会在每次写入工作记忆时自动检查是否达到压缩阈值。暖机模式下,新 Agent 使用更低的阈值(更频繁压缩),帮助新 Agent 快速积累长期记忆。
Q: 使用场景聚合和画像生成需要什么前置条件?
A: 场景聚合和画像生成功能由系统内置 LLM 驱动,您只需调用对应的 API 端点即可,无需额外配置任何 LLM 参数。系统会自动完成事实提取、场景聚合和画像生成。
Q: 场景聚合和用户画像有什么区别?
A: 场景聚合将多条相关记忆按主题分组并生成摘要(如"策略回测系列讨论"),保留原始记忆 ID 列表支持溯源。用户画像从全局记忆中提取用户的结构化特征(偏好、习惯、擅长领域),是对用户整体的描述。场景是"事情"的聚合,画像是"人"的描述。