API参考手册

更新时间:
复制 MD 格式

本文给出 Context0 数据面与管理面全部 REST API 的详细说明,包括端点路径、请求参数、请求示例和响应示例。

概览

项目

说明

Base URL

http://<host>:4040(数据面);部分管理接口在 :8080

认证方式

请求头 X-API-Key: <your-api-key>,本文示例中通过 $API_KEY 环境变量传入

响应格式

{"code": 0, "msg": "ok", "data": <T>, "trace_id": "..."}

错误格式

{"code": <非0>, "msg": "错误描述", "trace_id": "..."}

Key 类型

Admin Key(平台级引导凭证,仅管理面)/ Owner Key(租户管理员,管理端全权限)/ User Key(终端用户,隔离到自身数据)

说明
  • 部分 Mem0 兼容端点(/v1/memories、/v1/memories/search 等)返回裸 JSON(无 Box 包装),以保持与 Mem0 SDK 的线协议兼容。

  • 时间字段约定:所有 *_at 字段都是 ISO-8601 瞬间,UTC,以 Z 结尾(如 2026-09-17T18:03:43.226352Z),客户端负责按本地时区渲染。2026-09-16新版本修正了一组违反该约定的字段:本体目录/版本(created_at、generated_at)、本体任务(created_at)、文档修订历史与修订产物(created_at)、评审通知投递(created_at、delivered_at)此前返回的是数据库墙上时间 2026-09-17 18:03:43.226352(无 T、无时区),无法被 new Date() 可靠解析。若您的客户端对这些字段做过“补 T 补 Z”的兼容处理,可以移除。

更新日志

2026-09-16:知识库权限重构:四处行为变化

本次重构把知识库鉴权从“漏了就放行”改成默认拒绝,角色为 viewer < editor < owner。以下四点会改变既有调用方的可观测行为,升级前请确认(其中 1、4 是放宽,2、3 是收紧或改码):

  1. 公开库默认档提升为可写。visibility=workspace(别名 public)的库,workspace 内任意成员的默认角色是 editor。不仅能搜、能读,还能上传与删除库内文档(含别人上传的)。若不希望如此,把库改成 private 后按需授权,或给具体成员写一条 viewer 显式行(见知识库章节的「知识库权限(ACL)」)。

  2. ACL 行到期是硬失效。expires_at 过期的授权行等同于不存在:调用方直接回落到库默认档(公开库 editor / 私有库无权限),不会保留任何“曾经授权过”的残留权限。过期行仍会出现在 ACL 列表里,便于清理。

  3. 图谱数据面的跨 workspace 响应由 403 改为 404。GET /v1/knowledge-bases/{kbId}/graph/nodes|edges 在知识库ID(kbId)跨 workspace 或不存在时,此前返回 403,现在返回 404(不泄漏知识库ID存在性)。按 403 分支做兜底的客户端需同时接受 404。

  4. User Key 删库不再只认创建者。DELETE /v1/knowledge/bases/{id} 此前对 User Key 走独立的“创建者”判定,被显式授予 owner 的成员拿到 my_role=owner 却删不掉库;现已统一到 ACL 判定链,owner 即可删。

权限不足统一返回 403 + code=40303(ACL_FORBIDDEN)。知识库ID跨 workspace 或不存在统一返回 404。知识库详情与列表响应新增 my_role / role_source / can_manage_acl,调用方据此渲染入口,不必再靠“先试一次看是不是 403”探测权限。

API目录

上下文(Context)

POST /v1/context/ingest

将一批对话消息写入指定 session,触发后续记忆抽取与去重。

请求

请求参数

参数

类型

必填

说明

session_id

string

是

会话 ID(外部 session_id),1~128 字符 [A-Za-z0-9_\-.:@]

user_id

string

否

终端用户 ID(mem0 user_id),缺省回退到 member 维度

messages

array

是

消息列表,每批最多 100 条

messages[].role

string

是

user / assistant / system / tool

messages[].content

string

是

消息文本,小于等于65535 字符

messages[].tool_name

string

条件

仅 role=tool 时必填

messages[].metadata

object

否

消息级元数据

messages[].resource_ids

string[]

否

绑定的多模态资源 ID,至多 10 个

messages[].timestamp

long

否

消息发生时间(epoch 秒)

metadata

object

否

  • eager 模式:事件快照

  • batch 模式:存入 session.metadata_json

agent_id

string

否

Agent 标识,持久化到 session.agent_id

extract_mode

string

否

缺省回退全局配置。

  • eager:立即抽取

  • batch:延迟到 flush。

custom_instructions

string

否

请求级蒸馏指令(仅 eager 模式合法),≤8192 字符

timestamp

long

否

记忆发生时间(epoch 秒),缺省用服务端当前时间

请求示例

curl -X POST http://<host>:4040/v1/context/ingest \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{
    "session_id": "sess-2026-08-19-001",
    "user_id": "alice",
    "messages": [
      {"role": "user", "content": "我最近在学习 Rust"},
      {"role": "assistant", "content": "Rust 是一门关注安全性和性能的系统编程语言。"}
    ],
    "extract_mode": "eager"
  }'

响应

响应参数

字段

类型

说明

session_id

string

外部会话 ID(即请求传入的 session_id)

session_internal_id

long

内部数据库自增 ID(可能为 null,首次创建时返回)

message_ids

array

写入的消息引用列表

message_ids[].id

long

消息内部 ID

message_ids[].seq

int

消息序列号

event_id

long

记忆抽取事件 ID(eager 模式下有值,batch 模式为 null)

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "session_id": "sess-2026-08-19-001",
    "session_internal_id": 42,
    "message_ids": [
      {"id": 1, "seq": 1},
      {"id": 2, "seq": 2}
    ],
    "event_id": 789
  },
  "trace_id": "trace-001"
}

POST /v1/context/assemble

按查询装配面向 LLM 的上下文 PromptBlock,返回召回记忆与原文引用。核心端点,Agent 每次对话时调用。

请求

请求参数

参数

类型

必填

说明

session_id

string

条件

与 user_id 至少一项必填

user_id

string

条件

与 session_id 至少一项必填

query

string

否

查询文本,空值触发 memory_bootstrap 零查询冷启动

token_budget

integer

否

Token 预算,取值范围:[1, 32000]

strategy_id

long

否

覆盖 ws 默认策略

recall.top_k

integer

否

记忆召回 top_k,取值范围:[1, 50]

recall.filters

object

否

ES filter 键值对

recall.cosine_threshold

double

否

余弦相关性下限,取值范围:[0, 1]

include

string[]

否

强制包含的 PromptBlock 类型

exclude

string[]

否

强制排除的 PromptBlock 类型

recent_messages_fetch_limit

integer

否

近期消息抓取上限,取值范围:[1, 1000]

bootstrap_top_l0

integer

否

冷启动 L0 实体卡 top-N,取值范围:[0, 100]

bootstrap_top_l1

integer

否

冷启动 L1 事实 top-N,取值范围:[0, 100]

budget_allocator

object

否

Token 预算分配比例覆盖

budget_allocator.memory_ratio

double

否

记忆占比

budget_allocator.knowledge_ratio

double

否

知识库占比

budget_allocator.history_ratio

double

否

历史占比

budget_allocator.system_ratio

double

否

系统占比

knowledge_base_ids

long[]

否

限定知识库检索的知识库 ID 列表;去重后上限 100 个,含 null 元素返回 400,逐知识库执行 ACL 校验(无权返回 403)

knowledge_top_k

integer

否

知识库检索 top_k,取值范围:[1, 50]

include_multimodal

boolean

否

是否注入多模态 PromptBlock,默认 true

multimodal_max_images

integer

否

每次最多注入的多模态块数,取值范围:[0, 50]

context_scope

string

否

full / minimal / memory_only / knowledge_only

include_memories

boolean

否

细粒度覆盖:强制开/关记忆维度

include_knowledge

boolean

否

细粒度覆盖:强制开/关知识库维度

include_wiki

boolean

否

是否注入 Wiki 页面 lane(tag wiki_pages),默认关闭;仅在服务端 context.wiki.enabled=true 且请求携带非空 knowledge_base_ids 时生效。生效且有命中时,knowledge 预算(默认 20%)内部切分为 chunk 12% + wiki 8%

inherit_summary

boolean

否

是否继承上次的 compact_summary

inherit_from_session_id

string

否

显式指定继承哪个 session 的 compact_summary

请求示例

curl -X POST http://<host>:4040/v1/context/assemble \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{
    "session_id": "sess-2026-08-19-001",
    "query": "Rust 的所有权机制是什么?",
    "token_budget": 4096,
    "recall": {"top_k": 10, "cosine_threshold": 0.3}
  }'

响应

响应参数

字段

类型

说明

prompt_blocks

array

PromptBlock 列表,Agent 应按序拼入 LLM prompt

prompt_blocks[].role

string

system / user / assistant

prompt_blocks[].tag

string

类型标签(user_profile / memory_recall/ recent_history / knowledge / multimodal 等)

prompt_blocks[].content

string

正文

prompt_blocks[].tokens

int

该 block 消耗的 token 数

prompt_blocks[].sources

string[]

来源引用列表(如 memory:<id>、knowledge:<chunk_id>、multimodal:<resource_id>)

token_used

int

实际消耗的总 token 数

token_budget

int

请求传入的 token 预算

trace_id

string

链路追踪 ID

stats

object

装配统计信息

stats.recall_total

int

总召回记忆数

stats.recall_kept

int

经裁剪后保留的记忆数

stats.messages_total

int

总消息数

stats.messages_kept

int

经裁剪后保留的消息数

stats.took_ms

long

装配耗时(毫秒)

stats.multimodal_kept

int

多模态 block 数量

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "prompt_blocks": [
      {"role": "system", "tag": "user_profile", "content": "用户正在学习 Rust...", "tokens": 42, "sources": ["memory:mem_1_2_abc"]},
      {"role": "system", "tag": "memory_recall", "content": "- 用户喜欢系统编程\n- ...", "tokens": 128, "sources": ["memory:mem_1_2_def"]},
      {"role": "system", "tag": "recent_history", "content": "...", "tokens": 256, "sources": []}
    ],
    "token_used": 426,
    "token_budget": 4096,
    "trace_id": "trace-001",
    "stats": {
      "recall_total": 5,
      "recall_kept": 3,
      "messages_total": 20,
      "messages_kept": 10,
      "took_ms": 142,
      "multimodal_kept": 0
    }
  }
}

POST /v1/context/compact

增量压缩会话上下文,按 chunk_size 折叠最早的活跃消息为叶子摘要。

请求

请求参数

参数

类型

必填

说明

session_id

string

是

会话 ID

keep_recent_n

integer

否

保留最近活跃消息条数,默认 50,范围 [1, 500]

chunk_size

integer

否

单次折叠消息条数,默认 20,范围 [5, 200]

model_hint

string

否

覆盖默认 LLM 模型

请求示例

curl -X POST http://<host>:4040/v1/context/compact \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"session_id": "sess-2026-08-19-001", "keep_recent_n": 30}'

响应

响应参数

字段

类型

说明

session_id

string

外部会话 ID

session_internal_id

long

内部数据库自增 ID

summary_message_id

long

生成的摘要消息 ID

compacted_message_count

int

被压缩的消息数

summary_token_count

int

摘要 token 数

active_message_count

int

压缩后仍活跃的消息数

depth

integer

压缩深度(叶子摘要为 0)

source_seq_range

int[]

被压缩的消息序列范围 [firstSeq, lastSeq]

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "session_id": "sess-2026-08-19-001",
    "session_internal_id": 42,
    "summary_message_id": 101,
    "compacted_message_count": 20,
    "summary_token_count": 180,
    "active_message_count": 50,
    "depth": 0,
    "source_seq_range": [1, 20]
  }
}

POST /v1/context/flush

将短期上下文落盘为长期记忆与事件。

请求

请求参数

参数

类型

必填

说明

session_id

string

是

会话 ID

compact_first

boolean

否

落盘前是否先 compact,默认 true

keep_recent_n

integer

否

compact 时保留的近 N 条消息,默认 20,范围 [1, 500]

请求示例

curl -X POST http://<host>:4040/v1/context/flush \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"session_id": "sess-2026-08-19-001", "compact_first": true}'

响应

响应参数

字段

类型

说明

session_id

string

外部会话 ID

session_internal_id

long

内部数据库自增 ID

status

string

会话状态(flushed)

flushed_at

string

落盘时间(ISO-8601)

compact_summary

object

落盘前 compact 的摘要(compact_first=true 时有值),结构同 compact 响应

evolve_event_id

long

记忆蒸馏事件 ID

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "session_id": "sess-2026-08-19-001",
    "session_internal_id": 42,
    "status": "flushed",
    "flushed_at": "2026-08-19T10:30:00Z",
    "compact_summary": {
      "session_id": "sess-2026-08-19-001",
      "compacted_message_count": 20,
      "summary_token_count": 180,
      "active_message_count": 30
    },
    "evolve_event_id": 1001
  }
}

POST /v1/context/lifecycle

上报上下文生命周期事件,按 action 分发驱动 session 状态机。action=start 会创建/打开会话并返回首屏装配的 PromptBlock;action=end 会关闭会话并返回收尾统计。

请求

请求参数

参数

类型

必填

说明

action

string

是

start / end

session

object

是(start)

action=start 时必填,描述新会话的元信息

session.external_id

string

是(start)

外部 session ID,action=start 时必填。取值范围:[A-Za-z0-9_\-.:@]{1,128}

session.user_id

string

否

终端用户 ID(mem0 user_id),落库到 session.user_id。省略 / null 表示未指定,非空时必须匹配 [A-Za-z0-9_\-.:@]{1,128}

session.agent_id

string

否

Agent 标识,≤128 字符

session.title

string

否

会话标题,≤256 字符

session.metadata

object

否

自定义元数据

session_id

string

条件

action=end 时必填,会话 ID

user_id

string

否

action=end 可选。

  • Owner Key 关闭指定终端用户会话时使用,应与 action=start 的 session.user_id 使用同一身份值。

  • 省略 / null 表示未指定,非空时必须匹配[A-Za-z0-9_\-.:@]{1,128}

query

string

否

action=start 可选,配合 token_budget 决定首条 prompt 装配

token_budget

integer

否

action=start 可选,Token 预算 [1, 32000]

请求示例

  • start

    curl -X POST http://<host>:4040/v1/context/lifecycle \
      -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
      -d '{
        "action": "start",
        "session": {"external_id": "sess-2026-08-19-001", "user_id": "alice", "agent_id": "my-agent"},
        "query": "继续上次的 Rust 讨论",
        "token_budget": 4096
      }'
  • end

    curl -X POST http://<host>:4040/v1/context/lifecycle \
      -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
      -d '{"action": "end", "session_id": "sess-2026-08-19-001", "user_id": "alice"}'
说明

Owner Key 代表 workspace,不能仅凭 Key 推断某个终端用户。

  • 若 start 时使用了 session.user_id,end 时应传相同的顶层 user_id,使关闭与 flush 落在同一终端用户/member 身份上。

  • 只有 start/end 都省略该值时,两个动作才都回退到 Key 绑定的 member。User Key 仍受 own-user 校验约束;空串不作为“缺失”接受。

响应

响应参数

字段

类型

说明

session_id

string

外部会话 ID

session_internal_id

long

内部数据库自增 ID

prompt_blocks

array

仅 action=start 返回,结构同 /v1/context/assemble

token_used / token_budget / trace_id / stats

-

仅 action=start 返回,语义同 assemble

message_count

int

仅 action=end 返回,会话累计消息数

total_tokens

long

仅 action=end 返回,会话累计 Token

event_id

long

仅 action=end 返回,收尾生成的事件 ID

说明

空值字段(NON_NULL)不输出:start 只返回装配相关字段,end 只返回收尾相关字段。

响应示例

  • start,含装配结果:

    {
      "code": 0, "msg": "ok",
      "data": {
        "session_id": "sess-2026-08-19-001",
        "session_internal_id": 42,
        "prompt_blocks": [
          {"role": "system", "tag": "user_profile", "content": "用户正在学习 Rust...", "tokens": 42, "sources": ["memory:mem_1_2_abc"]}
        ],
        "token_used": 42,
        "token_budget": 4096,
        "trace_id": "trace-001",
        "stats": {"recall_total": 3, "recall_kept": 1, "messages_total": 0, "messages_kept": 0, "took_ms": 88}
      }
    }
  • end,含收尾统计:

    {
      "code": 0, "msg": "ok",
      "data": {"session_id": "sess-2026-08-19-001", "message_count": 45, "total_tokens": 12800, "event_id": 789}
    }

POST /v1/context/dialectic

在上下文召回结果上进行辩证分析,输出多视角证据与判断。需提供 session_id 或 user_id 至少一项(禁止 workspace 全域召回)。

请求

请求参数

参数

类型

必填

说明

query

string

是

查询文本

session_id

string

条件

会话 ID(可选,绑定召回作用域);与 user_id 至少一项必填

user_id

string

条件

用户 ID(可选,限定召回的用户隔离);与 session_id 至少一项必填

depth

string

否

分析深度:fast / standard / deep / highest,默认 standard

top_k

integer

否

返回 top-k [1, 20],默认 5

scope

string

否

保留字段(未来用于 session/user/workspace 维度收敛)

请求示例

curl -X POST http://<host>:4040/v1/context/dialectic \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{
    "query": "Rust 的所有权模型有什么优缺点?",
    "user_id": "alice",
    "depth": "standard",
    "top_k": 5
  }'

响应

响应参数

字段

类型

说明

depth

string

实际使用的分析深度

hits_count

int

召回命中数

latency_ms

long

分析耗时(毫秒)

prompt_blocks

array

PromptBlock 列表,结构同 /v1/context/assemble

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "depth": "standard",
    "hits_count": 5,
    "latency_ms": 230,
    "prompt_blocks": [
      {"role": "system", "tag": "dialectic_analysis", "content": "## 多视角分析\n\n**正面证据**:...\n**反面证据**:...", "tokens": 320, "sources": ["memory:mem_1_2_abc"]}
    ]
  }
}

会话(Session)

POST /v1/sessions

创建或获取现有会话(幂等)。若 externalId 已存在则返回已有会话。

请求

请求参数

参数

类型

必填

说明

external_id

string

是

外部会话 ID,取值范围:1~128 字符 [A-Za-z0-9_\-.:@]

agent_id

string

否

Agent 标识,小于等于128 字符

title

string

否

会话标题,小于等于256 字符

metadata

string

否

JSON 格式元数据字符串

user_id

string

否

终端用户 ID,小于等于128 字符

session_key

string

否

线程 key,用于跨会话继承链,小于等于64 字符

parent_session_id

string

否

显式父会话的 external_id,小于等于128 字符

请求示例

curl -X POST http://<host>:4040/v1/sessions \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"external_id": "sess-2026-08-19-001", "agent_id": "my-agent", "user_id": "alice"}'

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "session": {
      "id": 1,
      "external_id": "sess-2026-08-19-001",
      "agent_id": "my-agent",
      "user_id": "alice",
      "status": "open",
      "title": null,
      "message_count": 0,
      "total_tokens": 0,
      "session_key": null,
      "parent_session_id": null,
      "created_at": "2026-08-19T10:00:00Z",
      "updated_at": "2026-08-19T10:00:00Z",
      "closed_at": null
    },
    "created": true
  }
}
说明

session.id 是内部数据库自增主键(Long 类型),session.external_id 是调用方传入的外部会话标识。

GET /v1/sessions

分页列出当前租户会话。User Key 只看自己的,Owner Key看全 workspace。

请求

请求参数

参数

类型

必填

说明

agent_id

string

否

按 agent 过滤

status

string

否

按状态过滤(open/closed/deleted/flushed)

page

integer

否

页码(从0开始),默认 0

page_size

integer

否

每页大小,默认 20,上限 200

请求示例

curl "http://<host>:4040/v1/sessions?status=open&page_size=10" \
  -H "X-API-Key: $API_KEY"

响应说明:返回 Box<List<SessionDto>>,分页信息通过响应头 X-Total-Count、X-Page、X-Page-Size、X-Has-More 暴露。

GET /v1/sessions/{id}

获取指定会话详情。{id} 为 externalId 或内部 ID。

请求

请求示例

curl "http://<host>:4040/v1/sessions/sess-2026-08-19-001" \
  -H "X-API-Key: $API_KEY"

PATCH /v1/sessions/{id}

部分更新会话属性(如 title / metadata)。

请求

请求示例

curl -X PATCH http://<host>:4040/v1/sessions/sess-2026-08-19-001 \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"title": "Rust 学习会话"}'

POST /v1/sessions/{id}/messages

向会话追加一批消息。

请求

请求参数

参数

类型

必填

说明

messages

array

是

消息列表,每条含 role / content

messages[].role

string

是

user / assistant / system / tool

messages[].content

string

是

消息文本

messages[].toolName

string

条件

role=tool 时必填

