16 KiB
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-gatewayskill。 - 新增通用 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。
完整方案见:
docs/generic-memory-gateway-design.md
架构
Agent / Harness / CLI
-> Memory Gateway REST / MCP
-> OpenViking memory / resource
-> Obsidian markdown vault
-> OpenAI-compatible LLM summary
目录结构
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
环境
使用当前虚拟环境:
cd /home/tom/memory-gateway
source /home/tom/OpenViking/.venv/bin/activate
本地配置文件:
/home/tom/memory-gateway/config.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。
source /home/tom/OpenViking/.venv/bin/activate
openviking-server --host 127.0.0.1 --port 1933
启动本机 EverMemOS 服务:
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:
cd /home/tom/memory-gateway
source /home/tom/OpenViking/.venv/bin/activate
python -m memory_gateway.server --config /home/tom/memory-gateway/config.yaml
健康检查:
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。
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。
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。
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。
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,保存到 Obsidian,LLM 总结后写入 OpenViking knowledge。
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"
默认保存到:
obsidian-vault/01_Knowledge/Uploaded/
v1 通用 Memory API
v1 API 面向多 agent 框架,带 user / agent / workspace / session 上下文和基础 ACL。
创建用户
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"}}'
写入记忆
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"
}'
检索记忆
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。
修改记忆
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
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;高价值或冲突候选不会直接进入长期记忆,会写入:
obsidian-vault/Reviews/Queue/
MCP Tools
POST /mcp/rpc 支持:
searchadd_memoryadd_resourcecommit_summaryget_statuslist_memorieslist_resourcesmemory_searchmemory_upsertmemory_append_episodememory_commit_sessionmemory_get_profilememory_list_namespacesmemory_deletememory_feedback
Hermes Skill
通用 Hermes skill:
/home/tom/.hermes/skills/memory-gateway/
仓库副本:
integrations/hermes/memory-gateway/
安装或更新到本机 Hermes skill 目录:
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-gatewayskill,让 agent 按 skill 文档主动调用脚本。 - skill 不等于自动记忆;只有 agent 根据 skill/policy 主动调用脚本时才会写入或检索记忆。
- 适合人工可控的显式操作:创建用户、检索记忆、追加 episode、commit session、上传知识和检查 EverMemOS。
主要脚本:
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:
python /home/tom/.hermes/skills/memory-gateway/scripts/evermemos_health.py
检索记忆:
python /home/tom/.hermes/skills/memory-gateway/scripts/retrieve_memory.py \
--query "document upload summary memory gateway" \
--uri viking://resources \
--limit 5
总结沉淀:
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 "最终结论或可复用知识..."
上传知识:
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
完整长短期记忆测试:
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 位于:
plugins/memory-gateway-agent/
它是独立 adapter,不 import Gateway 内部 services/repositories/server,所有调用都通过现有 /v1 HTTP API。它面向 Hermes/OpenClaw 这类 agent runtime 暴露统一工具:
memory_searchmemory_append_episodememory_commit_sessionmemory_upsertmemory_feedback
Hermes 本机安装:
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
如果软链接已存在,先确认它指向当前仓库:
ls -l /home/tom/.hermes/plugins/memory-gateway-agent
运行配置:
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_gatewaytoolset。pre_llm_call会自动检索 Memory Gateway。post_llm_call会按 policy 写入摘要型 candidate episode。on_session_end默认不会 commit;只有MEMORY_GATEWAY_AUTO_COMMIT_SESSION=true才会 commit。
真实 Hermes chat 验证:
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 验证:
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
清理测试数据:
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 草案:
plugins/memory-gateway-agent/openclaw.plugin.yaml
需要等 OpenClaw runtime 可用后再做第五阶段实测。
测试
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”输出约束。
- 增加更多文档解析格式和异常处理测试。