当需要从其他应用或新的集成层调用 agent-management 工作流时,按本参考实现服务调用。
本文聚焦接口契约。前端如何展示运行过程(面板结构、折叠策略、交互逻辑)见 run-history-ui.md;可直接复用的 JS/Vue 参考实现见 js-implementation.md。
http(s)://<host>:<port>/api/v12438/api/v1/** 请求需携带 X-API-Key: <key> 请求头(仅支持请求头,不支持 query 参数)/api/** 全开放(任意 Origin、allowedHeaders: *),浏览器可跨域直连JSON 成功响应包:
{ "code": "OK", "message": "", "data": {} }
错误响应包:
{ "code": "VALIDATION_FAILED", "message": "可读错误信息", "data": null }
主要错误码:UNAUTHORIZED、VALIDATION_FAILED、WORKFLOW_NOT_FOUND、RUN_NOT_FOUND、GRAPH_INVALID、RUN_ALREADY_STARTED、INTERNAL_ERROR
判断成功用 resp.code === 'OK'(字符串,非数字 0)
外部 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 可访问的工作流 |
POST |
/api/v1/workflows/{workflowName}/runs |
创建一次运行,可携带变量与可选文件(JSON 或 multipart) |
POST |
/api/v1/workflows/{workflowName}/runs/{runId}/start |
启动一个已创建的异步运行 |
GET |
/api/v1/workflows/{workflowName}/runs/{runId}/stream |
订阅 SSE 节点/运行事件(支持 Last-Event-ID 续传) |
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 |
POST /workflows/{workflowName}/runs,带 async: true。{workflowName} 推荐使用 kebab-case name。data.runId 和 data.links。响应中的 workflowId(数字主键)和 workflowName(kebab-case)可分别作为元数据保存。POST /workflows/{workflowName}/runs/{runId}/start。GET /workflows/{workflowName}/runs/{runId}/stream,请求头 Accept: text/event-stream。workflow_complete 或 workflow_error 后,关闭流或标记为终态。GET /workflows/{workflowName}/runs/{runId} 获取持久化输出与节点摘要。GET /workflows/{workflowName}/runs/{runId}/workspace 作为二进制下载入口提供给用户。仅当期望"单次阻塞请求直接返回 SSE"时才使用 async: false(此时创建即启动,响应直接是 StartRunResponse 结构)。
纯 JSON 请求:
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,
"ttlHours": 720
}
Multipart 请求:
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 形式返回。ttlHours:工作空间保留小时数;默认 720。files:可重复的 multipart 二进制 part;可选。上传后自动注入 variables.uploadedFiles(相对路径数组)。X-Relative-Path:multipart part 的可选 header,用于保留目录路径。若客户端技术栈不支持,则退化为仅使用文件名并明确记录该限制。async: true 的响应:
{
"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"
}
}
}
打开连接(路径段使用 workflowName,即 kebab-case name):
GET /api/v1/workflows/{workflowName}/runs/{runId}/stream
X-API-Key: <key>
Accept: text/event-stream
断线重连时携带:
Last-Event-ID: 42
每条事件遵循标准 SSE 格式(id 为 run 内单调递增的序号):
event: node_stream
id: 43
data: {"runId":"a3f9b2c1","type":"node_stream","nodeId":"node-2","visitUuid":"5c1f...","kind":"thinking","content":"首先我需要搜索相关资料...","toolName":null}
| type | 触发时机 | 关键字段 |
|---|---|---|
node_status |
节点状态变更(启动/完成/失败/跳过) | nodeId、visitUuid、status、output、error、logs、contextSnapshot;RUNNING 时另携带 nodeType、nodeLabel(v1.2) |
node_stream |
节点执行中的流式增量 | nodeId、visitUuid、kind、content、toolName |
visit_recorded |
一次节点访问(Visit)已持久化 | visit(完整 Visit 快照对象) |
planner_decision |
AGENTIC 模式下 AI 决定下一步访问哪个节点 | decision(含 nextNodeId 与 reason) |
workflow_complete |
终态成功 | output、success: true、workingDirFiles |
workflow_error |
终态失败 | error、success: false |
注意:没有 run_started 事件,运行启动信号由 start 接口的 HTTP 响应承担。
node_status 详解status 取值:RUNNING / SUCCESS / FAILED / SKIPPED(大写枚举)。RUNNING,除 nodeId + visitUuid 外还携带 nodeType 与 nodeLabel(v1.2)——无画布数据的集成方应在此时直接建卡片并使用这两个字段识别节点类型/显示名,避免显示"未知"(终态事件不携带)。output:节点输出 envelope,结构为 {status: 200, message, data}(status 是数字:200 成功 / 400 失败),业务字段在 data 内(解包规则见 run-history-ui.md)。logs:节点执行日志数组,元素结构 {type, message, detail, timestamp},可用于回放思考过程、工具调用、待办清单(回放场景优先从 visit_recorded 的 visit.logsJson 取)。contextSnapshot:节点完成后的完整变量快照(debug 用途,可忽略)。node_stream 详解(8 种 kind)| kind | 语义 | content 格式 |
toolName |
前端处理 |
|---|---|---|---|---|
thinking |
LLM 思考增量 | 纯文本片段 | null | 追加到思考过程面板(markdown 渲染) |
status |
实时状态文案(如"压缩上下文中") | 纯文本 | null | 覆盖式显示,节点完成后隐藏 |
step |
每轮 LLM 调用进度 | JSON 字符串 {"iteration":N,"prev_tools":[...]} |
null | 追加到执行日志 |
tool_progress |
工具细粒度进度 | JSON 字符串 {"event_type":"...","name":"...","preview":...} |
工具名 | 更新对应工具卡片的运行中状态 |
tool_call |
工具调用开始 | 参数 JSON(截断到 500 字符) | 工具名 | 新建工具调用卡片 |
tool_result |
工具调用结束 | 结果摘要(截断到 500 字符) | 工具名 | 关闭对应卡片,展示结果 |
todo_update |
待办清单更新 | JSON 字符串(TodoWrite 工具完整输出) | "todo" |
覆盖式更新待办面板 |
clarify_request |
AskFor:请求用户确认 | JSON 字符串 {"clarify_id":"...","question":"...","choices":[...]} |
null | 渲染 AskFor 面板(提交/恢复见下方"AskFor(用户确认)") |
tool_call / tool_result 的 content 均被截断到 500 字符,完整内容通过 node_status.logs 或节点日志接口获取。
每个 node_status / node_stream 事件都携带 visitUuid,标识一次节点访问:
visitUuid 与 nodeId 一一对应。visitUuid。前端必须按 visitUuid 聚合事件、渲染卡片,不能按 nodeId 合并——否则同节点重访时思考过程、工具调用会混在一起。visit_recorded 事件携带的 visit.sortOrder 决定卡片排列顺序;visit.iterSeq 表示同节点第几次访问;visit.fromNodeId 表示直接来源节点。
visitUuid 为主键维护每个 Visit 卡片的状态。node_status RUNNING 创建卡片;终态更新卡片状态并触发折叠。node_stream.kind === "thinking" 的 content 追加到该 Visit 的思考缓冲区。tool_call / tool_result / tool_progress 按到达顺序维护工具调用列表。workflow_complete 与 workflow_error 视为终态,停止一切重连。id。服务端保障:
:keep-alive 心跳注释帧(不触发业务逻辑)。Last-Event-ID 请求头,服务端补发该 id 之后的全部事件。workflow_complete 或 workflow_error),客户端据此直接进入终态。客户端建议(完整实现见 js-implementation.md):
GET /runs/{runId}(30s/次),依据返回的 status 判断终态。EventSource 原生 API 不支持自定义请求头,无法携带 X-API-Key。两个选择:
fetch + ReadableStream 手动解析 SSE 流(参考实现即此方案,另需自行实现重连与 Last-Event-ID 传递);/agent-api/* → /api/v1/* 并注入密钥,前端走同源 EventSource。工作流中的智能体节点可能触发 clarify_request(AskFor),此时整个工作流暂停等待用户选择选项或输入自定义答案。外部 API 已开放对应端点(v1.2):
POST /api/v1/runs/{runId}/resume
X-API-Key: demo-key
Content-Type: application/json
{ "clarifyId": "clar-5678", "answer": "v2.0" }
响应 data:{ "accepted": true, "runId": "...", "clarifyId": "..." }。accepted=false 表示答案已落库但 Bridge 唤醒失败(或平台未启用 Hermes Bridge);错误场景直接返回 HTTP 错误码:
| HTTP | code | 场景 |
|---|---|---|
| 400 | VALIDATION_FAILED |
runId/clarifyId 格式非法或缺请求体 |
| 404 | RUN_NOT_FOUND |
runId 不存在,或 Key 无该 run 所属工作流权限(不泄露存在性) |
| 404 | CLARIFY_NOT_FOUND |
clarifyId 不存在、不属于该 run,或运行未启动 |
| 409 | CLARIFY_ALREADY_ANSWERED |
同一 clarifyId 重复提交——按幂等约定视为成功 |
| 410 | RUN_ALREADY_FINISHED |
运行已 SUCCESS/FAILED |
GET /api/v1/runs/{runId}/state
X-API-Key: demo-key
响应 data:{ runId, status, currentPause },status 为 CREATED/RUNNING/SUCCESS/FAILED(大写);currentPause 为当前未答暂停点(无则 null),含 clarifyId、nodeId、question、choices(已解析为数组,区别于内部 API 的 JSON 字符串)、createdAt(ISO_LOCAL_DATE_TIME)。
恢复流程:先查 /state 恢复 AskFor 面板,再以 Last-Event-ID 请求头续传 SSE 补齐节点过程数据。注意两端点路径不带 workflows/{name} 段(runId 全局唯一),页面刷新后 workflowName 丢失也不影响调用。
GET /api/v1/workflows/military-analyze-agent/runs/a3f9b2c1
X-API-Key: demo-key
预期的 data 形态:
{
"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": {
"status": 200,
"message": "工作流执行成功",
"data": { "summary": "本报告探讨了..." }
},
"nodes": [
{
"nodeId": "node-2",
"nodeType": "agent",
"label": "研究助手",
"status": "SUCCESS",
"output": { "status": 200, "message": "调用成功", "data": { "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。
注意:outputs 与 nodes[].output 均为 envelope 结构(服务端不解包),业务字段取自 data(解包规则见 run-history-ui.md)。AGENTIC 模式的运行结果中 nodes 可能为空数组(该模式按 Visit 持久化,不生成节点级记录);完整过程数据以 SSE 重放或 visit_recorded 事件为准。
节点日志:
GET /api/v1/workflows/{workflowName}/runs/{runId}/nodes/{nodeId}/logs
日志元素结构 {type, message, detail, timestamp},type 取值 THINKING、TOOL_CALL、TOOL_RESULT、STATUS、STEP、TOOL_PROGRESS、TODO_UPDATE、CLARIFY_REQUEST、ERROR。把思考过程抽到独立展示区,非思考日志放在可折叠的日志列表中。
工作空间下载:
GET /api/v1/workflows/{workflowName}/runs/{runId}/workspace
响应是二进制 zip 内容,不要走 JSON 响应拦截器。
fetch 直连方案不要给 read 超时;依赖心跳帧(30s)+ 重连机制保证活性。X-API-Key。优先使用后端代理,由服务端注入密钥。ExternalApiProperties 中配置,同时支持 workflowNames(推荐,按 kebab-case name 精确匹配)和 workflowIds(兼容,按数字主键匹配);两者皆空表示不限制。新集成建议使用 workflowNames 与 URL 路径保持一致。../ 路径穿越。X-Accel-Buffering: no),保留事件名、id 和 data 负载。text/event-stream 和工作空间 zip 端点绕过 JSON 响应包解析。