执行工厂 · Skill API (0.1.3)

Download OpenAPI specification:

Skill 是一个文件包——一份 SKILL.md 加上配套脚本与资源,描述「怎么做一件 事」。Agent 按需装载它,而不是把全部说明塞进上下文。

与工具的区别:工具是可调用的函数,Skill 是给 Agent 读的 工作手册 + 随手册附带的可执行文件。召回入口在 context-loader 的 search_capabilities,那边只返回最小元数据;真正的内容读取与下载在这里。

三条读取路径,别用错:

接口 视角 读的是
/skills/{id}/content、/files/read、/download 消费态 已发布的版本
/skills/{id}/management/* 管理态 当前草稿,含未发布改动
/skills/{id}/history + history/publish / history/republish 历史 已发布过的版本

Studio 的编辑页读管理态,Agent 运行时读消费态。拿错会看到不一致的内容。

上传不是 JSON:注册与更新技能包只接受 multipart/form-data 或 application/x-www-form-urlencoded,发 JSON 直接 400 (unsupported content type)。

时间戳一律是纳秒:所有 *_time 字段由 time.Now().UnixNano() 生成。

认证:Authorization: Bearer <token>(OAuth access token 或 bak_ 前缀的 AppKey)。

内部面(internal-v1)的读授权按档位:原有 /content 与 /files/read 在公开面 一律按账户判定(execute / public_access / view 三者有其一),内部面则看 SKILL_INTERNAL_READ_AUTHZ——shadow(默认)查了但不拦、判定不通过只打日志, enforce 与公开面一致返回 403,off 完全不查。分档是为了不打断其它存量内部调用方。 新增的 /internal-v1/caller/skills/... 专供已有可信账户头的服务间调用:它不受该兼容 档位影响,而是与公开面一样按真实调用者强制授权。context-loader 有 bearer 时走公开面, 只有可信账户头时走该 caller-scoped 内部面;两者都不会切换成服务身份绕过权限判断。 调用方没带账户身份时任何档位都跳过判定——那是「无从判断」,不是「判定为无权」。 /execute 不受该档位影响,一直按账户强制且只认 execute,public_access 不能执行。

内部面另有两个只读元数据接口:GET /skills/{skill_id} 与 POST /skills/names。 它们不做调用者维度的判定,答的是「技能是否存在、什么状态」,供 bkn-backend 校验 知识网络能力绑定与回填元数据。

检索入口是统一能力检索:POST /internal-v1/capabilities/search,请求体 { query, refs, top_k, types }。refs 是三段式身份的数组 (capability_type / owner_id / capability_id),Skill 的 owner_id 为空。 只要 Skill 就传 types: ["skill"]。

原先的 POST /internal-v1/skills/search 已随 Skill 专属数据集一起退役。Skill、 函数工具、MCP 工具现在是同一个索引里的文档,在同一个排序空间里竞争——三条 链路各自出结果再首尾相接不是排序:BM25 分数无上界、SQL LIKE 根本没有分数, 拼起来的顺序只表示「哪一堆先放」。

refs 是必填白名单,空数组与字段缺失都返回空结果,不是「不过滤」—— 后者会把全平台能力交给一个没有任何绑定的调用方。执行工厂只收一组身份,不认识 kn_id,语义由调用方负责。

白名单是前置过滤,不是先取 top_k 再相交:它进 knn 字段对象内部的 filter, 引擎在白名单范围内取最近邻。反过来做的话,平台能力一多,只挂了几个能力的网络在 全局 top_k 里一个都轮不到,挂得越少越搜不到。

两个通道分两次请求、按 rank 做 RRF 融合,不拼成一个 should:knn 分数在 0~1、BM25 无上界,OpenSearch 直接相加会把向量命中挤出候选池。

每项出参带 score 与 matched_by:knn(仅向量命中)、match(仅全文命中)、 hybrid(两个通道都命中)、like(不带 query 的枚举,没有排序可言)。

排序没有 reranker,与概念召回是同一个已知问题。 不收进上面的 paths:内部面不校验令牌,按 docs/api/README.md 的口径不作为 集成合同发布。

Skill

注册技能

上传一个技能包。**Content-Type 只接受 multipart/form-data 或 application/x-www-form-urlencoded**,发 application/json 会被直接拒绝, 报 unsupported content type。

file_type 决定 file 字段怎么解读:

file_type file 是什么
zip 技能包压缩文件(multipart 上传)
content 直接给的技能内容

响应里的 files 列出解包后识别到的文件。

Authorizations:
OAuth2AppKey
Request Body schema:
required
file_type
required
string (SkillFileType)
Enum: "zip" "content"

上传形态:zip 是技能包压缩文件,content 是直接给的技能内容。

file
required
string <binary>

技能包。file_type=zip 时是压缩文件,file_type=content 时是内容本身。

category
string
Default: "other_category"

分类。

source
string
Default: "custom"
Enum: "custom" "internal"

来源。

extend_info
string

扩展信息(JSON 字符串)。

Responses

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "name": "string",
  • "description": "string",
  • "version": "string",
  • "status": "unpublish",
  • "files": [
    ]
}

分页查询技能

分页列出当前主体获授权访问的技能,支持按名称、状态、分类、创建人过滤。

Authorizations:
OAuth2AppKey
query Parameters
page
integer >= 1
Default: 1

页码,从 1 开始。

page_size
integer [ 1 .. 100 ]
Default: 10

每页数量,1–100。

sort_by
string
Default: "update_time"
Enum: "create_time" "update_time" "name"

排序字段。

sort_order
string
Default: "desc"
Enum: "asc" "desc"

排序方向。

name
string

按名称过滤。

status
string (BizStatus)
Enum: "unpublish" "published" "offline" "editing"

按状态过滤。

category
string

按分类过滤。

create_user
string

按创建人过滤。

all
boolean

忽略分页返回全部。

Responses

Response samples

Content type
application/json
{
  • "total": 0,
  • "page": 0,
  • "page_size": 0,
  • "total_pages": 0,
  • "has_next": true,
  • "has_prev": true,
  • "data": [
    ]
}

按 ID 批量取技能名

与 /tool-box/names 同契约:不存在的 ID 静默略过、不占位。

**也注册在 internal-v1**。公开面按调用者的 view 过滤(无权限的 ID 与不存在的 ID 一样被略过),内部面不过滤——服务间调用要的是「这些 ID 还在不在」,用于知识网络 能力绑定的元数据回填与悬空判定。

Authorizations:
OAuth2AppKey
Request Body schema: application/json
required
ids
Array of strings

待取名的技能 ID 列表。空列表返回空 entries。

Responses

Request samples

Content type
application/json
{
  • "ids": [
    ]
}

Response samples

Content type
application/json
{
  • "entries": [
    ]
}

查询调用者可发现的已发布技能

从技能发布版本表分页列出当前调用者拥有 view 权限的技能,供 Agent 能力发现使用。 该接口读取已发布快照,不读取工作区仓库行的当前状态;因此已发布技能在编辑下一版本时 仍可被发现。它与 /skills/market 的区别是权限口径:本接口只认 view,市场接口只认 public_access。

Authorizations:
OAuth2AppKey
query Parameters
page
integer >= 1
Default: 1

页码,从 1 开始。

page_size
integer [ 1 .. 100 ]
Default: 10

每页数量,1–100。

sort_by
string
Default: "update_time"
Enum: "create_time" "update_time" "name"

排序字段。

sort_order
string
Default: "desc"
Enum: "asc" "desc"

排序方向。

name
string

按发布版本名称过滤。

category
string

按分类过滤。

create_user
string

按创建人过滤。

all
boolean

忽略分页返回全部。

Responses

Response samples

Content type
application/json
{
  • "total": 0,
  • "page": 0,
  • "page_size": 0,
  • "total_pages": 0,
  • "has_next": true,
  • "has_prev": true,
  • "data": [
    ]
}

技能市场列表

已发布技能的列表。比工作区列表少一个 status 过滤——市场里的都是已发布的。

Authorizations:
OAuth2AppKey
query Parameters
page
integer >= 1
Default: 1

页码,从 1 开始。

page_size
integer [ 1 .. 100 ]
Default: 10

每页数量,1–100。

sort_by
string
Default: "update_time"
Enum: "create_time" "update_time" "name"

排序字段。

sort_order
string
Default: "desc"
Enum: "asc" "desc"

排序方向。

name
string

按名称过滤。

category
string

按分类过滤。

create_user
string

按创建人过滤。

all
boolean

忽略分页返回全部。

Responses

Response samples

Content type
application/json
{
  • "total": 0,
  • "page": 0,
  • "page_size": 0,
  • "total_pages": 0,
  • "has_next": true,
  • "has_prev": true,
  • "data": [
    ]
}

技能市场详情

市场视角的技能详情,结构与 GET /skills/{skill_id} 一致。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Responses

Response samples

Content type
application/json
{
  • "operations": [
    ],
  • "skill_id": "string",
  • "name": "string",
  • "description": "string",
  • "version": "string",
  • "status": "unpublish",
  • "source": "string",
  • "category": "string",
  • "category_name": "string",
  • "dependencies": { },
  • "extend_info": { },
  • "create_user": "string",
  • "create_time": 0,
  • "update_user": "string",
  • "update_time": 0,
  • "release_user": "string",
  • "release_time": 0
}

查询技能详情

取技能的元数据。文件清单与内容走 /content,包体走 /download。

**也注册在 internal-v1**,供 bkn-backend 校验知识网络能力绑定。内部面不做 调用者维度的 view 判定,同一技能对任何调用者返回相同结果;未发布的技能通过 status 字段体现,不返回 404。别拿 /skills/market/{skill_id} 代替它——那条路 走 public_access 且未发布即 404,会把「存在但未发布」误报成「不存在」。

404 只表示技能不存在或已删除。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Responses

Response samples

Content type
application/json
{
  • "operations": [
    ],
  • "skill_id": "string",
  • "name": "string",
  • "description": "string",
  • "version": "string",
  • "status": "unpublish",
  • "source": "string",
  • "category": "string",
  • "category_name": "string",
  • "dependencies": { },
  • "extend_info": { },
  • "create_user": "string",
  • "create_time": 0,
  • "update_user": "string",
  • "update_time": 0,
  • "release_user": "string",
  • "release_time": 0
}

删除技能

删除技能及其全部版本。已被 Agent 挂载的技能删除后装载会失败; 指向它的知识网络能力绑定会变成悬空引用——search_capabilities 列不出来, execute_skill 也执行不了。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Responses

Response samples

Content type
application/json
{
  • "error_code": "string",
  • "description": "string",
  • "error_details": null,
  • "metadata": { }
}

发布 / 下架技能

只接受 published 与 offline 两个值——不能通过这个接口把技能改回 unpublish 或 editing,那两个状态由注册与编辑动作产生。

本面用的是 PUT(工具箱的同类接口用 POST),注意区别。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Request Body schema: application/json
required
status
required
string
Enum: "published" "offline"

目标状态。只接受这两个值。

Responses

Request samples

Content type
application/json
{
  • "status": "published"
}

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "status": "unpublish"
}

更新技能元数据

改名称 / 描述 / 分类,不动技能包本身。三个字段都是必填——整体覆盖。

更新会产生新 version。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Request Body schema: application/json
required
name
required
string
description
required
string
category
required
string
source
string
Enum: "custom" "internal"
object

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "category": "string",
  • "source": "custom",
  • "extend_info": { }
}

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "version": "string",
  • "status": "unpublish"
}

更新技能包

换掉技能的文件内容。与注册一样只接受 form / multipart,不接受 JSON。 更新产生新 version,原版本进历史。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Request Body schema:
required
file_type
required
string (SkillFileType)
Enum: "zip" "content"

上传形态:zip 是技能包压缩文件,content 是直接给的技能内容。

file
required
string <binary>

新的技能包内容。

Responses

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "version": "string",
  • "status": "unpublish"
}

查询技能发布历史

列出该技能发布过的版本,含每次发布的说明与发布人。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Responses

Response samples

Content type
application/json
[
  • {
    }
]

把历史版本回灌成草稿

取某个历史版本的内容,写回当前草稿——不直接发布。用于「拿旧版本当起点 继续改」。改完再走正常发布流程。

与 history/publish 的区别:那个是直接发布旧版本,跳过草稿。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Request Body schema: application/json
required
version
required
string

要回灌的历史版本。

Responses

Request samples

Content type
application/json
{
  • "version": "string"
}

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "version": "string",
  • "status": "unpublish"
}

直接发布历史版本

把某个历史版本直接发布成当前版本,跳过草稿。回滚用。 草稿里未发布的改动不受影响,仍留在草稿态。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Request Body schema: application/json
required
version
required
string

要发布的历史版本。

Responses

Request samples

Content type
application/json
{
  • "version": "string"
}

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "version": "string",
  • "status": "unpublish"
}

查询技能内容(消费态)

返回已发布版本的文件清单与包地址。Agent 运行时读的是这个。

要看草稿里未发布的改动,用 /management/content。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Responses

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "url": "string",
  • "status": "unpublish",
  • "files": [
    ]
}

读取技能内的单个文件(消费态)

按包内相对路径读一个文件。返回的是文件的下载 URL 而不是内容本身—— 拿到 url 再去取。路径从 /content 返回的 files[].rel_path 里挑。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Request Body schema: application/json
required
rel_path
required
string

包内相对路径,取自 /content 的 files[].rel_path。

Responses

Request samples

Content type
application/json
{
  • "rel_path": "SKILL.md"
}

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "rel_path": "string",
  • "url": "string",
  • "mime_type": "string",
  • "file_type": "string"
}

下载技能包(消费态)

下载已发布版本的技能包。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Responses

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "file_name": "string",
  • "content": "string"
}

查询技能内容(管理态)

/content 的管理态版本:读的是当前草稿,含尚未发布的改动。 Studio 的编辑页用它。

响应结构与消费态不同,比 /content 多了 name / description / version / source / file_type,以及 response_mode=content 时的 content 正文——编辑页要一次拿全,不想再跑一趟详情接口。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

query Parameters
response_mode
string
Default: "url"
Enum: "url" "content"

url(默认)只给包地址与文件清单;content 额外把技能正文塞进 content 字段,省一次取文件的往返。

Responses

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "name": "string",
  • "description": "string",
  • "version": "string",
  • "status": "unpublish",
  • "source": "string",
  • "file_type": "zip",
  • "url": "string",
  • "content": "string",
  • "files": [
    ]
}

读取技能内的单个文件(管理态)

/files/read 的管理态版本:读草稿里的文件。默认返回下载地址; response_mode=content 时直接返回文件文本内容。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

query Parameters
response_mode
string
Default: "url"
Enum: "url" "content"

url(默认)返回文件下载地址 url,不带 content;content 把文件 内容放进 content 字段(url 为空串)。content 模式下文件按文本读取 下载,二进制文件不适用。

Request Body schema: application/json
required
rel_path
required
string

包内相对路径。

Responses

Request samples

Content type
application/json
{
  • "rel_path": "string"
}

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "rel_path": "string",
  • "url": "string",
  • "mime_type": "string",
  • "file_type": "string",
  • "size": 0,
  • "content": "string"
}

下载技能包(管理态)

/download 的管理态版本:下的是当前草稿。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Responses

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "file_name": "string",
  • "content": "string"
}

执行技能

在沙箱里跑技能包里的一条命令。技能包被上传到沙箱工作目录,然后执行 entry_shell 指定的命令。

当前主体必须对具体 skill:{skill_id} 持有 execute。请求体不能替换 OAuth/AppKey 或受信任内部上下文产生的执行主体。

mocked 字段要看:为 true 表示这次并没有真的在沙箱里执行 (沙箱不可用等原因下的降级),返回的 stdout/stderr 不是真实结果。

与函数执行一样,命令失败不体现在 HTTP 状态码上——看 exit_code。

Authorizations:
OAuth2AppKey
path Parameters
skill_id
required
string

技能 ID。

Request Body schema: application/json
required
entry_shell
required
string

要执行的命令。

timeout
integer

超时(秒)。

Responses

Request samples

Content type
application/json
{
  • "entry_shell": "python scripts/run.py --mode full",
  • "timeout": 0
}

Response samples

Content type
application/json
{
  • "skill_id": "string",
  • "session_id": "string",
  • "work_dir": "string",
  • "file_name": "string",
  • "uploaded_path": "string",
  • "command": "string",
  • "exit_code": 0,
  • "stdout": "string",
  • "stderr": "string",
  • "execution_time": 0,
  • "mocked": true
}

SkillIndex

创建技能索引构建任务

重建技能的检索索引——search_capabilities 的语义召回依赖它。

execute_type 决定范围:full 全量重建,incremental 只处理游标之后 变更的技能。任务异步执行,用返回的 task_id 查进度。

Authorizations:
OAuth2AppKey
Request Body schema: application/json
required
execute_type
required
string (IndexExecuteType)
Enum: "full" "incremental"

索引构建范围:全量 / 增量。

Responses

Request samples

Content type
application/json
{
  • "execute_type": "full"
}

Response samples

Content type
application/json
{
  • "task_id": "string",
  • "status": "pending",
  • "execute_type": "string"
}

查询索引构建任务列表

分页列出索引构建任务。

**status 过滤不接受 canceled**:任务状态本身有 5 个值 (pending / running / completed / failed / canceled), 但这个查询参数的白名单只有前 4 个,传 canceled 会 400。

Authorizations:
OAuth2AppKey
query Parameters
page
integer >= 1
Default: 1

页码,从 1 开始。

page_size
integer [ 1 .. 100 ]
Default: 10

每页数量,1–100。

sort_by
string
Default: "update_time"
Enum: "create_time" "update_time" "name"

排序字段。

sort_order
string
Default: "desc"
Enum: "asc" "desc"

排序方向。

status
string
Enum: "pending" "running" "completed" "failed"

按状态过滤。**不接受 canceled**,尽管任务确实会有这个状态。

execute_type
string (IndexExecuteType)
Enum: "full" "incremental"

按执行类型过滤。

create_user
string

按创建人过滤。

all
boolean

忽略分页返回全部。

Responses

Response samples

Content type
application/json
{
  • "total": 4,
  • "page": 1,
  • "page_size": 2,
  • "total_pages": 2,
  • "has_next": true,
  • "has_prev": false,
  • "data": [
    ]
}

查询索引构建任务详情

取单个任务的进度与计数。

Authorizations:
OAuth2AppKey
path Parameters
task_id
required
string

索引构建任务 ID。

Responses

Response samples

Content type
application/json
{
  • "task_id": "string",
  • "status": "pending",
  • "execute_type": "string",
  • "queue_state": "string",
  • "total_count": 0,
  • "success_count": 0,
  • "delete_count": 0,
  • "failed_count": 0,
  • "retry_count": 0,
  • "max_retry": 0,
  • "cursor_update_time": 0,
  • "cursor_skill_id": "string",
  • "error_msg": "string",
  • "create_user": "string",
  • "create_time": 0,
  • "update_time": 0,
  • "last_finished_time": 0
}

取消索引构建任务

取消排队中或运行中的任务。响应里的 action 说明实际做了什么, queue_state 说明取消时任务在队列里的位置——已经跑完的任务取消是无操作。

Authorizations:
OAuth2AppKey
path Parameters
task_id
required
string

索引构建任务 ID。

Responses

Response samples

Content type
application/json
{
  • "task_id": "string",
  • "action": "string",
  • "queue_state": "string"
}

重试索引构建任务

以失败任务为模板新建一个任务重跑。响应里 source_task_id 是原任务、 task_id 是新任务——原任务记录保留不变。

Authorizations:
OAuth2AppKey
path Parameters
task_id
required
string

索引构建任务 ID。

Responses

Response samples

Content type
application/json
{
  • "source_task_id": "string",
  • "task_id": "string",
  • "status": "pending",
  • "execute_type": "string"
}