# 外部工作流 API 参考 当需要从其他应用或新的集成层调用 agent-management 工作流时,按本参考实现服务调用。 ## 契约概要 - 基础路径:`http(s)://:/api/v1` - 默认后端端口:`2438` - 鉴权:每个 `/api/v1/**` 请求需携带 `X-API-Key: ` - JSON 成功响应包: ```json { "code": "OK", "message": "", "data": {} } ``` - 错误响应包: ```json { "code": "VALIDATION_FAILED", "message": "可读错误信息", "data": null } ``` - 主要错误码:`UNAUTHORIZED`、`VALIDATION_FAILED`、`WORKFLOW_NOT_FOUND`、`RUN_NOT_FOUND`、`GRAPH_INVALID`、`RUN_ALREADY_STARTED`、`INTERNAL_ERROR` ## 工作流标识 外部 API 的所有 `{workflowName}` 路径段同时接受两种值,**优先使用 `name`**: - **`name`(推荐)**:kebab-case 字符串,正则 `^[a-z0-9]+(-[a-z0-9]+)*$`,最大 64 字符,全局唯一。例:`military-analyze-agent`、`report-pipeline`。 - **`id`(兼容兜底)**:纯数字字符串。当传入值不是 `name` 且为纯数字时,按内部主键 `id` 查找。仅用于兼容历史调用方,新集成不要依赖。 解析顺序:先 `findByName(nameOrId)`,未命中且为纯数字时回退 `findById(Long.valueOf(nameOrId))`。 响应中的标识字段约定: | 字段 | 类型 | 含义 | |---|---|---| | `workflowId` | number | 内部数字主键,仅作为元数据返回,**不用于 URL 路径** | | `workflowName` | string | kebab-case 唯一标识,所有 links、downloadUrl、logsUrl 都用它拼接 | | `displayName` | string | 中文展示名,仅用于 UI 展示 | 工作流列表响应还会返回 `description`、`inputs`、`outputs`(从 `userInput` / `output` 节点自动提取的字段定义)。 ## 端点 | 方法 | 路径 | 用途 | |---|---|---| | `GET` | `/api/v1/workflows` | 列出当前 API key 可访问的工作流。响应项含 `id`、`name`、`displayName`、`description`、`inputs`、`outputs`;当前实现返回所有可访问工作流,分页/搜索查询参数仅作前向兼容保留。 | | `POST` | `/api/v1/workflows/{workflowName}/runs` | 创建一次运行,可携带变量与可选文件。`{workflowName}` 接受 kebab-case `name` 或纯数字 `id`。 | | `POST` | `/api/v1/workflows/{workflowName}/runs/{runId}/start` | 启动一个已创建的异步运行 | | `GET` | `/api/v1/workflows/{workflowName}/runs/{runId}/stream` | 订阅 SSE 节点/运行事件 | | `GET` | `/api/v1/workflows/{workflowName}/runs/{runId}` | 查询运行状态、输出、节点和工作空间信息 | | `GET` | `/api/v1/workflows/{workflowName}/runs/{runId}/nodes/{nodeId}/logs` | 查询某节点的持久化日志 | | `GET` | `/api/v1/workflows/{workflowName}/runs/{runId}/workspace` | 下载工作空间 zip | ## 推荐的异步流程 1. `POST /workflows/{workflowName}/runs`,带 `async: true`。`{workflowName}` 推荐使用 kebab-case `name`。 2. 读取 `data.runId` 和 `data.links`。响应中的 `workflowId`(数字主键)和 `workflowName`(kebab-case)可分别作为元数据保存。 3. `POST /workflows/{workflowName}/runs/{runId}/start`。 4. 打开 `GET /workflows/{workflowName}/runs/{runId}/stream`,请求头 `Accept: text/event-stream`。 5. 收到 `workflow_complete` 或 `workflow_error` 后,关闭流或标记为终态。 6. 查询 `GET /workflows/{workflowName}/runs/{runId}` 获取持久化输出与节点摘要。 7. 将 `GET /workflows/{workflowName}/runs/{runId}/workspace` 作为二进制下载入口提供给用户。 仅当期望"单次阻塞请求直接返回 SSE"时才使用 `async: false`。 ## 创建运行 纯 JSON 请求: ```http POST /api/v1/workflows/military-analyze-agent/runs X-API-Key: demo-key Content-Type: application/json { "variables": { "topic": "大语言模型在企业中的应用", "maxTokens": 2048, "options": { "lang": "zh", "verbose": false } }, "async": true, "failStrategy": "abort", "ttlHours": 720 } ``` Multipart 请求: ```http POST /api/v1/workflows/military-analyze-agent/runs X-API-Key: demo-key Content-Type: multipart/form-data payload: {"variables":{"topic":"汇总报告"},"async":true} files: report.md files: inputs/2024/data.csv ``` 字段说明: - `variables`:自定义工作流输入变量;对象;可选。 - `async`:默认 `true`。为 `true` 时仅创建;为 `false` 时立即启动并以 SSE 形式返回。 - `failStrategy`:取值 `abort` 或 `skip`;可选且前向兼容。当前 agent-management 实现中该字段虽被 DTO 接收,但执行仍依赖 `graphData` 中节点级别的 `failStrategy`;除非目标版本显式支持请求级覆盖,否则不要依赖此字段。 - `ttlHours`:工作空间保留小时数;默认 `720`。 - `files`:可重复的 multipart 二进制 part;可选。 - `X-Relative-Path`:multipart part 的可选 header,用于保留目录路径。若客户端技术栈不支持,则退化为仅使用文件名并明确记录该限制。 `async: true` 的响应: ```json { "code": "OK", "data": { "runId": "a3f9b2c1", "workflowId": 12, "workflowName": "military-analyze-agent", "displayName": "军事分析助手", "status": "CREATED", "createdAt": "2026-07-01T08:30:00Z", "links": { "start": "/api/v1/workflows/military-analyze-agent/runs/a3f9b2c1/start", "stream": "/api/v1/workflows/military-analyze-agent/runs/a3f9b2c1/stream", "result": "/api/v1/workflows/military-analyze-agent/runs/a3f9b2c1", "workspace": "/api/v1/workflows/military-analyze-agent/runs/a3f9b2c1/workspace" } } } ``` ## SSE 流 打开连接(路径段使用 `workflowName`,即 kebab-case `name`): ```http GET /api/v1/workflows/{workflowName}/runs/{runId}/stream X-API-Key: Accept: text/event-stream ``` 断线重连时携带: ```http Last-Event-ID: 42 ``` 每条事件遵循标准 SSE 格式: ```text event: node_stream id: 43 data: {"runId":"a3f9b2c1","type":"node_stream"} ``` 事件类型: - `run_started`:引擎已启动。 - `node_status`:节点状态变更。用于创建/更新节点卡片。 - `node_stream`:节点增量流。`kind` 取值为 `thinking`、`tool_call` 或 `tool_result`。 - `workflow_complete`:终态成功。包含最终输出和工作空间/结果 URL。 - `workflow_error`:终态失败。包含错误信息,通常带有失败节点 ID。 关键负载字段示例: ```json { "runId": "a3f9b2c1", "nodeId": "node-2", "nodeType": "agent", "label": "研究助手", "status": "RUNNING", "kind": "thinking", "content": "首先我需要搜索相关资料...", "toolName": null, "timestamp": "2026-07-01T08:30:07Z" } ``` 客户端行为约定: - 以 `nodeId` 为主键维护每个节点的状态。 - 将 `node_stream.kind === "thinking"` 的内容追加到该节点的思考缓冲区。 - 将 `tool_call` 与 `tool_result` 作为日志存储,保留工具名和内容。 - 把 `workflow_complete` 与 `workflow_error` 视为终态。 - 如需支持重连,持久化最近一条 SSE 的 `id`。 ## 查询结果 ```http GET /api/v1/workflows/military-analyze-agent/runs/a3f9b2c1 X-API-Key: demo-key ``` 预期的 data 形态: ```json { "runId": "a3f9b2c1", "workflowId": 12, "workflowName": "military-analyze-agent", "displayName": "军事分析助手", "status": "SUCCESS", "startedAt": "2026-07-01T08:30:05Z", "completedAt": "2026-07-01T08:31:12Z", "error": null, "outputs": { "summary": "本报告探讨了...", "_workingDirFiles": ["report.md"], "_runId": "a3f9b2c1" }, "nodes": [ { "nodeId": "node-2", "nodeType": "agent", "label": "研究助手", "status": "SUCCESS", "output": { "research": "..." }, "error": null, "logsCount": 124, "logsUrl": "/api/v1/workflows/military-analyze-agent/runs/a3f9b2c1/nodes/node-2/logs" } ], "workspace": { "fileCount": 12, "totalBytes": 456789, "downloadUrl": "/api/v1/workflows/military-analyze-agent/runs/a3f9b2c1/workspace" } } ``` 状态取值:`CREATED`、`RUNNING`、`SUCCESS`、`FAILED`。 ## 日志与工作空间 节点日志: ```http GET /api/v1/workflows/{workflowName}/runs/{runId}/nodes/{nodeId}/logs ``` 日志类型通常为 `THINKING`、`TOOL_CALL`、`TOOL_RESULT`、`INFO`、`ERROR`。把思考过程抽到独立展示区,非思考日志放在可折叠的日志列表中。 工作空间下载: ```http GET /api/v1/workflows/{workflowName}/runs/{runId}/workspace ``` 响应是二进制 zip 内容,不要走 JSON 响应拦截器。 ## 安全与集成注意事项 - 默认不要在前端代码中暴露 `X-API-Key`。优先使用后端代理,由服务端注入密钥。 - base URL 与 API key 应存放在环境/配置中,不要硬编码到源码。 - API Key 的访问范围(白名单)在 agent-management 后端 `ExternalApiProperties` 中配置,同时支持 `workflowNames`(推荐,按 kebab-case `name` 精确匹配)和 `workflowIds`(兼容,按数字主键匹配);两者皆空表示不限制。新集成建议使用 `workflowNames` 与 URL 路径保持一致。 - 如实现代理上传,需校验路径,防止 `../` 路径穿越。 - 代理 SSE 时关闭缓冲,保留事件名、id 和 data 负载。 - 未经用户同意,不要悄悄把 SSE 降级为轮询。 - 使用 axios/fetch 等封装时,对 `text/event-stream` 和工作空间 zip 端点绕过 JSON 响应包解析。