Dify Console API OpenAPI 契约文档精读:790 个管理端点、认证模型与自动文档生成管线
api/openapi/markdown/console-openapi.md 是 Dify 控制台管理接口(Console API)的完整 OpenAPI 契约 Markdown 版本,共约 2.5 万行,覆盖账号、应用、工作空间、知识库、Agent 等全部后端管理端点及字段级 Schemas。本文基于该文档逐节拆解其端点全貌、认证与安全约束、典型接口签名,并结合 文档生成脚本、规范导出器 与 控制器注册入口 等仓库源码,说明这份文档是如何从 Flask-RESTX 路由“无损”生成、如何保证与实现同源,以及开发者应如何消费与再生成它。
一、文档定位:Console 管理面的机器可读契约
console-openapi.md 对应运行时的 JSON 契约 /console/api/openapi.json。从 规范导出器 可以看到四个 API 面的映射关系:
| 运行时规范地址 | 导出的 JSON 文件 | 导出的 Markdown 文件 |
|---|---|---|
/console/api/openapi.json |
console-openapi.json |
console-openapi.md |
/api/openapi.json |
web-openapi.json |
web-openapi.md |
/v1/openapi.json |
service-openapi.json |
service-openapi.md |
/openapi/v1/openapi.json |
openapi-openapi.json |
openapi-openapi.md |
四份文档同源、同管线生成,本文只聚焦其中的 console 面。该契约的标题与版本直接来自 控制器注册入口:
bp = Blueprint("console", __name__, url_prefix="/console/api")
api = ExternalApi(
bp,
version="1.0",
title="Console API",
description="Console management APIs for app configuration, monitoring, and administration",
)
因此文档头部的 “Console management APIs for app configuration, monitoring, and administration” 与 “Version: 1.0” 不是手工维护的文案,而是 ExternalApi 初始化参数的直接投影——改代码即改文档,天然防止文档漂移。
1.1 文档的四大组成部分
按行号划分,console-openapi.md 的结构非常规整:
- 头部元信息(L1-L11):标题、描述、版本、可用授权方式;
## console命名空间(L12 起,约 13000 行):790 个端点的完整签名,含参数表、请求体表、响应表;## default命名空间 + Schemas 附录(L13012 起):default命名空间收录未挂到/console前缀下的端点(如GET /explore/banners),随后### Schemas附录从 L13031 一直排到文档主体末尾,给出全部*Payload、*Response等模型的字段表,字段以[AccountResponse](#accountresponse)形式的锚点与端点表互相引用;## FastOpenAPI Preview (OpenAPI 3.1)附录(L25016 起):Dify 正在验证的 OpenAPI 3.1 新管线的 PoC 输出,目前仅含少量初始化类端点。
1.2 认证方式:Bearer 声明
文档头部明确声明:
Available authorizations — Bearer (HTTP, bearer):Use the Service API key as a Bearer token in the Authorization header. Bearer format:
API_KEY
即把 API Key 原样放入 Authorization: Bearer <API_KEY>。从源码结构看,Console 命名空间同时存在两类准入路径:一类是 login、refresh-token、email-register 等建立的会话流(见 auth 控制器),另一类是各资源接口上的准入装饰器,例如 spec.py 中的 @console_account_admission(),在返回 JSON 前完成账号级会话校验。消费该文档时,应以具体端点是否依赖登录态为准,而非只看头部授权声明。
二、端点全貌:按资源域划分的 790 个接口
对文档全部端点标题做统计后,各资源域(/console/api/<域>)的分布为:
| 资源域 | 端点数 | 典型能力 |
|---|---|---|
workspaces |
223 | 成员、模型供应商、工具、插件、RBAC、端点密钥等管理面 |
apps |
175 | 传统应用(chat/completion/workflow)的配置、日志、运行与统计 |
datasets |
81 | 知识库、文档、分段、外部知识库 |
agent |
57 | 新版 Agent 应用:清单、构建草稿、Composer、配置文件与技能包 |
rag |
53 | RAG 管线:数据源授权、内容预览、管线工作流与草稿变量 |
snippets |
37 | 代码片段工作流及其草稿变量 |
installed-apps |
27 | 已安装应用(模板市场安装物)管理 |
account |
17 | 当前账号资料、改密、换邮箱、教育认证、注销 |
oauth |
15 | OAuth 2.1 设备码/OAuth Server 相关 |
trial-apps |
14 | 试用应用目录与用量 |
auth 及其余(activate、login、billing、tags、mcp 等) |
约 80 | 登录激活、计费、标签、MCP 等 |
下面按资源域继承原文档的关键端点签名(参数、请求体、响应表均摘自文档,未做删减改写)。
2.1 账号域(/account,17 个端点)
账号域是 Console 管理面的“自身管理”入口,文档给出如下端点集合:
| 方法与路径 | 请求体 | 成功响应 |
|---|---|---|
GET /account/avatar |
query:avatar(必填,Avatar file ID) |
200 AvatarUrlResponse |
POST /account/change-email |
ChangeEmailSendPayload |
200 SimpleResultDataResponse |
POST /account/change-email/check-email-unique |
CheckEmailUniquePayload |
200 SimpleResultResponse |
POST /account/change-email/reset |
ChangeEmailResetPayload |
200 AccountResponse |
POST /account/change-email/validity |
ChangeEmailValidityPayload |
200 VerificationTokenResponse |
POST /account/delete |
AccountDeletePayload |
200 SimpleResultResponse |
POST /account/delete/feedback |
AccountDeletionFeedbackPayload |
200 SimpleResultResponse |
GET /account/delete/verify |
无 | 200 SimpleResultDataResponse |
GET /account/education |
无 | 200 EducationStatusResponse |
POST /account/education |
EducationActivatePayload |
200 EducationActivateResponse |
GET /account/education/autocomplete |
query:keywords(必填)、limit(默认 20)、page |
200 EducationAutocompleteResponse |
GET /account/education/verify |
无 | 200 EducationVerifyResponse |
POST /account/init |
AccountInitPayload |
200 SimpleResultResponse |
GET /account/integrates |
无 | 200 AccountIntegrateListResponse |
POST /account/password |
AccountPasswordPayload |
200 AccountResponse |
GET /account/profile |
无 | 200 AccountResponse |
PATCH /account/profile |
AccountProfilePatchPayload |
200 AccountResponse |
值得注意的演进痕迹:文档中 5 个端点以删除线标记为 DEPRECATED(POST /account/avatar、/account/interface-language、/account/interface-theme、/account/name、/account/timezone),并统一注明 “Use PATCH /account/profile instead”。这说明账号资料(昵称、界面语言、界面主题、时区、头像)已从多个单字段 POST 收敛为单个 PATCH 部分更新语义,而废弃端点仍保留在契约中以兼容存量客户端。全文共有 9 个此类废弃端点,阅读文档时看到 ~~[POST] ...~~ 加粗 DEPRECATED 标记即应改走替代端点。
2.2 激活与邀请:带安全语义的 /activate
邀请激活接口在文档中附带了少见的行为级安全说明(原文继承):
POST /activate:Accept an invitation without letting an existing session act for another account。token-only 激活对旧客户端仍然可用;当请求已携带 Console 会话时,该会话必须属于邀请 token 所编码的账号,才会消费 token 或变更租户成员关系。请求体ActivatePayload,成功返回 200ActivationResponse,400 表示已激活或 token 无效。GET /activate/check:校验激活 token 是否有效,query 参数token(必填)、email(可选)、workspace_id(可选),返回 200ActivationCheckResponse。
这种“请求携带的会话身份必须与 token 内嵌身份一致”的约束,属于在 API 层防御会话混淆(session fixation / 账号切换竞态)的典型设计,文档把它直接写进端点描述而非隐藏在实现里,是这份契约的一个亮点。
2.3 应用清单:GET /agent 的参数表样例
新版 Agent 应用域(/agent,57 个端点)是文档中最完整的 CRUD + 子资源示例之一。以 GET /agent 的参数表为例(完整继承原文档):
| 参数 | 位置 | 说明 | 必填 | 类型 |
|---|---|---|---|---|
creator_ids |
query | Filter by creator account IDs | 否 | string[] |
is_created_by_me |
query | Filter by creator | 否 | boolean |
limit |
query | Page size (1-100) | 否 | integer,默认 20 |
mode |
query | App mode filter | 否 | string,可选值 "advanced-chat", "agent", "agent-chat", "all", "channel", "chat", "completion", "workflow",默认 all |
name |
query | Filter by app name | 否 | string |
page |
query | Page number (1-99999) | 否 | integer,默认 1 |
publication_status |
query | 已发布/草稿 Agent 配置状态过滤 | 否 | string,可选值 "drafts", "published" |
sort_by |
query | 排序 | 否 | string,可选值 "earliest_created", "last_modified", "recently_created",默认 last_modified |
tag_ids |
query | Filter by tag IDs | 否 | string[] |
成功返回 200 AgentAppPagination。写操作的错误语义同样完整:
POST /agent(创建):请求体AgentAppCreatePayload;201 返回AgentAppDetailWithSite,400 参数非法,403 权限不足,409 名称已存在;PUT /agent/{agent_id}(更新):200AgentAppDetailWithSite,400/403 同上;DELETE /agent/{agent_id}:204 成功(无响应体),403 权限不足;POST /agent/{agent_id}/copy(复制):201 返回新应用详情,400/403 同上。
/agent/{agent_id} 下的子资源覆盖了 Agent 应用的一整套生命周期能力,均按“资源/动作”子路径组织:
- Service API 访问:
GET /api-access、POST /api-enable(请求体AgentApiStatusPayload)、GET|POST /api-keys(POST 201 返回ApiKeyItem,400 表示超出最大 key 数)、DELETE /api-keys/{api_key_id}(204); - 音频转写:
POST /audio-to-text使用multipart/form-data(file二进制 +draft_type可选debug_build|draft,默认draft),错误码区分 400(语音转文字未启用或音频不支持)、404(Agent 或构建草稿不存在)、413(音频过大); - 构建草稿(build-draft):
GET|PUT|DELETE /build-draft、POST /build-draft/apply(应用草稿)、POST /build-draft/checkout(检出,请求体AgentBuildDraftCheckoutPayload)、POST /build-chat/finalize(运行一轮“让 Agent 推送配置更新”的构建对话); - Composer:
GET|PUT /composer、GET /composer/candidates、POST /composer/validate,请求体统一为ComposerSavePayload; - 配置文件与技能包:
GET|POST /config/files、DELETE /config/files/{name}、GET /config/files/{name}/download|preview、GET /config/manifest、GET /config/skills、POST /config/skills/upload(multipart 上传 zip 技能包)、DELETE /config/skills/{name}、GET /config/skills/{name}/inspect|download以及技能包内文件的content|preview|download(download/preview需带path参数指向 zip 内归一化成员路径)。这些端点普遍支持draft_type(省略或draft为普通草稿,debug_build为构建草稿)与version_id(只读查看已发布快照)两个 query 参数,形成“草稿面 × 版本面”的双维寻址; - 消息与会话:
GET /chat-messages(必填conversation_id,first_id+limit(1-100,默认 20)做无限滚动分页,返回MessageInfiniteScrollPaginationResponse)、GET /chat-messages/{message_id}/suggested-questions、POST /chat-messages/{task_id}/stop(停止生成中任务)。
2.4 工作空间域:管理面的最大体量
/workspaces 域贡献了全部 223 个端点中的最大份额,覆盖成员管理(邀请、转移 Owner、RBAC)、模型与工具供应商配置、插件管理、端点密钥、模型负载均衡(load_balancing_config)等。文档中同样收录了静态资源型端点,例如 GET /workspaces/{tenant_id}/model-providers/{provider}/{icon_type}/{lang} 返回模型供应商图标(200,无 JSON 响应体)。这些端点的控制器分布在 controllers/console/workspace/ 目录下,与文档一一对应。
2.5 default 命名空间
## default 段(L13012)收录了不挂在 console 命名空间路径下的端点,目前为 GET /explore/banners(query:language,默认 en-US,返回 BannerListResponse)。随后 L13031 的 ### Schemas 附录给出全部被引用的请求/响应模型字段表,例如 AIModelEntity 字段包括 fetch_from、label(i18n 对象)、model、model_properties、model_type、parameter_rules、pricing 等,与端点表通过锚点链接([PriceConfig](#priceconfig))构成可跳转的交叉引用网络。
三、FastOpenAPI Preview:OpenAPI 3.1 预览段
文档末尾(L25016 起)是 ## FastOpenAPI Preview (OpenAPI 3.1) 段,标题即 “FastOpenAPI proof of concept for Dify API”。这一段不是手工补写的,而是由独立管线生成后降级标题两档追加到 console 文档末尾的(见 生成脚本 的 _append_fastopenapi_markdown)。当前 PoC 段收录的端点与模型如下(完整继承原文档):
| 方法与路径 | 说明 | 请求体 / 参数 | 成功响应 |
|---|---|---|---|
GET /console/api/init |
Get initialization validation status | 无 | 200 InitStatusResponse |
POST /console/api/init |
Validate initialization password | InitValidatePayload |
201 InitValidateResponse |
GET /console/api/ping |
Health check endpoint for connection testing | 无 | 200 PingResponse |
GET /console/api/setup |
获取系统安装状态;设计上未认证——首次引导期还没有管理员账号,前端初始化必须能在任何登录流存在之前查询安装进度,因此只允许返回 bootstrap-safe 的状态信息 | 无 | 200 SetupStatusResponse |
POST /console/api/setup |
以管理员账号初始化系统;设计上未认证,仅限自托管版(COMMUNITY 与 ENTERPRISE),由一次性安装守卫与 init-password 校验而非用户会话来保护 |
SetupRequestPayload |
201 SetupResponse |
GET /console/api/version |
检查应用版本更新 | query:current_version(必填) |
200 VersionResponse |
对应模型定义了首装引导的完整字段契约:SetupRequestPayload(email 必填、name 必填且最长 30 字符、password 必填、language 可选)、SetupStatusResponse(step 枚举 finished|not_started,setup_at 为 ISO 时间)、InitStatusResponse(status 枚举 finished|not_started)、VersionResponse(version + release_notes)、ErrorSchema(details/message/status/type 错误四元组)。值得注意的是,文档把“该端点为何不认证”直接写进端点描述——这类安全边界说明通常只存在于内部设计文档,出现在自动生成的契约里对 Agent 调用方与第三方集成者都有直接价值。
四、文档如何生成:从路由到 Markdown 的完整管线
理解“文档为什么长这样”,关键在于 api/dev/ 下三个脚本的协作。整条管线刻意不启动完整后端,这也是文档与代码保持同源却又不依赖运行环境的设计核心。
4.1 第一步:不启动后端导出 OpenAPI JSON
generate_swagger_specs.py 的 docstring 说明了动机:正常后端启动会急加载数据库、Redis、Celery 与存储扩展,而导出契约只需要序列化 Flask-RESTX 的 /openapi.json。其 create_spec_app() 的做法是:
- 通过
apply_runtime_defaults()注入最小配置(SECRET_KEY=spec-export、本地存储路径、强制SWAGGER_UI_ENABLED=True); - 新建一个裸
Flask应用,仅注册controllers.console、controllers.web、controllers.service_api、controllers.openapi四个 blueprint,让路由装饰器在导入期完成登记; - 对每个 namespace 调用
_materialize_inline_model_definitions(),把遗留代码里匿名的fields.Nested({...})内联字段映射,用 SHA-1 签名指纹改写成稳定命名的_AnonymousInlineModel_<12位摘要>命名模型,保证输出确定且可 diff; - 在
app.test_request_context(target.route)中调用Swagger(api).as_dict(),再经 flask_restx_compat.finalize_openapi_payload 排序数组后落盘为键序稳定的console-openapi.json等四个文件。
4.2 第二步:swagger-markdown 转换与三处定点修补
generate_swagger_markdown_docs.py 以 swagger-markdown@3.0.0(npx --yes swagger-markdown@3.0.0 -i <spec> -o <out>)做 JSON→Markdown 转换,并在转换前后做四件确定性的修补,这些细节直接解释了本文档的版式特征:
- 去 null 值(
_drop_null_values_for_markdown):仅对转换器临时输入剔除 null 成员,避免空字段干扰渲染; - union 类型回填(
_patch_union_schema_markdown):swagger-markdown对oneOf/anyOf联合类型会把表格单元格留空,脚本会解析 spec 中每个 schema 的属性与联合变体,把[Ref](#anchor)形式的类型链接回填进表格——这就是文中大量[ string ]、string, **Available values:** "a", "b"写法由生成器统一产出的原因; - 通配媒体类型防误渲染(
_patch_wildcard_media_type_markdown):把***/***改写为`*/*`,防止 Markdown 把*/*当强调符; - 行尾空白清理(
_strip_trailing_line_whitespace):仅去尾随空白,不改变行结构,保证产物可稳定 diff。
对 FastOpenAPI 的 spec 则走 _append_fastopenapi_markdown():先把其 Markdown 的标题统一降级两档(# → ###),再挂到 console 文档的 ## FastOpenAPI Preview (OpenAPI 3.1) 之下;同时删除历史遗留的合并版 api-reference.md(STALE_COMBINED_MARKDOWN_FILENAME),防止双份文档并存。
4.3 本地再生成与校验命令
文档头部没有手工维护项,官方推荐的再生产与校验方式是(摘自 API_SCHEMA_GUIDE.md 的 “Verifying Swagger” 一节):
# schema 与文档相关单元测试
uv run --project . pytest tests/unit_tests/controllers/common/test_schema.py
uv run --project . pytest tests/unit_tests/commands/test_generate_swagger_specs.py tests/unit_tests/controllers/test_swagger.py
# 重新导出 OpenAPI JSON 并抽查
uv run --project . dev/generate_swagger_specs.py --output-dir /tmp/dify-openapi-check
生成 Markdown 全量文档(含 FastOpenAPI 追加段)则运行:
cd api && uv run python dev/generate_swagger_markdown_docs.py \
--openapi-dir openapi --markdown-dir openapi/markdown --keep-swagger-json
其中 --keep-swagger-json 会保留中间 JSON spec 便于比对;--openapi-dir/--markdown-dir 分别控制 JSON 与 Markdown 的落盘目录(默认 openapi/ 与 openapi/markdown/,即本文档所在目录)。指南同时给出 jq 抽查清单:GET 参数必须是 in: query、请求体只出现在有 body 的端点、响应引用期望的 *Response schema、响应 schema 使用公开序列化名而非 inputs_dict 之类内部校验别名。
4.4 契约与实现同源的命名与注册约定
文档里 *Payload/*Query/*Response 的系统化命名不是格式巧合,而是 API_SCHEMA_GUIDE.md 强约束的实现模式:请求体用 Payload 后缀的 Pydantic 模型,query 参数用 Query 后缀模型并通过 query_params_from_model(...) 展开(禁止对 GET 使用 @ns.expect,那会把 query 参数错标成请求体),响应 DTO 继承 fields.base.ResponseModel 并经 dump_response(...) 显式序列化。运行时校验与 Swagger 文档绑定在同一个 Pydantic 模型上——这正是 console-openapi.md 中每个端点的参数表、请求体表能与真实校验行为完全一致的根本原因。
五、消费这份文档的三种姿势
- 集成开发(面向人):以本文为端点目录与字段字典,按资源域定位能力;所有枚举、默认值、取值范围(如
limit1-100、page1-99999)直接来自 Pydantic 约束,可原样用于客户端代码生成与请求构造; - 面向 LLM/Agent 的工具调用:文档的“端点 → 参数表 → 响应 Schema 锚点”结构天然适合检索式消费——按资源域前缀检索端点,再顺锚点跳转到 Schemas 附录取字段定义。FastOpenAPI 3.1 段的出现意味着未来将有一份原生 3.1 JSON 契约可供更强的代码生成链路消费;
- 变更审查(面向维护者):由于文档是生成物,任何 PR 只要改动控制器模型或路由,重跑 4.3 节的管线即可在 diff 中看到契约变化;这也是仓库选择“CI 与本地再生成都走同一转换器”的原因——转换器不兼容的 OpenAPI 输出会在再生成阶段被提前暴露。
六、小结
console-openapi.md 不是一篇需要人工维护的 API 手册,而是 Dify Console 管理面(790 个端点、四个 API 面之一)在 Flask-RESTX 路由与 Pydantic 模型之上自动投影出的机器可读契约:端点签名、枚举、默认值、废弃标记(9 个)与安全语义说明(如 /activate 的会话一致性约束、/setup 的免认证引导边界)全部与实现同源。配合 文档生成脚本、规范导出器 与 API 模式指南,本文给出了从“读懂这份 2.5 万行契约”到“再生成、校验与消费它”的完整路径。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00