请求示例

curl -X POST http://<host>:4040/v1/sessions/sess-2026-08-19-001/messages \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "什么是 borrow checker?"}]}'

GET /v1/sessions/{id}/messages

按 since_seq 增量拉取或按 before_seq 倒序拉取会话消息。

请求

请求参数

参数

类型

必填

说明

since_seq

integer

否

从该序列号之后开始拉取,默认 0

before_seq

integer

否

拉取该序列号之前的消息

order

string

否

asc(默认)/ desc

limit

integer

否

返回条数,默认 50,上限 200

page_size

integer

否

limit 的兼容别名,范围 [1, 200]

size

integer

否

limit 的兼容别名,范围 [1, 200]

说明

limit、page_size、size 只能提供一个;同时提供多个时返回 400。

请求示例

curl "http://<host>:4040/v1/sessions/sess-2026-08-19-001/messages?since_seq=0&limit=50" \
  -H "X-API-Key: $API_KEY"

响应

返回 Box<MessagePage>,MessagePage 含 items(消息数组)和 total(总数)。响应头包含 X-Total-Count。

PUT /v1/sessions/{id}/close

关闭会话,可选生成交接摘要(handoff)。

请求

请求参数

参数

类型

必填

说明

generate_summary

boolean

否

是否生成 handoff 摘要,默认 true

请求示例

curl -X PUT http://<host>:4040/v1/sessions/sess-2026-08-19-001/close \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"generate_summary": true}'

DELETE /v1/sessions/{id}

物理删除指定会话及其消息。

请求

请求示例

curl -X DELETE http://<host>:4040/v1/sessions/sess-2026-08-19-001 \
  -H "X-API-Key: $API_KEY"

GET /v1/sessions/{id}/inheritance

返回会话的继承链,展示跨会话上下文传递关系。

请求

请求示例

curl "http://<host>:4040/v1/sessions/sess-2026-08-19-001/inheritance" \
  -H "X-API-Key: $API_KEY"

GET /v1/sessions/stats

返回会话聚合统计(总数/活跃/关闭/继承/累计 Token)。

请求

请求示例

curl "http://<host>:4040/v1/sessions/stats" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "total": 5,
    "open": 4,
    "closed": 1,
    "inherited": 0,
    "total_tokens": 32
  }
}

GET /v1/sessions/{id}/token-stats

返回指定会话的 Token 用量统计,包含按角色拆分的 Token 计数和所用 tokenizer。

请求

请求示例

curl "http://<host>:4040/v1/sessions/3/token-stats" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "total_tokens": 26,
    "message_count": 4,
    "by_role": {
      "user": 23,
      "assistant": 3
    },
    "token_estimator": "cl100k_base"
  }
}

记忆(Memory)

POST /v1/memories

Mem0 兼容的记忆创建接口。自动触发去重与蒸馏。

请求

请求参数

参数

类型

必填

说明

messages

array

是

对话消息列表(role + content)

user_id

string

否

终端用户 ID,省略时由 API key 身份推导

agent_id

string

否

Agent 标识

run_id

string

否

运行实例标识

metadata

object

否

自定义元数据键值对

custom_instructions

string

否

请求级蒸馏指令,小于等于8192 字符

timestamp

long

否

发生时间(epoch 秒)

请求示例

curl -X POST http://<host>:4040/v1/memories \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "user", "content": "我喜欢用 Vim 编辑器"},
      {"role": "assistant", "content": "好的,我记住了你偏好 Vim。"}
    ],
    "user_id": "alice"
  }'

响应

响应示例

{"results": [{"id": "mem_1_2_abc123", "memory": "用户偏好使用 Vim 编辑器", "event": "ADD"}]}

POST /v3/memories/add

V3 记忆写入,返回包含 memory_id / event_id / created 的 Box 响应。 请求参数:与 POST /v1/memories 相同。

请求

请求示例

curl -X POST http://<host>:4040/v3/memories/add \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{
    "messages": [{"role": "user", "content": "我的技术栈是 Java + Spring Boot"}],
    "user_id": "alice"
  }'

响应

响应示例

{"code": 0, "msg": "ok", "data": {"memory_id": "mem_1_2_def456", "event_id": "evt_789", "created": true}}

POST /v3/memories

Mem0 v1.1 SDK 兼容的记忆列表接口。实体过滤参数(user_id / agent_id / run_id)既可放在请求体顶层,也可放在 filters map 中,分页通过 query 参数控制。返回 Mem0 云端同款分页信封(裸 JSON,无 Box 包装)。

请求

请求参数

参数

位置

类型

必填

说明

user_id / userId

body

string

否

顶层用户过滤;服务端解析为租户内 member_id 后查询

agent_id / agentId

body

string

否

顶层 Agent 过滤

run_id / runId

body

string

否

顶层 Run 过滤

filters

body

object

否

实体过滤 map,接受上述 snake_case/camelCase键,其他键报错

page

query

integer

否

页码(从1开始),默认 1

page_size

query

integer

否

每页大小,默认 100,范围 [1, 200]

请求示例

curl -X POST "http://<host>:4040/v3/memories?page=1&page_size=50" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"user_id": "alice"}'

响应

响应参数

字段

类型

说明

count

long

匹配的记忆总数

next

string

下一页 URL;无更多时为 null

previous

string

上一页 URL;首页为 null

results

array

本页记忆列表(Mem0 记忆结构)

响应示例

{
  "count": 156,
  "next": "/v3/memories/?page=2&page_size=50",
  "previous": null,
  "results": [
    {"id": "mem_1_2_abc123", "memory": "用户偏好使用 Vim 编辑器", "metadata": {}}
  ]
}

POST /v3/entity_cards/{id}/edit

对 L0 实体卡的 role / preferences / attributes 进行部分更新(partial update)。仅传入的字段被覆写,未传(null)字段保持不变。

请求

请求参数

参数

类型

必填

说明

role

string

否

实体角色(如 person / project / technology 卡的角色描述)

preferences

string[]

否

偏好列表

attributes

object

否

开放属性 map,键随卡类型而定(org / repo_url / version / domain 等)

请求示例

curl -X POST http://<host>:4040/v3/entity_cards/card_1_2_alice/edit \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"role": "资深后端工程师", "preferences": ["Java", "Spring Boot"]}'

响应

响应参数

字段

类型

说明

card_id

string

实体卡 ID

metadata

object

合并后的完整实体卡 metadata(含 role / preferences / attributes)

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "card_id": "card_1_2_alice",
    "metadata": {"role": "资深后端工程师", "preferences": ["Java", "Spring Boot"], "attributes": {}}
  }
}

GET /v1/memories

按 user_id / agent_id / run_id 过滤分页列出记忆。Mem0 兼容裸 JSON 数组响应。

说明

分页窗口约束:offset + limit 不得超过 10000,超出返回 400。

请求

请求参数

参数

类型

必填

说明

user_id

string

否

终端用户过滤

agent_id

string

否

Agent 过滤

run_id

string

否

运行实例过滤

doc_type

string

否

按类型过滤(L1 / L0_ENTITY_CARD / L2)

limit

integer

否

返回条数,默认 100,上限 200(与 page_size 互斥)

offset

integer

否

偏移量,默认 0(与 page 互斥)

page

integer

否

页码(从0开始),兼容老调用

page_size

integer

否

每页大小,兼容老调用

start_date

string

否

更新时间下界(ISO-8601)

end_date

string

否

更新时间上界(ISO-8601)

请求示例

curl "http://<host>:4040/v1/memories?user_id=alice&limit=20" \
  -H "X-API-Key: $API_KEY"

GET /v1/memories/{id}

根据 memory_id 获取单条记忆详情。

请求

请求示例

curl "http://<host>:4040/v1/memories/mem_1_2_abc123" -H "X-API-Key: $API_KEY"

PUT /v1/memories/{id}

更新指定记忆的内容或元数据。

请求

请求示例

curl -X PUT http://<host>:4040/v1/memories/mem_1_2_abc123 \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "用户偏好使用 Neovim 编辑器"}'

DELETE /v1/memories/{id}

删除单条记忆。

请求

请求示例

curl -X DELETE http://<host>:4040/v1/memories/mem_1_2_abc123 -H "X-API-Key: $API_KEY"

响应

响应示例

{"message": "memory deleted", "id": "mem_1_2_abc123"}

DELETE /v1/memories/clear

批量清理记忆,按 scope 范围删除。不可逆操作,需 confirm=true。

请求

请求参数

参数

类型

必填

说明

confirm

boolean

是

必须为 true

scope

string

否

all(默认)/ before_date / by_session_ids

before_date

string

条件

scope=before_date 时必填,ISO-8601

session_ids

string[]

条件

scope=by_session_ids 时必填

请求示例

curl -X DELETE http://<host>:4040/v1/memories/clear \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"confirm": true, "scope": "all"}'

响应

响应示例

{"message": "memories cleared", "deleted": 42, "scope": "all"}

POST /v1/memories/search

V1 记忆语义检索,仅 L1-only(不执行 L2 原文 BM25 召回),作为 Mem0 基线路径。

请求

请求参数

参数

类型

必填

说明

query

string

是

查询语句

user_id

string

否

终端用户过滤

agent_id

string

否

Agent 过滤

run_id

string

否

运行实例过滤

filters

object

否

附加 ES filter

limit

integer

否

返回条数 [1, 200],默认 10(兼容 top_k)

vector_only

boolean

否

true 关闭 BM25 词法通道,纯向量 kNN

cosine_threshold

float

否

余弦相关性下限 [0, 1](兼容 threshold);缺省时由服务端注入默认阈值 0.2

exclude_l2

boolean

否

true 排除 L2 占位符

说明

Owner Key 调用 search 端点必须显式传入 user_id,否则返回 400 VALIDATION_FAILED。

请求示例

curl -X POST http://<host>:4040/v1/memories/search \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"query": "用户喜欢什么编辑器?", "user_id": "alice", "limit": 5}'

响应

响应示例

[
  {"id": "mem_1_2_abc123", "memory": "用户偏好使用 Vim 编辑器", "score": 0.92, "metadata": {}},
  {"id": "mem_1_2_def456", "memory": "用户使用 Neovim 插件", "score": 0.85, "metadata": {}}
]

POST /v2/memories/search

V2 记忆检索,L1 + L2 原文 BM25 召回。相比 V1 额外执行 L2 源文本的 BM25 检索,适合需要原文溯源的场景。

请求

请求参数

请求参数与 V1 相同,额外支持:

参数

类型

必填

说明

include_l2

boolean

否

显式控制 L2 开关(未传时服务端默认开启)

请求示例

curl -X POST "$HOST/v2/memories/search"

POST /v3/memories/search

V3 搜索,Mem0 v1.1 SDK 兼容格式。user_id 等实体参数放在 filters map 中。

请求

请求参数

参数

类型

必填

说明

query

string

是

查询语句

filters

object

否

含 user_id / agent_id / run_id等实体键

limit

integer

否

返回条数

vector_only

boolean

否

纯向量模式

include_l2

boolean

否

L2 开关

cosine_threshold

float

否

余弦下限;缺省时由服务端注入默认阈值 0.1

说明

Owner Key 调用 search 端点必须显式传入 user_id,否则返回 400 VALIDATION_FAILED。V3 的 user_id 承载在 filters map 内(filters.user_id,也接受 filters.userId 与顶层 user_id);顶层与 filters 内取值冲突时同样返回 400 VALIDATION_FAILED。

请求示例

curl -X POST http://<host>:4040/v3/memories/search \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"query": "用户的技术栈", "filters": {"user_id": "alice"}, "limit": 10}'

响应

响应示例

{"results": [{"id": "mem_1_2_def456", "memory": "用户技术栈是 Java + Spring Boot", "score": 0.88}]}

POST /v1/memories/{id}/pin

置顶记忆,提升召回优先级。

请求

请求示例

curl -X POST http://<host>:4040/v1/memories/mem_1_2_abc123/pin -H "X-API-Key: $API_KEY"

POST /v1/memories/{id}/unpin

取消置顶。

请求

请求示例

curl -X POST http://<host>:4040/v1/memories/mem_1_2_abc123/unpin -H "X-API-Key: $API_KEY"

POST /v3/memories/{id}/invalidate

标记记忆失效(invalid_at=now()),使其不再被检索召回。

请求

请求示例

curl -X POST http://<host>:4040/v3/memories/mem_1_2_abc123/invalidate -H "X-API-Key: $API_KEY"

响应

响应示例

{"code": 0, "msg": "ok", "data": {"id": "mem_1_2_abc123", "invalid_at": "2026-08-19T10:30:00Z"}}

POST /v3/memories/{id}/promote

将 session 作用域的记忆提升为 user 作用域,使其跨会话保留。

请求

请求示例

curl -X POST http://<host>:4040/v3/memories/mem_1_2_abc123/promote -H "X-API-Key: $API_KEY"

GET /v1/memories/{id}/history

返回指定记忆的所有版本变更记录。Mem0 兼容裸 JSON 数组。

请求

请求示例

curl "http://<host>:4040/v1/memories/mem_1_2_abc123/history" -H "X-API-Key: $API_KEY"

响应

响应示例

[
  {"id": 1, "version": 1, "event_type": "ADD", "content_after": "用户偏好 Vim", "created_at": "2026-08-19T10:00:00Z"},
  {"id": 2, "version": 2, "event_type": "UPDATE", "content_before": "用户偏好 Vim", "content_after": "用户偏好 Neovim", "created_at": "2026-08-19T11:00:00Z"}
]

GET /v1/memories/{id}/source-texts

查看产生该 L1 记忆的 L2 原始对话消息(溯源)。

请求

请求示例

curl "http://<host>:4040/v1/memories/mem_1_2_abc123/source-texts" -H "X-API-Key: $API_KEY"

GET /v1/memories/distill-prompt

查询当前成员的蒸馏规则配置及生效状态。无需 OWNER 权限,每个认证成员可管理自己的蒸馏规则。

请求

请求参数

参数

类型

说明

configured

boolean

是否存在配置行

custom_prompt

string

已配置的自定义蒸馏提示词;未配置为 null

enabled

boolean

配置行业务开关

rollout_enabled

boolean

特性开关是否对本 Workspace 放量

effective

boolean

是否实际生效(configured && enabled && rollout_enabled)

effective_source

string

生效来源:member_level / workspace_default / built_in

updated_at

string

最后更新时间(ISO-8601)

member_id

long

所属 member ID(workspace 默认行为 null)

请求示例

curl "http://<host>:4040/v1/memories/distill-prompt" -H "X-API-Key: $API_KEY"

响应

响应参数

字段

类型

说明

configured

boolean

是否存在配置行

custom_prompt

string

已配置的自定义蒸馏提示词;未配置为 null

enabled

boolean

配置行业务开关

rollout_enabled

boolean

特性开关是否对本 Workspace 放量

effective

boolean

是否实际生效(configured / enabled / rollout_enabled)

effective_source

string

生效来源:member_level / workspace_default / built_in

updated_at

string

最后更新时间(ISO-8601)

member_id

long

所属 member ID(workspace 默认行为 null)

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "configured": true,
    "custom_prompt": "请重点提取用户的技术栈偏好和工作流习惯",
    "enabled": true,
    "rollout_enabled": true,
    "effective": true,
    "effective_source": "member_level",
    "updated_at": "2026-08-19T10:00:00Z",
    "member_id": 2
  }
}

PUT /v1/memories/distill-prompt

创建或更新当前成员的蒸馏规则;返回更新后的完整状态。

请求

请求参数

参数

类型

必填

说明

custom_prompt

string

是

自定义蒸馏提示词,小于等于 8192 字符

enabled

boolean

否

业务开关,缺省 true

请求示例

curl -X PUT http://<host>:4040/v1/memories/distill-prompt \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"custom_prompt": "请重点提取用户的技术栈偏好和工作流习惯", "enabled": true}'

响应

同GET /v1/memories/distill-prompt。

DELETE /v1/memories/distill-prompt

删除当前成员的蒸馏规则(幂等);删除后回退到 workspace 默认或内置 prompt。

请求

请求示例

curl -X DELETE http://<host>:4040/v1/memories/distill-prompt -H "X-API-Key: $API_KEY"

响应

响应示例

{"code": 0, "msg": "ok", "data": null}

POST /v3/memories/{id}/feedback

提交记忆反馈信号(thumbs up/down / 显式/隐式反馈)。负反馈触发 Dream 反证流水线。

请求

请求参数

参数

类型

必填

说明

signal_type

string

是

反馈类型(四种):

  • positive_explicit

  • negative_explicit

  • positive_implicit

  • negative_implicit

channel

string

否

反馈渠道标识

session_id

string

否

关联的会话 ID

recall_path

string

否

召回路径:bm25 / vector / graph(用于 WeightAdaptation)

corrected_content

string

否

用户提供的修正内容

信号类型说明

类型

效果

positive_explicit

用户/Agent 显式点赞。hotness +0.2

negative_explicit

用户/Agent 显式踩踏。hotness -0.2 + 触发 Dream 反证流水线

positive_implicit

隐式正向信号(复用、停留)。hotness +0.1

negative_implicit

隐式负向信号(跳过、拒绝)。hotness -0.1

请求示例

curl -X POST http://<host>:4040/v3/memories/mem_1_2_abc123/feedback \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"signal_type": "negative_explicit", "recall_path": "vector", "corrected_content": "用户已从 Vim 切换到 Neovim"}'

GET /v3/memories/{id}/feedback

分页查询指定记忆的反馈历史。

请求

page(从0开始,默认 0)、size(默认 20,上限 100)。

请求示例

curl -X GET "$HOST/v3/memories/{id}/feedback"

GET /v1/memories/stats

返回记忆聚合统计(总数/事实/实体/源文本)。Box 包装响应。

请求

请求参数

Query 参数:user_id、agent_id、run_id(均可选)。

请求示例

curl "http://<host>:4040/v1/memories/stats?user_id=alice" -H "X-API-Key: $API_KEY"

响应

响应示例

{"code": 0, "msg": "ok", "data": {"total": 156, "facts": 120, "entities": 12, "sources": 24}}

GET /v1/memories/relations

查询指定实体的记忆关系图谱(节点 + 边),用于可视化记忆之间的关联关系。返回以 entity_id 为中心、指定深度内的关系网络。

请求

请求参数

参数

类型

必填

说明

entity_id

string

是

起始实体 ID

depth

integer

否

遍历深度,默认 1

include_all_members

boolean

否

是否包含 workspace 全部成员的关系(默认 false,仅 Owner Key可开启;User Key 传 true 返回 403)

请求示例

curl "http://<host>:4040/v1/memories/relations?entity_id=alice&depth=2" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "nodes": [
      {"id": "alice", "label": "alice"},
      {"id": "rust-project", "label": "rust-project"}
    ],
    "edges": [
      {"from": "alice", "to": "rust-project", "label": "works_on"}
    ]
  }
}

GET /v1/memory_promotions

分页列出当前成员的记忆晋升记录(含手动发起和定时产生的晋升)。

请求

请求参数

参数

类型

必填

说明

page

integer

否

页码(从0开始),默认 0

pageSize

integer

否

每页大小,默认 20

status

string

否

按状态过滤:generating / pending_review / approved / rejected

memberId

long

否

按成员过滤(Owner Key可用;User Key 自动限定为自己)

请求示例

curl "http://<host>:4040/v1/memory_promotions?page=0&pageSize=10" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "content": [
      {
        "id": 1,
        "topic": "总结本周架构决策",
        "title": null,
        "status": "generating",
        "source_type": "scheduled",
        "target_member_id": 4,
        "memory_count": 0,
        "verification_degraded": false,
        "created_at": "2026-09-16T01:03:20Z",
        "updated_at": "2026-09-16T01:03:20Z"
      }
    ],
    "total_elements": 1,
    "total_pages": 1
  }
}
  • status 说明:generating(生成中)、pending_review(待审批)、approved(已通过)、rejected(已驳回)。

  • source_type 说明:manual(手动发起)、scheduled(定时任务触发)。

POST /v1/memory_promotions/generate

手动发起一次记忆晋升生成,将当前成员的记忆根据 topic 提炼为知识文档候选。

请求

请求参数

参数

类型

必填

说明

topic

string

是

晋升主题 / 提示词

target_kb_id

long

否

自动审批的目标知识库 ID

请求示例

curl -X POST "http://<host>:4040/v1/memory_promotions/generate" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"topic": "总结本周架构决策", "target_kb_id": 3}'

GET /v1/memory_promotions/{promotionId}

获取指定晋升记录详情。

请求

请求示例

curl "http://<host>:4040/v1/memory_promotions/1" -H "X-API-Key: $API_KEY"

附录:V1/V2/V3 搜索版本差异

版本

路径

L2 原文召回

响应格式

适用场景

V1

/v1/memories/search

关闭(L1-only)

裸数组

Mem0 基线兼容

V2

/v2/memories/search

默认开启

裸数组

推荐,支持原文溯源

V3

/v3/memories/search

