Files
memory-gateway/README.md

582 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Memory Gateway
Memory Gateway 是一个通用记忆网关,用于给 AI agent / harness 提供统一的记忆检索、文档上传、LLM 总结和知识沉淀能力。
它的定位不是某个单一业务场景的垂直应用,而是一个可复用的本地 memory/context gateway上层 agent 通过 REST、MCP 或 Hermes skill 调用它,底层由 OpenViking 承载 memory/resource由 Obsidian 承载人工可维护的 Markdown 知识。
## 当前能力
- 搜索 OpenViking memory / resource。
- 写入普通 memory。
- 写入结构化 resource。
- 对任意文本调用 LLM 总结,并按需沉淀到 OpenViking。
- 上传文档,使用 MarkItDown 转 Markdown。
- 将上传文档保存到 Obsidian vault。
- 将文档摘要和结构化 artifact 写入 OpenViking knowledge。
- 给 Hermes 提供通用 `memory-gateway` skill。
- 新增通用 Memory Gateway v1 方案与 POC 骨架多用户、namespace、visibility/ACL、episode、session commit、audit、skills 分层。
- v1 metadata 默认持久化到 SQLite覆盖 users、memories、episodes、profiles、audit。
- `/v1/memory/search` 先做本地 ACL 过滤,再按可见 namespace 查询 OpenViking。
- v1 MCP tools 已接入现有 `/mcp/rpc`
- `/v1/sessions/{session_id}/commit` 优先调用独立 EverMemOS HTTP 服务;服务不可用且允许 fallback 时,才使用 Gateway 进程内 POC worker。
完整方案见:
```text
docs/generic-memory-gateway-design.md
```
## 架构
```text
Agent / Harness / CLI
-> Memory Gateway REST / MCP
-> OpenViking memory / resource
-> Obsidian markdown vault
-> OpenAI-compatible LLM summary
```
## 目录结构
```text
memory-gateway/
├── memory_gateway/ # Gateway 服务代码
│ ├── server.py # REST / MCP 接口
│ ├── openviking_client.py # OpenViking client
│ ├── llm.py # OpenAI-compatible LLM summary
│ ├── document_ingest.py # MarkItDown + Obsidian write helpers
│ ├── config.py
│ └── types.py
├── integrations/hermes/
│ └── memory-gateway/ # 通用 Hermes skill
├── obsidian-vault/
│ ├── 01_Knowledge/Uploaded/ # 上传文档转成的 Markdown
│ └── 05_Templates/ # 通用知识模板
├── tests/
├── config.example.yaml
└── pyproject.toml
```
## 环境
使用当前虚拟环境:
```bash
cd /home/tom/memory-gateway
source /home/tom/OpenViking/.venv/bin/activate
```
本地配置文件:
```text
/home/tom/memory-gateway/config.yaml
```
关键配置:
```yaml
memory:
default_namespace: memory-gateway
llm:
base_url: https://oai.bwgdi.com/v1
api_key: <local secret, git ignored>
model: MiniMaxAI
obsidian:
vault_path: /home/tom/memory-gateway/obsidian-vault
knowledge_dir: 01_Knowledge/Uploaded
review_dir: Reviews/Queue
storage:
backend: sqlite
sqlite_path: /home/tom/memory-gateway/memory_gateway.sqlite3
```
`config.yaml` 已被 `.gitignore` 忽略,不会提交密钥。
## 启动
OpenViking 需要先运行在 `127.0.0.1:1933`
```bash
source /home/tom/OpenViking/.venv/bin/activate
openviking-server --host 127.0.0.1 --port 1933
```
启动本机 EverMemOS 服务:
```bash
cd /home/tom/memory-gateway
source /home/tom/OpenViking/.venv/bin/activate
python -m memory_gateway.evermemos_service \
--config /home/tom/memory-gateway/config.yaml \
--host 127.0.0.1 \
--port 1995
```
启动 Memory Gateway
```bash
cd /home/tom/memory-gateway
source /home/tom/OpenViking/.venv/bin/activate
python -m memory_gateway.server --config /home/tom/memory-gateway/config.yaml
```
健康检查:
```bash
curl http://127.0.0.1:1934/health
curl http://127.0.0.1:1995/health
curl http://127.0.0.1:1934/v1/evermemos/health
```
## REST 接口
### `GET /health`
检查 Gateway 和 OpenViking 状态。
### `POST /api/search`
搜索 OpenViking memory / resource。
```bash
curl -X POST http://127.0.0.1:1934/api/search \
-H "Content-Type: application/json" \
-d '{
"query": "memory gateway document upload summary",
"uri": "viking://resources",
"limit": 5
}'
```
### `POST /api/memory`
写入普通 memory。
```bash
curl -X POST http://127.0.0.1:1934/api/memory \
-H "Content-Type: application/json" \
-d '{
"namespace": "memory-gateway",
"memory_type": "preference",
"content": "The user prefers concise technical summaries."
}'
```
### `POST /api/resource`
写入结构化 resource。
```bash
curl -X POST http://127.0.0.1:1934/api/resource \
-H "Content-Type: application/json" \
-d '{
"uri": "viking://resources/memory-gateway/knowledge/example.json",
"resource_type": "json",
"content": "{\"title\":\"example\"}"
}'
```
### `POST /api/summary`
调用 LLM 总结任意文本,并按需沉淀到 OpenViking。
```bash
curl -X POST http://127.0.0.1:1934/api/summary \
-H "Content-Type: application/json" \
-d '{
"title": "Project decision summary",
"content": "需要总结和沉淀的内容...",
"namespace": "memory-gateway",
"memory_type": "decision",
"tags": ["project", "decision"],
"persist_as": "resource"
}'
```
`persist_as` 支持:`none``memory``resource``both`
### `POST /api/knowledge/upload`
上传文档MarkItDown 转 Markdown保存到 ObsidianLLM 总结后写入 OpenViking knowledge。
```bash
curl -X POST http://127.0.0.1:1934/api/knowledge/upload \
-F "file=@/path/to/document.pdf" \
-F "title=Design Notes" \
-F "namespace=memory-gateway" \
-F "knowledge_type=design_doc" \
-F "tags=project,design,reference" \
-F "persist_as=resource"
```
默认保存到:
```text
obsidian-vault/01_Knowledge/Uploaded/
```
## v1 通用 Memory API
v1 API 面向多 agent 框架,带 user / agent / workspace / session 上下文和基础 ACL。
### 创建用户
```bash
curl -X POST http://127.0.0.1:1934/v1/users \
-H "Content-Type: application/json" \
-d '{"user_id":"user_tom","display_name":"Tom","preferences":{"language":"zh-CN"}}'
```
### 写入记忆
```bash
curl -X POST http://127.0.0.1:1934/v1/memory \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_tom",
"agent_id": "agent_hermes",
"workspace_id": "ws_memory_gateway",
"memory_type": "preference",
"content": "用户偏好中文输出,结构化但不要过度工程化。",
"summary": "中文、结构化、轻量 POC 优先。",
"tags": ["preference", "style"],
"importance": 0.8,
"confidence": 0.9,
"visibility": "private",
"source": "manual"
}'
```
### 检索记忆
```bash
curl -X POST http://127.0.0.1:1934/v1/memory/search \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_tom",
"agent_id": "agent_hermes",
"workspace_id": "ws_memory_gateway",
"query": "中文输出",
"limit": 5
}'
```
返回会包含:
- `local_total`SQLite metadata 命中的记忆数量。
- `openviking_total`:按可见 namespace 查询 OpenViking 的命中数量。
- `searched_namespaces`Gateway 展开并允许查询的 namespace。
### 修改记忆
```bash
curl -X PATCH "http://127.0.0.1:1934/v1/memory/MEMORY_ID?user_id=user_tom&agent_id=agent_hermes&workspace_id=ws_memory_gateway" \
-H "Content-Type: application/json" \
-d '{"summary":"用户偏好中文、结构化、少废话。","importance":0.9}'
```
### 写入 episode 并 commit session
```bash
curl -X POST http://127.0.0.1:1934/v1/episodes \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_tom",
"agent_id": "agent_hermes",
"workspace_id": "ws_memory_gateway",
"session_id": "sess_demo",
"content": "结论:这个项目必须保留用户隔离和 namespace ACL。",
"tags": ["decision"]
}'
curl -X POST http://127.0.0.1:1934/v1/sessions/sess_demo/commit \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_tom",
"agent_id": "agent_hermes",
"workspace_id": "ws_memory_gateway",
"session_id": "sess_demo",
"promote": true,
"min_importance": 0.6
}'
```
流程说明:
- 短期记忆先写入 SQLite 的 `episodes`namespace 通常是 `session/{session_id}/episodic`
- commit session 时Gateway 把当前 session episodes、可见长期记忆和访问上下文发给 `http://127.0.0.1:1995/v1/sessions/consolidate`
- EverMemOS 返回候选记忆、可直接提升的长期记忆、重复/冲突信息和 review draft 路径。
- Gateway 只把正常稳定候选写入长期 memory高价值或冲突候选不会直接进入长期记忆会写入
```text
obsidian-vault/Reviews/Queue/
```
## MCP Tools
`POST /mcp/rpc` 支持:
- `search`
- `add_memory`
- `add_resource`
- `commit_summary`
- `get_status`
- `list_memories`
- `list_resources`
- `memory_search`
- `memory_upsert`
- `memory_append_episode`
- `memory_commit_session`
- `memory_get_profile`
- `memory_list_namespaces`
- `memory_delete`
- `memory_feedback`
## Hermes Skill
通用 Hermes skill
```text
/home/tom/.hermes/skills/memory-gateway/
```
仓库副本:
```text
integrations/hermes/memory-gateway/
```
安装或更新到本机 Hermes skill 目录:
```bash
mkdir -p /home/tom/.hermes/skills/memory-gateway
rsync -a --delete \
/home/tom/memory-gateway/integrations/hermes/memory-gateway/ \
/home/tom/.hermes/skills/memory-gateway/
```
使用方式:
- Hermes 对话中可以加载 `memory-gateway` skill让 agent 按 skill 文档主动调用脚本。
- skill 不等于自动记忆;只有 agent 根据 skill/policy 主动调用脚本时才会写入或检索记忆。
- 适合人工可控的显式操作:创建用户、检索记忆、追加 episode、commit session、上传知识和检查 EverMemOS。
主要脚本:
```text
scripts/evermemos_health.py
scripts/memory_create_user.py
scripts/memory_append_episode.py
scripts/memory_commit_session.py
scripts/memory_search.py
scripts/memory_upsert.py
scripts/retrieve_memory.py
scripts/commit_summary.py
scripts/upload_knowledge.py
scripts/search_obsidian.py
```
检查 EverMemOS
```bash
python /home/tom/.hermes/skills/memory-gateway/scripts/evermemos_health.py
```
检索记忆:
```bash
python /home/tom/.hermes/skills/memory-gateway/scripts/retrieve_memory.py \
--query "document upload summary memory gateway" \
--uri viking://resources \
--limit 5
```
总结沉淀:
```bash
python /home/tom/.hermes/skills/memory-gateway/scripts/commit_summary.py \
--title "Reusable conclusion" \
--namespace memory-gateway \
--memory-type decision \
--tag project \
--persist-as resource \
--text "最终结论或可复用知识..."
```
上传知识:
```bash
python /home/tom/.hermes/skills/memory-gateway/scripts/upload_knowledge.py \
--file /path/to/document.md \
--title "Knowledge note" \
--namespace memory-gateway \
--knowledge-type reference \
--tags project,reference \
--persist-as resource
```
完整长短期记忆测试:
```bash
python /home/tom/.hermes/skills/memory-gateway/scripts/memory_create_user.py \
--user-id user_tom \
--display-name "Tom" \
--preference language=zh-CN
python /home/tom/.hermes/skills/memory-gateway/scripts/memory_append_episode.py \
--user-id user_tom \
--agent-id agent_hermes \
--workspace-id ws_memory_gateway \
--session-id sess_demo \
--tag decision \
--text "结论:本机 EverMemOS 服务负责从 session episode 中整理稳定长期记忆。"
python /home/tom/.hermes/skills/memory-gateway/scripts/memory_append_episode.py \
--user-id user_tom \
--agent-id agent_hermes \
--workspace-id ws_memory_gateway \
--session-id sess_demo \
--tag review \
--tag high-value \
--text "重要:高价值记忆应该进入 Obsidian review queue避免错误记忆污染长期系统。"
python /home/tom/.hermes/skills/memory-gateway/scripts/memory_commit_session.py \
--user-id user_tom \
--agent-id agent_hermes \
--workspace-id ws_memory_gateway \
--session-id sess_demo \
--min-importance 0.6
python /home/tom/.hermes/skills/memory-gateway/scripts/memory_search.py \
--user-id user_tom \
--agent-id agent_hermes \
--workspace-id ws_memory_gateway \
--session-id sess_demo \
--query "EverMemOS 服务负责" \
--limit 5
```
## Hermes / OpenClaw Agent Plugin
通用 Agent plugin 位于:
```text
plugins/memory-gateway-agent/
```
它是独立 adapter不 import Gateway 内部 `services/repositories/server`,所有调用都通过现有 `/v1` HTTP API。它面向 Hermes/OpenClaw 这类 agent runtime 暴露统一工具:
- `memory_search`
- `memory_append_episode`
- `memory_commit_session`
- `memory_upsert`
- `memory_feedback`
Hermes 本机安装:
```bash
mkdir -p /home/tom/.hermes/plugins
ln -s /home/tom/memory-gateway/plugins/memory-gateway-agent \
/home/tom/.hermes/plugins/memory-gateway-agent
hermes plugins enable memory-gateway-agent
hermes plugins list
hermes tools list
```
如果软链接已存在,先确认它指向当前仓库:
```bash
ls -l /home/tom/.hermes/plugins/memory-gateway-agent
```
运行配置:
```bash
export MEMORY_GATEWAY_URL=http://127.0.0.1:1934
export MEMORY_GATEWAY_API_KEY=
export MEMORY_GATEWAY_DEFAULT_USER_ID=test_user_memory_gateway_plugin
export MEMORY_GATEWAY_DEFAULT_AGENT_ID=test_hermes_memory_gateway_plugin
export MEMORY_GATEWAY_DEFAULT_WORKSPACE_ID=test_workspace_memory_gateway_plugin
export MEMORY_GATEWAY_AUTO_SEARCH=true
export MEMORY_GATEWAY_AUTO_APPEND_EPISODE=true
export MEMORY_GATEWAY_AUTO_COMMIT_SESSION=false
```
Hermes plugin 已验证:
- `hermes plugins list` 可发现并启用 `memory-gateway-agent`
- `hermes tools list` 可看到 `memory_gateway` toolset。
- `pre_llm_call` 会自动检索 Memory Gateway。
- `post_llm_call` 会按 policy 写入摘要型 candidate episode。
- `on_session_end` 默认不会 commit只有 `MEMORY_GATEWAY_AUTO_COMMIT_SESSION=true` 才会 commit。
真实 Hermes chat 验证:
```bash
PYTHONPATH=/home/tom/memory-gateway/plugins/memory-gateway-agent \
python /home/tom/memory-gateway/plugins/memory-gateway-agent/scripts/hermes_interactive_session_check.py
```
插件 E2E 验证:
```bash
PYTHONPATH=/home/tom/memory-gateway/plugins/memory-gateway-agent \
python /home/tom/memory-gateway/plugins/memory-gateway-agent/scripts/gateway_e2e_check.py
PYTHONPATH=/home/tom/memory-gateway/plugins/memory-gateway-agent \
python /home/tom/memory-gateway/plugins/memory-gateway-agent/scripts/hermes_hook_probe.py
```
清理测试数据:
```bash
PYTHONPATH=/home/tom/memory-gateway/plugins/memory-gateway-agent \
python /home/tom/memory-gateway/plugins/memory-gateway-agent/scripts/cleanup_test_memories.py
```
安全边界:
- plugin 不保存完整原始对话,只写摘要型 episode。
- 默认拒绝 password、token、API key、cookie、private key、完整 transcript 和大段日志。
- `memory_upsert` 是高风险长期记忆写入,不会自动触发。
- 用户要求 forget/delete 时,应走 `memory_feedback` 或 delete 能力。
- hook trace 默认关闭;需要排查时设置 `MEMORY_GATEWAY_PLUGIN_TRACE_HOOKS=true`,只会写入 hook 名称、短 session id、Gateway action 和状态到 `plugins/memory-gateway-agent/.tmp/hook_trace.log`
OpenClaw manifest 目前是 best-effort 草案:
```text
plugins/memory-gateway-agent/openclaw.plugin.yaml
```
需要等 OpenClaw runtime 可用后再做第五阶段实测。
## 测试
```bash
cd /home/tom/memory-gateway
source /home/tom/OpenViking/.venv/bin/activate
PYTHONPATH=/home/tom/memory-gateway pytest -q
PYTHONPATH=/home/tom/memory-gateway/plugins/memory-gateway-agent \
pytest -q plugins/memory-gateway-agent/tests
```
当前测试覆盖:
- API key 校验。
- MCP tools/list。
- OpenViking search 透传。
- LLM summary artifact 构建。
- document upload -> markdown -> Obsidian -> OpenViking resource。
## 下一步
- 在 Gateway 层加强 `/api/search` 的 URI prefix 过滤和去重。
-`/api/knowledge/upload` 增加文件大小限制、类型白名单和 dry-run。
- 增加 Obsidian -> OpenViking 增量同步脚本。
- 给 Memory Gateway skill 增加更稳定的“回答时引用 memory/resource/Obsidian note”输出约束。
- 增加更多文档解析格式和异常处理测试。