Dify /openapi/v1 用户域 OpenAPI 深度指南:Bearer 鉴权、端点全解与源码实现剖析
本文以 Dify 仓库中 openapi-openapi.md 这份 /openapi/v1 面的完整接口规范为骨架,逐组讲解其用户域(user-scoped)操作端点、请求/响应契约与鉴权模型,并结合 api/controllers/openapi/ 下的控制器源码说明版本门禁、分页封装、字段裁剪等关键机制的实现原理。读完本篇后,你可以用 Bearer Token 完整驱动 Dify 的应用运行、DSL 导入导出、工作区与成员管理、会话吊销以及 OAuth 设备授权流程,并能定位每个契约在源码中的定义位置。
1. OpenAPI 面是什么:定位、前缀与版本
Dify 后端暴露了多个 API 面(console、service、web、inner 等),其中 /openapi/v1 是面向用户域程序化访问的独立面:所有操作都以“某个账号(或 SSO 外部身份)”为主体,使用 Bearer Token 鉴权,主要服务于 difyctl CLI 与程序化客户端。规范文档明确其版本为 1.0,授权方式为:
- Bearer(HTTP, bearer):将 Service API key 作为 Bearer token 放入
Authorization头,格式为Bearer API_KEY。
这一面在 api/controllers/openapi/init.py 中注册,源码与规范文档一一对应:
bp = Blueprint("openapi", __name__, url_prefix="/openapi/v1")
attach_anti_framing(bp)
attach_version_gate(bp)
api = ExternalApi(
bp,
version="1.0",
title="OpenAPI",
description="User-scoped programmatic API (bearer auth)",
error_body_formatter=OpenApiErrorFormatter(),
)
openapi_ns = Namespace("openapi", description="User-scoped operations", path="/")
几个值得注意的工程细节(均有源码依据):
api并非普通 flask_restxApi,而是 libs/external_api.py 中的ExternalApi,并挂接了统一的错误体格式化器OpenApiErrorFormatter(定义于 api/controllers/openapi/_errors.py),这正是所有端点default: Error统一返回ErrorBody的来源。attach_anti_framing(bp)来自 libs/device_flow_security.py,为整个蓝图添加防嵌套框架(anti-framing)安全响应头。attach_version_gate(bp)是客户端版本门禁,见下文第 2.2 节。- api/controllers/openapi/init.py 中先集中
register_schema_models/register_response_schema_models/register_enum_models注册全部请求、响应与枚举模型,再导入各控制器模块,保证@returns/@accepts装饰器能解析模型名——这与规范文档末尾 "Schemas" 一节列出的模型清单完全同源。
2. 元端点与版本门禁:/_health、/_version
2.1 免鉴权探针
规范中列出的前两个端点不需要 Bearer 认证,实现见 api/controllers/openapi/index.py:
| 端点 | 说明 | 200 响应 |
|---|---|---|
GET /_health |
存活检查 | HealthResponse:{ "ok": true } |
GET /_version |
服务器版本 | ServerVersionResponse:version(字符串)+ edition(DeploymentEdition 枚举) |
源码中 ServerVersionResponse 直接取 dify_config.project.version 与 dify_config.DEPLOYMENT_EDITION 两个配置值。HealthResponse 的模型注释写明 "no auth required",与文档中这两个端点只声明 200/default 的响应表一致。
2.2 客户端版本门禁(426 Upgrade Required)
/openapi/v1 面与 difyctl CLI 同步演进。api/controllers/openapi/_version_gate.py 实现了一个应用级请求钩子:
- 仅拦截
User-Agent匹配difyctl/<semver>的请求(正则见 _version_gate.py); - 与
dify_config.tool.dify.min_difyctl_version比较,只比较 major.minor.patch 数值核(避免0.2.0-rc.1这类预发布版本被误判低于0.2.0下限); - 版本过低的客户端收到
426,响应体是标准ErrorBody:code为UPGRADE_REQUIRED,hint指向 difyctl 升级说明(docs.dify.ai 的 CLI 安装文档); - 白名单路径
/openapi/v1/_version与/openapi/v1/_health永远放行,保证过旧客户端仍能"发现自己过旧"; - 钩子注册在
before_app_request而非蓝图级before_request,因此即使用户过旧客户端调用已删除的路径(本应 404),也会先收到 426 升级提示; - 对非 difyctl 或无法解析的 User-Agent 采用"失败放行"策略,只有可确认过旧时才拦截。
这对集成方的实际含义:调用该面时建议带上规范化的 User-Agent(difyctl/x.y.z (<os>; <arch>; <channel>)),以便在服务端升级破坏性路径时获得明确的 426 而非裸 404。
3. 账户与会话管理:/account、/account/sessions
| 方法 | 路径 | 说明 | 关键响应 |
|---|---|---|---|
| GET | /account |
当前账户信息 | AccountResponse |
| GET | /account/sessions |
会话列表(查询参数 limit 默认 100、page 默认 1) |
200 SessionListResponse;422 校验错误 |
| DELETE | /account/sessions/self |
吊销当前会话 | 200 RevokeResponse:{ "status": ... } |
| DELETE | /account/sessions/{session_id} |
吊销指定会话 | 200 RevokeResponse |
相关契约(对应文档 Schemas 节):
- AccountResponse:
subject_type(必填)、subject_email、subject_issuer、account(AccountPayload:id/email/name均必填)、default_workspace_id、workspaces(WorkspacePayload[],每项含id/name/role)。 - SessionRow:
id、client_id、device_label、prefix必填;created_at、expires_at、last_used_at可选——即每个设备授权会话都携带设备标签与 token 前缀,便于管理员识别"哪个设备、哪条 token"。 - 会话列表分页查询模型
SessionListQuery标注 "Strict (extra='forbid')",即传入未定义参数会直接 422,这是该面分页契约的统一风格(MemberListQuery、PermittedExternalAppsListQuery同理)。
4. 工作区:列表、切换、成员管理
| 方法 | 路径 | 说明 | 响应 |
|---|---|---|---|
| GET | /workspaces |
工作区列表 | 200 WorkspaceListResponse:workspaces: WorkspaceSummaryResponse[] |
| GET | /workspaces/{workspace_id} |
工作区详情 | 200 WorkspaceDetailResponse |
| POST | /workspaces/{workspace_id}:switch |
切换当前工作区 | 200 WorkspaceDetailResponse |
| GET | /workspaces/{workspace_id}/members |
成员列表(limit 默认 20、page 默认 1) |
200 MemberListResponse;422 校验错误 |
| POST | /workspaces/{workspace_id}/members |
邀请成员 | 201 MemberInviteResponse;422 校验错误 |
| DELETE | /workspaces/{workspace_id}/members/{member_id} |
移除成员 | 200 MemberActionResponse:result(默认 "success") |
| PATCH | /workspaces/{workspace_id}/members/{member_id} |
更新成员角色 | 200 MemberActionResponse;422 校验错误 |
字段契约要点:
- WorkspaceSummaryResponse:
id、name、role、status、current均必填;WorkspaceDetailResponse 额外带created_at。 - MemberInvitePayload:
email必填,role为闭枚举"admin" | "normal"。 - MemberRoleUpdatePayload:
role同上闭枚举。 - MemberInviteResponse:
email、invite_url、member_id、role、tenant_id必填,result默认"success"——响应中的invite_url使 CLI/脚本能直接把邀请链接交付给被邀请人。 - MemberResponse:
email、id、name、role、status必填,avatar可选。
注意端点命名风格:动作型端点采用 :switch、:confirm 这类 RFC 风格后缀而非把动作塞进 REST 资源层级,这在下面的 run/stop/submit/confirm 端点上一以贯之。
5. 应用列表与详情:/apps、/apps/{app_id}
5.1 GET /apps 列表
查询参数:
| 参数 | 位置 | 必填 | 说明 |
|---|---|---|---|
workspace_id |
query | 是 | 目标工作区,uuid |
mode |
query | 否 | 闭枚举 advanced-chat / agent-chat / chat / completion / workflow |
name |
query | 否 | 名称过滤(也接受 UUID) |
page / limit |
query | 否 | 默认 1 / 20 |
响应 AppListResponse 为分页信封:data(AppListRow[],必填)、page、limit、total、has_more(均必填)。每行 AppListRow 含 id、name、mode(AppMode 枚举)、updated_at、description、workspace_id、workspace_name。
源码侧有三个值得展开的机制(api/controllers/openapi/apps.py):
- 可列应用类型的单一来源。
mode过滤枚举并非随意定义:api/controllers/openapi/_models.py 中SupportedAppType是AppMode的精选子集,显式排除了仅运行时存在、并非独立应用的模式标签(rag-pipeline是知识 Pipeline,channel未使用)以及由 roster 面承接的agent类型。每个成员通过AppMode.*.value引用父枚举,形成"删减AppMode会在导入期报错"的编译期约束。参数、过滤与生成的 CLI 白名单全部派生自这一定义。 - RBAC 可见性下推。当
dify_config.RBAC_ENABLED开启且调用者为账号时,AppAccessFilter会把可访问应用 ID 集合下推进 SQL 查询参数(apps.py),保证pagination.total在各页之间一致——不可见行从不计入总数。终端用户(end user)不走此过滤,其访问由上游 scope 控制。 - UUID 快速路径。
name若可解析为 UUID,直接走get_visible_app_by_id单查并校验tenant_id与workspace_id一致,返回 total=1 的单行分页,避免全量分页。
5.2 GET /apps/{app_id} 详情与 ?fields= 裁剪
路径参数 app_id 支持 UUID;?fields= 是响应块 allow-list,允许值见 apps.py:info、parameters、input_schema。语义(对应 AppDescribeQuery 模型注释):
- 省略或为空 → 返回全部块;
- 传入未知成员 →
ValidationError→ 422。
响应 AppDescribeResponse 由三个可选块组成:
- info(
AppDescribeInfo):id、name、mode必填,另含updated_at、description、service_api_enabled(是否启用 Service API)、is_agent(agent-chat/advanced-chat为 true)。 - parameters:与 service_api 面的应用参数端点同构,包含
opening_statement、suggested_questions、user_input_form、file_upload、system_parameters等键;应用不可用时回退为空结构。 - input_schema:JSON Schema 风格的应用输入 schema,供客户端/LLM 在运行前校验输入。
app_id 为名称而非 UUID 时(列表端点的 name 参数语义在详情端点同样适用),_load() 要求必须同时给出 workspace_id 做按名查找;命中多个同名应用时返回 409,并在 message 中以表格列出所有候选 ID/MODE/NAME,提示"改用 UUID 重试"(apps.py)。
6. 应用运行、文件与任务:run / files / events / stop
| 方法 | 路径 | 说明 | 响应 |
|---|---|---|---|
| POST | /apps/{app_id}:run |
运行应用,请求体 AppRunRequest |
200 EventStreamResponse(SSE 流);422 校验错误 |
| POST | /apps/{app_id}/files |
上传运行输入用的文件(multipart) | 201 FileResponse;400(无文件/多文件/非法名/扩展名被禁);401(token 无效或过期);413(过大);415(类型不支持) |
| GET | /apps/{app_id}/tasks/{task_id}/events |
重连/订阅任务事件流 | 200 SSE 流 |
| POST | /apps/{app_id}/tasks/{task_id}:stop |
停止任务 | 200 TaskStopResponse:{ "result": "success" } |
AppRunRequest 字段(全部可选,除 inputs):
| 字段 | 类型 | 说明 |
|---|---|---|
inputs |
object | 必填,应用输入 |
query |
string | 对话查询 |
conversation_id |
string | 续接既有会话 |
files |
object[] | 文件变量(通常引用 /files 上传后的 upload_file_id) |
auto_generate_name |
boolean | 默认 true,自动生成会话名 |
workflow_id |
string | 针对指定 workflow 版本 |
workspace_id |
string | 工作区限定 |
文件上传是 run 流程的配套能力("上传文件以作为运行应用时的输入变量")。响应 FileResponse 关键字段:id(uuid,必填)、name(必填)、size(必填)、extension、mime_type、preview_url、original_url、created_at、created_by 等;201 后拿到的文件句柄即可填入 AppRunRequest.files。错误码细分(400/401/413/415)在规范中逐一写明,方便脚本侧精确分支处理。
任务停止端点的 TaskStopResponse 契约在文档中被特别注明:handler 恒定返回 {"result": "success"},因此 result 是必填字段且无默认值,生成的客户端契约将其类型化为必填的 'success',而非可选字段——这是"契约即断言"的写法。
事件流(EventStreamResponse)的模型注释表明它是 SSE 文本流;GET .../tasks/{task_id}/events 的两个查询参数:
continue_on_pause(boolean):暂停时是否保持事件流打开;include_state_snapshot(boolean):是否包含 workflow 状态快照。
实现位于 api/controllers/openapi/app_run.py 与 api/controllers/openapi/workflow_events.py。
7. DSL 导出与导入:/apps/{app_id}/dsl、/apps/{app_id}/dependencies:check、/workspaces/{workspace_id}/apps/imports
7.1 导出
GET /apps/{app_id}/dsl,查询参数(AppDslExportQuery):
| 参数 | 类型 | 说明 |
|---|---|---|
include_secret |
boolean | 在导出的 DSL 中包含加密后的密文值 |
workflow_id |
string (uuid) | 导出指定 workflow 版本而非当前草稿 |
响应 AppDslExportResponse 仅一个必填字段:data(DSL YAML 字符串)。
7.2 依赖体检
GET /apps/{app_id}/dependencies:check 返回 CheckDependenciesResult:leaked_dependencies(PluginDependency[],可选)。PluginDependency 的 type 为 PluginDependencyType 枚举,value 是 Github / Marketplace / Package 三态之一:
- Github:
github_plugin_unique_identifier、package、repo、version均必填; - Marketplace:
marketplace_plugin_unique_identifier必填,version可选; - Package:
plugin_unique_identifier必填,version可选。
这使导入前能程序化发现"引用了目标环境不可安装插件"的泄漏依赖。
7.3 导入(两阶段确认)
POST /workspaces/{workspace_id}/apps/imports,请求体 AppDslImportPayload:
| 字段 | 必填 | 说明 |
|---|---|---|
mode |
是 | "yaml-content" 或 "yaml-url" |
yaml_content |
条件必填 | mode 为 yaml-content 时必填的 YAML DSL 字符串 |
yaml_url |
条件必填 | mode 为 yaml-url 时要抓取 YAML 的远程 URL |
name / description |
否 | 覆盖 DSL 中的应用名/描述 |
icon / icon_type / icon_background |
否 | 图标覆盖 |
app_id |
否 | 覆盖已有应用(仅 workflow/advanced-chat) |
响应为 Import(来自 services/app_dsl_service.py 的 Import 实体,与 init.py 的注册一致):
| 字段 | 类型/必填 | 说明 |
|---|---|---|
id |
string,必填 | 导入任务 ID |
status |
ImportStatus 枚举,必填 |
导入状态机 |
app_id / app_mode |
可选 | 已落地的应用 |
current_dsl_version |
默认 0.7.0 |
目标端 DSL 版本 |
imported_dsl_version |
可选 | 源 DSL 版本 |
permission_keys |
string[],可选 | 需要的权限键 |
warnings |
DslImportWarning[],可选 |
未能在目标工作区恢复的可移植引用(code、message、path 必填,details 可选) |
error |
可选 | 失败原因 |
HTTP 状态三态:200(导入完成)、202(待确认)、400(导入失败),加上 422 校验错误。
POST /workspaces/{workspace_id}/apps/imports/{import_id}:confirm 完成第二阶段确认:200(已确认)/ 400(失败)均返回 Import,供客户端轮询至终态。两阶段设计意味着跨环境迁移在确认前不产生副作用。
8. Human Input 表单:暂停点的人机交互回传
| 方法 | 路径 | 响应 |
|---|---|---|
| GET | /apps/{app_id}/human-input-forms/{form_token} |
200 HumanInputFormDefinitionResponse |
| POST | /apps/{app_id}/human-input-forms/{form_token}:submit |
200 FormSubmitResponse(精确的空对象 {});422 校验错误 |
- 定义响应:
form_content(必填,表单定义字符串)、resolved_default_values(必填,已解析的默认值对象)、inputs、user_actions(可选数组)、expiration_time(可选,秒级过期)。 - 提交载荷
HumanInputFormSubmitPayload:action(必填):收件人点选的按钮 ID,必须匹配定义中user_actions的某个id;inputs(必填):以输出变量名为键的人机输入值。段落/下拉取值用字符串;文件输入用文件映射,文件列表输入用文件映射列表。本地文件映射用transfer_method=local_file+upload_file_id;远程文件映射用transfer_method=remote_url+url或remote_url。
- FormSubmitResponse 的模型注释写明
extra='forbid'将additionalProperties钉死为false,生成的契约是精确的{}而非欠标注的开放对象。
实现见 api/controllers/openapi/human_input_form.py。该组端点让外部系统(如邮件、IM 机器人)成为 workflow human-input 节点的"收件人",用 form_token 定位具体挂起实例。
9. OAuth 设备授权流程:/oauth/device/*
规范包含完整的设备授权(device authorization)面,五端点闭环:
| 方法 | 路径 | 请求体 / 参数 | 响应 |
|---|---|---|---|
| POST | /oauth/device/code |
DeviceCodeRequest:client_id、device_label(均必填) |
DeviceCodeResponse:device_code、user_code、verification_uri、expires_in、interval(均必填) |
| GET | /oauth/device/lookup |
必填 query user_code |
DeviceLookupResponse:valid(必填)、client_id、expires_in_remaining |
| POST | /oauth/device/approve |
DeviceMutateRequest:user_code(必填) |
DeviceMutateResponse:status(必填) |
| POST | /oauth/device/deny |
同上 | 同上 |
| POST | /oauth/device/token |
DevicePollRequest:client_id、device_code(均必填) |
DeviceTokenResponse(见下) |
DeviceTokenResponse 是流程终点载荷:token、token_id、expires_at、subject_type(闭枚举 "account" | "external_sso",必填)均必填;另含 account(AccountPayload)、default_workspace_id、subject_email、subject_issuer、workspaces(WorkspacePayload[])等可选字段。subject_type 区分本机账号与外部 SSO 主体,设备授权因此同时覆盖两类身份。
流程语义:无头设备先申请 user_code/verification_uri(响应给出轮询 interval 与 expires_in)→ 用户在浏览器 lookup 验证 code 有效性后 approve/deny → 设备端按 interval 轮询 /oauth/device/token 直至拿到 Bearer token。配套安全设施包括 libs/device_flow_security.py 的防 framing 头(第 1 节的 attach_anti_framing)以及 api/controllers/openapi/oauth_device.py、api/controllers/openapi/oauth_device_sso.py 两个控制器分别承接 account 与 SSO 路径。
10. 允许对外暴露的应用:/permitted-external-apps
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /permitted-external-apps |
列出当前用户允许对外访问的应用 |
| GET | /permitted-external-apps/{app_id} |
单个应用详情 |
列表查询参数与 /apps 几乎同构(limit 默认 20、page 默认 1、mode 同为 SupportedAppType 闭枚举、name 名称过滤),但不需要 workspace_id(它按调用者权限域解析,且查询模型是 strict 的 PermittedExternalAppsListQuery)。响应 PermittedExternalAppsListResponse 与 AppListResponse 同构(data/page/limit/total/has_more),详情端点复用 AppDescribeResponse 与 ?fields= 语义。实现位于 api/controllers/openapi/apps_permitted_external.py。
11. 统一错误契约与分页信封
11.1 ErrorBody
规范中每个端点的 default 行都指向同一个规范错误体("Canonical non-2xx body"):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
code |
string | 是 | 错误码。线上类型是开放 string 而非枚举——生成的客户端 schema 保持开放枚举,服务端未来新增 code 时旧 CLI 仍可解析;枚举 OpenApiErrorCode 仅用于合约代码生成,格式化器测试将其发出的值钉死在枚举上 |
message |
string | 是 | 人类可读消息 |
status |
integer | 是 | HTTP 状态码 |
details |
ErrorDetail[] |
否 | 校验细节,每项 type/msg 必填,loc 为 string/integer 混合数组(Pydantic 风格定位) |
hint |
string | 否 | 行动建议(如 426 的升级提示) |
422 在校验失败时显式出现在端点表中,其 details 即为 Pydantic 校验错误的 loc/type/msg 三元组。
11.2 分页信封与 limit 上限
所有列表端点共用同一分页信封(PaginationEnvelope,api/controllers/openapi/_models.py):page / limit / total / has_more / data 五字段,has_more = page * limit < total 由 build() 统一计算,杜绝各端点口径漂移。同时该文件定义了服务端 limit 硬上限 MAX_PAGE_LIMIT = 200,即列表端点查询参数中 limit 的实际取值上限——文档默认值(100/20)之外,脚本在拉大单页时以 200 为界。
12. 关键 Schema 索引(对照文档 Schemas 节)
下表汇总文档 Schemas 节中高频出现的核心契约及其源码出处,便于按图索骥:
| Schema | 用途 | 源码位置 |
|---|---|---|
AccountResponse / AccountPayload / WorkspacePayload |
账户与所属工作区投影 | api/controllers/openapi/_models.py |
SessionRow / SessionListResponse |
设备会话 | 同上 |
AppListQuery / AppListRow / AppListResponse |
应用列表 | 同上 + apps.py |
AppDescribeQuery / AppDescribeResponse |
应用详情与 ?fields= |
同上 |
AppRunRequest / EventStreamResponse |
运行与 SSE | app_run.py;EventStreamResponse 定义于 api/controllers/common/fields.py |
FileResponse |
文件上传 | api/fields/file_fields.py |
AppDslExportQuery / AppDslExportResponse / AppDslImportPayload / Import / DslImportWarning / CheckDependenciesResult / PluginDependency |
DSL 导入导出 | app_dsl.py;Import 来自 services/app_dsl_service.py;CheckDependenciesResult 来自 services/entities/dsl_entities.py |
HumanInputFormDefinitionResponse / HumanInputFormSubmitPayload / FormSubmitResponse |
human-input 表单 | human_input_form.py |
DeviceCode* / DeviceLookup* / DeviceMutate* / DevicePollRequest / DeviceTokenResponse |
设备授权 | oauth_device.py、oauth_device_sso.py |
ErrorBody / ErrorDetail / OpenApiErrorCode |
统一错误 | api/controllers/openapi/_errors.py |
HealthResponse / ServerVersionResponse / DeploymentEdition |
元探针 | index.py |
TaskStopResponse / SimpleResultResponse |
动作型 200 响应 | init.py 引入 |
MemberInvitePayload / MemberResponse / MemberListResponse 等 |
工作区成员 | workspaces.py |
鉴权链路本身由 api/controllers/openapi/auth/ 下的组合器实现:auth_router.guard(scope=..., allowed_token_types=..., rbac=...) 装饰器在控制器入口统一完成 Bearer 校验、scope 检查与 RBAC 判定(例如应用详情端点要求 Scope.APPS_READ + TokenType.OAUTH_ACCOUNT + 应用查看布局 RBAC 权限),AuthData / CallerKind / RBACRequirement 等类型定义在 auth/data.py。
13. 规范文档的生成与维护
仓库中该 Markdown 规范由开发工具链生成:api/dev/generate_swagger_markdown_docs.py 将各 API 面的 swagger 模型渲染为 api/openapi/markdown/ 下的四个面文档(console / service / web / openapi)。这意味着:
- 端点参数、枚举取值、默认值等契约细节随控制器装饰器(
@accepts/@returns)与 Pydantic 模型演进自动同步; - 本地校验响应契约的入口是 scripts/lint_controller_sqlalchemy.py 等仓库脚本与 api/tests/ 下的单测;
- 阅读该面最新契约时,以仓库内这份 Markdown 与 api/controllers/openapi/ 源码为准即可,无需依赖外部文档站。
14. 快速上手:一条最小调用链
以 curl 形式串起前文能力(<API_KEY> 为 Bearer 凭据,<WS> 为目标工作区 ID):
# 0. 免鉴权探针
curl -s "$BASE/openapi/v1/_health" # {"ok": true}
curl -s "$BASE/openapi/v1/_version" # {"version": "...", "edition": "..."}
# 1. 确认身份与所属工作区
curl -s "$BASE/openapi/v1/account" -H "Authorization: Bearer <API_KEY>"
curl -s "$BASE/openapi/v1/workspaces" -H "Authorization: Bearer <API_KEY>"
# 2. 列出应用并查看详情(含输入 schema,用于构造运行请求)
curl -s "$BASE/openapi/v1/apps?workspace_id=<WS>&mode=chat" \
-H "Authorization: Bearer <API_KEY>"
curl -s "$BASE/openapi/v1/apps/<APP_ID>?fields=info,input_schema" \
-H "Authorization: Bearer <API_KEY>"
# 3. 上传文件并运行应用(SSE 流)
curl -s -F "file=@report.pdf" "$BASE/openapi/v1/apps/<APP_ID>/files" \
-H "Authorization: Bearer <API_KEY>"
curl -N -X POST "$BASE/openapi/v1/apps/<APP_ID>:run" \
-H "Authorization: Bearer <API_KEY>" -H "Content-Type: application/json" \
-d '{"inputs": {"file": [{"transfer_method": "local_file", "upload_file_id": "<FILE_ID>"}]}}'
# 4. 导出 DSL / 导入到其他工作区(两阶段确认)
curl -s "$BASE/openapi/v1/apps/<APP_ID>/dsl" -H "Authorization: Bearer <API_KEY>"
curl -s -X POST "$BASE/openapi/v1/workspaces/<WS>/apps/imports" \
-H "Authorization: Bearer <API_KEY>" -H "Content-Type: application/json" \
-d '{"mode": "yaml-content", "yaml_content": "<DSL YAML>"}'
# 5. 清理:吊销当前会话
curl -s -X DELETE "$BASE/openapi/v1/account/sessions/self" \
-H "Authorization: Bearer <API_KEY>"
错误处理约定:非 2xx 一律按 ErrorBody 解析,details 用于 422 字段级定位,hint 用于 426 升级提示;422 多由 strict 查询模型(extra='forbid')拒绝未知参数触发,排查时先核对参数拼写与所属端点。
15. 小结
/openapi/v1 是 Dify 面向程序化访问的用户域 API 面:版本 1.0、Bearer 鉴权、资源导向路径与 :action 动作端点混用、strict Pydantic 查询模型、统一 ErrorBody 与五字段分页信封、以及针对 difyctl 的 426 版本门禁。其端点覆盖了账户会话、工作区与成员、应用列表/详情/运行/文件、DSL 两阶段导入导出与依赖体检、human-input 表单回传、任务事件流与停止、设备授权登录以及外部可暴露应用清单。所有契约在 api/controllers/openapi/_models.py 与 api/controllers/openapi/_errors.py 中集中定义,并通过 api/dev/generate_swagger_markdown_docs.py 同步为本文所依据的 openapi-openapi.md,实现"源码即契约、契约即文档"。
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