默认开启

{"results": [...]}

Mem0 v1.1 SDK 兼容

知识库(Knowledge)

知识库权限(ACL)

四个端点全部要求该知识库的 owner 权限:Owner Key 全局放行;知识库创建者与被授予 owner 角色的成员是委派管理员;其他成员 403(40303),kbId 跨 workspace 或不存在 404。

方法

路径

说明

POST

/v1/knowledge/bases/{kbId}/acl

授予一条显式权限行(同一主体重复授予 409,不是改写)

GET

/v1/knowledge/bases/{kbId}/acl

列出该库全部显式权限行(含已过期行)

GET

/v1/knowledge/bases/{kbId}/acl/candidates

授权候选人:本 workspace 成员 + 各自已有的显式行角色

DELETE

/v1/knowledge/bases/{kbId}/acl/{aclId}

撤销一条权限行

三条必须先理解的语义:

  • 显式行是终局裁决,不是下限。写一条 viewer 到公开库上,该成员就从默认的 editor 降为只读,而不是“至少 viewer”。

  • denied 是动作而不是一档权限。它用于在公开库上彻底关掉某个成员的默认档;它不出现在 my_role 里(无权访问时 my_role 为 null、role_source 为 denied)。

  • 到期是硬失效。过期行等同于没有这一行 → 回落到库默认档(公开库 editor / 私有库无权限)。过期行仍在 GET .../acl 结果中列出,便于清理;判断是否已失效请比较 expires_at 与当前时间。

POST /v1/knowledge/bases/{kbId}/acl

请求

请求参数

参数

类型

必填

说明

subject_type

string

是

固定 member(不支持 workspace / role 等其他主体;传别的值返回 400 VALIDATION_FAILED)

subject_id

string

是

授权主体 ID,即 members.id 的十进制字符串(从 .../acl/candidates 的 member_id 取)。写 "m_42" 之类非数字值返回 400 —— 鉴权侧按数字比对,这类行永不生效

role

string

是

viewer / editor / owner / denied;其他值 400

expires_at

string

否

到期时间(ISO-8601)。null = 长期有效

granted_by

string

否

授权人标识;缺省取调用方 member_id 的十进制字符串

  • 请求体里的 kb_id 会被忽略,一律以 path 上的 kbId 为准。

  • (kb_id, subject_type, subject_id) 唯一:同一主体重复 POST 返回 409(40901,msg 为 ACL already exists for (kb_id, subject_type, subject_id)),不是改写。改角色请先 DELETE .../acl/{aclId} 再 POST。

  • 参数校验失败统一 400 40001(VALIDATION_FAILED)。

请求示例

# 给 member 42 授予编辑权,7 天后到期
curl -X POST http://<host>:4040/v1/knowledge/bases/1/acl \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"subject_type": "member", "subject_id": "42", "role": "editor", "expires_at": "2026-09-23T00:00:00Z"}'

# 把公开库上的 member 43 降为只读(显式行终局裁决,不是"至少 viewer")
curl -X POST http://<host>:4040/v1/knowledge/bases/1/acl \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"subject_type": "member", "subject_id": "43", "role": "viewer"}'

# 彻底关掉公开库上 member 44 的默认档
curl -X POST http://<host>:4040/v1/knowledge/bases/1/acl \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"subject_type": "member", "subject_id": "44", "role": "denied"}'

响应

响应参数

字段

类型

说明

id

long

授权行 ID,撤销时用(DELETE .../acl/{aclId})

kb_id / workspace_id

long

所属知识库 / workspace

subject_type

string

固定 member

subject_id

string

members.id 的十进制字符串

role

string

viewer / editor / owner / denied

granted_by

string

授权人标识

granted_at

string

授权时间(ISO-8601)

expires_at

string

到期时间;null = 长期有效。硬失效语义见上

subject_name

string

主体成员名(只读展示字段;member 已被删除时为 null)

subject_user_id

string

主体成员的外部 user_id(只读展示字段;member 已被删除时为 null)

说明

subject_name / subject_user_id 是本次追加的只读展示字段,老字段的类型与语义未变。member 被删除后授权行仍在(此时两者为 null),需要显式 DELETE 清理。

响应示例

GET 返回同结构的数组:

{"code": 0, "msg": "ok", "data": {"id": 7, "kb_id": 1, "workspace_id": 1, "subject_type": "member", "subject_id": "42", "role": "editor", "granted_by": "2", "granted_at": "2026-09-16T10:00:00Z", "expires_at": "2026-09-23T00:00:00Z", "subject_name": "alice", "subject_user_id": "u-alice"}}

GET /v1/knowledge/bases/{kbId}/acl/candidates

请求

请求示例

curl "http://<host>:4040/v1/knowledge/bases/1/acl/candidates" -H "X-API-Key: $API_KEY"

响应

响应参数

字段

类型

说明

member_id

long

成员 ID,即写 ACL 时提交的 subject_id

user_id

string

成员的外部 user_id

name

string

成员名

current_role

string

该成员在本知识库上已有显式行的角色;null 表示没有生效的显式行 —— 此时他吃库默认档(公开库 editor / 私有库无权限),不代表无权限

说明

2026-09-16 修复:current_role 此前把已过期的行(expires_at <= now)也算作当前角色,与鉴权侧「过期行等同于没有这一行」的硬失效语义相反 —— 同一个成员在知识库详情里是 role_source: kb_default,在这里却还挂着上个月就到期的 denied。现在过期行不再出现在 current_role 里(字段类型与取值范围未变,仅口径与鉴权对齐)。要看到并清理过期行请用 GET /v1/knowledge/bases/{kbId}/acl,它按设计含过期行。

响应示例

{"code": 0, "msg": "ok", "data": [
  {"member_id": 42, "user_id": "u-alice", "name": "alice", "current_role": "editor"},
  {"member_id": 43, "user_id": "u-bob", "name": "bob", "current_role": null}
]}

DELETE /v1/knowledge/bases/{kbId}/acl/{aclId}

请求

请求示例

curl -X DELETE http://<host>:4040/v1/knowledge/bases/1/acl/7 -H "X-API-Key: $API_KEY"

撤销后该成员回落到库默认档(公开库 editor / 私有库无权限)—— 撤销 denied 行会把公开库的默认可写权限还给他。返回 Box<Void>(data 为 null)。

说明

aclId 必须属于 URL 里的 kbId,否则 404(与“该行不存在”同码,不泄漏“这个 id 存在但属于别的库”)。2026-09-17 修复:此前只按 (aclId, workspaceId) 定位行,而鉴权看的是 kbId —— 于是任何在某一个库上是 owner 的成员(哪怕只是自己刚建的库)都能拿那个 kbId 当门票,删掉同 workspace 内任意其它库的授权行,包括别人的 owner 行和正锁着自己的 denied 行。这是收紧:以前能成功的跨库删除现在返回 404,配对正确的 kbId 行为不变。

POST /v1/knowledge/bases

创建一个新知识库。visibility 不传时按 Key 类型取默认值:User Key → private,Owner Key → workspace;显式传入则以传入值为准(User Key 也可以建公开库)。

请求

请求参数

参数

类型

必填

说明

name

string

是

知识库名称

description

string

否

描述

visibility

string

否

workspace(公开库,workspace 成员默认 editor,可读可写)/ private(私有库,仅创建者与被显式授权者可访问)。public 是 workspace 的请求侧别名,不是第三档 —— 存储与响应一律归一为 workspace。缺省值见上

graph_enabled

boolean

否

是否启用知识图谱

wiki_enabled

boolean

否

是否开启 Wiki 蒸馏,默认 false

tuning

object

否

可选初始化 tuning 参数

tuning.top_k

integer

否

检索 top_k

tuning.rerank_enabled

boolean

否

是否启用重排序

tuning.hybrid_weight

double

否

BM25 vs 向量权重

tuning.chunk_size

integer

否

分块大小

tuning.chunk_overlap

integer

否

分块重叠

请求示例

curl -X POST http://<host>:4040/v1/knowledge/bases \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "项目文档库", "description": "存放项目技术文档"}'

响应

响应示例

{"code": 0, "msg": "ok", "data": {"id": 1, "name": "项目文档库", "description": "存放项目技术文档", "visibility": "workspace", "wiki_enabled": false, "created_at": "2026-08-19T10:00:00Z", "my_role": "owner", "role_source": "owner_member", "can_manage_acl": true}}

GET /v1/knowledge/bases

分页模式下每一行都带 my_role / role_source / can_manage_acl(字段含义见下方知识库详情的字段表),调用方可直接据此渲染“上传/删除/权限管理”入口的可用状态。compact=true 的精简 catalog 只含 name / description / doc_count / updated_at(同样只列有权访问的库),不带角色字段。

说明
  • 分页列出当前调用方有访问权的知识库(无权访问的库不出现在结果里,而不是出现后调用报 403)。支持 compact=true 精简 catalog + ETag 增量同步。

  • 判定“有访问权”的口径与鉴权侧完全一致:本人创建的库 ∪ 有未过期且非 denied 显式行的库 ∪ 公开库中自己没有任何显式行的(有显式行时以显式行为准,见下方知识库权限(ACL))。

请求

请求参数

参数

类型

必填

说明

page

integer

否

页码(从0开始),默认 0

page_size

integer

否

每页大小,默认 20,[1, 100]

compact

boolean

否

true 时返回精简 catalog(不分页),支持 ETag

请求示例

curl "http://<host>:4040/v1/knowledge/bases?page_size=10" -H "X-API-Key: $API_KEY"

GET /v1/knowledge/bases/{id}

获取指定知识库详情。需 viewer 及以上权限;权限不足返回 403(40303),kbId 跨 workspace 或不存在返回 404。

请求

请求示例

curl "http://<host>:4040/v1/knowledge/bases/1" -H "X-API-Key: $API_KEY"

响应

响应参数

字段

类型

说明

id

long

知识库 ID

workspace_id

long

所属 workspace ID

name

string

知识库名称

description

string

描述

visibility

string

workspace(公开库)/ private(私有库)。请求侧可用 public 作为 workspace 的别名,响应统一为 workspace

owner_member_id

long

创建者 member_id

doc_count

int

文档总数(缓存值,由摄入路径维护)

graph_enabled

boolean

是否启用知识图谱

wiki_enabled

boolean

是否开启 Wiki 蒸馏,默认 false

created_at / updated_at

string

创建 / 更新时间(ISO-8601)

my_role

string

调用方在该库上的生效角色:owner / editor / viewer;null 表示无访问权(此时该库不会出现在列表里)

role_source

string

生效角色的来源:owner_key(Owner Key 全局放行)/ owner_member(本人创建)/ acl(显式授权行,终局裁决)/ kb_default(公开库默认档)/ denied(被显式禁止)

can_manage_acl

boolean

是否可管理该库的 ACL(等价于 my_role == "owner")。控制台据此决定权限入口可见性,不必靠试探 403

角色能力对照:

角色

可以做

viewer

搜索、读文档、读 Wiki、读图谱节点/边

editor

viewer + 上传/删除文档、重建索引、作为记忆晋升(promotion)的目标库

owner

editor + 质量评审决策、改知识库设置与调优、删库、管理 ACL

响应示例

{"code": 0, "msg": "ok", "data": {"id": 1, "workspace_id": 1, "name": "项目文档库", "description": "存放项目技术文档", "visibility": "workspace", "owner_member_id": 2, "doc_count": 42, "graph_enabled": false, "wiki_enabled": false, "created_at": "2026-08-19T10:00:00Z", "updated_at": "2026-08-19T10:00:00Z", "my_role": "editor", "role_source": "kb_default", "can_manage_acl": false}}

DELETE /v1/knowledge/bases/{id}

删除知识库。需该知识库的 owner 权限,判定与 my_role 完全同源:Owner Key 全局放行、知识库创建者恒为 owner、被显式授予 owner 的成员同样可删。权限不足 403(40303),跨 workspace 或不存在 404(重复删除第二次即 404)。

说明

2026-09-16 起,User Key 删库不再只认“创建者”。此前这里走的是独立的 ownerMemberId 判定,导致被授予 owner 的成员拿到 my_role=owner 却删不掉库;现已统一到 ACL 判定链。这是一处权限放宽,只影响被显式授予 owner 的成员。

请求

请求示例

curl -X DELETE http://<host>:4040/v1/knowledge/bases/1 -H "X-API-Key: $API_KEY"

POST /v1/knowledge/bases/{kbId}/documents/upload

上传文档到指定知识库。支持多模态(文本/PDF/图片/音频)。相同内容幂等。需 editor 及以上权限(公开库的成员默认就是 editor);权限不足 403(40303),kbId 跨 workspace 或不存在 404。

请求

Form参数(multipart/form-data)

参数

类型

必填

说明

file

file

是

上传的文件

title

string

否

文档标题

external_id

string

否

外部唯一标识(幂等 key)

source_url

string

否

来源 URL

file_path

string

否

同步来源路径

source_updated_at

string

否

源文件更新时间(ISO-8601)

folder_path

string

否

批量上传的文件夹路径

images

file[]

否

Markdown 的 sidecar 图片附件

metadata

string

否

JSON 格式用户元数据

请求示例

curl -X POST http://<host>:4040/v1/knowledge/bases/1/documents/upload \
  -H "X-API-Key: $API_KEY" \
  -F "file=@./docs/architecture.md" \
  -F "title=架构设计文档"

POST /v1/knowledge/documents

通过 URL 或文本内容创建文档(flat API,body 中指定 knowledge_base_id)。需目标库的 editor 及以上权限;权限不足 403(40303),知识库跨 workspace 或不存在 404。

请求

请求参数

参数

类型

必填

说明

knowledge_base_id

long

是

目标知识库 ID

title

string

否

文档标题

content

string

条件

文本内容(与 source_url 二选一)

source_url

string

条件

来源 URL

external_id

string

否

外部唯一标识

请求示例

curl -X POST http://<host>:4040/v1/knowledge/documents \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"knowledge_base_id": 1, "title": "API 设计规范", "content": "RESTful API 应该..."}'

GET /v1/knowledge/bases/{kbId}/documents

分页列出指定知识库下的文档。需 viewer 及以上权限;权限不足 403(40303),kbId 跨 workspace 或不存在 404。

请求

请求参数

Query 参数:page(默认 0)、size(默认 20,上限 100)、q(可选,最长 200 字符,标题或 external_id 的字面子串,非 SQL 通配符)、ingest_status(可选:pending / processing / indexed / done / failed)。过滤、分页和总数均由服务端计算,不限于浏览器已加载的前 100 条。原有响应字段和无过滤请求保持兼容。扁平文档列表入口也支持相同过滤。

请求示例

curl "http://<host>:4040/v1/knowledge/bases/1/documents?size=10" -H "X-API-Key: $API_KEY"

POST /v1/knowledge/documents/reindex

把一篇已有文档按正常 knowledge.ingest 流程重新入队,用于 embedding fingerprint / 模型、chunking 或索引配置发布后的存量重建。需 editor 及以上权限。

安全与并发契约:

  • workspace/member 只从 X-API-Key 推导,请求体不提供 workspace_id。

  • knowledge_base_id 必须属于当前 workspace,且 document_id 必须属于该 KB;跨 workspace 返回 404,ACL 不足返回 403。

  • expected_ingest_revision 必须使用文档列表刚读取的值。成功后 revision 加一并返回新的 event_id;旧 revision 重放返回 409,避免重复重建。

  • 每次只重建一个文档。文档状态更新与 outbox 入队在一个短事务内完成,embedding / OSS / OpenSearch 在事务提交后异步执行。

请求

请求参数

参数

类型

必填

说明

knowledge_base_id

long

是

目标知识库 ID

document_id

long

是

目标文档 ID

expected_ingest_revision

long

是

列表/详情中读到的当前 revision,必须 ≥ 0

请求示例

curl -X POST http://<host>:4040/v1/knowledge/documents/reindex \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"knowledge_base_id":1,"document_id":42,"expected_ingest_revision":3}'

响应

响应说明

成功响应的 data.ingest_status 为 pending、data.ingest_revision 为 4,data.event_id 可用于事件追踪。全知识库/ 全 workspace 的分页重建请使用 scripts/reindex-knowledge.sh,发布步骤见 docs/operations/runbooks/embedding-dimension-change.md。

GET /v1/knowledge/documents/{id}

获取文档详情。需该文档所属库的 viewer 及以上权限;权限不足 403(40303),文档跨 workspace 或不存在 404。

请求

请求示例

curl "http://<host>:4040/v1/knowledge/documents/42" -H "X-API-Key: $API_KEY"

DELETE /v1/knowledge/documents/{id}

删除文档,需该文档所属库的 editor 及以上权限(不要求是上传者本人 —— 公开库里任意成员默认可删他人上传的文档,见概览「2026-09-16 知识库权限重构」行为变化 1)。权限不足 403(40303),文档跨 workspace 或不存在 404。

请求

请求示例

curl -X DELETE http://<host>:4040/v1/knowledge/documents/42 -H "X-API-Key: $API_KEY"

POST /v1/knowledge/search

在租户可访问的知识库上进行混合检索(BM25 + 向量 + RRF 融合)。

请求

请求参数

参数

类型

必填

说明

query

string

是

查询语句,小于等于4096 字符

kb_ids

long[]

条件

User Key 必须指定;Owner Key 可省略(全 ws 搜索)。去重后上限 100

top_k

integer

否

返回条数 [1, 100],默认 5

filters

object

否

白名单 filter(type/block_type/tags/source_url/modality)

rrf_k

integer

否

RRF 融合常数 K,取值范围:[1, 1000]

recall_multiplier

integer

否

召回扩展倍数,取值范围:[1, 20]

hybrid_weight

double

否

BM25 vs 向量权重,取值范围:[0.0, 1.0]

rewrite

boolean

否

是否启用 LLM 查询改写

type

string

否

文档类型过滤

tags

string[]

否

标签过滤

block_type

string

否

块类型过滤(text/title/list/table/code/image/formula)

metadata_condition

object

否

结构化元数据条件

decompose

boolean

否

是否启用多跳查询分解;缺省由部署开关 context.knowledge.multi-hop.enabled 决定,生产环境默认 false

cross_languages

string[]

否

查询改写生成的跨语言变体(BCP-47 风格语言标签),最多 5 个;原查询始终保留

请求示例

curl -X POST http://<host>:4040/v1/knowledge/search \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"query": "如何配置 OpenSearch?", "kb_ids": [1, 2], "top_k": 5}'

响应

响应参数

字段

类型

说明

chunk_id

string

文本块 ID

document_id

string

文档 ID

knowledge_base_id

string

知识库 ID

title

string

文档标题

snippet

string

内容片段(前 ~4096 字符预览)

score

double

RRF 融合分数(非归一化)

position

int

结果排序位置(从0开始)

rerank_score

double

重排序分数(启用 rerank 时有值)

modality

string

模态类型(text/image/audio,多模态时有值)

block_type

string

块类型(text/title/list/table/code/image/formula,多模态时有值)

section_path

string

章节路径(多模态时有值)

page_number

integer

页码(PDF 文档有值)

oss_url

string

Context0 短时签名下载 URL(有效期由业务配置决定)

graph_hit

boolean

是否由知识图谱召回

graph_path

string

图谱实体链路径

说明
  • 空值(null)字段不输出。未知请求字段会被严格拒绝(防止 kb_id 单数 typo 被静默忽略导致全 ws 搜索)。

  • ACL 语义:kb_ids 是逐个校验 viewer 权限的 —— 列表里只要有一个库无权访问,整个请求返回 403(40303),不会“跳过无权的库、返回其余结果”。请先用 GET /v1/knowledge/bases 拿到可访问列表(该接口只返回有权访问的库)再检索。Owner Key 省略 kb_ids 时搜全 workspace;User Key 省略 kb_ids 直接 403(不再回退到“搜全 workspace”)。

响应示例

{
  "code": 0, "msg": "ok",
  "data": [
    {
      "chunk_id": "chunk_001",
      "document_id": "42",
      "knowledge_base_id": "1",
      "title": "OpenSearch 配置指南",
      "snippet": "OpenSearch 需要配置 cluster.name、node.name...",
      "score": 0.91,
      "position": 0,
      "rerank_score": 0.95,
      "modality": "text",
      "block_type": "text"
    }
  ]
}

GET /v1/knowledge/bases/{kbId}/tuning

读取指定知识库的检索调优参数(需 viewer 及以上权限)。任一字段为 null 表示“使用全局默认”(top_k=5 / rerank=true / hybrid_weight=0.7 / graph_weight=0.3 / chunk_size=800 / chunk_overlap=100)。

请求

请求示例

curl "http://<host>:4040/v1/knowledge/bases/1/tuning" -H "X-API-Key: $API_KEY"

响应

响应参数

字段

类型

说明

top_k

integer

检索返回条数

rerank_enabled

boolean

是否启用重排序

hybrid_weight

double

BM25 vs 向量权重 [0.0, 1.0]

chunk_size

