项目 Graphiti 图谱 API
配置项目模型、写入图谱 episode、读取任务和执行可信语义搜索。端点使用平台组合认证,并检查实际调用者的项目 ACL。站点管理员身份不替代项目 read/write/admin 权限。
| 端点 | 项目权限 | 全局开放开关 |
|---|---|---|
GET /projects/:projectId/graph/config | read | 可关闭 |
PUT /projects/:projectId/graph/config | admin | 可关闭 |
POST /projects/:projectId/graph/search | read | 须开放 |
GET /projects/:projectId/graph/memory-status | read | 不受开关限制 |
GET /projects/:projectId/graph/memory/bootstrap | project admin / site admin(JWT) | 不受开关限制 |
PUT /projects/:projectId/graph/memory/source | project admin / site admin(JWT) | 不受开关限制 |
PUT /projects/:projectId/graph/memory/files | project admin / site admin(JWT) | 不受开关限制 |
POST /projects/:projectId/graph/memory/build | project admin / site admin(JWT) | 不受开关限制 |
POST /projects/:projectId/graph/memory/rebuild | project admin / site admin(JWT) | 不受开关限制 |
项目模型配置
GET /projects/:projectId/graph/config
直接返回配置 DTO,不使用 success/data 封装:
{
"usingDefaults": true,
"override": null,
"effectiveConfig": {
"enabled": true,
"llmModelId": "published-main-model",
"smallModelId": null,
"embeddingProviderId": "embedding-provider",
"embeddingModelId": "provider-embedding-model",
"embeddingPublicModelId": "published-embedding-model"
},
"canWrite": false,
"canManage": false,
"version": null,
"options": {
"llmModels": [],
"embeddingModels": [],
"embeddingDimension": 1024
},
"runtimeReady": true,
"runtimeError": null
}usingDefaults 表示继承后台默认模型,override 为 null 或五个模型字段,effectiveConfig 是实际模型与全局 enabled 的组合。
canWrite 由项目 write ACL 决定,用于显示图谱写入能力;canManage 由项目 admin ACL 决定,用于显示模型设置保存能力。只读成员两者均为 false,可写成员为 true / false,项目管理员两者均为 true。两字段只表示项目权限,不代表全局入口开放、服务健康或模型运行就绪,后端仍在每次操作时重验对应权限与运行条件。站点管理员身份不替代项目 ACL。
canWrite 是兼容新增的只读响应字段,GET 与成功 PUT 都返回;请求结构和权限要求不变。旧客户端可忽略该字段,新客户端连接尚未升级的服务端时须将缺失的 canWrite 视为 false,不能用 canManage 推断写入权限。
version 是独立配置行的 UUID revision。没有配置行时为 null;它不是 projects.updated_at。配置保存在 service-role-only project_graphiti_settings,不从通用 projects.config 读取模型覆盖。
options.llmModels 返回 { id, name },主/小模型须匹配文本能力与 openai-chat 供应。options.embeddingModels 返回 id、name、providerId、modelId、publicModelId、protocol、credentialReady;维度固定为 1024。候选来自已发布模型,并按实际项目团队的模型准入过滤。
runtimeReady / runtimeError 表示项目模型、供应、价格和团队准入的运行预检,不检查全局 enabled。因此开关关闭时仍可配置和预检,默认模型不完整时完整项目覆盖仍可就绪。实际图服务健康单独查询;不应仅凭 runtimeReady 发起模型操作。
PUT /projects/:projectId/graph/config
仅项目管理员可以保存覆盖。首次保存传 version: null;后续保存须原样传最近 GET/PUT 返回的 UUID。覆盖请求须提供全部五个模型字段:
{
"usingDefaults": false,
"version": null,
"models": {
"llmModelId": "published-main-model",
"smallModelId": null,
"embeddingProviderId": "embedding-provider",
"embeddingModelId": "provider-embedding-model",
"embeddingPublicModelId": "published-embedding-model"
}
}模型字段可以为 null,但覆盖须通过当前项目团队的运行预检才可保存;小模型留空时复用主模型。Embedding 的供应商模型 ID 与公开计费模型 ID 各有用途,不能互换。旧配置缺公开 ID 时只允许唯一已发布映射,歧义须重新选择。
恢复继承请求只包含 usingDefaults 与 version,不得携带 models:
{
"usingDefaults": true,
"version": "67f98164-7600-4831-b736-1182e6b5b31e"
}恢复继承清除模型覆盖,并生成新 revision;即使默认模型未就绪也可恢复。成功响应与 GET 相同。版本过期或并发首次插入返回 409 graphiti_project_config_conflict,客户端须重新读取并确认修改,不自动覆盖或重试保存。
请求不接受 enabled、计费 API Key、付款团队、actor 或执行 token。未知字段或无效版本返回 400 invalid_request。保存新配置只影响新受理任务,不改变已有任务和管理员验证会话。
项目操作与计费
已删除端点(2026-10-15)
「引擎调试」功能整体下线:GET /graph/status、POST /graph/episodes、GET /graph/jobs/:jobId、GET /graph/graph-data (实验图谱 p_<projectId> 的提交/任务/快照与服务状态)已从后端删除,路由与鉴权清单同步更新;需要时从 git 历史找回。 排查引擎问题时可使用站点管理后台的 Graphiti 全局状态与各图谱状态页的失败诊断。
POST /projects/:projectId/graph/search(兼容:默认记忆)
只接受当前权威视图:mode 省略时默认为 current,显式值也只能是 current;as_of、history 或携带 asOf 返回 400 graph_search_current_only。query 最大 2000 字符,limit 为 1–50,默认 10。
服务端使用当前 active Memory generation 的 provider ref 执行语义搜索,再用 Postgres 在同一事务快照验证 artifact、contribution、current source version 以及真实 Database/File 权威行。缺少控制面、active generation 或数据库验证失败时返回稳定 503,不回退到原始 Graphiti namespace 结果。搜索调用同样从项目所属团队计费,并固定其受理模型。
响应为:
{
"generationId": "uuid",
"results": [
{
"uuid": "provider-artifact-ref",
"fact": "...",
"evidence": [
{
"sourceType": "database | file",
"sourceVersionId": "uuid",
"locator": {}
}
]
}
]
}(已删除的 /graph/episodes 手工内容本就没有 Memory provenance,从未进入可信搜索结果。)
兼容说明(2026-10-12):本端点不带
graphId路径参数,固定作用于项目的默认记忆图谱(is_default=true的那一套)。 新建的其它图谱需要用POST /projects/:projectId/graphs/:graphId/search(见下文《图谱库:项目级多图谱接口》)。
图谱库:项目级多图谱接口(2026-10-12)
一个项目可以同时维护多套图谱,而不再只有唯一的「默认记忆」。以下接口前缀 /projects/:projectId/graphs, 前端对接的完整字段合同见仓库内 docs/features/graphiti/memory-graph-library-api.md, 产品语义见 docs/features/graphiti/graph-library.md。
本批所有以下接口只接受 JWT 用户会话,api-key / agent / oauth 一律 403 { "error": "User session token required" }。 权限三档:读 = 项目 read(含团队成员隐式只读);条目写 = 项目 write;管理 = 项目 admin 或站点管理员。 站点总开关 memory.control_plane 未开启时,全部新接口 403 memory_control_plane_disabled。
| 方法 + 路径 | 权限 | 说明 |
|---|---|---|
GET /projects/:projectId/graphs | 读 | 图谱列表(首次调用惰性创建默认记忆),含 canManage、canWriteEntries、limit: 5 |
POST /projects/:projectId/graphs | 管理 | 新建图谱(name 1–100 字,id 可选前端幂等键),新图谱默认不开启提炼 |
GET /projects/:projectId/graphs/ingest-trace | 管理 | 按月只读查询提炼任务与模型调用计费留痕(month=YYYY-MM&status=failed|all);任务与调用明细各自键集分页:limit/cursor(任务,1–500,默认 100)、callsLimit/callsCursor(调用,1–999,默认 500),part=items|calls 只翻其中一个列表;响应带 nextCursor / nextCallsCursor |
PATCH /projects/:projectId/graphs/:graphId | 管理 | 改名(expectedRevision 乐观锁) |
DELETE /projects/:projectId/graphs/:graphId?expectedRevision=N | 管理 | 删除非默认图谱并回收已提炼数据;默认记忆 400 memory_default_graph_undeletable |
POST /projects/:projectId/graphs/:graphId/enable | 管理 | { confirmBilling: true } 计费确认后开启提炼;幂等,已开启直接返回 |
GET /projects/:projectId/graphs/:graphId/status | 读 | 图谱状态(五阶段)、来源逐项状态、失败诊断、抽取提示、degraded 计数 |
GET /projects/:projectId/graphs/:graphId/bootstrap | 管理 | 状态 + 可选表/文件及跨图谱使用情况(管理视图) |
PUT /projects/:projectId/graphs/:graphId/sources/tables/:collectionId | 管理 | { fieldNames }(空数组=停用该表,只影响这一张表) |
PUT /projects/:projectId/graphs/:graphId/sources/files | 管理 | { enable?, disable? }(合计 1–50 个) |
POST /projects/:projectId/graphs/:graphId/build | 管理 | 立即推进一拍;未开启 400 memory_graph_not_enabled |
POST /projects/:projectId/graphs/:graphId/rebuild | 管理 | { requestId, force? } 人工重建(付费,requestId 幂等) |
POST /projects/:projectId/graphs/:graphId/search | 读 | { query, mode?, limit? } 按该图谱当前版本检索可信事实;同一查询词再次查询复用查询向量、不再调用 embedding 模型(不计费);响应头 Server-Timing 给出分段耗时(仅分段名与毫秒) |
GET /projects/:projectId/graphs/:graphId/entries?cursor=&limit= | 读 | 记忆条目分页列表(按更新时间倒序) |
POST /projects/:projectId/graphs/:graphId/entries | 条目写 | { content, occurredAt?, id? } 新建记忆条目;图谱未开启也可写 |
POST /projects/:projectId/graphs/:graphId/entries/sample-temporal | 条目写 | 生成两条时序示例记忆条目(教学用) |
PATCH /projects/:projectId/graphs/:graphId/entries/:entryId | 条目写 | { content, occurredAt?, expectedRevision } 修改记忆条目 |
DELETE /projects/:projectId/graphs/:graphId/entries/:entryId?expectedRevision=N | 条目写 | 软删记忆条目 |
GET /projects/:projectId/graphs/:graphId/rules | 读 | 本图谱提炼规则视图(官方关系表 + 本图谱改动 + 实际生效情况),见下文《图谱提炼规则(按图谱配置)》 |
POST /projects/:projectId/graphs/:graphId/rules/preview | 读 | 预览合成结果(免费,不写库) |
PUT /projects/:projectId/graphs/:graphId/rules | 管理 | 保存本图谱改动 |
DELETE /projects/:projectId/graphs/:graphId/rules?expectedRevision=N | 管理 | 恢复为全站默认 |
GET /projects/:projectId/graphs/:graphId/rules/history | 读 | 改动历史列表 |
GET /projects/:projectId/graphs/:graphId/rules/history/:overrideId | 读 | 单条历史及内容 |
POST /projects/:projectId/graphs/:graphId/rules/restore | 管理 | 恢复为某条历史 |
POST /projects/:projectId/graphs/:graphId/rules/copy-from | 管理 | 从同项目另一图谱复制当前改动 |
要点
- 开启前置:新图谱默认
ingestEnabled=false。未开启时可以正常配置来源、写记忆条目,都会被保存,但不会产生任何付费提炼 (不会被领取、不会建代);只有带confirmBilling: true调用enable之后才开始提炼,约 15 秒内生效。 - 上限 5 套(含默认记忆):超限
400 memory_graph_limit_reached。 - 来源可跨图谱复用:同一张表/文件可被多套图谱各自接入,
bootstrap响应里usedByOtherGraphs非空时前端会提示「会另外计费」。 - 删除:回收已提炼数据但不影响原始数据表/文件;处理中的图谱删除返回
409 memory_graph_busy(可重试)。 - 错误码全表(含
memory_graph_*/memory_entry_*)见memory-graph-library-api.md§1.1;来源/构建类接口仍复用memory-project-api.md的白名单业务码(如memory_bootstrap_fields_invalid、memory_rebuild_items_in_flight)。
旧接口兼容(不下线,行为调整)
| 旧接口 | 2026-10-12 后的行为 |
|---|---|
GET /graph/memory-status、GET/PUT/POST /graph/memory/*、POST /graph/search | 保留,不带 graphId 时固定落在默认记忆;响应结构不变(phase 新增 ready_with_failed_rebuild 取值;默认记忆始终已开启)。PUT /graph/memory/source 仍是「单表替换」语义,仅作用于默认记忆 |
/admin/memory/projects/:projectId/* | 保留,同样落在默认记忆 |
POST /graph/episodes、GET /graph/jobs/:jobId、GET /graph/graph-data、GET /graph/status | 已删除(2026-10-15):引擎调试整体下线,实验图谱不再有后端入口 |
GET/PUT /graph/config | 不变 |
图谱提炼规则(按图谱配置,2026-10-22)
每个图谱可以在全站生效的提炼规则(官方版本)之上做自己的改动:改写 / 屏蔽 / 新增关系、改未登记关系的默认策略、追加抽取补充与消歧补充。入图时后端把「生效官方版本 + 本图谱当前改动 + 站点允许覆盖的部分」合成一份完整规则。产品说明见仓库 docs/features/graphiti/relation-rules.md「按图谱自定义」,精确约定(差异格式、合成算法、校验)见 plans/2026-10-22-graph-rules-per-graph/contract.md。
通用约定
- 前缀
/projects/:projectId/graphs/:graphId/rules,只接受 JWT 用户会话;权限:读 = 项目 read,管理 = 项目 admin 或站点管理员。 - 站点总开关
memory.control_plane未开启 →403 memory_control_plane_disabled;图谱不存在 / 已删除 / 不在本部署区域 →404 memory_graph_not_found。 - 路径里的
projectId/graphId/overrideId大小写不敏感(服务端统一转小写);不是 UUID →400 invalid_resource_id;请求体有未知字段 →400 invalid_request;请求体 > 64 KB →413 request_too_large。 - 写操作都带乐观锁
expectedRevision(非负整数,JSON number 或十进制字符串均可;0= 从未自定义),取自最近一次GET …/rules的revision。 - 下发开关关闭时允许保存(只是暂不生效);没有生效官方版本时预览与写操作一律
409 graph_rules_no_active_ruleset。 - 只影响之后的入图:不自动重建、不调模型、不扣费。
差异内容 OverrideContent
{
"schemaVersion": 1,
"relations": {
"rows": [
{ "row": { "type": "WORKS_AT", "...": "完整 RelationSpec" }, "baseRowHash": "<64 hex> | null" }
],
"blocks": [
{ "target": "LIVES_IN", "baseRowHash": "<64 hex>" }
]
},
"defaultPolicy": null,
"extractionSupplement": "",
"disambiguationSupplement": ""
}rows(0–100):与官方同type→ 整行改写官方行;官方没有 → 本图谱新增。baseRowHash= 改写时所基于的官方行哈希(GET …/rules的official.relations[].rowHash),新增行为null。blocks(0–100):屏蔽官方关系,合成后该行保留但enabled=false。target为官方规范名。defaultPolicy:null= 沿用官方,或model_only/same_subject_same_type/never。extractionSupplement(≤ 4000 字)/disambiguationSupplement(≤ 2000 字):空串 = 不追加;非空时以原文 + 空行 + 补充接在全站抽取指令 / 消歧 user 模板之后;不得包含{{变量}}写法。- 规范化后整体 ≤ 56 KB;合成后的完整规则仍受全站上限约束(关系 ≤ 100 行、抽取指令与消歧模板各 ≤ 20000 字、整体 ≤ 64 KB)。
Issue 结构(预览与 400 / 409 错误共用)
{
"code": "name_duplicate",
"location": { "section": "relations", "kind": "row", "type": "WORKS_IN", "field": "aliases[1]" },
"params": { "name": "WORKS_IN", "conflictsWith": "official:WORKS_AT", "parts": ["default_policy", "disambiguation_supplement", "extraction_supplement", "relations"] }
}合成级问题(下表 name_duplicate 起往下各项)的 params 额外带 parts,见下文「合成校验口径」。
location.section ∈ relations / default_policy / extraction_supplement / disambiguation_supplement / content;kind ∈ row / block / null。
| code | 含义 | 主要 params |
|---|---|---|
field_invalid | 字段级校验失败 | rule ∈ required / unknown_key / pattern / length / one_of / max_items / duplicate;行 / 屏蔽项的问题额外带 index(在提交数组中的下标);长度类带 min / max(补充文字还带 actual) |
block_and_row_same_type | 同一名称既被屏蔽又被改写 / 新增(定位到屏蔽项:kind: "block"、field: "target") | name、index(该屏蔽在提交数组中的下标) |
template_variable_forbidden | 补充文字里出现 {{变量}} | — |
content_too_large | 差异内容 > 56 KB,或合成后内容 > 64 KB | limit、actual |
name_duplicate | 合成表中名称(含别名、含屏蔽行)重复,定位到图谱侧的行 | name、conflictsWith(official:<TYPE> / graph:<TYPE>) |
terminated_by_not_event | 某行登记的结束事件在合成表里不是事件类关系 | name,官方行引用时带 referencedBy |
too_many_relations | 合成表 > 100 行 | limit、actual |
extraction_too_long | 合成后抽取指令 > 20000 字 | limit、actual |
disambiguation_too_long | 合成后消歧模板 > 20000 字 | limit、actual |
base_stale | 提交的 baseRowHash 已过时(官方行在此期间变了);只在预览的 issues 里出现,PUT 时改为整体 409 graph_rules_override_base_stale | expected(当前官方行哈希或 null) |
合成校验口径:保存、恢复、复制、预览时,对四个部分的全部 16 种「允许部分」组合逐一合成校验(纯计算,代价小),任一组合不合法就拒绝,而不是只看站点当前允许的部分。
- 原因:站点随时可能改「允许覆盖哪些部分」,冲突回退要求「改动保存时的基准」在任何允许组合下都能合成。只校验「四项全开」不够——例如图谱把官方的一条大行改写成精简行、同时写了补充文字;站点关闭关系覆盖后官方大行回来、补充仍在,合成内容可能超过 64 KB。
- 问题定位:每个合成问题的
params.parts标出首次出现它的组合(部分代号数组,码点升序)。组合按部分数从多到少、同数按 parts_key 顺序检查;同一问题(code + 定位 + 其余参数相同)只报一次。前端可据此提示「当站点只允许 X、Y 时……」。 - 代价:站点当前关闭的部分如果有问题,也会被拦下不让保存(前端照常展示)。
- 预览返回的合成结果(
composition)仍按当前允许部分计算,ignoredParts列出被站点关闭的部分。
GET …/rules
权限:读。返回 RulesView(直接返回对象,无 success/data 封装):
{
"canManage": true,
"dispatch": { "enabled": false, "projectAllowlisted": true, "effective": true },
"allowedParts": ["relations", "default_policy", "extraction_supplement", "disambiguation_supplement"],
"official": {
"rulesetId": "uuid", "version": 6, "hash": "<64hex>",
"relations": [ { "row": { "type": "WORKS_AT", "...": "RelationSpec" }, "rowHash": "<64hex>" } ],
"defaultPolicy": "same_subject_same_type",
"extractionInstructionsLength": 1461,
"disambiguationTemplateLength": 1020
},
"override": {
"id": "uuid", "seq": 4, "revision": 4, "source": "edit",
"changeCount": 3, "createdAt": "2026-10-22T08:00:00Z", "createdBy": "uuid", "baseVersion": 5,
"content": { "schemaVersion": 1, "...": "OverrideContent" }
},
"revision": 4,
"effective": {
"source": "composed",
"officialVersion": 6,
"hash": "<64hex>",
"conflict": null,
"conflictState": "none",
"predictedConflictState": "none",
"ignoredParts": [],
"notices": [ { "code": "block_target_missing", "target": "LIVES_IN" } ]
},
"rowStatus": [
{ "type": "WORKS_AT", "origin": "graph", "state": "overridden",
"officialUpdated": false, "officialAddedLater": false, "officialRemoved": false }
],
"evaluation": { "status": "never" }
}dispatch.effective:本项目当前是否下发规则(总开关打开,或项目在站点「试运行项目名单」里)。official:没有生效官方版本时为null。不返回官方提示词与抽取指令全文,只给长度,供前端计算补充余量。override:从未自定义为null;source∈edit/reset/restore/copy。effective.source:not_dispatched(未下发)/official(等同官方)/composed(官方 + 本图谱)/fallback(与当前官方冲突,按旧基准合成;officialVersion为回退基准)/unavailable(无可用规则,入图暂停)。conflict在与当前生效版本合成失败时为{ againstVersion, issues }。conflictState见下表;为fallback时回退基准的官方版本号即officialVersion。没有生效官方版本时officialVersion与hash为null(此时source = not_dispatched);source = unavailable时officialVersion为当前生效版本号、hash为null。ignoredParts= 本图谱有改动但站点未允许的部分。rowStatus:每个官方行和每个图谱独有行一条。officialUpdated= 改写 / 屏蔽所基于的官方行后来变了;officialAddedLater= 图谱新增的关系官方后来也加了同名;officialRemoved= 改写 / 屏蔽的官方行已被删除。只是提示,不影响入图。evaluation:按effective.hash查是否有完整评测(全部用例、每条 ≥ 3 次、成功);第一期图谱没有自己的用例,绝大多数为{ "status": "never" };有时为{ "status": "evaluated", "runId", "passed", "total", "finishedAt" },其中passed/total在评测摘要缺该字段时为null(不补 0),finishedAt在运行未记录完成时间时为null。- 其它可为
null的字段:override.createdBy(写入时没有操作者,正常保存都有值)、override.baseVersion(基准版本读不到,正常不会出现)。
冲突状态 conflictState(RulesView.effective、状态接口 extractionRules、管理端图谱自定义列表与冲突预检共用):
| 值 | 含义 |
|---|---|
none | 与当前生效官方版本合成成功(或没有自定义 / 不下发) |
fallback | 与当前生效版本冲突,回退到上次能合成的官方版本继续入图 |
paused | 与当前生效版本冲突,且没有任何能合成的版本,该图谱入图暂停(派发报 graph_rules_graph_composition_unavailable),改好规则保存后恢复 |
- 运行态 vs 预测态:
conflictState是运行态,与实际派发一致——项目未下发规则(总开关关闭且不在试运行名单)时恒为none(规则根本不生效)。RulesView.effective与管理端图谱自定义列表另给predictedConflictState(同样三种取值,不看下发开关),用于在未下发时提示「启用下发后此图谱会回退 / 暂停」。 effective.conflict明细不论是否下发都照常给出。- 状态接口
extractionRules只给运行态conflictState。 - 管理端冲突预检的
conflicts[].conflictState本身就是「按该版本发布后」的预测,不受下发开关影响。
POST …/rules/preview
权限:读。请求 { "content": OverrideContent }。不写库、不调模型、不收费,用当前生效官方版本合成。字段不合法也返回 200,问题放在 issues 里。
{
"valid": true,
"issues": [],
"normalizedHash": "<64hex>",
"changeCount": 3,
"composition": {
"identical": false,
"hash": "<64hex>",
"partsKey": "default_policy,relations",
"ignoredParts": [],
"relations": [ { "row": { "type": "WORKS_AT", "...": "RelationSpec" }, "origin": "graph", "state": "overridden" } ],
"defaultPolicy": "never",
"extractionInstructionsLength": 1500,
"disambiguationTemplateLength": 1100,
"notices": []
},
"evaluation": { "status": "never" }
}valid=false时composition为null;normalizedHash、changeCount在字段级校验不通过(无法规范化)时为null,其余情况总有值。issues含字段级、合成级问题与base_stale。identical=true表示合成结果与官方完全相同,入图按官方处理。
PUT …/rules
权限:管理。请求 { "expectedRevision": 4, "content": OverrideContent },成功返回最新 RulesView,并写入一条来源 edit 的历史。
保存前核对每个改写 / 屏蔽的 baseRowHash:必须等于当前官方行哈希,或与本图谱上一版同名行原样相同;否则 409 graph_rules_override_base_stale(附 issues)。「确认保留我的版本」= 把该行 baseRowHash 改成当前官方行哈希后再保存。
DELETE …/rules?expectedRevision=N
权限:管理。恢复为全站默认:写入一条空改动记录(来源 reset),返回 RulesView。
GET …/rules/history?limit=&cursor=
权限:读。limit 1–50(默认 20),cursor 为上一页返回的 nextCursor。按保存顺序倒序:
{
"items": [
{ "id": "uuid", "seq": 3, "source": "copy",
"sourceOverrideId": "uuid", "sourceGraphId": "uuid",
"changeCount": 2, "contentHash": "<64hex>", "baseVersion": 5,
"createdAt": "2026-10-22T08:00:00Z", "createdBy": "uuid", "current": true }
],
"nextCursor": "2"
}source = restore的记录只记sourceOverrideId,sourceGraphId为null;source = copy两者都记;edit/reset两者都为null。baseVersion:保存时所基于的官方版本号;只在该记录的基准规则集读不到时为null(正常不会出现)。createdBy可为null。
GET …/rules/history/:overrideId
权限:读。返回 { "item": HistoryItem, "content": OverrideContent }。记录不存在或不属于本图谱 → 404 graph_rules_override_not_found。
POST …/rules/restore
权限:管理。请求 { "expectedRevision": 4, "overrideId": "uuid" }。把该条历史的内容复制成一条新记录(来源 restore),返回 RulesView。会用当前生效官方版本重新合成校验,失败 400 graph_rules_override_invalid。不做 baseRowHash 核对(原样沿用)。
POST …/rules/copy-from
权限:管理。请求 { "expectedRevision": 4, "sourceGraphId": "uuid" }。复制同项目另一个图谱的当前改动(来源 copy),返回 RulesView。校验口径同 restore。
错误码
错误响应为 { "error": "<code>" },校验类附 issues:{ "error": "graph_rules_override_invalid", "issues": [Issue] }。
| 状态 | error | 出现 |
|---|---|---|
| 400 | invalid_request / invalid_resource_id | 全部 |
| 400 | graph_rules_override_invalid(附 issues) | PUT / restore / copy-from:字段级或合成级校验失败 |
| 400 | graph_rules_copy_source_same | copy-from:源与目标是同一图谱 |
| 403 | memory_auth_method_forbidden / memory_manage_forbidden / forbidden / memory_control_plane_disabled | 非 JWT、无管理权限、无读权限、控制面关闭 |
| 404 | memory_graph_not_found / memory_project_not_found / project_not_found | 图谱或项目不存在 |
| 404 | graph_rules_override_not_found | history/:id、restore:记录不存在或不属于本图谱 |
| 404 | graph_rules_copy_source_not_found | copy-from:源图谱不存在、已删除、不在同一项目或区域 |
| 409 | graph_rules_copy_source_empty | copy-from:源图谱没有自定义或当前为空改动 |
| 409 | graph_rules_override_revision_conflict | 写操作:expectedRevision 与当前不一致 |
| 409 | graph_rules_override_base_stale(附 issues) | PUT:baseRowHash 已过时 |
| 409 | graph_rules_no_active_ruleset | 写操作与预览:没有生效官方版本 |
| 413 | request_too_large | 请求体 > 64 KB |
| 503 | graph_rules_storage_unavailable | 数据库失败 |
| 500 | graph_rules_composition_invalid / graph_rules_internal_error | 内部不一致 |
状态接口新增字段 extractionRules
GET /projects/:projectId/graphs/:graphId/status、…/bootstrap 以及其它返回 MemoryBootstrapStatus 的接口新增:
"extractionRules": {
"current": { "kind": "composed", "officialVersion": 6, "overrideSeq": 4, "hash": "<64hex>" },
"built": { "kind": "official", "officialVersion": 5, "overrideSeq": null, "hash": "<64hex>" },
"changedBy": ["official", "graph"],
"conflict": false,
"conflictState": "none"
}current:现在入图会用哪份规则;built:当前可用版本按哪份规则生成(没有可用版本,或建代时没有记录规则指纹时为null)。kind:legacy(未下发规则,旧逻辑)/official(官方版本)/composed(官方 + 本图谱)/unknown(认不出,界面写「较早的规则」)。changedBy:只在「规则已更新」(extractionRulesOutdated = true)时非空,说明built与current的差别来自全站(official)、本图谱(graph)或两者;否则为[]。built.kind = "unknown"(反查不到,按「较早的规则」展示)时说不清来源,也为[]。conflict:当前生效官方版本与本图谱改动冲突(正在回退或已暂停),保留兼容;细分看conflictState(运行态,项目未下发时恒为none;状态接口不给predictedConflictState)(none/fallback/paused,含义见上文冲突状态表)。fallback时回退基准版本号 =current.officialVersion。- 没有可用规则(入图已暂停)时:
extractionRulesOutdated = false、current.kind = "unknown"、conflict = true、conflictState = "paused"。 built.kind = "unknown"时说不清变化来源,changedBy为[]。- 原字段
extractionRulesOutdated保留,语义改为按本图谱实际在用的规则计算:别的图谱改动不会触发本图谱的「规则已更新」。
Memory 项目级自助接口(2026-10-11)
Memory 初始化不再只能由站点管理员配置:项目管理员(项目显式 admin 权限)可自助开启,站点管理员同样可用。以下端点只接受 JWT 用户会话,api-key / agent / oauth 一律 403 memory_auth_method_forbidden;权限判定失败/超时返回 503,不当作无权限。完整字段合同(MemoryBootstrapStatus 等)见仓库内 docs/features/graphiti/memory-project-api.md。
GET /projects/:projectId/graph/memory-status
轻量就绪状态,项目 read 权限即可、不要求 JWT(接受原有全部认证方式):
{ "ready": true, "reason": null, "generationId": "uuid", "canManage": true }canManage 为当前会话是 JWT 且为项目管理员或站点管理员;非 JWT 会话恒为 false。该接口先做项目 read 权限前置检查(无读权限仍是普通 403),通过后才计算 canManage;只有这一步的权限查询失败/超时才返回 503 { "error": "memory_access_unavailable" },客户端应保持原状态,不等同于 canManage=false。503 保证仅适用于 canManage 查询本身,前置 read 检查失败仍可能是 403。
GET /projects/:projectId/graph/memory/bootstrap
返回 { success: true, data: MemoryBootstrapStatus },包含已配置数据表/文件源、可选项、扫描进度、生成代状态、degraded 计数与自动重建剩余次数(autoRebuildBudgetLeft)。
PUT /projects/:projectId/graph/memory/source
{ "collectionId": "table-key-or-null", "fieldNames": ["field1", "field2"] }单选替换数据表源:collectionId 非空时启用该表并停用其余已启用表源(fieldNames 1–64 个);collectionId: null 停用全部表源。返回同 bootstrap。
PUT /projects/:projectId/graph/memory/files
{ "enable": ["file-uuid"], "disable": ["file-uuid"] }逐个勾选文本文件(text/plain / text/markdown / application/json),enable + disable 合计 1–50 个。不合格文件返回 400 memory_bootstrap_file_invalid:<reason>(reason ∈ unsupported_mime / too_large / empty_document / invalid_utf8 / invalid_json / disk_sync_unsupported / content_hash_missing / deleted / unreadable)。返回同 bootstrap。
POST /projects/:projectId/graph/memory/build
无请求体。只立即推进本项目的对账与建代/验证/激活一拍;扫描(区域级 outbox 摄入)由后台同步循环(15 秒一拍)统一处理,不随本接口触发或加速。正常使用无需反复调用本接口。返回同 bootstrap。
POST /projects/:projectId/graph/memory/rebuild
{ "requestId": "uuid", "force": false }人工重新构建(显式付费操作)。requestId 为前端每次点击意图生成的 UUID,失败重试沿用同一个,同一 requestId 重放返回原结果(replayed: true)而不会再建代。最新代仍有在途任务时,不带 force 返回 400 memory_rebuild_items_in_flight;force: true 会放弃在途任务并强制重建。
成功响应:
{ "success": true, "data": MemoryBootstrapStatus, "rebuild": { "scanRestarted": false, "replayed": false, "generationId": "uuid" } }scanRestarted: true 表示本次只是恢复了死信/失败的存量扫描(未建代),需等扫描完成后再次调用 build/rebuild。
错误状态码映射
| HTTP | error | 含义 |
|---|---|---|
| 400 | invalid_request / 业务白名单码 | 请求非法或业务规则拒绝(完整白名单见项目文档) |
| 401 | unauthorized | 会话失效 |
| 403 | memory_auth_method_forbidden | 非 JWT 会话 |
| 403 | memory_manage_forbidden | 不是项目管理员 / 站点管理员 |
| 403 | memory_control_plane_disabled | 站点总开关未开启 |
| 404 | memory_project_not_found | 项目不存在或已删除 |
| 503 | memory_access_unavailable | 权限查询失败/超时(不是无权限) |
| 503 | memory_deployment_region_invalid 等 | 站点配置异常 |
| 500 | memory_internal_error | 其他内部错误(固定码) |
旧站点管理员入口 /admin/memory/projects/:projectId/* 保留并共用同一 service,详见 管理员 Graphiti API。
Graph Lab 与管理员验证
项目路由 /o/:teamSlug/p/:projectId/graph-lab 的普通入口只受全局开放开关控制,项目有效配置决定模型操作是否就绪。只读成员可查看配置,项目管理员可保存。菜单与页面共用权限加载;瞬时失败可重试,并发请求合并,旧会话响应不能恢复旧权限。
侧栏高亮跟随当前已完成的路由。侧栏按权限和功能开关决定入口是否显示;页面访问仍执行原有准入检查。异步加载完成后,图谱入口显示对应图标。直达或刷新图谱页不会误选文档,导航等待或中止时保留当前页面的高亮。
持有既有 site:admin 的管理员可在开关关闭时进入诊断,复用 GET /admin/graphiti/status 查看服务,并读取项目配置显示实际预检。原项目操作仍要求各自 read/write ACL 和公开开关。
管理员有限预算验证另要求 JWT、site admin 与当前项目 write ACL。会话使用项目有效模型和付款团队,显式预算 1–1000000 毫积分,最长 15 分钟、两个不同 episode 幂等键、64 次模型调用。已有会话固定模型,新配置不改变它;预算预留不等于实际扣费,未知结果不自动重试或退款。验证独立空间不进入 Memory,也不改变公开开关或可信来源门禁。
本文按 2026-10-05 源码更新,不证明配置表迁移已应用、线上已部署或真实模型/费用/浏览器验收通过。
记忆条目的时序规则(v3)
迁居和换工作会提炼为持续的居住、任职状态,变化时间用于结束旧状态并开始新状态。补录旧记忆按发生时间处理。离职会结束任职状态;入职和搬家等历史事件仍保留。兼职、多住所、同时任职和出差保留原文限定,不仅因城市或公司不同就使旧事实失效。
保存前会补查同一人物的居住/任职候选(每类最多 50 条已存事实,另合并本轮事实),有日期的明确离职终止同一人物在对应公司的较早任职,不影响离职后的重新入职。补录同一人物在同一地点/公司的状态时,会复用覆盖补录起点(或起点未知)的同类已结束区间,以最早的已知结束时间收紧补录事实;不会把较晚的另一段回迁或重聘套到更早段,也不延长更早的结束时间。有候选时会增加消歧调用并正常计费。其它状态替代仍依赖模型理解,不能保证任意大图找全冲突。已有图谱需要项目管理员手动重新构建(付费)才能使旧记忆应用新规则;系统不会因为规则升级自动重建。
图谱数据库浏览(2026-10-14)
网页默认打开关系画布,不需要先选实体。点击「加载整套图谱」可按批次读取;也可切换到数据列表选择起点。用户主动切换列表后,订阅通知不会把页面切回画布。记录详情仅在点击记录后从侧边展开。
此组接口前缀 /projects/:projectId/graphs/:graphId/browse。只接受 JWT 用户会话、项目 read(或既有站点管理员管理权限),复用 Memory 控制面、部署区域和图谱归属校验。API key、OAuth、Agent 不可调用。只读,不触发模型调用或重新提炼。
| GET 后缀 | 用途 |
|---|---|
/stats | active generation 原始库计数 |
/entities | 实体候选按 UUID 分页后核验来源 |
/entities/:entityId | 实体原始字段与当前有效证明 |
/relations | 关系候选按 UUID 分页后核验来源 |
/relations/:relationId | 关系事实、端点、区间及证据 |
/neighbors/:entityId | 一跳关系,按方向和类型逐批读取 |
/sources | 当前有效来源版本,不保证已完成本代摄入 |
/sources/:versionId | 核验来源后读取对应原文 |
查询参数白名单:limit(1–100,默认20)、query(名称/事实/UUID 字面子串,最多200字符)、mode=current|history|all、relationType(精确类型,最多200字符)、direction=both|in|out、cursor、generationId(UUID)。实体没有时间区间,实体列表证明可包含有效来源下的历史事实;mode 只限制关系。来源列表没有文字筛选;界面只传 limit/cursor/generationId。详情与 stats 不接受 cursor;公开接口不接受 namespace、Cypher 或 asOf。
stats 返回 {generationId, scope:"raw_storage", generatedAt, counts:{entities,relations,current,historical,episodes}, total:null, hasMore:false, nextCursor:null}。current + historical = relations。库计数可包含来源撤销后的存储残留,不能当作已授权可见总数。
列表返回 {generationId,total:null,hasMore,nextCursor,generatedAt,nodes,relations};来源页为 sources,无 nodes/relations。实体含 uuid/name/labels/created_at/summary/summaryRestricted/proofsComplete/evidence;关系含 UUID、关系类型、事实、两端 UUID/名称、valid_at/invalid_at/expired_at/created_at/score 及 evidence。source 详情为 {generationId,source:{sourceType,sourceVersionId,locator,name,content},total:null,hasMore:false,nextCursor:null}。evidence 为 {sourceType,sourceVersionId,locator} 的数组,仅含当前仍有效来源链。
cursor 绑定 project/graph/generation/操作/资源/筛选;变更筛选返回400,切换 active generation 返回409。按原始候选推进游标;过滤后可能空页但仍有下一页。它不是事务快照,新插入且排在当前游标之前的记录需刷新。total 始终 null,不伪造来源过滤后的总量。
历史模式允许 artifact active/invalidated 和 temporal invalidated contribution;撤销判定始终通过 source/version active+current+原文 hash/config 校验。summary 跨来源聚合,只有实体全部 MENTIONS 证明完整且有效时可显示,否则 null。每实体 episode/fact 各20个证明、每事实最多20来源版本;最多4,000refs/20批来源RPC,安全漏显而不越权。文件返回已物化文本片段,不提供下载原始文件字节。
错误:400 memory_graph_browse_request_invalid / memory_graph_browse_cursor_invalid / invalid_resource_id;404 memory_graph_browse_record_unavailable / memory_graph_browse_source_unavailable;409 memory_graph_generation_changed;503 表示 active generation、读取服务或来源核验不可用。当前公开语义搜索仍仅支持 current,不修改原搜索RPC。
部署依赖:新增三个 service_role-only RPC,见迁移 20261014160000_memory_graph_browse.sql;先部署数据库函数与 Graphiti API,再启用后端/前端新版本。此页不代表迁移已经在线上应用。
大图拓扑与变更补读(2026-10-15)
| 方法 / 路径后缀 | 返回内容 | 上限 |
|---|---|---|
GET /topology/entities | 来源核验后的 uuid/name,含有 episode 证明的孤立实体 | 每批 500 |
GET /topology/relations | uuid/name、两个端点 UUID/名称、valid_at/invalid_at/expired_at | 每批 1,000 |
GET /changes | 当前修订、授权后的变化数据、需移除的关系 UUID,或完整重核标记 | 见下 |
拓扑沿用列表的筛选、generationId 与游标绑定。默认批量分别为 500/1,000;普通列表仍为 20、最多100。拓扑不返回事实正文、聚合摘要或来源原文;点击后调用既有详情接口。所有候选先核验来源。过滤后空批仍须按 nextCursor 继续;total 始终为 null。最多 20+20 个证明/实体,顺序不保证稳定,截断会安全漏显。
changes 接受相同筛选(不接受 cursor)以及可选 afterRevision:0 至 9223372036854775807 的十进制字符串。首次省略只取得当前修订,供全量加载前记录水位;后续带该水位补读。返回 {generationId, revision, resetRequired, nodes, relations, removedRelations}。revision 始终是字符串,不能转成 JS Number。关系被时间筛选、来源核验或删除排除时,UUID 进入 removedRelations。新 episode 的独立实体也走证明核验。
日志按 namespace 的事务提交顺序分配修订,保留最近512条。跨越日志窗口、超过50次事务、来源/配置/世代变化,或单次变化超过100个来源版本/1,000个事实/200个episode/500个episode关联实体候选时,返回 resetRequired=true,不返回部分增量冒充完整结果。客户端须完整重核;切代仍返回409。通知触发授权补读,不作为授权结果,也不携带原文。图谱页面不轮询;在途通知合并后补读,重连时完整重核,并保留手动刷新。原文现值漂移却未推进来源版本时,可能不产生该日志;须在手动刷新、重新打开页面或重连完整重核时移除旧显示,不承诺移除时限。普通增量补读不覆盖未列入变化集的记录。
依赖:在基础 browse migration 后按时间顺序应用 20261015120000_memory_graph_changes.sql、20261015123000_memory_graph_bulk_visibility.sql、20261015130000_memory_graph_changes_read.sql。批量核验每次合计最多2,000个证明,单SQL内合并来源版本后校验现值;旧200上限RPC通过同一核心执行,没有跨请求缓存。此契约和本机测试不代表已上线。
changes 的 limit 不控制增量大小;变化上限由服务端固定契约决定,超限返回 resetRequired。removedRelations 表示应从当前筛选的画布移除,不等同于数据库记录被删除。