一套多租户的长期记忆 HTTP API:生产模式下,API key 映射到稳定租户命名空间,同一租户可配置多个 key 做无停机轮换;不同租户互相隔离。显式开发开放模式才把 Bearer 文本本身当作命名空间。
A. 直接用已部署的服务(最快,零搭建)
- Base URL:
http://42.193.220.197:8456 - 自己起一个 key 当命名空间(例如
demo-test),数据互相隔离。 - 只适合公开演示;数据会存在该服务器上,请勿发送隐私或生产数据。
B. 自己部署(数据完全本地)
cp deploy/.env.example deploy/.env
# 把 deploy/.env 的 ENGRAM_API_KEYS 示例值换成 tenant:强随机密钥
docker compose --env-file deploy/.env -f deploy/docker-compose.yml up -d --build
curl -fsS http://127.0.0.1:8000/ready生产不要设置
ENGRAM_OPEN/ENGRAM_ALLOW_ANONYMOUS。直接 Python 部署可安装engram-memory[server],设置ENGRAM_API_KEYS="alice:key-a,bob:key-b"后运行 Uvicorn。 同一租户轮换:alice:key-new,alice:key-old;一个 key 不允许映射到多个租户。
跨 Claude Code / Codex / Cursor / 自研 agent 的推荐生命周期见
docs/cross-agent-memory.md 和
docs/agent-adapters.md:开工先看 agent status,回答前 recall,长期事实 remember,
线程结束 close session,再用 session report 审计这一轮保存了什么。单会话生命周期自测(本地零服务或 HTTP)见
examples/cross_agent_lifecycle.py。
所有 /v1/* 接口都要带:
Authorization: Bearer <你的key>
Content-Type: application/json
健康检查不需要鉴权:
curl -s $B/health
curl -f $B/ready/health 是 liveness/诊断,始终返回不含密钥/用户内容的运行形态;/ready 只有在鉴权和存储可接流量时
返回 200,否则返回 503:
{
"ok": true,
"ready": true,
"service": "engram",
"version": "0.1.0",
"auth_mode": "api_keys",
"anonymous_allowed": false,
"embedder": "HashingEmbedder",
"llm_configured": false,
"answerer_configured": false,
"storage": "memory",
"users_hot": 0,
"max_hot_users": 64
}POST /v1/remember
{ "content": "用户:我在字节跳动做后端,最喜欢周杰伦。\n助手:好的,记住啦。",
"session_id": "s1", // 同一会话用同一个 id(可选)
"scope": "auto" } // auto(默认) | long(强制长期) | working(临时,不进长期)返回:{"ok":true,"extracted":2,"total_facts":N},或临时记忆 {"ok":true,"scope":"working",...}。
scope=auto会把"今天嗓子不舒服"这类临时状态自动路由到工作记忆(不污染长期画像,但原始对话仍按日期留存、可查询)。批量灌长期记忆建议scope:"long"。
POST /v1/facts
{ "subject": "user", "predicate": "works_at", "object": "字节跳动" }手动写/改的事实标记为"用户设定 🔒",权威,不会被自动抽取覆盖。
POST /v1/recall
{ "query": "我最喜欢哪个歌手", "lean": true, "n_chunks": 4, "as_of": null, "redact_sensitive": false }as_of 可选,传 epoch 秒时返回该历史时刻的记忆视图。
redact_sensitive=true 时只返回已分类的非敏感结构化事实,不包含画像、摘要或原始对话片段,适合
共享上下文或注入第三方模型。
返回:
{ "answer": "你最喜欢周杰伦。",
"context": "USER PROFILE:...\nFACTS:...\nRELEVANT CONVERSATIONS:...", // 喂给模型的精炼上下文
"tokens_est": 9958, // 精炼上下文 token
"full_tokens": 81408 } // 整段历史 token(full-context 基线)→ 省 8×POST /v1/sessions/close
{ "session_id": "codex:super-memory:thread-123",
"summarize": true,
"clear_working": true }用于 Claude Code / Codex / Cursor 这类客户端在一个线程结束或切换任务时调用。它不会删除原始对话, 而是补齐这个 session 的待整理 episode、生成缺失摘要、把知识更新反映到摘要层、清掉该 session 的 临时 working memory,并保存到磁盘。
配置了 LLM 时,关闭会话还会把这段会话蒸馏成结论事实(decision / finding / lesson /
open_question,谓词即结论类型、主语是 session id),返回体里的 outcomes 是本次新增的结论条数;
重复关闭同一个未变化的 session 不会重复写入。这是每次关会话花一次 LLM 调用的默认行为:
请求体可传 "outcomes": false 单次关闭,运维要设成本上限则设 ENGRAM_SESSION_OUTCOMES=0
(服务端强制关闭,请求体的 outcomes: true 也无法解除)。没有配置 LLM 时该分支不执行,outcomes 恒为 0。
如需审计这一轮到底写入了哪些长期事实:
GET /v1/sessions/report?session_id=codex:super-memory:thread-123
默认 include_sensitive=false,敏感事实正文会被替换为 [redacted sensitive fact];用户明确要完整私有审计时再传
include_sensitive=true。
推荐生命周期:
会话开始 / 接线自检:GET /v1/agent/status?session_id=...
回答前:POST /v1/recall
用户说了稳定偏好、项目约定、长期事实:POST /v1/remember
会话结束 / 切换任务:POST /v1/sessions/close
需要审计保存结果:GET /v1/sessions/report?session_id=...
GET /v1/agent/status?session_id=codex:super-memory:thread-123
返回当前 key/namespace、session 计数、working memory 数、focus 策略、长期记忆计数和建议下一步调用。 它不返回 profile、fact 文本、原始对话或摘要,适合 agent 开工前确认自己接到了正确的记忆层。
POST /v1/chat/completions 可在请求体里带:
{ "model": "engram",
"messages": [{ "role": "user", "content": "继续上次 benchmark 的事" }],
"memory": {
"session_id": "codex:super-memory:thread-123",
"recall": true,
"remember": true,
"scope": "auto",
"n_chunks": 6,
"as_of": null,
"redact_sensitive": false
} }这样已有 OpenAI SDK 应用只要换 base_url,就能在回答前自动召回、回答后把用户轮次写回同一个
agent session。
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /v1/agent/status?session_id=... |
Agent 开工自检:namespace/session/focus/counts/下一步建议;不含记忆正文 |
| GET | /v1/sessions?limit=20&q=codex |
跨 agent/app 会话索引:session id、时间、episode/fact/working 计数;不含正文 |
| GET | /v1/sessions/report?session_id=... |
审计某个 session 写入了哪些长期事实;默认隐藏敏感事实正文 |
| GET | /v1/stats |
内容无关统计:episode pending/consolidated、hot/cold facts、cold page-in/out、时间范围、敏感事实数量、pending conflicts、运行后端;适合监控 |
| GET | /v1/memories |
默认安全视图:非敏感 facts + 数量;完整私有查看需 include_sensitive=true;kind=outcomes 只看会话结论、kind=attributes 只看属性事实(未知值忽略,与 status 同语义) |
| GET | /v1/profile/structured |
结构化用户画像(基本信息/偏好/习惯) |
| GET | /v1/graph |
默认安全关系图:排除敏感 fact 对应的边;完整私有图需 include_sensitive=true |
| GET | /v1/conflicts |
待确认的疑似冲突(LLM 检测,需开 ENGRAM_CONFLICT_DETECTION=1) |
| POST | /v1/conflicts/{id}/resolve |
{"keep":"newer|older|both"} 让冲突由人确认 |
| PATCH | /v1/facts/{id} |
改事实 {"object":"...","sensitive":true} |
| DELETE | /v1/facts/{id} |
删一条 |
| GET | /v1/audit?limit=60 |
记忆体检:逐条列出值得修的事实(机器 token、空值、未归约断言、孤立实体等)以及按槽分组的 slot_overflow;只读,不改任何数据 |
| POST | /v1/facts/clear-slot |
不可逆:{"subject":"user","predicate":"occupation","expect_count":84} 硬删除该 (subject, predicate) 槽上的全部 live 事实。用于处理 slot_overflow;expect_count 必填,是乐观并发校验(与体检时的条数不一致则整体拒绝、不删除任何行)——无保护的批量删除是这个端点唯一不该提供的形态,因此没有省略它的写法。已被 supersede 的历史事实、以及 source="user"(你亲手写过或就地改过的)事实都不在删除范围内 |
| GET | /v1/export?include_sensitive=false |
安全结构化导出:仅非敏感 facts + graph;不含画像、摘要、原始对话 |
| POST | /v1/forget |
需 {"confirm":true};清空该 key 的全部记忆(不可逆) |
浏览器开 <Base URL>/ui/ → 输入你的 key → 看「画像 / 会话结论 / 事实管理 / 时间线 / 关系图谱 / 记忆问答 / 冲突待确认 / 记忆体检」。
把数据整理成一个 JSON 文件(一个数组,每条是对话或事实),用配套脚本一键灌:
python examples/ingest_client.py \
--base http://42.193.220.197:8456 --key demo-test \
--data your_data.json --reset数据格式见 examples/ingest_client.py 顶部说明(支持"原始对话"和"结构化事实"两种记录)。
B=http://42.193.220.197:8456 ; K=demo-test
# 灌
curl -s -X POST $B/v1/remember -H "Authorization: Bearer $K" -H "Content-Type: application/json" \
-d '{"content":"我在字节跳动做后端,最喜欢周杰伦。","scope":"long"}'
# 测
curl -s -X POST $B/v1/recall -H "Authorization: Bearer $K" -H "Content-Type: application/json" \
-d '{"query":"我喜欢哪个歌手"}'