integer

分块大小

chunk_overlap

integer

分块重叠

rrf_k

integer

RRF 融合常数 K

recall_multiplier

integer

召回扩展倍数

query_rewrite_enabled

boolean

是否启用 LLM 查询改写

enable_contextual_retrieval

boolean

是否启用上下文增强检索

graph_weight

double

知识图谱召回权重(GraphRAG)

graph_skip_extensions

string[]

图抽取跳过扩展名;null 继承全局,空数组关闭该知识库过滤,非空数组完全替换全局值

enable_parent_child

boolean

父子分块与命中后父上下文补全;null 继承全局配置(默认 false)

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "top_k": 8,
    "rerank_enabled": true,
    "hybrid_weight": 0.5,
    "chunk_size": 800,
    "chunk_overlap": 100,
    "rrf_k": 60,
    "recall_multiplier": 3,
    "query_rewrite_enabled": false,
    "enable_contextual_retrieval": false,
    "graph_weight": null,
    "graph_skip_extensions": null,
    "enable_parent_child": null
  }
}

PUT /v1/knowledge/bases/{kbId}/tuning

局部更新知识库调优参数(patch 语义,仅覆写传入的键),需 editor 及以上权限。请求体为调优字段的任意子集,字段名与GET /v1/knowledge/bases/{kbId}/tuning响应一致。

请求

请求示例

curl -X PUT http://<host>:4040/v1/knowledge/bases/1/tuning \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"top_k": 8, "rerank_enabled": true}'

响应

响应说明

同 GET 响应结构(返回合并后的完整 tuning)。

PUT /v1/knowledge/bases/{kbId}/settings

更新知识库设置——质量评审开关、知识图谱开关与可见性,三个字段至少传一项(需该知识库的 owner 权限)。

请求

请求参数

参数

类型

必填

说明

review_enabled

boolean

条件

是否开启质量评审。开启需部署级 worker 与 workspace Feature Flag 均已打开,否则返回 40304 feature-disabled。

graph_enabled

boolean

条件

是否开启知识图谱构建(GraphRAG),无额外门控

visibility

string

条件

workspace(别名 public)/ private。这是一个权限操作:改成 workspace 后,workspace 内所有没有显式 ACL 行的成员立即获得 editor(可读可写);改成 private 后他们立即失去访问权,只留创建者与显式授权行

说明

review_enabled / graph_enabled / visibility 至少传一项。改 visibility 不会动任何显式 ACL 行 —— 显式行是终局裁决,切换可见性只改变“没有显式行的人”落到哪个默认档。

请求示例

curl -X PUT http://<host>:4040/v1/knowledge/bases/1/settings \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"review_enabled": true, "graph_enabled": false, "visibility": "private"}'

响应

响应示例

{"code": 0, "msg": "ok", "data": {"kb_id": 1, "review_enabled": true, "graph_enabled": false, "visibility": "private"}}

GET /v1/knowledge/bases/{kbId}/index-stats

查看该库的索引统计——文档数、分块数、索引体积、摄入队列深度与最后一次摄入时间。需 viewer 及以上权限;权限不足 403(40303),kbId 跨 workspace 或不存在 404。

请求

请求示例

curl "http://<host>:4040/v1/knowledge/bases/1/index-stats" -H "X-API-Key: $API_KEY"

响应

响应示例

{"code": 0, "msg": "ok", "data": {"kb_id": 1, "kb_name": "项目文档库", "doc_count": 42, "chunks_count": 1380, "index_size_bytes": 10485760, "ingest_queue_depth": 0, "last_ingest_at": "2026-09-16T09:31:00Z"}}
说明

这些计数会泄漏库内容的规模特征,因此与“读知识库内容”同档。2026-09-16 起新增 viewer 门槛:此前只有 workspace 围栏,同 workspace 的任意 User Key 都能读到私有库的文档数/分块数/索引体积/最后摄入时间。

GET /v1/knowledge-bases/{kbId}/graph/nodes

分页查看该库的图谱实体节点(pagerank 降序)。需 viewer 及以上权限。

说明

路径注意:图谱数据面挂在 /v1/knowledge-bases/...(连字符),与本章其余 /v1/knowledge/bases/... 的写法不同。

请求

请求参数

Query 参数:page(默认 0)、size(默认 50,上限 1000,超限静默夹到上限)。

请求示例

curl "http://<host>:4040/v1/knowledge-bases/1/graph/nodes?page=0&size=50" -H "X-API-Key: $API_KEY"

响应

响应示例

{"code": 0, "msg": "ok", "data": {"page": 0, "size": 50, "nodes": [{"id": "…", "label": "PolarDB-X", "type": "product", "pagerank": 0.42}]}}

GET /v1/knowledge-bases/{kbId}/graph/edges

查看某个实体的 1 跳邻接子图(nodes + edges)。需 viewer 及以上权限。depth 参数目前仅支持 1 跳,保留做 API 兼容。

请求

请求示例

curl "http://<host>:4040/v1/knowledge-bases/1/graph/edges?node=PolarDB-X&depth=1" -H "X-API-Key: $API_KEY"

响应

响应示例

{"code": 0, "msg": "ok", "data": {"nodes": [{"id": "…", "label": "PolarDB-X", "type": "product", "pagerank": 0.42}], "edges": [{"from": "PolarDB-X", "to": "CN", "predicate": "part_of", "weight": 0.8}]}}
说明
  • 权限与行为变化:图谱实体/关系是从 chunk 抽出来的内容摘要,因此这两个端点与“读知识库内容”同档 —— 需 viewer 及以上,权限不足 403(40303)。2026-09-16 起,kbId 跨 workspace 或不存在时返回 404(此前为 403),以免自增 kbId 被枚举探测出存在性。

  • 图谱新增下述知识库数据面管理接口;原管理面 /ops/knowledge-bases/{kbId}/graph 仍要求 Owner Key + OPS 端口 8080。知识库owner 的 User Key 不因此获得全局 OPS 权限。

Graph 数据面清空与补建

方法 / 路径

权限与返回

DELETE /v1/knowledge-bases/{kbId}/graph

当前知识库owner(管理权限);data={"deleted":true}

POST /v1/knowledge-bases/{kbId}/graph/backfill

当前知识库owner(管理权限);data={"enqueued":3},实际计数可以为 0

无需请求体,均返回 Box;路径使用 knowledge-bases 连字符。User Key 具有该知识库owner 权限即可调用,viewer / editor 不可执行。资源按 workspace/KB 校验,复用原图谱 guard / barrier;补建计数表示已入队数量,不是同步构建完成,不绕过既有审核。

Graph 冲突检测与人工评审(2026-09-16新增)

多文档合并(consolidate)时的两类静默裁决信号——同实体跨文档类型分歧(type_conflict)与同别名被多实体声明(alias_conflict)——可按需扫描入队,由 editor+ 人工裁决。检测是同步只读扫描(零 LLM、不写图谱);type / alias 裁决与图谱更新事件在同一事务提交,后台合并后生效。功能由 context.knowledge.graph.conflict-detection.enabled(默认 true)门控,关闭时端点返回 404。

方法 / 路径

权限

说明

POST /v1/knowledge-bases/{kbId}/graph/conflicts/detect

editor+

同步扫描存活子图:新冲突入队、已存在冲突刷新 detected_at、本轮未复现的 open 行转 stale;幂等,重复点击无害

GET /v1/knowledge-bases/{kbId}/graph/conflicts?status=&page=&size=

viewer+

评审队列分页;status 缺省返回全状态(open/resolved/dismissed/stale)

GET /v1/knowledge-bases/{kbId}/graph/conflicts/{conflictId}

viewer+

单条详情(payload 已解析为候选值 + 来源文档/chunk 证据链,与列表项同构)

POST /v1/knowledge-bases/{kbId}/graph/conflicts/{conflictId}/decision

editor+

人工裁决;仅 open 状态可裁决

示例:

# 触发检测(editor+)
curl -X POST "http://<host>:4040/v1/knowledge-bases/1/graph/conflicts/detect" -H "X-API-Key: $API_KEY"
{"code": 0, "msg": "ok", "data": {"scanned_documents": 12, "conflicts": 3, "opened": 2, "refreshed": 1, "staled": 0}}
# type 冲突裁决:选定正确类型(chosen_type 必须在候选集内,否则 400)
curl -X POST "http://<host>:4040/v1/knowledge-bases/1/graph/conflicts/11/decision" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"action":"resolve","chosen_type":"project"}'

# alias 冲突裁决:选定别名归属 / 忽略不再提醒
curl -X POST "http://<host>:4040/v1/knowledge-bases/1/graph/conflicts/12/decision" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"action":"resolve","chosen_owner":"阿里云"}'
curl -X POST "http://<host>:4040/v1/knowledge-bases/1/graph/conflicts/12/decision" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" -d '{"action":"dismiss"}'
  • 裁决语义:resolved 表示裁决和更新事件已提交,不表示图谱已完成更新。type / alias 均由 graph-consolidate worker 异步更新;失败按既有事件策略重试,事件入队失败则裁决一起回滚。人工别名裁决优先于旧映射;类型裁决在别名归并后应用到最终实体,后续合并继续重放。dismiss 后同指纹(payload_hash)冲突不再重开;信号消失的 open 行转 stale,复现时复活为 open;已 resolved/dismissed 的冲突不因重复检测重开。冲突列表对 viewer 只读知情,检测与裁决是写权限操作(403)。删除知识库或工作空间时同步清理冲突记录。

  • 实体自动确认保留 context.knowledge.graph.consolidate.auto-confirm.containment-enabled 配置名,但仅允许既有归一规则下名称相同的候选直接确认;单纯子串包含(如 PolarDB / PolarDB-X)仍须经过消歧。Jaccard 自动确认仍需显式开启,默认关闭。

Graph 管理面路由收敛(2026-09-16更新)

