初始化:记忆系统源代码上传(已脱敏)

- 排除 .env / *.bak / 内部运维文档(README_INTERNAL.html)
- config.py 默认密码已替换为占位符 CHANGE_ME_*
- init_db.sql 移除生产数据库用户 GRANT 段
- README.html 数据库用户名已脱敏
- 保留:源码 + 公网 API 文档 + 建表 SQL(无授权语句)
This commit is contained in:
zqf
2026-08-03 04:53:48 +08:00
commit b1f93588f1
30 changed files with 5591 additions and 0 deletions
+353
View File
@@ -0,0 +1,353 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多智能体记忆系统 — 内部运维文档</title>
<style>
:root { --bg: #0d1117; --card: #161b22; --border: #30363d; --text: #c9d1d9; --heading: #58a6ff; --accent: #3fb950; --warn: #d29922; --code-bg: #0d1117; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); line-height: 1.7; padding: 2rem; max-width: 960px; margin: 0 auto; }
h1 { color: var(--heading); margin-bottom: 0.5rem; font-size: 1.8rem; }
h2 { color: var(--heading); margin: 2.5rem 0 0.5rem; border-bottom: 1px solid var(--border); padding-bottom: 0.3rem; font-size: 1.3rem; }
h3 { color: var(--accent); margin: 1.5rem 0 0.3rem; font-size: 1.1rem; }
.meta { color: #8b949e; margin-bottom: 2rem; font-size: 0.9rem; }
table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
th, td { text-align: left; padding: 0.5rem 0.75rem; border: 1px solid var(--border); }
th { background: var(--card); color: var(--heading); font-weight: 600; }
td { background: var(--card); }
code { font-family: 'Fira Code', monospace; background: var(--code-bg); border: 1px solid var(--border); padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; color: var(--accent); }
pre { background: var(--code-bg); border: 1px solid var(--border); border-radius: 6px; padding: 1rem; overflow-x: auto; margin: 0.75rem 0; font-size: 0.85rem; line-height: 1.5; }
pre code { border: none; padding: 0; background: none; color: var(--text); }
.method { display: inline-block; padding: 0.15rem 0.5rem; border-radius: 4px; font-weight: bold; font-size: 0.8rem; margin-right: 0.5rem; }
.get { background: #1f6feb33; color: #58a6ff; }
.post { background: #3fb95033; color: #3fb950; }
.put { background: #d2992233; color: #d29922; }
.delete { background: #f8514933; color: #f85149; }
.endpoint { font-family: monospace; color: var(--text); }
.warn-box { background: #d2992222; border: 1px solid var(--warn); border-radius: 6px; padding: 1rem; margin: 1rem 0; }
.ok-box { background: #3fb95022; border: 1px solid var(--accent); border-radius: 6px; padding: 1rem; margin: 1rem 0; }
.danger-box { background: #f8514922; border: 1px solid #f85149; border-radius: 6px; padding: 1rem; margin: 1rem 0; }
ul, ol { margin: 0.5rem 0 0.5rem 1.5rem; }
li { margin: 0.25rem 0; }
a { color: var(--heading); }
.tag { display: inline-block; padding: 0.1rem 0.4rem; border-radius: 3px; font-size: 0.75rem; margin-left: 0.3rem; }
.tag-new { background: #3fb95033; color: #3fb950; }
.tag-auth { background: #d2992233; color: #d29922; }
</style>
</head>
<body>
<h1>🧠 多智能体记忆系统 — 内部运维文档</h1>
<p class="meta">
服务器: 43.156.57.141 (新加坡腾讯云) &nbsp;|&nbsp;
域名: <a href="https://memory.lsz.name">memory.lsz.name</a> &nbsp;|&nbsp;
版本: 3.0.2 &nbsp;|&nbsp;
最后更新: 2026-06-22
</p>
<div class="ok-box">
<strong>✅ 系统状态:</strong> 所有组件运行正常<br>
MySQL 8.0.46 · Redis 6.0.16 · BGE-small-zh-v1.5 (512维) · Gunicorn + Flask · Nginx + SSL (Let's Encrypt)<br>
2 个团队 · 4 个 Agent · 32+ 个人记忆 · 4 条团队记忆 · v3.0.2 性能优化(LLM thinking mode 禁用)
</div>
<h2>🏗️ 架构概览</h2>
<table>
<tr><th>组件</th><th>技术</th><th>端口</th><th>说明</th></tr>
<tr><td>API 服务</td><td>Flask + Gunicorn</td><td>8081 (local)</td><td>HTTP JSON API</td></tr>
<tr><td>Nginx</td><td>nginx 1.18</td><td>443 (SSL)</td><td>反向代理 + SSL 终止</td></tr>
<tr><td>持久存储</td><td>MySQL 8.0.46</td><td>3306</td><td>记忆数据 + 向量 BLOB</td></tr>
<tr><td>缓存层</td><td>Redis 6.0.16</td><td>6379</td><td>工作记忆 (TTL 24h)</td></tr>
<tr><td>Embedding</td><td>BGE-small-zh-v1.5</td><td>8080 (local)</td><td>512维语义向量</td></tr>
</table>
<h2>🔐 API 认证 <span class="tag tag-auth">HMAC-SHA256</span></h2>
<p><code>GET /health</code><code>/admin/*</code> 外,所有 API 端点均需以下 HTTP 头:</p>
<table>
<tr><th>Header</th><th>说明</th></tr>
<tr><td><code>X-API-Key</code></td><td>API Key(以 <code>msk_</code> 前缀开头)</td></tr>
<tr><td><code>X-Timestamp</code></td><td>Unix 时间戳(秒,5分钟内有效)</td></tr>
<tr><td><code>X-Signature</code></td><td><code>HMAC-SHA256(secret, timestamp + request_body)</code></td></tr>
</table>
<h3>认证流程</h3>
<ol>
<li>获取 API Key 和 Secret(通过 <code>/admin/api-keys</code> 端点,仅限 localhost</li>
<li>构造请求体(JSON),取当前 Unix 时间戳</li>
<li>计算签名:<code>signature = HMAC-SHA256(secret, str(timestamp) + json_body)</code></li>
<li>在请求头中附加三个认证字段</li>
</ol>
<h3>Python 认证示例</h3>
<pre><code>import time, hmac, hashlib, json, requests
API_KEY = "msk_xxx..."
SECRET = "xxx..."
BASE = "https://memory.lsz.name"
def api(method, path, body=None):
ts = str(time.time())
body_bytes = json.dumps(body).encode() if body else b""
sig = hmac.new(
SECRET.encode(), ts.encode() + body_bytes, hashlib.sha256
).hexdigest()
headers = {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
"X-Timestamp": ts,
"X-Signature": sig,
}
resp = requests.request(method, BASE + path, data=body_bytes, headers=headers)
return resp.json()
# 使用示例
result = api("POST", "/memories/personal/search", {
"agent_id": "yihui",
"query": "策略回测",
"limit": 5
})</code></pre>
<div class="warn-box">
<strong>⚠️ 注意:</strong> Secret 仅在创建时显示一次,不会再次展示。请妥善保管。<br>
Admin 端点仅限 <code>127.0.0.1</code> 访问,外部请求会被拒绝(403)。
</div>
<h2>👥 多团队隔离</h2>
<p>所有记忆数据通过 <code>team_id</code> 字段实现硬隔离。查询时强制 <code>WHERE team_id = ?</code>。每个团队的 API Key 绑定固定的 <code>team_id</code>,跨团队数据完全不可见。</p>
<h3>当前团队</h3>
<table>
<tr><th>Team ID</th><th>名称</th><th>Agent 数</th><th>API Key</th></tr>
<tr><td><code>hermes1</code></td><td>策略研究部</td><td>2 (弈回, 云策)</td><td><code>msk_a192...85</code></td></tr>
<tr><td><code>wangcheng</code></td><td>王成</td><td>2 (Hermes Agent, OpenClaw Main)</td><td><code>msk_6804...18</code></td></tr>
</table>
<h2>📋 记忆类型</h2>
<table>
<tr><th>类型</th><th>存储</th><th>生命周期</th><th>说明</th></tr>
<tr><td>个人长期记忆</td><td>MySQL</td><td>持久化</td><td>每个 Agent 独立的持久记忆,支持语义检索</td></tr>
<tr><td>个人工作记忆</td><td>Redis List</td><td>TTL 24h</td><td>短期上下文缓存</td></tr>
<tr><td>团队共享记忆</td><td>MySQL</td><td>持久化</td><td>同团队内所有 Agent 可访问的知识库</td></tr>
</table>
<h2>📡 API 端点</h2>
<h3>公开端点(无需认证)</h3>
<table>
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/health</td><td>健康检查</td></tr>
</table>
<h3>团队管理</h3>
<table>
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/teams</td><td>创建团队</td></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/teams/{team_id}</td><td>获取团队信息</td></tr>
<tr><td><span class="method delete">DELETE</span></td><td class="endpoint">/teams/{team_id}</td><td>删除团队(级联删除所有关联数据)</td></tr>
</table>
<h3>Agent 管理</h3>
<table>
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/agents</td><td>创建 Agent</td></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/agents/{agent_id}</td><td>获取 Agent 信息</td></tr>
</table>
<h3>个人记忆</h3>
<table>
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/memories/personal</td><td>添加个人记忆(自动生成 embedding)</td></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/memories/personal/search</td><td>语义检索个人记忆(团队隔离)</td></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/memories/personal/recent/{agent_id}</td><td>获取最近个人记忆</td></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/memories/personal/{memory_id}</td><td>获取单条个人记忆</td></tr>
<tr><td><span class="method put">PUT</span></td><td class="endpoint">/memories/personal/{memory_id}</td><td>更新个人记忆</td></tr>
<tr><td><span class="method delete">DELETE</span></td><td class="endpoint">/memories/personal/{memory_id}</td><td>删除个人记忆</td></tr>
</table>
<h3>工作记忆</h3>
<table>
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/memories/working</td><td>添加工作记忆(RedisTTL 24h</td></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/memories/working/{agent_id}</td><td>获取工作记忆</td></tr>
<tr><td><span class="method delete">DELETE</span></td><td class="endpoint">/memories/working/{agent_id}</td><td>清空工作记忆</td></tr>
</table>
<h3>团队记忆</h3>
<table>
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/memories/team</td><td>添加团队共享记忆</td></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/memories/team/search</td><td>语义检索团队记忆</td></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/memories/team/recent/{team_id}</td><td>获取最近团队记忆</td></tr>
<tr><td><span class="method put">PUT</span></td><td class="endpoint">/memories/team/{memory_id}</td><td>更新团队记忆</td></tr>
<tr><td><span class="method delete">DELETE</span></td><td class="endpoint">/memories/team/{memory_id}</td><td>删除团队记忆</td></tr>
</table>
<h3>生命周期管理</h3>
<table>
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/lifecycle/compress</td><td>压缩工作记忆到长期记忆</td></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/lifecycle/cleanup</td><td>清理过期/低重要性记忆</td></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/lifecycle/extract-facts</td><td>原子事实提取(LLM, 5-15s</td></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/lifecycle/aggregate-scenes</td><td>场景聚合(LLM, 5-15s</td></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/lifecycle/generate-persona</td><td>画像生成(LLM, 5-15s</td></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/lifecycle/auto-config</td><td>Pipeline 自动化配置</td></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/lifecycle/scenarios/{agent_id}</td><td>获取场景块</td></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/lifecycle/persona/{agent_id}</td><td>获取用户画像</td></tr>
</table>
<h3>统计</h3>
<table>
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/stats?team_id=xxx</td><td>获取系统统计信息</td></tr>
</table>
<h3>Admin 端点 <span class="tag tag-new">仅 localhost</span></h3>
<table>
<tr><th>方法</th><th>路径</th><th>说明</th></tr>
<tr><td><span class="method post">POST</span></td><td class="endpoint">/admin/api-keys</td><td>创建 API Key(需 team_id, name</td></tr>
<tr><td><span class="method get">GET</span></td><td class="endpoint">/admin/api-keys</td><td>列出所有 API Key</td></tr>
<tr><td><span class="method delete">DELETE</span></td><td class="endpoint">/admin/api-keys/{key_id}</td><td>禁用 API Key</td></tr>
</table>
<h2>⚡ 性能指标(2026-06-08 验证)</h2>
<table>
<tr><th>指标</th><th>实测值</th><th>目标</th><th>状态</th></tr>
<tr><td>写入延迟 P50</td><td>14.4ms</td><td></td><td></td></tr>
<tr><td>写入延迟 P99</td><td>16.3ms</td><td>&lt; 100ms</td><td>✅ PASS</td></tr>
<tr><td>检索延迟 P50</td><td>17.9ms</td><td></td><td></td></tr>
<tr><td>检索延迟 P99</td><td>27.5ms</td><td>&lt; 50ms</td><td>✅ PASS</td></tr>
<tr><td>进程 RSS</td><td>51 MB</td><td>&lt; 1.5 GiB</td><td>✅ PASS</td></tr>
<tr><td>团队隔离</td><td>100%</td><td>100%</td><td>✅ PASS</td></tr>
</table>
<h2>🗄️ 数据库表结构</h2>
<table>
<tr><th>表名</th><th>说明</th></tr>
<tr><td><code>teams</code></td><td>团队信息(id, name, description, config JSON</td></tr>
<tr><td><code>agents</code></td><td>Agent 信息(id, team_id FK, name, role</td></tr>
<tr><td><code>personal_memories</code></td><td>个人长期记忆(agent_id, team_id, content, embedding BLOB, importance, metadata JSON</td></tr>
<tr><td><code>team_memories</code></td><td>团队共享记忆(team_id, content, embedding BLOB, importance, category, metadata JSON</td></tr>
<tr><td><code>api_keys</code></td><td>API 认证密钥(team_id, api_key, secret, is_active</td></tr>
<tr><td><code>pipeline_config</code></td><td>Pipeline 自动化配置(compress_every_n, cleanup_idle_days, warmup 等)</td></tr>
<tr><td><code>memory_scenarios</code></td><td>场景块(team_id, agent_id, name, summary, memory_ids JSON</td></tr>
<tr><td><code>user_personas</code></td><td>用户画像(team_id, agent_id, preferences/habits/expertise JSON, summary</td></tr>
</table>
<h2>🔧 运维操作</h2>
<h3>服务管理</h3>
<pre><code># 查看服务状态
sudo systemctl status memory-system
# 重启服务
sudo systemctl restart memory-system
# 查看日志
sudo journalctl -u memory-system -f --no-pager -n 100
# Nginx 配置测试
sudo nginx -t
# 重载 Nginx
sudo systemctl reload nginx</code></pre>
<h3>项目路径</h3>
<pre><code>/opt/memory-system/ # 项目根目录
/opt/memory-system/venv/ # Python 虚拟环境
/opt/memory-system/config.py # 配置文件
/opt/memory-system/app.py # Flask 入口 + JSON 序列化
/opt/memory-system/api/routes.py # API 路由
/opt/memory-system/auth/api_auth.py # HMAC 认证中间件
/opt/memory-system/storage/ # MySQL + Redis + 向量检索
/opt/memory-system/lifecycle/ # 记忆生命周期管理
/opt/memory-system/tests/ # 测试
/opt/memory-system/docs/ # 公网文档</code></pre>
<h3>关键配置</h3>
<pre><code># config.py
MYSQL_HOST = "127.0.0.1"
MYSQL_PORT = 3306
MYSQL_USER = "your_db_user"
MYSQL_DATABASE = "memory_system"
MYSQL_UNIX_SOCKET = "/var/run/mysqld/mysqld.sock"
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
EMBEDDING_SERVICE_URL = "http://127.0.0.1:8080"
EMBEDDING_DIM = 512
API_PORT = 8081
WORKING_MEMORY_TTL = 86400 # 24小时</code></pre>
<h3>创建新 API Key(SSH 到服务器)</h3>
<pre><code># 通过 localhost 访问 admin 端点
curl -X POST http://127.0.0.1:8081/admin/api-keys \
-H 'Content-Type: application/json' \
-d '{"team_id": "your_team_id", "name": "Your Key Name"}'
# 响应中会包含 api_key 和 secret(仅显示一次)</code></pre>
<h3>SSL 证书</h3>
<pre><code># 自动续期已配置,手动测试:
sudo certbot renew --dry-run
# 证书路径:
/etc/letsencrypt/live/memory.lsz.name/fullchain.pem
/etc/letsencrypt/live/memory.lsz.name/privkey.pem</code></pre>
<h2>🔒 安全说明</h2>
<ul>
<li>Redis 已禁用 FLUSHALL/FLUSHDB/DEBUG/SHUTDOWN 命令</li>
<li>Redis CONFIG/KEYS 命令已重命名(CONFIG_b9f7e2d4, KEYS_a3c8f1e6</li>
<li>MySQL 使用 unix socket 连接</li>
<li>Nginx 强制 HTTPS (Let's Encrypt)</li>
<li>API 仅监听 127.0.0.1,通过 Nginx 暴露公网</li>
<li>Admin 端点仅限 localhost 访问</li>
<li>API 使用 HMAC-SHA256 签名认证,时间戳窗口 5 分钟</li>
</ul>
<h2>🧪 测试验证</h2>
<pre><code># 运行测试
cd /opt/memory-system
./venv/bin/python tests/test_memory.py</code>
<p>测试覆盖: 创建团队/Agent → 写入记忆 → 语义检索 → 跨团队隔离 → 工作记忆 → 性能基准</p>
<div class="ok-box">
<strong>✅ 2026-06-08 验证结果:</strong><br>
14/14 项测试全部通过,包括:<br>
• 健康检查 · 统计端点 · 团队信息查询<br>
• 个人记忆语义检索 · 团队记忆语义检索<br>
• 写入+搜索+更新+删除全流程<br>
• 跨团队隔离验证(wangcheng 看不到 hermes1 数据)<br>
• 工作记忆 CRUD · 认证拒绝测试
</div>
<h2>📋 变更日志</h2>
<h3>v3.0.2 (2026-06-22) — 性能优化</h3>
<div class="ok-box">
<strong>核心修复</strong>:禁用 DeepSeek thinking mode<br>
根因:DeepSeek v4-flash 默认开启思考模式,每次 LLM 调用输出 3000-7500 字符中文推理链,token 预算被吃光<br>
修复:llm_client.py 新增 thinking 参数透传;llm_parse.py 所有 JSON 生成任务添加 thinking={"type": "disabled"}<br>
<strong>实测提速</strong>aggregate-scenes 7.9x, generate-persona 4.9x, extract-facts 2.0s
</div>
<h3>v3.0.1-bugfix (2026-06-22) — Bug 修复</h3>
<div class="ok-box">
• BGE 长文本双保险截断(服务端 512 tokens + 客户端 2000 字符)<br>
• 空 query fallback 到 get_recent<br>
• embedding 失败返回友好错误,不暴露内部 URL<br>
• GET /memories/personal/{id} 405 → 补上 GET 路由<br>
• aggregate-scenes JSON 解析失败 → thinking mode 禁用
</div>
<h3>v3.0.0 (2026-06-08) — 生命周期管理</h3>
<div class="ok-box">
• Pipeline 自动化引擎(自动压缩、清理、暖机)<br>
• 原子事实提取(/lifecycle/extract-facts<br>
• 场景聚合(/lifecycle/aggregate-scenes<br>
• 用户画像生成(/lifecycle/generate-persona
</div>
</body>
</html>