管理面(OPS 端口 8080、Owner Key)图谱路由改用 query param 传 kb_id,与 /ops/knowledge/wiki/** 同形。旧的路径参数版本仍然可用,进入 deprecation 周期后再摘除。

新路径(推荐)

旧路径(deprecated,行为不变)

GET /ops/knowledge/graph/nodes?kb_id=&page=&size=

GET /ops/knowledge-bases/{kbId}/graph/nodes

GET /ops/knowledge/graph/edges?kb_id=&node=&depth=

GET /ops/knowledge-bases/{kbId}/graph/edges

DELETE /ops/knowledge/graph/delete?kb_id=

DELETE /ops/knowledge-bases/{kbId}/graph

POST /ops/knowledge/graph/backfill?kb_id=

POST /ops/knowledge-bases/{kbId}/graph/backfill

两组路由共用同一实现,请求/响应 JSON、鉴权(Owner Key)与 workspace fence(跨 workspace 403)逐字相同;size 上限仍为 1000。改动原因是后端红线「/ops/** 路由禁止 @PathVariable,标识符走 query param 或 body」。

同一批收敛还包括晋升删除接口:新增 DELETE /ops/promotion/delete?promotionId=,旧的 DELETE /ops/promotion/{promotionId} 同样在 deprecation 周期内保持可用。

说明
  • Wiki 数据面门控:Search-Read-Expand controller 的搜索、按 ID / slug 阅读、目录读取、原文追溯及 issues 方法仅在服务端 context.wiki.enabled=true(环境变量 WIKI_ENABLED,默认 true,显式 false 仍有效)时注册;关闭时对应方法不可用(404,或同路径有其他 HTTP 方法时为 405)。这不等于整个 /v1/knowledge/wiki 前缀关闭:页面列表 / 更新、单页重新生成、死信 / 日志和 config / backfill 数据面管理接口不受此读侧开关门控;生成仍受 worker 与知识库配置限制。原 OPS 权限与蒸馏管线门控保持不变。

  • ACL:User Key 必须显式列出知识库 ID(search 请求体字段为 knowledge_base_ids,read 类端点为查询参数 kb_id;误写为 kb_ids 等其他字段名会因未识别而按未授权处理返回 403),否则返回 403(workspace 级 Wiki 检索为 Owner Key 专属);请求中的 kb_id 列表去重后不得超过 100 个(超限 400),并逐知识库校验读权限。GET /v1/knowledge/wiki/read 结果默认走服务端读缓存(context.wiki.read-cache.*,默认开启、TTL 300s,缓存 key 含 workspaceId 隔离)。

GET /v1/knowledge/wiki/config?kb_id=<id>

查看单个知识库的生成开关与部署能力,需要知识库读权限,返回 Box<SettingsDto>:

响应

响应示例

{"code":0,"msg":"ok","data":{"kb_id":1,"wiki_enabled":false,"build_available":true,"search_available":true,"wiki_config":{"wiki_language":"Chinese","extraction_granularity":"standard","content_instructions":""}}}

build_available 表示 distill/finalize worker 已启用,search_available 表示读侧服务开关;均不代表已有页面。

PUT /v1/knowledge/wiki/config?kb_id=<id>

设置单个知识库的持续生成开关与生成配置,需要知识库owner(管理权限),User Key 有相应角色即可。wiki_enabled 与 wiki_config 至少提供一个;旧的仅开关请求保持有效。DATA 的 wiki_config 是 JSON 对象:

请求

请求示例

{"wiki_enabled":true,"wiki_config":{"wiki_language":"Chinese","extraction_granularity":"focused","content_instructions":"侧重架构决策"}}

响应

响应说明

返回上述设置结构。开启时要求生成 worker 可用;开启不补建已有文档,关闭不删除已有页面,配置修改不立即重建历史页。

  • wiki_config 按字段合并而非整对象替换:省略的字段保留,字段值 null 清除对应覆盖并恢复读取默认值。

  • 规范字段为:

    • wiki_language(Chinese / English / Japanese / Korean / French / German / Spanish)

    • extraction_granularity(standard / focused / exhaustive)

    • content_instructions(最多 8000 字符)。

  • 读取默认值依次为 Chinese、standard、空字符串。

  • 兼容 granularity → extraction_granularity、custom_instructions → content_instructions。

  • 同请求冲突别名拒绝。新传入未知字段拒绝,存量未知配置字段仍保留;历史非法 JSON 不阻断开关读取,但写配置时拒绝静默覆盖。

POST /v1/knowledge/wiki/backfill?kb_id=<id>

为已开启 Wiki 的知识库补建现有 indexed 文档,需要知识库owner(管理权限)。无需请求体,返回:

响应

响应示例

{"code":0,"msg":"ok","data":{"kb_id":1,"status":"accepted","enqueued":3}}

enqueued 是入队文档操作数,不是已生成页数;可以为 0。任务异步处理且不绕过审核,无请求级去重保证,超时后先查状态再决定是否重试。该接口不代开知识库生成开关。

PUT /ops/knowledge/wiki/config?kb_id=<id>(高级生成配置)

使用管理面地址和工作区 Owner Key,可设置 wiki_config JSON 字符串。此旧 OPS 契约保留,不改成 DATA 的对象格式;知识库页面配置优先使用上述数据面接口,知识库owner 身份不等于工作区 Owner Key。

请求

请求示例

curl -X PUT "http://<host>:8080/ops/knowledge/wiki/config?kb_id=1" \
  -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
  -d '{"wiki_config":"{\"extraction_granularity\":\"focused\",\"wiki_language\":\"Chinese\",\"content_instructions\":\"侧重架构决策\"}"}'

配置修改不表示历史页面立即重建。完整上手步骤见构建 RAG + Wiki 企业知识库。

Wiki 数据面页面管理与任务摘要

前缀 /v1/knowledge/wiki,全部返回 Box。viewer 只读;editor 可编辑 / 发布 / 归档 / 恢复页面、单页重新生成及重试本知识库失败任务;配置、ACL 与全库补建仍需知识库owner。ES 全局维修仍仅在 OPS,未对普通知识库角色开放。

方法 / 相对路径

请求与返回

GET /pages?kb_id=1&page=0&size=20

知识库隔离分页页面列表;可选 status / type / folder_id

POST /pages

editor;手工建页,kb_id 在 body 里(不是 query);必填 slug / title,可选 page_type / content_markdown / summary / category / folder_id

GET /stats?kb_id=1

本知识库统计,任务计数不混入其他 KB

PUT /pages/update?kb_id=1&page_id=101

editor;部分更新 title / content_markdown / summary / category / folder_id / status,返回页面 DTO

POST /pages/regenerate?kb_id=1&page_id=101

editor;无需请求体,返回 {"accepted":true}

GET /dead-letters?kb_id=1&page=0&size=20

viewer;分页脱敏死信摘要

GET /log?kb_id=1&page=0&size=50

viewer;分页脱敏任务日志摘要

POST /dead-letters/retry?kb_id=1&id=7

editor;无需请求体,返回 {"retried":true};参数是 id,不是 dead_letter_id

页面、死信、日志分页要求 page 非负、size 为 1–200,非法值拒绝。分页 data 包含 content / total_elements 等分页字段,不是裸数组。页面、目标目录、死信及其关联来源文档必须属于已授权 workspace/KB,跨范围资源不能借合法 kb_id 访问。创建 / 更新目录的 parent_id 也必须同知识库。

  • status 与 page_type 是封闭取值域,写入面按白名单校验,域外值一律 400 40001:

    • status ∈ draft / published / archived。搜索与召回只索引 published,反向链接图只认 published 与可解析 draft,/stats 只统计 published_pages / draft_pages,控制台的发布 / 归档 / 恢复按钮也只在 draft / archived 下渲染 —— 写入域外值会让页面同时从这四处消失。

    • page_type ∈ entity / concept / summary / index(生成侧实际产出的四种)。不传时默认 entity。标题解析与去重候选只看 entity / concept。GET /pages?type= 的过滤值同样限于这四种。

  • slug 与 title 必填且不可为空白,两端空格按 wikilink 目标的同一规则 trim;slug ≤ 256 字符、title ≤ 512 字符,超长返回 400 并在 message 里给出列预算。漏传或空白 slug 是校验错误(40001),不再落到存储层约束上(历史行为是 40009 missing or invalid required column: slug)。

  • 页面更新的分类请求字段是 category,响应仍为 category_path;不修改 slug。设置 status=published 可发布草稿或恢复归档页;设置 status=archived 是 UI“删除”的归档语义,不是物理删除。正文编辑应先请求 /pages/{pageId}?for_edit=true 取得完整正文,不能把普通预算读取的截断内容保存回去。

  • 重新生成先检查全部来源归属,再对仍有效的同知识库来源入队;没有有效来源的手工页或来源已全部删除时返回 409,不假装已入队。重试死信必须同时验证死信及关联文档归属,成功入队并移除该死信记录;accepted / retried 都不表示模型处理已完成。

  • 死信摘要字段:id、knowledge_id、fail_count、created_at、error_code=WIKI_DISTILL_FAILED、last_error(固定为“蒸馏失败,请重试或联系管理员”)。日志摘要字段:id、action、summary、created_at;action 仅 distill_batch / distill_coverage / link_validation / other,summary 为固定脱敏提示。两类接口均不回传原始模型结果或供应商错误。

POST /v1/knowledge/wiki/search

对 Wiki 蒸馏页面进行 BM25 全文检索,返回命中列表(不含全文正文)。区别于 /v1/knowledge/search(chunk 级混合检索),Wiki 搜索面向蒸馏后的结构化知识页面。仅 status=published 的页面可被检索(服务端强制过滤);draft 页可由 editor 经数据面页面更新发布,也可沿用原管理面发布,索引同步后才会出现在搜索结果中。

请求

请求参数

参数

类型

必填

说明

query

string

条件必填

单个查询;与非空 queries 至少提供一个

queries

string[]

否

最多 10 个查询;非空时优先于 query

knowledge_base_ids

long[]

否

限定检索的知识库 ID 列表(接受 kb_ids / kbIds 别名)。省略时 Owner Key 检索整个 workspace 的全部 Wiki;User Key 必须显式传入

top_k

integer

否

返回条数,范围 1–100(接受 topK 别名)

mode

string

否

keyword(默认,BM25)或 regex(字面匹配)

说明

未知字段严格拒绝:请求体中出现上表以外的字段(如把 kb_ids 误写成单数 kb_id)会直接返回 400 40001 unknown field '<name>',与 /v1/knowledge/search 一致。此前这类 typo 会被静默丢弃,使请求从“检索指定 KB”降级为“检索整个 workspace”。

请求示例

curl -X POST http://<host>:4040/v1/knowledge/wiki/search \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"query": "部署流程", "knowledge_base_ids": [1], "top_k": 5}'

响应

响应示例

说明

正文需再调 GET /v1/knowledge/wiki/pages/{pageId} 获取。

{
  "code": 0, "msg": "ok",
  "data": [
    {
      "id": "101",
      "title": "部署指南",
      "slug": "deploy-guide",
      "page_type": "concept",
      "category": "运维",
      "summary": "介绍 Docker Compose 与镜像部署流程",
      "snippet": "...部署前需准备 .env 中的 DASHSCOPE_API_KEY...",
      "score": 8.42
    }
  ]
}

GET /v1/knowledge/wiki/pages/{pageId}

按页面 ID 从 MySQL 读取 Wiki 页面(含 markdown 正文)。普通读取按页面实际知识库校验读权限,并遵循输出预算;for_edit=true 按页面实际知识库要求 editor 写权限,返回完整正文,忽略普通读取预算。不接受由客户端换一个 kb_id 绕过页面归属。

请求

请求参数

参数

类型

必填

说明

max_output_chars

int

否

普通读取正文输出预算(按 Unicode code point 计数),范围 1000–200000;超预算时保留头 70% + 尾 30% 并插入截断标记行。缺省使用 context.wiki.read-budget.default-max-output-chars(默认 0 = 不截断)

for_edit

boolean

否

默认 false;true 要求该页面实际知识库的写权限并返回完整正文,不应用 max_output_chars 或部署默认预算

预算生效时(参数或配置 > 0),响应 data 额外回显 content_truncated(boolean,是否发生截断)与 content_total_chars(int,截断前正文总字符数);预算关闭时这两个字段不出现。

请求示例

curl "http://<host>:4040/v1/knowledge/wiki/pages/101" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "id": 101,
    "knowledge_base_id": 1,
    "slug": "deploy-guide",
    "title": "部署指南",
    "page_type": "concept",
    "category_path": "运维/部署",
    "summary": "介绍 Docker Compose 与镜像部署流程",
    "content_markdown": "# 部署指南\n...",
    "source_refs": "[\"doc:42\"]",
    "aliases": "部署,deploy",
    "status": "published",
    "view_count": 12,
    "created_at": "2026-08-19T10:00:00Z",
    "updated_at": "2026-08-19T11:00:00Z"
  }
}

GET /v1/knowledge/wiki/pages/by-slug

按知识库 ID + slug 读取 Wiki 页面(响应结构同上)。

请求

请求参数

参数

类型

必填

说明

kb_id

long

是

知识库 ID

slug

string

是

页面 slug

max_output_chars

int

否

正文输出预算,语义同 GET /pages/{pageId}(1000–200000;缺省走 context.wiki.read-budget.default-max-output-chars,默认 0 = 不截断)。预算生效时响应回显 content_truncated / content_total_chars

请求示例

curl "http://<host>:4040/v1/knowledge/wiki/pages/by-slug?kb_id=1&slug=deploy-guide" \
  -H "X-API-Key: $API_KEY"

GET /v1/knowledge/wiki/folders

列出指定知识库的 Wiki 目录(文件夹)结构,可按父目录过滤。

请求

请求参数

参数

类型

必填

说明

kb_id

long

是

知识库 ID

parent_id

long

否

父目录 ID。缺省返回顶层目录

请求示例

curl "http://<host>:4040/v1/knowledge/wiki/folders?kb_id=1" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": [
    {"id": 10, "knowledge_base_id": 1, "name": "运维", "path": "/运维", "parent_id": null, "sort_order": 0}
  ]
}

排序:返回顺序按 sort_order 升序,sort_order 相同时按 id 升序兜底(跨 DB 稳定)。

目录写入规则(POST /ops/knowledge/wiki/folders、PUT /ops/knowledge/wiki/folders/update)

目录的写入面在管理面(/ops/knowledge/wiki/folders*,均要求 Owner Key)。约束如下:

字段

规则

name

必填;两端空格会被 trim,trim 后不得为空;最长 256 字符;不得包含 /(否则会伪造出一层不存在的层级)。违反时返回 400 / 40001,如 name is required、name must not contain '/'、name must be at most 256 characters

path

只读,由服务端按 父目录 path + "/" + name 推导,不接受客户端传入;总长上限 1024 字符,超出时返回 400 / 40001 folder path must be at most 1024 characters

sort_order

可选,必须是整数(可为负)。传字符串 / null / 布尔 / 对象一律返回 400 / 40001 sort_order must be an integer

parent_id

创建时可选;更新时不支持改 parent,传入与当前不同的值返回 400 changing folder parent is not supported

  • 同父同名唯一:同一 kb_id + 同一 parent_id 下不允许重名,冲突返回 409 / 40901 a folder named 'X' already exists under the same parent。不同父目录下同名是合法的;把目录改成它自己当前的名字也是合法的(空操作)。

  • 改名会级联重算 path:重命名一个目录后,其整棵子树的 path 前缀会被同步重写(子目录自身的 name 不变)。前缀相同但不属于该子树的目录(如 /Alpha 与 /AlphaOther)不受影响。

  • 删除语义(DELETE /ops/knowledge/wiki/folders/delete):

    • 目录下还有子目录时返回 409 / 40901 folder still has N subfolder(s); delete or empty them first —— 因为不支持改 parent,被删父目录的子目录会成为无法列出也无法修复的孤儿。

    • 目录下只有页面时仍返回 200,这些页面的 folder_id 被就地置空(回到未归档状态),不会留下悬垂引用。

    • kb_id 参与校验:目录不属于该 kb_id 时返回 404,与 /folders/update、/pages/move 行为一致。

GET /v1/knowledge/wiki/read

Read 步骤核心端点。按 kb_id + slug 读取 Wiki 页面全文,并返回 out_links / in_links slug 列表与邻居页面摘要卡(neighbors),供 Agent 沿链接图导航展开(Expand)。

请求

请求参数

参数

类型

必填

说明

kb_id

long

是

知识库 ID

slug

string

是

页面 slug

max_output_chars

int

否

page.content_markdown 输出预算,语义同 GET /pages/{pageId}(1000–200000;缺省走 context.wiki.read-budget.default-max-output-chars,默认 0 = 不截断)。预算生效时 page 内回显 content_truncated / content_total_chars;截断在读缓存之后进行,不影响缓存内容

请求示例

curl "http://<host>:4040/v1/knowledge/wiki/read?kb_id=1&slug=deploy-guide" \
  -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "page": {
      "id": 101,
      "knowledge_base_id": 1,
      "slug": "deploy-guide",
      "title": "部署指南",
      "page_type": "concept",
      "content_markdown": "# 部署指南\n...",
      "status": "published"
    },
    "out_links": ["env-config", "docker-compose"],
    "in_links": ["getting-started"],
    "neighbors": [
      {
        "id": 102,
        "slug": "env-config",
        "title": "环境变量配置",
        "page_type": "entity",
        "summary": "介绍 .env 关键变量(截断至 150 字)",
        "direction": "out"
      },
      {
        "id": 99,
        "slug": "getting-started",
        "title": "快速开始",
        "page_type": "concept",
        "summary": "5 分钟上手指南",
        "direction": "in"
      }
    ]
  }
}
说明

neighbors 中 direction 为 out(当前页指向邻居)或 in(邻居指向当前页),summary 截断至 150 字。结果默认命中服务端读缓存(TTL 300s)。

GET /v1/knowledge/wiki/pages/{pageId}/sources

原文追溯端点。列出 Wiki 页面的来源文档(含 OSS 短时签名下载链接,TTL 1800s)及每文档默认 10 个代表性 chunk 片段(可配 context.wiki.source-query.preview-chunks),用于核对蒸馏内容与原文。

请求

请求参数(检索模式)

参数

类型

必填

说明

query

string

否

检索词,≤256 字符;命中 chunk 并附加相邻上下文

mode

string

否

keyword(默认)/ regex,其他取值返回 400

max_chunks

int

否

每文档返回 chunk 上限,默认 20,范围 1–20

context_window

int

否

上下文窗口,默认 1,范围 0–2

检索模式与区间读取互斥:query 与 start_chunk 同时传返回 400。query 与区间参数都不传时,返回默认概览(每文档代表性 chunk 片段)。

请求参数(区间读取模式)

参数

类型

必填

说明

start_chunk

int

否

区间起始 chunk position(>= 0)。与 query 检索参数互斥(同时传返回 400)

end_chunk

int

否

区间结束 position(含端点)。只传 start_chunk 时默认窗口 10(即 [start, start+9]);区间跨度上限 50(可配 context.wiki.source-query.max-range-span),超限返回 400;不可单独传

响应中每个源文档回显 total_chunks(该文档 chunk 总数),供 Agent 规划下一个读取区间。

请求示例

curl "http://<host>:4040/v1/knowledge/wiki/pages/101/sources" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": [
    {
      "document_id": 42,
      "title": "部署手册.pdf",
      "source_url": null,
      "file_path": "docs/deploy.pdf",
      "mime_type": "application/pdf",
      "oss_presigned_url": "/v1/files/download?key=...&expires=...&signature=...",
      "total_chunks": 128,
      "chunks": [
        {"chunk_id": "42_3", "position": 3, "content": "...部署前需准备 .env..."}
      ]
    }
  ]
}

POST /v1/knowledge/wiki/issues

对 Wiki 页面内容标记质量问题(过时/不准确/缺失/断链),供后台评审与重新蒸馏参考。按页面真实知识库要求 editor 写权限;viewer 不可提交,这是只读角色的授权修复。成功返回 200(Box 包裹)。

请求

请求参数

参数

类型

必填

说明

page_id

long

是

页面 ID

issue_type

string

是

outdated / inaccurate / missing / broken_link

description

string

否

问题描述,≤2048 字符

请求示例

curl -X POST http://<host>:4040/v1/knowledge/wiki/issues \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"page_id": 101, "issue_type": "outdated", "description": "部署端口已从 8080 改为 4040"}'

响应

响应示例

{"code": 0, "msg": "ok", "data": {"id": 7, "status": "open"}}

GET /v1/knowledge/documents/{id}/images

列出文档抽取出的图片(OSS 原图 + 短时签名下载链接 + Vision 描述/OCR 文本),需 reader 及以上权限。跨 workspace / 不存在返回 404。

请求

请求参数

参数

类型

说明

oss_key

string

OSS 对象 key

signed_url

string

短时预签名 GET URL。OSS 未接入时为 null(仍返回 oss_key)

page_number

integer

页码(PDF 有值)

block_type

string

块类型(通常为 image)

section_path

string

章节路径

caption

string

Vision 生成的描述 + OCR 文本(已嵌入向量库用于检索)

请求示例

curl "http://<host>:4040/v1/knowledge/documents/42/images" -H "X-API-Key: $API_KEY"

响应

响应参数

字段

类型

说明

oss_key

string

OSS 对象 key

signed_url

string

短时预签名 GET URL;OSS 未接入时为 null(仍返回 oss_key)

page_number

integer

页码(PDF 有值)

block_type

string

块类型(通常为 image)

section_path

string

章节路径

caption

string

Vision 生成的描述 + OCR 文本(已嵌入向量库用于检索)

响应示例

{
  "code": 0, "msg": "ok",
  "data": [
    {
      "oss_key": "ws1/doc42/img_001.png",
      "signed_url": "https://oss.example.com/...&Signature=...",
      "page_number": 3,
      "block_type": "image",
      "section_path": "架构/存储层",
      "caption": "存储三件套架构图:PolarDB-X + PolarDB-X Search + OSS"
    }
  ]
}

文档不可变来源修订(2026-09-16新增)

前缀:/v1/knowledge/bases/{kbId}/documents/{docId}/revisions。所有响应沿用 Box<T>(业务数据在 data),每次调用重新检查当前知识库viewer 权限,跨 workspace /知识库/ document 的 revision ID 返回 404;历史 ID 不是授权凭据。原文存储读取 / PDF 渲染结束后再次查询当前权限状态;期间已提交的 ACL 降权或公开库改私有不会沿用请求内缓存的旧权限返回正文。

方法 / 相对路径

行为

GET /

倒序列表;page=0、size=20,size 上限 100;data 为数组

GET /{revisionId}

固定来源快照

GET /{revisionId}/source

原件正文;不签发 OSS bearer URL,不回退到当前文档

GET /{revisionId}/source/pages/{page}

PDF 第 page 页(从 1 开始),服务端 PDFBox 渲染 PNG;不执行浏览器 PDF 动作

GET /{revisionId}/parsed

读取该来源修订最新一次留存的解析文本、块和覆盖范围;不存在返回 404,不回退到当前文章

POST /{revisionId}/restore

editor 显式恢复固定来源;请求 {expected_revision_id:"当前最新业务修订UUID"},冲突 / 同内容 409;返回原 KnowledgeDocumentDto 与新入库 event_id

  • Revision 字段:id(业务 UUID)、number、snapshot_hash、source、created_at、author_member_id(旧记录可空)。source 包含来源、原件哈希 / OSS key、标题、metadata 与文档元数据快照;解析 coverage 通过独立 /parsed 接口提供;不保存整库发布 manifest。恢复产生的新修订在 source.restored_from_revision_id 中记录来源;该审计注记不参与来源内容的 snapshot_hash。技术 ingest_revision、projection_generation 不是业务修订 ID。相同快照不重复创建;metadata 变化或 A→B→A 产生新业务修订。restore 保留 document ID / external_id,先在事务外校验原件,短事务内 CAS 并生成新来源修订与原有 ingest outbox;不恢复旧权限、旧审核决定或 Wiki / 图谱派生,也不等于整库 release 回滚。此接口不表示内容已审核或已发布。

  • 新增捕获及 restore 默认关闭:context.knowledge.revisions.capture-enabled=false。只有确认所有 reader / writer / worker / GC 已升级兼容版本后才设置 true;旧程序不认识历史引用,单纯 epoch 或开关不能隔离旧 GC。关闭捕获不会关闭既有历史对象的保护或读取。旧原件缺少可核实 content_hash 时不伪造历史基线。

  • Source 字段:revision_id、source_hash、mime_type、encoding(utf-8 或 base64)、content。原件 SHA-256 校验失败、对象丢失或超过 16 MiB 在线预览预算时显式失败;上传含附件时主文件校验使用固定 metadata_json.content_sha256。PDF 返回 page、total_pages、mime_type=image/png、base64 content;每份最多 1,000 页、每页最多 1,200×1,600,服务器同时最多渲染 2 页。二进制原件与解析证据分别提供。

  • Parsed 字段:revision_id、source_hash、artifact_hash、text、blocks、coverage、created_at。blocks 仅保留 page_number、block_type、section_path、text,不持久化签名 URL。成功摄入提交时,按 (revision_id, ingest_revision) 留存不可变解析;同一次摄入重试不覆盖证据,重新摄入可以新增解析,使初次部分解析可以修复。读取校验内容摘要,Ontology 任务固定 artifact_hash,后续重解析不会改变旧任务的证据。覆盖状态为 complete / partial / unknown,unknown 不能当作完整。单个解析产物上限 12,000,000 字节,workspace 默认最多 1 GiB(context.knowledge.revisions.max-parsed-bytes-per-workspace),并计入 workspace 逻辑存储配额。

  • 保留策略分为两层。自动裁剪:每次新增修订时,按 context.knowledge.revisions.max-kept-per-document(默认 5)保留最新 N 个修订,超出部分连同解析产物一并物理删除。硬上限:默认单文档最多 1,000 个修订(max-per-document)、workspace 历史源文件包最多 50 GiB(max-retained-bytes-per-workspace),超限拒绝新写入而不是静默删除历史。存在历史引用的原件 / sidecar 不随当前文档更新而删除,删除知识库/ workspace 才删除该范围历史。逻辑历史字节计入 workspace 存储配额。当前按 document/source_hash 包去重并取记录中的最大字节数,不是逐 OSS 对象台账;相同 source_hash 下后生成的派生附件不能据此精确计量。这不是最终的按 release 引用计数 / 保留窗口 / 物理账单实现。

  • ctxdb0 读取接线:knowledge documents versions <document-id> --source <name-or-id> --page 0 --limit 20 --json 与 knowledge documents source <document-id> --source <name-or-id> --revision <business-revision-uuid> --json。后者原样保留源响应 JSON 与编码,权限 / 丢失 / 损坏错误直接失败,不调用当前 document detail 作为替代;未增加 release pin 或语义 verify 能力。单篇恢复命令为 knowledge documents restore <document-id> --source <name-or-id> --revision <business-revision-uuid> --expected-revision <current-head-uuid> --json,使用同一 editor 权限与并发检查。

本体知识库(管理目录、候选版本与校验)

前缀:/v1/knowledge/bases/{kbId}/ontology;全部采用 Box 包装(code、msg、data、trace_id),以下字段均指 data。本体属于单个 KB;读需 viewer,保存、结构校验、发现、引用、停用、删除需 editor。viewer 只读。所有资源受当前 workspace/member/KB 权限限制。保存得到候选定义,不自动改变现有 Wiki / 图谱;显式应用后,新的图谱与 Wiki 任务固定所选定义,文章仍遵循现有审核。

管理目录与候选追加

方法 / 相对路径

请求与返回

GET /catalog?page=0&size=20

{items,page,size,total_elements,head_version_id,active};page 非负,size 为 1–100;active 为 {generation,schema_version_id}

POST /candidates

{request_id,expected_head_version_id,parent_version_id,source_kind,schema,instructions};成功返回新 Version,不自动引用

DELETE /versions/{id}?expected_generation=G

返回 {id,deleted:true};active 代数冲突、版本当前已引用或被运行任务使用时返回 409

目录行字段为 id、kind、status、schema_version_id、version_number、source_kind、created_at、generated_at、author_member_id、type_count、relation_count、is_active、task_id、error_code。kind=version 的状态为 candidate / active;kind=discovery 的状态为 pending / processing / dead / expired。来源为 legacy / json_import / manual_edit / sample_discovery。目录不返回 schema 全文、样本文本或原始模型请求。服务端合并版本与未隐藏任务后,按 created_at DESC,id DESC 统一分页;成功发现只显示生成的版本,不重复显示任务行。目录读取错误不是空目录,404 应检查实际请求地址与部署版本,不能降级成成功空列表。

候选保存契约:

  • request_id 必填、非空、最长 128 字符;同 ID 且完整请求内容一致返回原版本,不同内容返回 409。新请求校验后强制追加版本,即使 schema / 指令内容相同也不复用旧版本。

  • source_kind 只接受 manual_edit / json_import。schema、instructions 必填;instructions 的 ontology_discovery_instructions 与 graph_extraction_instructions 分别最多 8000 字符,随新版本固定保存。

  • expected_head_version_id 必须取目录返回的真实历史 head(空历史为 null),不是当前 active 或选中的编辑来源;管理墓碑也属于历史 head。

  • parent_version_id 仅标识编辑来源,可为 null;非空时必须属于同知识库且仍可选择,不承担 CAS。编辑旧版本时仍用最新 head 作 CAS。

  • head 冲突返回 409。客户端保留草稿,由用户显式刷新 head 后再次保存;不得自动重试覆盖。保存不等于引用或发布。

  • schema 字段名为 camelCase 且严格校验:schema 这一族(types[]、types[].attributes[]、relations[])的字段名是 camelCase(valueType / allowedUnits / typeId),与本文档其余 snake_case 请求体不同。出现未声明的字段(例如把 aliases 写成 alias、把 allowedUnits 写成 allowed_units)会返回 400 40001 unknown field '<name>' on OntologySchema…,POST /ontology/validate 同样如此。此前这类 typo 会被静默丢弃,保存成功但 aliases / allowedUnits 落库为 null,导致别名解析与单位校验静默失效。注意 validate-facts 的 facts 结构(instances / links)仍保持宽松,因为同一批类型也承载模型抽取输出。

  • 删除只隐藏管理目录与新选择,保留 schema、指令、历史 facts / 任务及按 ID 的历史读取;不回退 head / 版本号、不释放历史版本配额。重复删除幂等,删除不增加 active generation。唯一引用仍通过下述 /active 的 generation CAS 切换。

直接上传样本发现

这是独立样本协议,不是下文 /tasks 的 revision 发现 / 抽取协议。

方法 / 相对路径

请求与返回

POST /discoveries

multipart:重复 files 文件字段,options 部分为 application/json;HTTP 202,返回 {task_id,status,schema_version_id},首次为 pending / null

GET /discoveries/{id}

{task_id,status,schema_version_id,error_code,error,created_at,completed_at,files,can_retry,authority,quality_report};错误脱敏;quality_report(V103,可 null)为质量门报告:{metrics,issues[]},issue 含 path/rule/severity(error|warning)/message,strict 模式拦截(错误码 QUALITY_GATE)的报告同样可见供诊断

POST /discoveries/{id}/retry

请求必须是空 JSON 对象 {};返回任务状态;仅仍 active 且有 editor 权限的原作者可重试可恢复 dead 任务

DELETE /discoveries/{id}

返回 {task_id,deleted:true};仅隐藏 dead / expired;运行中或成功任务返回 409,不是取消接口

  • options 为 {request_id,ontology_discovery_instructions?,graph_extraction_instructions?,base_schema_version_id?,competency_questions?}。

  • request_id 必填、最长 128 字符,同 ID 同有效输入返回原任务,不同输入 409。

  • 两条指令分别最多 8000 字符:省略时继承固定基准版本的对应值,无基准则为空;显式空字符串表示清空该指令,不是继承。基准必须属于同知识库且可选择。实例抽取指令仅随任务与候选版本固定保存,供后续图谱抽取使用;样本模型提示词不包含抽取指令,不能由样本模型代写。

  • competency_questions(V103,选填):能力问题验收用例,字符串数组最多 10 条、每条 1..200 字符;提供时随发现调用一并评估,schema 无法回答的问题在任务 quality_report 中产生 competency_unsupported warning(不拦截发布),留空表示本次不评估。

示例:

curl -X POST "http://<host>:4040/v1/knowledge/bases/1/ontology/discoveries" \
  -H "X-API-Key: $API_KEY" \
  -F 'files=@sample-a.pdf' -F 'files=@sample-b.txt' \
  -F 'options={"request_id":"sample-request-001","ontology_discovery_instructions":"仅关注产品与条款","graph_extraction_instructions":"抽取时保留原文证据"};type=application/json'
  • 状态为 pending / processing / done / dead / expired。前两种在 UI 显示“运行中”,不能查看候选、编辑、引用或删除;刷新后从服务端目录恢复。done 原子生成一个未应用的版本,authority=unreviewed_candidate,不自动引用。样本模型只输出 schema / explanation,经结构校验,不伪造 revision 原文锚点,也不表示旧逐项证据协议已通过。

  • 样本限制(配置前缀 context.knowledge.ontology-samples):默认每批 1–4 文件、单文件 10 MiB、总计 20 MiB,仅 PDF / DOCX / TXT / MD;解析文本总计最多 32000 UTF-16 字符。超限整批失败,不截断、不只取部分文件。不进行 OCR、图片 / 嵌入附件处理或外链抓取;扫描无文本、加密、损坏、空文件或不支持格式明确失败。默认实际解析线程 2、单文件 30 秒、批次解析预算 120 秒;模型仍用现有 provider 超时,不承诺线程中断等于硬 CPU 隔离。

  • 零正式摄入副作用:样本使用独立私有存储,仅解析并发现;不调用正式文档上传、不创建 document / revision、不投递 INGEST、不执行 chunk / embedding / ES / Graph / Wiki / review 写入。原件按原始字节 SHA-256 固定,artifact hash 包含 parser version、source hash 与文本;任务固定基准、双指令、parser/template 版本及模型配置。重试复用已成功解析的固定输入,输入或运行配置失效时拒绝重试,需重新上传。

  • 临时故障默认首次加最多 3 次自动重试(5 / 10 / 20 秒),429 同样有界;结构、权限、无文本错误不作为临时成功。新旧任务合计默认每知识库最多 8 个活跃任务、1000 个保留任务;版本默认最多 1000,管理删除不释放配额。

  • files 摘要字段为 id、filename、mime、bytes、source_hash、artifact_hash、parser_version、retain_until、source_available,不返回原件 URL 或全文。样本原件和文本至少保留 7 天;运行任务不能回收。保留期到达不等于已经回收,source_available 依据实际回收标记与对象定位信息,而不是仅比较时间。已成功版本在样本回收后仍可使用;dead 任务失去样本或事件后为 expired,不可重试。未提交孤儿对象满 24 小时才可回收,数据库 / 对象年龄不确定时不删,删除失败保留定位以便重试。

兼容版本、事实校验与应用协议

方法 / 相对路径

请求与返回

GET /versions?page=0

每页 20 个固定版本,倒序数组

GET /active

{generation,schema_version_id};未应用时为 {generation:0,schema_version_id:null}

PUT /active

editor;{expected_generation,schema_version_id},CAS 冲突 409;设 null 停用本体,返回新的 Binding

GET /documents/{docId}/facts

viewer;最近 20 次固定 schema 抽取记录,含源修订、schema 版本、摄入次数、facts、模型/证据 provenance 与 published 标记

GET /versions/{id}

当前权限下读取固定版本

POST /versions

{expected_version_id, schema, instructions};知识库行锁内 CAS,冲突 409;保留相同 hash 复用语义,但命中管理墓碑时追加新版本,不返回墓碑作为新候选

POST /validate

请求为 schema;返回 {valid, issues:[{path,rule,message}]}

POST /versions/{id}/validate-facts

请求为 facts;依固定 schema 校验并验证原文锚点;返回相同 Validation

GET /versions/{id}/resolve?term=...

名称 / 别名忽略大小写匹配的稳定类型 ID 数组;歧义返回所有候选,不自动合并

schema / facts 内字段为 camelCase;外层版本、指令、任务字段为 snake_case。类型最多 100,关系最多 300,每类型属性最多 50,名称 / ID 非空且最长 128。示例定义:

{
  "expected_version_id": null,
  "schema": {
    "types": [{"id":"indicator","name":"Indicator","aliases":["指标"],"attributes":[{"id":"value","name":"Value","valueType":"number","required":true,"allowedUnits":["u_test"]}]}],
    "relations": []
  },
  "instructions": {"ontology_discovery_instructions":"仅输出候选及原文依据", "graph_extraction_instructions":"严格遵守固定类型和单位"}
}
  • 关系字段 {id,name,domain,range,min,max};max 为 null 表示无上限。facts 字段 {instances,links,complete},实例为 {id,typeId,properties,units,evidence},边为 {id,typeId,from,to,evidence};锚点为 {revisionId,sourceHash,quote,page,start,end}。定位必须提供 page 或同时提供 start/end;只有 quote 而无定位时返回 anchor 问题。文本偏移采用 UTF-16、左闭右开,给出偏移时必须精确匹配 quote;纯文本页码只支持 page=1;已留存的 PDF / Office 解析使用固定块页码,若同时提供页码和偏移则两者须一致。最多 5,000 个实例 / 20,000 条边;完整集合必须满足 required、数值 / 字符串 / 布尔类型、单位、domain/range、方向与基数。数值属性声明非空 allowedUnits 时,缺少或不匹配的单位返回结构化 unit 问题。原文验证最多 200 锚点 / 16 原件,未知或缺少历史解析的二进制来源显式不可核验;只有字面定位,不等于五态语义支持性验证或事实权威。complete=false 保留 partial 问题,不声称完整通过。

  • 应用不等于全库重建:已存在的文章需要显式重新处理,沿用当前文章摄入接口。Graph / Wiki 开关仍各自生效;不配置 schema 时保留原处理方式。运行中任务固定应用代数与定义版本;切换后旧任务不能发布覆盖新结果。图谱使用类型 ID、属性、单位、关系约束和原文锚点校验,再接入原图谱发布/聚合流程;完整解析及完整模型输出才允许替换该文章的图谱贡献。当前自动图谱抽取每篇上限 64,000 字符,超限、部分/未知解析或模型截断会明确失败并保留旧图谱。facts.published 表示该次结果曾通过图谱发布,当前应用版本以 /active 为准。

  • Wiki 在候选页面发现、文章摘要、页面合并三处使用同一固定 schema,保留既有 slug 和引用;正文与 schema 发布前分别检查文档代数和应用代数。现有 Wiki 日志 distill_coverage 记录 ontology_version 和 ingest_revision,可追溯处理配置。这保证定义进入真实模型请求,不承诺模型生成内容的业务准确率。

  • ctxdb0 提供 knowledge ontology versions|active|apply|save|discover|extract|tasks。各命令均指定 --source <name-or-id>;apply 使用 --version <uuid|none> --expected-generation <n>,save 从 --stdin 读取上述保存请求,discover 使用 --revision <uuid>(可选 --schema-version),extract 必须同时指定这两个固定版本参数。tasks 列出最近任务及其结果状态,单任务详情和重试可使用上述 API。

审核通过通知(2026-09-16新增,默认关闭)

前缀:/v1/knowledge/bases/{kbId}/review-notifications。全部返回 Box<T>,配置、投递记录和重试均要求当前知识库owner。

方法 / 相对路径

请求与返回

GET /

{generation,enabled,webhook_url};默认 {generation:0,enabled:false,webhook_url:null}

PUT /

{expected_generation,enabled,webhook_url};并发配置变化返回 409;每知识库一个 HTTP(S) 接收地址

GET /deliveries?page=0

每页 20 条数组;id,document_id,review_id,status,event_status,error,created_at,delivered_at,payload

POST /deliveries/{id}/retry

仅 pending 且 outbox 为 dead 的失败投递可重试;配置已变化或通知已发送/取消返回 409

  • 通知在原审核最终 accepted 提交事务内写入 outbox,自动审核和人工审核共用该入口。accepted_pending、拒绝或激活失败不发送“审核通过”;事务回滚不留通知。通知异步发送,失败使用已有事件重试机制,不回退文章审核状态。只对开启后的新审核通过生成通知,不补发历史审批。

  • Webhook 是 JSON POST,包含 event_id(稳定通知 UUID)、type=knowledge.document.review_approved、knowledge_base_id、document_id、review_id、revision_id(未捕获历史时为 null)、content_hash、approved_at。不包含文档全文。请求头 Idempotency-Key 和 X-Context0-Event-Id 均为该 UUID;接收器应以它去重。发送成功但本地确认失败时可能重复投递,不承诺 exactly-once。2xx 为成功,其他状态为失败。

  • status 为 pending / delivered / cancelled;pending 配合 event_status=dead 表示自动重试耗尽,可由 owner 手动重试。关闭或更改订阅后,尚未开始发送的旧配置通知会取消,不会投递到新地址;已经在途的 HTTP 请求可能完成。重试保留同一事件编号。

  • 地址限制在保存时和实际 DNS 连接时均校验:禁止重定向、URL 用户名密码、fragment、云元数据地址、链路本地和保留地址。默认拒绝私网/回环;内部接收器由管理员在 context.knowledge.review-notifications.allowed-internal-hosts 中逐个配置精确主机名,不能由 API 绕过。连接超时 5 秒、响应超时 10 秒;不读取响应正文,不把含接收器令牌的 URL 写入失败日志。定时发送默认开启(context.knowledge.review-notifications.scheduled-enabled=true),没有启用订阅不会发送。

固定 revision 本体发现 / 抽取异步任务(兼容协议)

前缀:/v1/knowledge/bases/{kbId}/ontology。服务端 context.knowledge.ontology-tasks.enabled 当前缺省为 true,显式 false 时旧任务创建 / 重试返回校验错误且不注册 worker。context.knowledge.ontology-tasks.scheduled-enabled 缺省为 true,控制轮询;两项配置应以实际部署覆盖值为准。新样本发现共用该 worker 与开关,显式关闭时样本创建 / 重试返回功能关闭错误。复用既有事件 outbox / lease / 重试队列,不新增 Agent runtime。

方法 / 相对路径

请求与返回

POST /tasks

{mode:"discover"或"extract",schema_version_id,revision_ids:[...]};需 editor

GET /tasks?page=0

每页 20 条任务;需 viewer

GET /tasks/{id}

固定任务、输入指纹、候选结果与运行状态;需 viewer

POST /tasks/{id}/retry

原作者 editor 显式重试仍保留的 dead 事件;固定输入不变,非 dead / 已清理 409;运行配置漂移仍会拒绝

  • extract 必须指定固定本体版本;discover 可选已有版本,指令随该版本固定。每次 1–4 个同知识库修订,支持保留的文本原件和已有历史解析的 PDF / Office,总长不超过 32,000 字符;每知识库最多 8 个排队 / 处理中任务。源修订 / 原件哈希 / 解析产物哈希与覆盖范围、schema / 指令、系统 templateVersion / hash、模型配置摘要及采样预算形成输入 fingerprint,重复输入返回同一任务。失败任务不会借重复创建悄悄重试;原作者可显式 retry,输入依赖变化则需创建新任务。默认每知识库最多保留 1,000 个任务与 1,000 个本体版本(context.knowledge.ontology-tasks.max-retained-per-kb / context.knowledge.ontology.max-versions-per-kb);到限拒绝,不自动删除历史。

  • 状态使用既有事件状态(pending / processing / done / dead)。模型结果截断、运行配置变化或失去权限会失败;失租 worker 不得写回。结果含 candidate、issues、valid、authority=unreviewed_candidate、coverage.scope=selected_originals_only、coverage.corpus_complete=false。done 只是任务结束,valid 只是结构与字面证据通过,二者都不是正式发布。接受 schema 需显式保存候选,随后通过 /active 应用;兼容任务面板允许编辑候选 JSON,原始模型结果保持留存。新版本体目录使用独立样本发现与版本处置,不展示已移除的 revision 试跑 / 画布面板,也不将版本引用、编辑、删除等同于旧逐项候选接受 / 合并 / 拒绝。文章审核继续采用既有审核机制;整库发布、整库版本回滚与专家双审不在本次简化范围内。

  • discover 输出为 {schema,candidates}。每个类型、属性、关系都必须有对应的 provenance candidate,path 分别采用 types.TYPE_ID、types.TYPE_ID.attributes.ATTRIBUTE_ID、relations.RELATION_ID;每项包含独立 id、0–1 有限数 confidence 及非空 evidence。最多 100 项,缺项 / 重复路径 / 未声明路径都会返回阻断问题;高置信度不豁免锚点校验。extract 输出为上文 facts 格式。任务引用只能来自请求已选修订,不能引入同知识库的其他未选原文。事件被保留策略清理后,有结果的任务仍为 done,无结果的任务显示 expired,不能借 retry 重新创建已失去的事件。

检索质量 Benchmark(金标准 + 跑分)

方法

路径

说明

POST

/v1/knowledge/benchmark/gold-standards

提交一条金标准样本,请求体 {query_text, kb_ids?, expected_chunk_ids, expected_document_ids?, notes?}(query_text 与 expected_chunk_ids 必填,缺失 400)

GET

/v1/knowledge/benchmark/gold-standards?page=0&size=50

列出本 workspace 的样本

POST

/v1/knowledge/benchmark/runs

跑一次 benchmark,请求体 {triggered_by?, kb_ids?}

GET

/v1/knowledge/benchmark/runs

列出历史跑分

GET

/v1/knowledge/benchmark/runs/{id}

单次跑分详情(含 metrics JSON)

说明

ACL 语义(2026-09-16 起):benchmark 本质是受控检索探针 —— 一条“expect chunk X 出现在库 N 的结果里”的样本,天然能当作“库 N 里有没有 chunk X”的存在性判定器。因此种探针与跑探针都要过 ACL:

  • POST .../gold-standards:kb_ids 里的每个库都需 viewer 及以上权限,无权即 403(40303),跨 workspace / 不存在 404。

  • POST .../runs:先对入参 kb_ids 逐个 requireRead(403 不会在 benchmark_runs 里留下 failed 记录 —— 校验在建 run 记录之前);随后逐条样本判定调用方对样本自己存的 kb_ids 有没有读权,无权的样本整条跳过(而不是缩到可读子集,否则回报的召回率与样本口径不一致)。

  • kb_ids 现在必须是数字数组,非数字元素返回 400(而非静默丢弃)。注意:此前 kb_ids 过滤因类型问题实际从未生效(请求体里的小整数被解析成 Integer,与样本里的 Long 比较恒不相等),跑分总是覆盖全 workspace 样本。修复后 kb_ids 真正生效,历史跑分数值与修复后的不可直接横比。

多模态资源(Multimodal)

多模态资源由 /v1/context/ingest(messages[].resource_ids)与上传接口写入。User Key 仅能访问自己的资源,Owner Key可访问全 workspace。跨租户查询统一返回 404。

POST /v1/multimodal/upload

上传多模态资源(图片/音频/文档),返回 queued 状态,后续由异步调度器抽取 OCR/ASR/转写。

说明

上传路径是 /v1/multimodal/upload(非 /v1/multimodal);POST /v1/multimodal 返回 405。

请求

Form参数(multipart/form-data)

参数

类型

必填

说明

file

file

是

要上传的文件

modality

string

是

模态类型:image / audio / video / doc

session_id

string

否

关联会话 ID

metadata

string

否

JSON 格式元数据字符串

请求示例

curl -X POST "http://<host>:4040/v1/multimodal/upload" \
  -H "X-API-Key: $API_KEY" \
  -F "file=@/path/to/image.png" \
  -F "modality=image"

响应

响应示例

{"code": 0, "msg": "ok", "data": {"resource_id": "res_abc123", "ingest_status": "queued"}}

GET /v1/multimodal

分页列出当前租户的多模态资源,按created_at 倒序。轻量投影,不含OCR/ASR/转写等重字段。

请求

请求参数

参数

类型

必填

说明

page

integer

否

页码(从0开始),默认 0

size

integer

否

每页大小,默认 50,上限 200

请求示例

curl "http://<host>:4040/v1/multimodal?page=0&size=20" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "content": [
      {
        "resource_id": "res_abc123",
        "modality": "image",
        "mime": "image/png",
        "oss_url": "http://context0.example.com/v1/files/download?key=...&expires=...&signature=...",
        "thumbnail_url": null,
        "size_bytes": 20480,
        "ingest_status": "done",
        "memory_id": "mem_1_2_abc",
        "session_id": "sess-2026-08-19-001",
        "member_id": 2,
        "created_at": "2026-08-19T10:00:00Z",
        "updated_at": "2026-08-19T10:00:05Z"
      }
    ],
    "total_elements": 1,
    "total_pages": 1,
    "number": 0,
    "size": 20
  }
}
说明

data 为 Spring Data Page 结构:条目在 content,分页元信息在 total_elements / total_pages / number / size(全局 SNAKE_CASE 命名策略生效)。

GET /v1/multimodal/{resourceId}

获取多模态资源详情,含 OCR / ASR / 转写文本与元数据。跨租户返回 404。

请求

请求示例

curl "http://<host>:4040/v1/multimodal/res_abc123" -H "X-API-Key: $API_KEY"

响应

响应参数

字段

类型

说明

resource_id

string

资源 ID

modality

string

模态(image / audio / video / doc 等)

mime

string

MIME 类型

oss_url

string

Context0 短时签名下载 URL

thumbnail_url

string

缩略图 URL

size_bytes

long

文件大小(字节)

transcribed_text

string

转写文本(音视频)

ocr

object

OCR 结果(图片/PDF)

asr

object

ASR 结果(音频)

metadata

object

用户元数据

memory_id

string

关联记忆 ID

session_id

string

关联会话 ID

member_id

long

所属成员 ID

ingest_status

string

摄取状态

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "resource_id": "res_abc123",
    "modality": "image",
    "mime": "image/png",
    "oss_url": "http://context0.example.com/v1/files/download?key=...&expires=...&signature=...",
    "thumbnail_url": null,
    "size_bytes": 20480,
    "transcribed_text": null,
    "ocr": {"text": "架构图标注文本"},
    "asr": null,
    "metadata": {},
    "memory_id": "mem_1_2_abc",
    "session_id": "sess-2026-08-19-001",
    "member_id": 2,
    "ingest_status": "done",
    "created_at": "2026-08-19T10:00:00Z",
    "updated_at": "2026-08-19T10:00:05Z"
  }
}

GET /v1/multimodal/{resourceId}/url

为资源生成临时预签名下载 URL(每次调用铸造新链接,不落库长期链接)。跨租户返回 404。

请求

请求参数

参数

类型

必填

说明

ttl

integer

否

预签名有效期(秒);非正数回退配置默认值,上限 86400(24h),超限返回 400

请求示例

curl "http://<host>:4040/v1/multimodal/res_abc123/url?ttl=3600" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "signed_url": "https://oss.example.com/...&Expires=...&Signature=...",
    "expires_at": "2026-08-19T11:00:00Z",
    "oss_key": "ws1/res_abc123.png"
  }
}

技能(Skill)

GET /v1/skills

分页列出当前 workspace 下的 Skill,按 updated_at 倒序。

请求

请求参数

参数

类型

必填

说明

page

integer

否

页码(从0开始),默认 0

page_size

integer

否

每页大小,默认 20,取值范围:[1, 100]

请求示例

curl "http://<host>:4040/v1/skills?page=0&page_size=10" -H "X-API-Key: $API_KEY"

POST /v1/skills/search

Skill 语义检索专用端点,返回按相关度排序的 Skill 列表(L0/L1 层信息,用于触发判断)。

请求

请求参数

字段

类型

必填

说明

query

string

是

检索文本

top_k

int

否

返回条数上限

tags

string[]

否

按标签过滤

请求示例

curl -X POST http://<host>:4040/v1/skills/search \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"query": "代码审查", "top_k": 5, "tags": ["review"]}'

响应

响应示例

响应(Box<List<SkillSearchResult>>):

{
  "code": 0,
  "msg": "ok",
  "data": [
    {"id": 1, "name": "code-review", "description": "...", "abstract": "...", "score": 0.87, "tags": ["review"]}
  ]
}

枚举已上传的 Skill 用 GET /v1/skills(支持分页,按 updated_at 倒序)。

GET /v1/skills/{id}

获取 Skill 元信息(L0 层,最轻量)。

请求

请求示例

curl "http://<host>:4040/v1/skills/1" -H "X-API-Key: $API_KEY"

GET /v1/skills/{id}/overview

获取 Skill 摘要/abstract(L1 层),用于触发判断后再决定是否加载完整正文。

请求

请求示例

curl "http://<host>:4040/v1/skills/1/overview" -H "X-API-Key: $API_KEY"

GET /v1/skills/{id}/content

获取 Skill 完整 markdown/脚本正文(L2 层)。

请求

请求示例

curl "http://<host>:4040/v1/skills/1/content" -H "X-API-Key: $API_KEY"

GET /v1/skills/{id}/package

一次性返回 Skill 正文 + 资源清单(含预签名下载 URL 与 SHA-256),供客户端校验后安装。

请求

请求参数

Query 参数:ttl(预签名有效期秒数,默认 3600)。

请求示例

curl "http://<host>:4040/v1/skills/1/package?ttl=7200" -H "X-API-Key: $API_KEY"

响应

客户端必须在落盘前分别校验正文和每个资源的摘要;摘要缺失或不匹配时应拒绝安装。download_url 是数据而不是信任授权:客户端还应限定允许的 scheme/origin、禁止凭据随重定向泄漏,并在完整性校验通过后再原子落盘。

响应参数

字段

类型

说明

id

integer

Skill ID

name

string

Skill 包名

version

integer

Skill 版本

visibility

string

可见性

content

string

将安装为 SKILL.md 的 UTF-8 正文

content_sha256

string

content 的 SHA-256(64 位十六进制)

resources[].rel_path

string

Skill 包内的相对路径

resources[].mime_type

string

资源 MIME 类型

resources[].size_bytes

integer

资源原始字节数

resources[].sha256

string

对应资源原始字节的 SHA-256(64 位十六进制)

resources[].download_url

string

Context0 短时签名下载 URL;后端流式读取 OSS,客户端无需访问 OSS

响应示例

{
  "code": 0,
  "msg": "ok",
  "data": {
    "id": 1,
    "name": "incident-response",
    "version": 3,
    "visibility": "workspace",
    "content": "---\nname: incident-response\n---\n# Incident response\n",
    "content_sha256": "<64-hex-sha256>",
    "resources": [
      {
        "rel_path": "references/runbook.md",
        "mime_type": "text/markdown",
        "size_bytes": 1024,
        "sha256": "<64-hex-sha256>",
        "download_url": "http://context0.example.com/v1/files/download?key=redacted&expires=redacted&signature=redacted"
      }
    ]
  }
}

POST /v1/skills

创建一个 Skill,上传元信息与正文(可选附带 base64 二进制资源),需 OWNER 权限。有三种创建模式(按优先级排序:input_schema > content > body):

  • input_schema 模式:传 input_schema(JSON Schema)+ name,自动生成 MCP Tool 格式的 Skill。

  • body 模式:传 body(结构化正文,无需 frontmatter)+ name(一般搭配 description / tags 等元信息字段)。

  • content 模式:传 content(完整 Skill Markdown,必须以 --- YAML frontmatter 开头,name / description 等从 frontmatter 解析)。

请求

请求参数

参数

类型

必填

说明

content

string

条件

完整 Skill Markdown,必须以 --- YAML frontmatter 开头(内含 name / description 等元信息),与 body 二选一

name

string

条件

Skill 名称。body 模式下必填(content 模式从 frontmatter 解析)

body

string

条件

配合 name / description 的结构化正文(无需 frontmatter),与 content 二选一

description

string

否

Skill 描述

allowed_tools

string[]

否

允许调用的工具白名单

tags

string[]

否

标签,用于检索筛选

input_schema

object

否

Skill 参数 JSON Schema

visibility

string

否

可见性,如 workspace / member

metadata

object

否

自定义元数据

resources

array

否

随 Skill 上传的资源(base64)

resources[].rel_path

string

是

资源相对路径

resources[].content_base64

string

是

Base64 编码的资源内容

resources[].mime

string

否

MIME 类型(如 image/png)

请求示例

  • body 模式

    curl -X POST http://<host>:4040/v1/skills \
      -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
      -d '{"name": "代码审查", "description": "PR 代码审查流程", "body": "# 代码审查流程\n...", "tags": ["review"]}'
  • content 模式,以 frontmatter 开头

    curl -X POST http://<host>:4040/v1/skills \
      -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
      -d '{"content": "---\nname: 代码审查\ndescription: PR 代码审查流程\n---\n# 代码审查流程\n...", "tags": ["review"]}'

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "id": 1,
    "name": "代码审查",
    "description": null,
    "version": 1,
    "source_format": "markdown",
    "abstract": null,
    "allowed_tools": [],
    "tags": ["review"],
    "visibility": "workspace",
    "owner_member_id": 2,
    "resource_count": 0,
    "ingest_status": "pending",
    "created_at": "2026-08-19T10:00:00Z",
    "updated_at": "2026-08-19T10:00:00Z"
  }
}

GET /v1/skills/{id}/resources

列出 Skill 关联的二进制 / 文本资源(如示例脚本、说明截图)。

请求

请求参数

参数

类型

说明

rel_path

string

资源相对路径

mime_type

string

MIME 类型

size_bytes

long

资源字节数

请求示例

curl "http://<host>:4040/v1/skills/1/resources" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": [
    {"rel_path": "scripts/run.sh", "mime_type": "text/x-shellscript", "size_bytes": 512}
  ]
}

GET /v1/skills/{id}/resources/{relPath}

为指定 Skill 资源生成 OSS 预签名下载 URL,可在 ttl 秒内匿名下载。{relPath} 为资源相对路径(可含 /)。

请求

请求参数

参数

类型

必填

说明

ttl

integer

否

预签名 URL 有效期(秒),默认 3600

请求示例

curl "http://<host>:4040/v1/skills/1/resources/scripts/run.sh?ttl=3600" -H "X-API-Key: $API_KEY"

响应

响应示例

data 为预签名 URL 字符串。

{"code": 0, "msg": "ok", "data": "https://oss.example.com/...&Signature=..."}

DELETE /v1/skills/{id}

按 ID 删除 Skill 及其资源,需OWNER权限。

请求

请求示例

curl -X DELETE http://<host>:4040/v1/skills/1 -H "X-API-Key: $OWNER_KEY"

响应

响应示例

{"code": 0, "msg": "ok", "data": null}

策略(Strategy)

策略管理需Owner Key。

GET /v1/strategies/presets

返回内置可用的策略预设列表。

请求

请求示例

curl "http://<host>:4040/v1/strategies/presets" -H "X-API-Key: $OWNER_KEY"

GET /v1/strategies

列出当前租户策略。支持按 preset / active 过滤。

请求

请求参数

Query 参数:preset(string)、active(boolean)。

请求示例

curl "http://<host>:4040/v1/strategies?active=true" -H "X-API-Key: $OWNER_KEY"

POST /v1/strategies

创建一条自定义策略。

请求

请求参数

参数

类型

必填

说明

name

string

是

策略名称,1–128 字符,仅 [A-Za-z0-9_\-.]

config_json

object

是

策略配置(JSON 对象)

preset

string

否

预设类型:chat / agent / rag-only / coding / custom,默认 custom

description

string

否

描述,最长 512 字符

说明

创建后 active 默认为 true。

请求示例

curl -X POST http://<host>:4040/v1/strategies \
  -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
  -d '{"preset": "coding", "name": "编码助手策略", "config_json": {"recall_top_k": 15}}'

GET /v1/strategies/{id}

获取指定策略详情。

请求

请求示例

curl "http://<host>:4040/v1/strategies/1" -H "X-API-Key: $OWNER_KEY"

PUT /v1/strategies/{id}

更新策略字段或参数。所有字段均可选,仅更新传入的字段(name 不可更新,需删除后重建)。

请求

请求示例

curl -X PUT http://<host>:4040/v1/strategies/1 \
  -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
  -d '{"config_json": {"recall_top_k": 20}}'

DELETE /v1/strategies/{id}

删除指定策略。

请求

请求示例

curl -X DELETE http://<host>:4040/v1/strategies/1 -H "X-API-Key: $OWNER_KEY"

POST /v1/strategies/{id}/apply

将策略应用为当前租户的生效配置。

请求

请求示例

curl -X POST http://<host>:4040/v1/strategies/1/apply -H "X-API-Key: $OWNER_KEY"

响应

响应示例

{"code": 0, "msg": "ok", "data": {"strategy_id": 1, "applied_at": "2026-08-19T10:00:00Z"}}

POST /v1/strategies/{id}/deactivate

将策略设为 inactive。

请求

请求示例

curl -X POST http://<host>:4040/v1/strategies/1/deactivate -H "X-API-Key: $OWNER_KEY"

策略钩子(Strategy Hooks)

策略钩子允许在策略执行的特定生命周期节点(hook_point)触发自定义行为。钩子按 priority 升序执行。策略管理需 Owner Key。

POST /v1/strategies/{strategyId}/hooks

为指定策略创建一个钩子。

请求

请求参数

参数

类型

必填

说明

hook_point

string

是

触发点标识,有效值:recall_pre / recall_post / assemble_pre / assemble_post / compact_pre / compact_post / dream_pre / dream_post / write_pre / write_post / dedup_pre / dedup_post

hook_type

string

是

钩子类型,有效值:llm / script / condition

config_json

object

否

钩子配置(JSON 对象,如 webhook URL、超时等)

enabled

boolean

否

是否启用,默认 true

priority

integer

否

执行优先级(升序),默认 0

请求示例

curl -X POST "http://<host>:4040/v1/strategies/1/hooks" \
  -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
  -d '{"hook_point": "recall_pre", "hook_type": "script", "config_json": {"expr": "ctx.topK = 20"}, "enabled": true, "priority": 10}'

GET /v1/strategies/{strategyId}/hooks

列出指定策略的所有钩子。

请求

请求示例

curl "http://<host>:4040/v1/strategies/1/hooks" -H "X-API-Key: $OWNER_KEY"

GET /v1/strategies/{strategyId}/hooks/{hookId}

获取指定钩子详情。

请求

请求示例

curl "http://<host>:4040/v1/strategies/1/hooks/1" -H "X-API-Key: $OWNER_KEY"

PUT /v1/strategies/{strategyId}/hooks/{hookId}

更新钩子配置。所有字段均可选,仅更新传入的字段。

请求

请求示例

curl -X PUT "http://<host>:4040/v1/strategies/1/hooks/1" \
  -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
  -d '{"enabled": false}'

DELETE /v1/strategies/{strategyId}/hooks/{hookId}

删除指定钩子。

请求

请求示例

curl -X DELETE "http://<host>:4040/v1/strategies/1/hooks/1" -H "X-API-Key: $OWNER_KEY"

认证(Auth)

GET /v1/auth/whoami

返回当前 API Key 解析出的身份信息,用于验证 key 有效性和查看当前身份。无 ACL 校验。

请求

请求示例

curl "http://<host>:4040/v1/auth/whoami" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "authenticated": true,
    "workspace_id": 1,
    "member_id": 2,
    "key_type": "USER",
    "bound_user_id": "alice"
  }
}

未认证时:

{"code": 0, "msg": "ok", "data": {"authenticated": false}}

API Key 管理(管理面)

管理面端点,需 Owner Key认证。前缀:/ops/workspaces/members/keys。

方法

路径

说明

POST

/ops/workspaces/members/keys

创建 API Key,返回一次性明文密钥

GET

/ops/workspaces/members/keys

分页列出 API Key;V56 版本后创建的 Key 在响应中包含 plain_key(可重新获取明文),更早的 Key 该字段为 null

POST

/ops/workspaces/members/keys/revoke

撤销指定 API Key

  • 创建请求参数:

    参数

    类型

    必填

    说明

    workspace_id

    long

    是

    工作空间 ID

    member_id

    long

    否

    成员 ID;省略时由服务端根据 Key 绑定的 member 推断

    key_type

    string

    是

    OWNER / USER

  • 创建响应(一次性明文):

    {"code": 0, "msg": "ok", "data": {"id": 5, "key_prefix": "ctx0_", "key_type": "USER", "plain_key": "ctx0_abc123..."}}
  • 列表响应(plain_key 仅 V56+ Key 非空):

    {"code": 0, "msg": "ok", "data": {"items": [{"id": 5, "workspace_id": 1, "member_id": 2, "key_prefix": "ctx0_", "plain_key": "ctx0_abc123...", "key_type": "USER", "status": "active", "created_at": "2026-08-19T10:00:00Z", "last_used_at": "2026-09-16T08:00:00Z"}], "total_elements": 1}}
  • 撤销请求:{"id": 5}

成员管理(管理面)

管理面端点,需 Owner Key认证。前缀:/ops/workspaces/members。

方法

路径

说明

POST

/ops/workspaces/members

创建成员

GET

/ops/workspaces/members?workspaceId=&page=&pageSize=

分页列出成员(上限 200 条/页)

PATCH

/ops/workspaces/members

更新成员信息

DELETE

/ops/workspaces/members

删除成员,请求体 {"id": N}

  • 列表请求示例:

    curl "http://<host>:8080/ops/workspaces/members?workspaceId=3&page=0&pageSize=20" -H "X-API-Key: $OWNER_KEY"
  • 列表响应示例:

    {
      "code": 0, "msg": "ok",
      "data": {
        "content": [
          {"id": 1, "workspace_id": 3, "user_id": "admin", "name": "Admin", "status": "active", "created_at": "2026-09-16T01:00:00Z", "updated_at": "2026-09-16T01:00:00Z"}
        ],
        "total_elements": 1,
        "total_pages": 1
      }
    }
    说明

    workspaceId 必须等于调用方自身的工作空间,不允许跨租户查询。

托管文件下载

GET /v1/files/download

统一从 OSS / MinIO 流式中转文件给客户端。Skill 包资源、Skill 单资源 URL、知识库检索命中的原文/图片、文档图片列表、Wiki 来源原文及多模态上传结果、列表、详情、资源 URL 和上下文中的下载链接均通过此接口交付。后台模型调用使用的存储预签名地址保留原用途。

业务接口先执行原有租户、成员和资源可见性检查,再签发具体对象的短时下载链接。原有 download_url、oss_url、signed_url 字段名称及字符串类型不变,客户端直接使用返回值,不应自行解析 OSS 域名或拼接对象路径。

请求

请求参数

参数

类型

必填

说明

key

string

是

服务端生成的对象键编码

expires

integer

是

服务端生成的 Unix 过期时间(秒)

signature

string

是

服务端生成的 HMAC-SHA256 签名

响应

成功响应

HTTP 200 原始文件字节(不是 Box JSON),Content-Disposition: attachment、Cache-Control: no-store、X-Content-Type-Options: nosniff。服务端流式传输并关闭存储流,不将整个文件缓存在内存中;不重定向到 OSS。

  • 生效条件:此端点仅在配置了 OSS 存储(context.oss.access-key)时生效。无 OSS 配置的部署不注册该路由。

  • 认证:完整签名 URL 即临时下载凭证,仅数据面端口(默认 4040)支持免 Key 访问,管理面端口仍需 X-API-Key。签名限定存储命名空间、对象键和有效期;篡改或过期返回 403,不能凭任意 OSS key 下载。签名链接和原 OSS 预签名链接一样,在有效期内持有者可读取该对象,应避免公开分享。有效期沿用签发业务接口的 TTL 规则(多模态资源 URL 接口上限仍为 86400 秒)。对象删除后链接无法读取原对象;权限变更不会提前撤销已签发、尚未过期的链接。

  • 部署:默认使用当前 API 请求的 origin,并随请求上下文传递到异步检索。如果通过反向代理访问且后端看到的是内部 origin,配置 OSS_DOWNLOAD_ENDPOINT=https://<Context0 对外域名>;该值是 Context0 服务 origin,不是 OSS origin。多个副本须使用一致的 OSS 配置和签名凭据。

  • CLI:ctxdb0 skills fetch 继续校验正文/资源 SHA-256、大小和路径并原子落盘,不执行下载内容。已配置的 Context0 origin 可按原连接协议下载(含已授权的 HTTP 托管实例);额外跨域 origin 仍须显式 HTTPS 白名单,禁止重定向,不向下载地址发送 API Key。

模型调用用量(管理面)

以下端点运行在管理面端口(默认 8080),需Owner Key认证,使用标准 Box 响应,只查询认证工作空间;可选 memberId 限定成员。

方法

路径

说明

GET

/ops/token-usage/summary?from=YYYY-MM-DD&to=YYYY-MM-DD

日聚合汇总,返回 total_tokens、total_calls 和按 call_type、model 分组的 items

GET

/ops/token-usage/trend?from=YYYY-MM-DD&to=YYYY-MM-DD

按日、调用类型、模型的趋势

GET

/ops/token-usage/hourly-trend?days=7

按小时和调用类型的趋势;days 支持 1–30

  • call_type 包含 llm、embedding、vision、ocr、rerank、dedup。新增四类分别覆盖 DashScope Vision、独立 OCR、DashScope/HTTP Rerank 和自定义 HTTP 去重裁决(单条及批量);默认 LlmProviderDedupAdjudicator 已归入 llm,不会再次归入 dedup。

  • 用量取自成功 HTTP 响应的 usage.prompt_tokens/completion_tokens 或 input_tokens/output_tokens,总量优先采用 total_tokens,没有总量时累加已知输入输出。Rerank 只返回总量时按输入 Token 记录;生成式调用只返回总量时不推测输入输出拆分。每个响应计一次,不按批量裁决对数重复乘算;业务解析失败后发生新的请求,分别统计各次成功响应。403、429、超时等没有成功响应的请求不凭输入长度推算消耗。

  • 自定义裁决服务须在响应顶层透传上述 usage,批量响应应给出整次请求的累计用量。缺失、非法 usage 或仅返回非 Token 计费单位(如 search_units)时,仅增加成功调用次数,Token 按 0 个已知值累计并记录 model token usage unavailable 告警;0 不代表实际免费。

  • 数据异步累加至共享数据库的 token_usage_daily/hourly,允许跨节点汇总;沿用现有尽力记录机制。后台调用可能只有工作空间、没有成员,按成员筛选时不包含这些用量。新增类别会进入现有总览及已启用的月 Token 配额判断;已有接口字段、表结构和配置不变。此处不涵盖流式回答及其他尚未接入的模型路径,也不能追补升级前漏记的数据。

定时记忆晋升(Scheduled Promotion)

定时任务按 schedule_mode 调度配置(daily / weekly / monthly / interval / cron 五种触发时机,另有 legacy 兼容模式,见下文)周期性触发一次记忆晋升生成,auto_approve=true(默认)时生成完成后自动审批入库到 target_kb_id 指定的知识库(此时 target_kb_id 必填)。整体能力由配置 context.promotion.scheduled.enabled(默认 false)与 workspace 级 feature flag scheduled_promotion_enabled 控制;自动审批另受 scheduled_promotion_auto_approve_enabled flag 控制(kill-switch,默认放行)。每 workspace 活跃任务上限 10 个,每日定时执行上限 24 次;手动触发有 5 分钟 cooldown。

任务对象字段(snake_case wire 格式):{id, member_id, name, prompt, schedule_type, schedule_mode, schedule_hour, schedule_minute, schedule_day_of_week, schedule_day_of_month, schedule_interval_hours, schedule_cron, trigger_summary, auto_approve, target_kb_id, enabled, last_run_at, next_run_at, fire_count, created_at, updated_at}。

调度配置(schedule_mode)

字段

适用模式

取值与说明

schedule_mode

—

daily / weekly / monthly / interval / cron / legacy;create 不传任何调度配置时默认 daily 09:00

schedule_hour

daily / weekly / monthly

0–23,触发小时

schedule_minute

daily / weekly / monthly

0–59,触发分钟

schedule_day_of_week

weekly

1–7,周一=1

schedule_day_of_month

monthly

1–31;超过当月最后一天时截断到月末执行(如配 31 号,2 月按月末触发)

schedule_interval_hours

interval

≥1,间隔小时数

schedule_cron

cron

Spring 6 位 cron 表达式(秒 分 时 日 月 周)

所有调度均按固定时区 Asia/Shanghai 触发,不可配置。

  • cron 限制:服务端除校验表达式合法性外,还会采样后续 3 次触发时刻,要求相邻触发间隔 ≥1 小时,否则拒绝;无任何未来触发时刻的 cron 同样拒绝。

  • trigger_summary:响应新增只读字段 trigger_summary,为服务端生成的中文调度摘要(如「每天 09:00」「每周 周一 10:00」),可直接展示给用户。

  • legacy 兼容:旧字段 schedule_type(hourly / every_other_day / weekly)继续接受——只传 schedule_type 的旧客户端按 legacy 模式处理,三档分别映射为 1h / 48h / 168h 间隔(响应中 schedule_mode 返回 legacy);使用新模式创建的任务,schedule_type 字段写入与 mode 同名的值。本次变更为纯 additive,旧 schedule_type 客户端不受影响,无 breaking change。

数据面(User / Agent Key)

User Key 只能看到并操作本人创建的任务;创建要求携带成员上下文。

方法与路径

说明

GET /v1/scheduled_promotions?page=0&pageSize=20

分页列出任务,返回 Box<Page<Response>>

POST /v1/scheduled_promotions

创建任务,请求体 {name, prompt, 调度配置字段(见上表)?, schedule_type?, auto_approve?, target_kb_id?};不传任何调度配置默认每天 09:00

PUT /v1/scheduled_promotions/{taskId}

更新任务,请求体各字段可选,另支持 enabled;任一调度配置字段变更即以当前时间重排 next_run_at

DELETE /v1/scheduled_promotions/{taskId}

删除任务(幂等:任务不存在也返回成功,重复 DELETE 均成功)

POST /v1/scheduled_promotions/{taskId}/trigger

手动立即触发一次(5 分钟 cooldown;上一轮晋升仍在 generating/pending_review 时拒绝)

说明
  • target_kb_id 的权限校验(2026-09-16 起):创建与更新时,target_kb_id 必须是任务归属成员(不是当次请求者)有 editor 及以上权限的知识库——无权返回 403(40303),跨 workspace / 不存在返回 404。此前只校验"这个知识库在不在本 workspace",任何成员都能把定时任务的落库目标指向同 workspace 的任意库(含私有库),此后每次调度都在无人值守的情况下往里写文档。

  • 判定主体用任务归属的 member_id 而不是当次请求身份:任务是长期存在的,执行时点上唯一有意义的主体就是它的归属人。

  • 已存在的任务不会被追溯校验;但执行时同样会过这道闸——如果归属人后来失去了目标库的写权限,该轮晋升会失败并把原因记录在任务的最近错误里,而不是照写。

  • 更新时只在请求体真的带了 auto_approve 或 target_kb_id 时才校验(2026-09-17 修正)。此前是无条件校验,于是一个纯改名请求 PUT {"name": "新名字"} 会把早已存在的 target_kb_id 重判一次;目标库的 ACL 后来收紧之后,改名会莫名 403 / 404,而任务本身根本没碰过那个库。判定对象是"这次请求要建立的新状态",不是历史遗留状态。

请求

  • 请求示例:

curl -X POST "http://<host>:4040/v1/scheduled_promotions" -H "X-API-Key: $USER_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name": "每周架构沉淀", "prompt": "总结本周的架构决策", "schedule_mode": "weekly", "schedule_day_of_week": 1, "schedule_hour": 10, "schedule_minute": 0, "auto_approve": true, "target_kb_id": 3}'
  • 五种模式请求体示例(均为 POST /v1/scheduled_promotions,auto_approve / target_kb_id 等公共字段同上,此处省略):

    • daily——每天 09:00:

      {"name": "每日沉淀", "prompt": "总结当日关键决策", "schedule_mode": "daily", "schedule_hour": 9, "schedule_minute": 0}
    • weekly——每周一 10:00:

      {"name": "周报沉淀", "prompt": "总结本周的架构决策", "schedule_mode": "weekly", "schedule_day_of_week": 1, "schedule_hour": 10, "schedule_minute": 0}
    • monthly——每月 15 号 09:00:

      {"name": "月度沉淀", "prompt": "总结本月里程碑", "schedule_mode": "monthly", "schedule_day_of_month": 15, "schedule_hour": 9, "schedule_minute": 0}
    • interval——每隔 6 小时:

      {"name": "高频沉淀", "prompt": "提炼近期讨论要点", "schedule_mode": "interval", "schedule_interval_hours": 6}
    • cron——工作日 09:00:

      {"name": "工作日沉淀", "prompt": "总结工作日进展", "schedule_mode": "cron", "schedule_cron": "0 0 9 * * 1-5"}

响应

响应示例:

{
  "code": 0, "msg": "ok",
  "data": {
    "id": 12, "member_id": 7, "name": "每周架构沉淀", "prompt": "总结本周的架构决策",
    "schedule_type": "weekly", "schedule_mode": "weekly",
    "schedule_hour": 10, "schedule_minute": 0, "schedule_day_of_week": 1,
    "schedule_day_of_month": null, "schedule_interval_hours": null, "schedule_cron": null,
    "trigger_summary": "每周 周一 10:00",
    "auto_approve": true, "target_kb_id": 3, "enabled": true,
    "last_run_at": null, "next_run_at": "2026-09-14T02:00:00Z", "fire_count": 0,
    "created_at": "2026-09-10T00:00:00Z", "updated_at": "2026-09-10T00:00:00Z"
  }
}

管理面

管理面端点需Owner Key认证,遵循 /ops/** 全 query param 约定(不使用路径参数);不带 memberId 时操作 workspace 全量任务。

方法与路径

说明

GET /ops/scheduled-promotions/list?memberId=&page=&pageSize=

分页列出(可按成员过滤)

GET /ops/scheduled-promotions/detail?task_id=

任务详情

POST /ops/scheduled-promotions/create

创建(请求体同数据面)

PUT /ops/scheduled-promotions/update?task_id=

更新(请求体同数据面)

DELETE /ops/scheduled-promotions/delete?task_id=

删除(幂等,语义同数据面)

POST /ops/scheduled-promotions/trigger?task_id=

手动触发

晋升审批与产物可见性(2026-09-16新增)

  • 审批时判定的是发起人,不是审批人。approve 一条晋升时,校验的是该晋升的 requested_by 成员对目标库有没有 editor 及以上权限——否则 403(40303),且晋升状态原样留在 pending_review(校验在状态 CAS 之前,不会卡在 approving)。这条规则挡住的是“我没有写权,但找个有权的人替我点确认”这条绕行路径。

  • 晋升产物就是一篇普通的知识库文档。落库后它继承目标知识库的 ACL,不自带任何额外可见性:目标库的 viewer 能搜到、能读它、能在 Wiki/图谱里看到;对目标库无权的成员在所有读路径上都拿不到它(403),包括原始记忆的归属人。

  • 审批前的草稿不在知识库路径上存在。pending_review 状态的晋升只出现在晋升列表里,GET /v1/knowledge/bases/{kbId}/documents 等知识库路径上查不到——目标库的成员不会提前看到还没批的内容。

Provider 管理与部署规则边界

模型请求高级 Header/顶层字段删除仅由部署文件在启动时加载(见「配置参考」文档的「模型请求高级配置独立 JSON」章节)。现有 Provider 管理接口仍使用 Box<T>,config_json 保持字符串;没有新增规则读写接口或响应字段。

既有接口

权限与行为

GET /ops/providers?workspaceId=&kind=

全局仅平台 ADMIN;租户仅本工作区 OWNER;响应不合并部署规则

GET /ops/providers/active?workspaceId=&kind=

沿用既有 active 解析与权限,历史 metadata 可读

GET /ops/providers/chain?workspaceId=&kind=

沿用既有 chain 排序、权限及 DTO,历史 metadata 不激活为部署规则

PUT /ops/providers?kind=

主 llm / embedding 有非空部署规则时,全局保存返回 HTTP 409 / CONFLICT(40901),数据库零写入;权限校验先于该检查

POST /ops/providers/reload?kind=

平台 ADMIN;managed kind 的非空 DB chain 返回 409。空 chain 沿用进程内 disable,锁仍保留,重新启用须部署重启

所有 Provider PUT 均拒绝保留命名空间 requestOverrides / request-overrides(外层 DTO 未知字段丢弃前以及 config_json 内检查;空值也拒绝)。这不扩大为对历史 extraHeaders / removeBodyFields 等 metadata 的封禁,不自动迁移数据库或改变合法 GET。

兼容性影响:不改变 endpoint、响应结构、已有字段类型或 Embedding fingerprint。未配置规则时保留原管理/请求/fallback 行为;明确的安全变化为上述新 PUT 命名空间拒绝、全部 Provider PUT 审计正文抑制(动作/身份/结果/trace 保留),以及 ASR 结果下载鉴权隔离与 taskId 路径校验。Provider PUT 的畸形 body/config JSON 错误使用固定提示,不回显提交值或底层解析片段。租户 Provider 配置仍是暂存状态,不会改写全局 live Provider。

Agent 用量上报

供 Agent 运行时上报模型调用用量,便于按 session/agent 维度统计 Token 消耗。

POST /v1/agent-usage

上报一条 Agent 用量记录。

请求

请求参数(扁平结构,不嵌套)

参数

类型

必填

说明

session_id

string

否

关联的会话 ID

agent_type

string

否

Agent 类型标识

model

string

否

模型名称

input_tokens

long

否

输入 Token 数(≥0)

output_tokens

long

否

输出 Token 数(≥0)

turns

integer

否

对话轮次(≥0)

duration_sec

integer

否

持续时长(秒,≥0)

请求示例

curl -X POST "http://<host>:4040/v1/agent-usage" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"session_id": "sess-001", "agent_type": "chat", "model": "qwen-plus", "input_tokens": 1000, "output_tokens": 500, "turns": 3, "duration_sec": 120}'

响应

响应示例

{"code": 0, "msg": "ok", "data": null}

POST /v1/agent-usage/batch

批量上报多条 Agent 用量记录(上限 100 条)。

请求

请求体

JSON 数组,每项结构同单条上报。

请求示例

curl -X POST "http://<host>:4040/v1/agent-usage/batch" \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '[{"session_id": "sess-001", "agent_type": "chat", "model": "qwen-plus", "input_tokens": 500, "output_tokens": 200, "turns": 1, "duration_sec": 30}, {"session_id": "sess-002", "agent_type": "rag", "model": "qwen-max", "input_tokens": 800, "output_tokens": 300, "turns": 2, "duration_sec": 60}]'

Agent 用量统计(管理面)

以下端点运行在管理面端口(默认 8080),需Owner Key。

GET /ops/agent-usage/summary

查询指定时间范围内的 Agent 用量汇总,按 agent_type + model 分组。

请求

Query 参数

参数

类型

必填

说明

from

date

是

起始日期(ISO 格式 YYYY-MM-DD,含)

to

date

是

截止日期(ISO 格式 YYYY-MM-DD,含)

memberId

string

否

按成员过滤

请求示例

curl "http://<host>:8080/ops/agent-usage/summary?from=2026-09-01&to=2026-09-19" -H "X-API-Key: $OWNER_KEY"

响应

响应示例

{"code": 0, "msg": "ok", "data": {"total_tokens": 15000, "total_sessions": 5, "items": [{"agent_type": "chat", "model": "qwen-plus", "input_tokens": 8000, "output_tokens": 4000, "sessions": 3}]}}

GET /ops/agent-usage/trend

查询指定时间范围内的 Agent 用量趋势,按日期分组。

请求

Query 参数

同 summary。

请求示例

curl "http://<host>:8080/ops/agent-usage/trend?from=2026-09-01&to=2026-09-19" -H "X-API-Key: $OWNER_KEY"

审计与合规

审计日志(Audit Logs)

审计日志自动记录 API 操作,Owner Key和User Key均可读取。User Key只能查看自己的操作记录。

GET /v1/audit/logs

分页列出审计日志,支持按操作类型、结果、时间范围过滤。

请求

Query 参数

参数

类型

必填

说明

action

string

否

按操作类型过滤(如 context.ingest、session.create、kb.read、memory.create)

result

string

否

按结果过滤:success / failure

from

string

否

起始时间(ISO-8601,含)

to

string

否

截止时间(ISO-8601,含)

page

integer

否

页码(0-indexed),默认 0

size

integer

否

每页大小,默认 50,上限 200

请求示例

curl "http://<host>:4040/v1/audit/logs?action=context.ingest&result=success&page=0&size=20" \
  -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "content": [
      {
        "id": 42,
        "workspace_id": 1,
        "action": "context.ingest",
        "subject_type": "user",
        "subject_id": "4",
        "result": "success",
        "path": "/v1/context/ingest",
        "created_at": "2026-09-16T01:00:00Z",
        "last_error_short": null
      }
    ],
    "total_elements": 1,
    "total_pages": 1
  }
}

GET /v1/audit/logs/{id}

获取单条审计日志详情,含完整请求/响应信息。

请求

请求示例

curl "http://<host>:4040/v1/audit/logs/42" -H "X-API-Key: $API_KEY"

GET /v1/audit/stats

按指定维度聚合审计统计(操作类型分布、成功率等)。

请求

Query 参数

参数

类型

必填

说明

group_by

string

是

聚合维度:action / result

action

string

否

按操作类型过滤

from

string

否

起始时间(ISO-8601)

to

string

否

截止时间(ISO-8601)

请求示例

curl "http://<host>:4040/v1/audit/stats?group_by=action" -H "X-API-Key: $API_KEY"

响应

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "groups": [
      {"key": {"action": "context.ingest"}, "count": 10, "success_rate": 0.9},
      {"key": {"action": "session.create"}, "count": 25, "success_rate": 0.8}
    ]
  }
}

审计策略(Audit Policies)

审计策略管理需Owner Key(高影响操作,可控制审计链路开关)。

GET /v1/audit/policies

列出当前 workspace 的审计策略。

请求

请求示例

curl "http://<host>:4040/v1/audit/policies" -H "X-API-Key: $OWNER_KEY"

POST /v1/audit/policies

创建一条审计策略。

请求

请求示例

curl -X POST "http://<host>:4040/v1/audit/policies" \
  -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
  -d '{"name": "记录所有写操作", "action_pattern": "*.create|*.update|*.delete", "enabled": true}'

GET /v1/audit/policies/{id}

获取指定审计策略详情。

请求

请求示例

curl "http://<host>:4040/v1/audit/policies/1" -H "X-API-Key: $OWNER_KEY"

PUT /v1/audit/policies/{id}

更新审计策略。

请求

请求示例

curl -X PUT "http://<host>:4040/v1/audit/policies/1" \
  -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
  -d '{"enabled": false}'

DELETE /v1/audit/policies/{id}

删除指定审计策略。

请求

请求示例

curl -X DELETE "http://<host>:4040/v1/audit/policies/1" -H "X-API-Key: $OWNER_KEY"

数据擦除

数据擦除端点均需Owner Key(高影响、不可逆级联删除,不向User Key 开放)。User Key调用返回端口/权限错误。

POST /v1/audit/gdpr/erasure

发起一个 GDPR “被遗忘权”数据擦除作业(异步排队,由后台 worker 全链路级联删除主体数据)。

请求

请求参数

参数

类型

必填

说明

subjectType

string

是

主体类型:user / member

subjectId

string

是

主体标识(user_id 或 member_id)

workspaceId

string

否

目标 workspace;缺省用当前(OWNER 可通过 X-Workspace-Id 定向非宿 workspace)

reason

string

否

擦除原因(审计留存)

scope

string[]

否

限定擦除目标,缺省全链路级联

说明

主体解析失败不会静默成功:subject_id 在该 workspace 内解析不到对应 member(user 无同名 user_id、member 非数字)时,作业终态为 failed 且 last_error 说明 subject unresolved,deleted_counts 为 {};不会回报 done + 全 0 计数。

请求示例

curl -X POST http://<host>:4040/v1/audit/gdpr/erasure \
  -H "X-API-Key: $OWNER_KEY" -H "Content-Type: application/json" \
  -d '{"subjectType": "user", "subjectId": "alice", "reason": "user request"}'

响应

响应示例

{"code": 0, "msg": "ok", "data": {"jobId": 1001, "status": "queued"}}

GET /v1/audit/gdpr/jobs

分页列出当前 workspace 的擦除作业(仅限调用方 workspace)。

请求

请求参数

参数

类型

必填

说明

status

string

否

按状态过滤(如 queued / running / done / failed)

page

integer

否

页码(从0开始),默认 0

size

integer

否

每页大小,默认 50,上限 200

请求示例

curl "http://<host>:4040/v1/audit/gdpr/jobs?status=done&size=20" -H "X-API-Key: $OWNER_KEY"

响应

返回 Box<Page<DetailResponse>>,条目在 content。

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "content": [
      {"id": 1001, "workspace_id": "1", "subject_type": "user", "subject_id": "alice", "status": "done", "attempt_count": 1, "submitted_at": "2026-08-19T10:00:00Z", "completed_at": "2026-08-19T10:00:30Z"}
    ],
    "total_elements": 1,
    "total_pages": 1,
    "number": 0,
    "size": 20
  }
}

GET /v1/audit/gdpr/jobs/{id}

获取单个擦除作业详情,含各目标删除计数与失败时的错误信息。跨 workspace 访问返回错误。

请求

请求示例

curl "http://<host>:4040/v1/audit/gdpr/jobs/1001" -H "X-API-Key: $OWNER_KEY"

响应

响应参数

参数

类型

说明

id

long

作业 ID

workspaceId

string

所属 workspace

subjectType / subjectId

string

擦除主体类型与标识

reason

string

擦除原因

scope

string[]

限定目标;全链路时为 null

status

string

作业状态

attemptCount

int

已尝试次数

lastError

string

最后一次失败的错误信息

deletedCounts

string

各目标删除计数(JSON 字符串)

submittedBy

string

提交方标识

submittedAt / completedAt

string

提交 / 完成时间(ISO-8601)

响应示例

{
  "code": 0, "msg": "ok",
  "data": {
    "id": 1001,
    "workspace_id": "1",
    "subject_type": "user",
    "subject_id": "alice",
    "reason": "user request",
    "scope": null,
    "status": "done",
    "attempt_count": 1,
    "last_error": null,
    "deleted_counts": "{\"memories\":42,\"sessions\":3}",
    "submitted_by": "owner-key-2",
    "submitted_at": "2026-08-19T10:00:00Z",
    "completed_at": "2026-08-19T10:00:30Z"
  }
}

附录:通用错误码

错误码

名称

HTTP Status

说明

0

OK

200

成功

40001

VALIDATION_FAILED

400

参数校验失败

40002

FILTER_SYNTAX_INVALID

400

filter 语法非法

40009

DATA_INTEGRITY_VIOLATION

400

数据完整性冲突(NOT NULL / FK / UK)

40010

SOURCE_CHUNK_READ_ONLY

400

l2:<chunk_id> 为只读投影,不支持按该 ID 读写删

40011

QUOTA_EXCEEDED

429

配额超限(OSS 存储 / 月度 token)

40012

UNSUPPORTED_CHARACTER

400

文本含存储层字符集无法承载的字符

40101

AUTH_INVALID_KEY

401

认证失败(API Key 无效或缺失)

40301

AUTH_PORT_MISMATCH

403

Key 类型与端口不匹配(如 USER key 调管理面)

40302

AUTH_REVOKED

403

API Key 已吊销

40303

ACL_FORBIDDEN

403

Knowledge ACL 校验失败(知识库权限不足)。注意:kbId 跨 workspace 或不存在返回 40401/404 而非 403,不泄漏存在性

40304

FEATURE_DISABLED

403

能力被配置开关关闭

40401

RESOURCE_NOT_FOUND

404

资源不存在

40901

CONFLICT

409

资源冲突

40902

SESSION_CLOSED

409

会话已关闭

42901

RATE_LIMITED

429

请求频率超限

50001

INTERNAL_ERROR

500

服务内部错误

50301

EMBEDDING_UNAVAILABLE

503

Embedding 服务不可用

50302

LLM_UNAVAILABLE

503

LLM 服务不可用

50303

OSS_UNAVAILABLE

503

OSS 服务不可用

50304

SERVICE_UNAVAILABLE

503

依赖的可选运行时组件在当前部署模式不可用

旧版文档错误码迁移对照:早前公开文档的错误码表与服务端实际枚举不符。按旧码编写的错误处理或告警规则请对照替换:

  • 旧 40001(认证失败)→ 40101 AUTH_INVALID_KEY;当前 40001 已表示 VALIDATION_FAILED(参数校验失败)

  • 旧 40003(权限不足)→ 40301 AUTH_PORT_MISMATCH(Key 类型与端口不匹配)/ 40302 AUTH_REVOKED(Key 已吊销)/ 40303 ACL_FORBIDDEN(ACL 校验失败)

  • 旧 40004(资源不存在)→ 40401 RESOURCE_NOT_FOUND

  • 旧 40010(参数校验失败)→ 40001 VALIDATION_FAILED;当前 40010 已表示 SOURCE_CHUNK_READ_ONLY

  • 旧 42900(请求频率超限)→ 42901 RATE_LIMITED;配额超限另用 40011 QUOTA_EXCEEDED(HTTP 429)

  • 旧 50000(服务内部错误)→ 50001 INTERNAL_ERROR

旧码 40003 / 40004 / 42900 / 50000 以及旧表中 40010 的「参数校验失败」语义,服务端从未返回过;40009(数据完整性冲突)码值与语义均未变。

附录:参数别名约定

API 同时接受 snake_case和 camelCase:

  • session_id ↔ sessionId

  • user_id ↔ userId

  • agent_id ↔ agentId

  • top_k ↔ topK

  • kb_ids ↔ kbIds

  • token_budget ↔ tokenBudget

  • keep_recent_n ↔ keepRecentN

  • include_l2 ↔ includeL2

  • vector_only ↔ vectorOnly

  • cosine_threshold ↔ cosineThreshold ↔ threshold