Files

430 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 任务分析定时 · 对外接口对接文档
> 面向外部任务系统(下称「对方系统」)的开发者。覆盖任务接入、时间线详情拉取、
> 总控问答、**定时数据交付**(任务 6 块 JSON)四组接口。智能体编排配置
> (选业务链 / 执行频率)在 DeerFlow 任务分析页操作,对方系统无需开发。
>
> 相关实现:`app/gateway/routers/task_analysis.py`(任务/绑定/运行记录)、
> `app/gateway/routers/task_analysis_qa.py`(问答)。
## 0. 通用约定
- **Base URL**:DeerFlow Gateway 地址(如 `http://<host>:8001`)。
- **鉴权**:所有接口需带 `Authorization: Bearer <token>` 请求头(token 获取方式见登录对接,本文不重复)。
- **Content-Type**:`application/json`(SSE 接口除外,响应为 `text/event-stream`)。
- **时间格式**:ISO 8601 字符串(含时区,如 `2026-09-10T10:14:55+08:00`)。
- **两类任务标识**:
- `source_task_id`:对方系统的任务号(创建时由你们传入);
- `task_id`:DeerFlow 内部任务 id(**创建接口的响应里返回**,问答接口使用它)。
创建任务后请保存响应中的 `task_id`;也可随时通过时间线详情接口重新取到。
## 1. 任务接入
### 1.1 创建任务
对方系统创建任务完成后调用,DeerFlow 落一条任务记录(初始未绑定分析方案)。
```
POST /api/task-analysis/external/tasks
```
请求体:
```json
{
"source_task_id": "TS-2026-0147",
"name": "东南亚舆论环境监测",
"description": "持续跟踪东南亚重点渠道舆论动向,输出结构化分析详情。"
}
```
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| source_task_id | string(≤128) | 是 | 对方任务号,全局唯一 |
| name | string(≤512) | 是 | 任务名称 |
| description | string(≤8192) | 否 | 任务简介。**定时执行时注入各智能体的任务上下文以此为准**(存量快照,执行时不会回拉) |
响应 `200`:
```json
{
"task_id": "ta-TS-2026-0147",
"default_chain_id": "ta-demo-chain"
}
```
- `task_id`:DeerFlow 内部任务 id,**问答接口需要它**,请保存。
- `default_chain_id`:DeerFlow 侧最近一次绑定使用的业务链 id,可作为你们界面上绑定流程的默认选项;无绑定为 `null`。
错误:`409` —— `source_task_id` 已存在。
### 1.2 删除任务
对方系统删除任务时同步调用,**彻底删除**:任务、绑定、全部执行记录、过程消息与时间线版本一并清除(不可恢复)。
```
DELETE /api/task-analysis/external/tasks/{source_task_id}
```
响应 `200`:`{"deleted": true, "task_id": "..."}`。错误:`404` —— 任务不存在。
## 2. 任务详情(时间线)
对方系统详情页的数据源。每次定时执行成功会落一期**时间线版本**(含各智能体产出),按时间倒序返回。
```
GET /api/task-analysis/external/tasks/{source_task_id}/detail?limit=20&offset=0
```
响应 `200`:
```json
{
"task": {
"task_id": "ta-TS-2026-0147",
"source_task_id": "TS-2026-0147",
"name": "东南亚舆论环境监测"
},
"binding": {
"chain_id": "ta-demo-chain",
"cron_expr": "0 9 * * *",
"schedule_type": "cron",
"enabled": true
},
"timeline": [
{
"id": "…",
"external_task_id": "ta-TS-2026-0147",
"run_id": "tar-…",
"blocks": {
"eightbf-roundtable-intent": {
"name": "8BF 任务理解",
"seat_agent_id": "eightbf-roundtable-intent",
"content": "(该智能体本次产出的 Markdown 正文)",
"format": "markdown"
},
"c0a8799da8724e179e086ea9ca723967": { "name": "策略分析师", "…": "…" }
},
"created_at": "2026-09-10T10:15:13+08:00"
}
]
}
```
- `binding`:当前绑定信息(未绑定为 `null`,此时 `timeline` 不会有新版本)。
`schedule_type` 为执行方式:`cron` = 按 `cron_expr` 频率定时执行;
`once` = 只执行一次(创建后立即执行,之后不再自动执行,`cron_expr` 不生效)。
- `timeline[].blocks`:**每个参与执行的智能体一块**,key 为该智能体的 agent_id,
`name` 为执行时的名称快照,`content` 为其交付正文(Markdown)。
按你们的详情分区规则渲染即可(如按 block 顺序分栏)。
- 分页:`limit`(默认 20)/ `offset`,按 `created_at` 倒序。
## 3. 总控问答(详情页对话)
详情页的对话入口:用户提问 → DeerFlow 总控按任务绑定的编排给对应智能体派活 →
智能体执行 → 总控汇总结论。一次问答会话记为一条「手动执行」记录,过程消息可查。
### 3.1 发起问答会话(init)
```
POST /api/task-analysis/tasks/{task_id}/qa/init
```
> 注意:此处 `{task_id}` 为 **DeerFlow 内部任务 id**(创建接口响应里的 `task_id`)。
请求体:空(无需参数)。
响应 `200`:
```json
{
"run_id": "tar-0743654e-…",
"coordinator": "roundtable-coordinator",
"thread_ids": {
"eightbf-roundtable-intent": "ta-seat-…-…",
"c0a8799da8724e179e086ea9ca723967": "ta-seat-…-…",
"roundtable-coordinator": "ta-seat-…-…"
},
"seats": [
{ "agent_id": "eightbf-roundtable-intent", "name": "8BF 任务理解" },
{ "agent_id": "c0a8799da8724e179e086ea9ca723967", "name": "策略分析师" }
]
}
```
- `run_id`:本次问答会话的运行记录 id(查历史 / 应用方向都用它)。
- `thread_ids`:**会话线程映射,请保存并在后续每轮 stream 原样传回**(会话不跨请求保存在服务端)。
- init 时已自动把任务上下文(名称/简介/编排/历次方向备注)注入总控,之后每轮消息传用户原话即可。
错误:`400` —— 任务未绑定分析方案 / 绑定链没有可调度席位。
### 3.2 发送消息(stream,SSE)
```
POST /api/task-analysis/tasks/{task_id}/qa/stream
Content-Type: application/json
Accept: text/event-stream
```
请求体:
```json
{
"run_id": "tar-0743654e-…",
"message": "请让两个席位各自分析当前的主要风险点,然后给我综合结论。",
"thread_ids": { "…init 返回的映射原样传回…" }
}
```
响应为 SSE 流,每帧 `data: {JSON}\n\n`。**帧类型**:
| 帧 | 触发时机 | 关键字段 |
|---|---|---|
| LangGraph 上游事件(无 `event` 字段的多种帧) | 总控正在生成(token 流) | 透传自运行时,可用于打字机效果 |
| `{"event": "leader", "status": [[seat_id, task], …], …}` | 总控一轮结束 | `status` 为派活表(二维数组)时表示已派活 |
| `{"event": "leader", "status": "clarification", …}` | 总控需要澄清 | `question` / `options`,前端展示追问,等用户补充后发下一轮 |
| `{"event": "leader", "status": [], "content": …}` | 总控给出结论(共识) | `content` 为结论正文 |
| `{"event": "seat", "agent": id, "name": …, "content": …}` | 某智能体执行完成 | `content` 为该智能体交付正文 |
| `{"event": "round_done", "consensus": true/false}` | 本轮结束 | `consensus=true` 会话已收口(run 置 succeeded);`false`(如澄清)可继续发下一轮 |
一轮完整时序:`leader(派活)→ 若干 seat(交付)→ leader(综合结论)→ round_done`。
约定:
- 澄清(`consensus=false, kind=clarification`):继续对**同一 run_id** 发下一轮 stream;
- 共识(`consensus=true`):run 已自动收口,如需再问请新开一次 `qa/init`;
- 客户端中断流不影响服务端继续执行(消息仍会落库,可从历史接口补读)。
错误:`404` 会话不存在;`409` 会话已收口(需重新 init)或 `thread_ids` 缺失(重新 init)。
### 3.3 应用调整方向(可选)
问答结束后,若用户确认「把本次调整应用到后续执行」,调用本接口把结论沉淀为
**执行方向备注**——该备注会注入此任务后续**每次定时执行**各智能体的任务上下文。
```
POST /api/task-analysis/qa/{run_id}/apply-direction
```
请求体:`{"note": "后续执行请重点关注台湾海峡北段动态,风险输出按高/中/低分级。"}`
响应 `200`:`{"applied": true, "direction_notes": ["…", "…"]}`(全部累计备注)。
### 3.4 对话历史查询
按运行记录查询完整过程消息(总控 + 各智能体),供会话回放或补读。
```
GET /api/task-analysis/external/runs/{run_id}/messages?seat=&limit=500
```
- `seat` 可选:传智能体 agent_id 只看该席位;传 `__coordinator__` 只看总控;不传看全部。
- 响应:`{"run": {"id", "trigger", "status", "started_at", "finished_at"}, "messages": […]}`
- 消息字段:`seq`(顺序)、`seat_agent_id`、`stage_index`、`event_type`
(`input` 输入 / `llm.ai` 智能体输出 / `artifact` 产物备注)、`content`。
## 4. 定时数据交付(任务 6 块数据)
按任务展示 **6 块结构化数据**(相当于 6 个页面分区,每块含多个部分),每块一个
JSON 对象。DeerFlow 只负责数据管道与调度:智能体在定时执行过程中把成果提交进
数据块,归配智能体 / 业务链的配置由管理方维护。
**口径要点**:
- 块 key 定死 `block_1`~`block_6`,标题默认「数据块一~六」,可经 4.4 修改;
存量 5 块任务在读接口 / 首次提交时懒补 `block_6`,已改过的标题不覆盖;
- payload 不做 schema 校验(结构会变),只要求是 **JSON 对象**;
- 不定席位↔块映射:多个智能体可各写一个块的不同部分,一个智能体也可写多个块;
- 同一块多次提交按「**顶层 key 合并、同 key 后写覆盖**」合并——某个部分一提交,
立刻体现在任务的当前数据里(实时更新);
- **不挂时间轴**:一个任务的数据只有一份「当前状态」,所有提交(定时轮次、
手动触发、对话修复)都合并进它,越提交越新;
- 调度不管上一轮跑没跑完:到期照常触发,**同任务允许多轮并行**,不跳过不顺延;
多轮提交按流水顺序收敛到同一份数据;
- 首次提交时若任务还没有数据承载记录,自动创建一条(`trigger=external`),
保证写入永远成功。
### 4.1 数据块定义列表
```
GET /api/task-analysis/external/tasks/{source_task_id}/blocks
```
响应 `200`:
```json
{
"task": {"task_id": "ta-TS-2026-0147", "source_task_id": "TS-2026-0147", "name": "东南亚舆论环境监测"},
"blocks": [
{"block_key": "block_1", "title": "数据块一", "sort_order": 1},
{"block_key": "block_2", "title": "数据块二", "sort_order": 2},
{"block_key": "block_3", "title": "舆情热点", "sort_order": 3},
{"block_key": "block_4", "title": "数据块四", "sort_order": 4},
{"block_key": "block_5", "title": "数据块五", "sort_order": 5},
{"block_key": "block_6", "title": "数据块六", "sort_order": 6}
]
}
```
固定 6 条,按 `sort_order` 升序返回;`title` 为修改后的标题(见 4.4)。
### 4.2 当前数据状态(兼容旧路径 periods)
```
GET /api/task-analysis/external/tasks/{source_task_id}/periods
```
时间轴已去掉:任务的数据只有一份当前状态,本接口固定返回**唯一一条**当前数据
承载记录(`periods` 数组长度恒为 1,`is_current` 恒为 `true`),供消费方感知
数据更新时间。响应 `200`:
```json
{
"task": {"task_id": "…", "source_task_id": "…", "name": "…"},
"current_period_index": 3,
"total": 1,
"periods": [
{
"period_index": 3,
"opened_at": "2026-09-14T15:00:00+08:00",
"trigger": "cron",
"run_id": "tar-…",
"is_current": true,
"blocks": {
"block_1": {"updated_at": "2026-09-14T15:03:12+08:00"},
"block_2": {"updated_at": null},
"block_3": {"updated_at": null},
"block_4": {"updated_at": null},
"block_5": {"updated_at": null},
"block_6": {"updated_at": null}
}
}
]
}
```
- 各块 `updated_at` 为 `null` 表示该块尚无数据;
- 首条承载记录由首次数据提交自动创建(`trigger=external`);存量任务沿用
历史期号(`period_index` 数值仅作标识,无时间轴含义)。
### 4.3 单期数据详情
```
GET /api/task-analysis/external/tasks/{source_task_id}/periods/{period}
```
`{period}` 传期号数字(如 `2`)或 `latest`(当前最新一期)。响应 `200`:
```json
{
"task": {"task_id": "…", "source_task_id": "…", "name": "…"},
"period": {
"period_index": 2,
"opened_at": "2026-09-14T12:00:00+08:00",
"trigger": "cron",
"run_id": "tar-…",
"is_current": false
},
"blocks": [
{
"block_key": "block_1",
"title": "数据块一",
"sort_order": 1,
"payload": {"热点列表": ["…"], "统计": {"提及量": 128}},
"updated_at": "2026-09-14T12:04:55+08:00"
},
{"block_key": "block_2", "title": "数据块二", "sort_order": 2, "payload": null, "updated_at": null}
]
}
```
- `blocks` 固定 6 条、按 `sort_order` 升序;尚未提交的块 `payload` / `updated_at`
为 `null`;
- `payload` 即该块的**合并结果**(多次提交按顶层 key 合并、同 key 后写覆盖),
结构由智能体产出决定,请按 JSON 对象渲染;
- `{period}` 推荐传 `latest`(当前数据);传数字期号可访问存量任务的历史
遗留数据(时间轴去掉前的旧期,仅供排查)。
错误:`404` —— 期不存在;`400` —— `period` 既不是数字也不是 `latest`。
### 4.4 修改块标题 / 排序(管理端)
块标题支持后续修改(页面 + API)。`{task_id}` 为 **DeerFlow 内部任务 id**(创建
接口响应里保存的那个)。
```
PUT /api/task-analysis/tasks/{task_id}/blocks
```
请求体(只传要改的块;块集合固定 6 条,不能增删):
```json
{
"blocks": [
{"block_key": "block_3", "title": "舆情热点"},
{"block_key": "block_1", "sort_order": 9}
]
}
```
响应 `200`:`{"blocks": […]}`(修改后的完整定义列表,形状同 4.1)。
错误:`400` —— `block_key` 不在 `block_1`~`block_6` 内。
### 4.5 演示数据(已预存)
开发环境已预存一个演示任务,可直接用于联调:
- 任务号 `source_task_id = BUSINESS-OVERVIEW-DEMO`;`block_1` 标题「商业态势总览」;
- 预存时按 13 期小时刻度写入(时间轴去掉前的演示口径);当前对外仅暴露最新一期
的 `block_1` payload = 页面整卡数据(`pageTitle` / `briefs` / `objectives` /
`events` / `businessNarratives` / `insights` / `chart` / `snapshotName` 等,
与页面 mock 快照同构);`block_2`~`block_6` 暂无数据;
- 预存脚本:`scripts/seed_business_overview_demo.py`(可重复运行,幂等重建)。
### 4.6 智能体数据提交(内部,供参考)
智能体侧由内置技能 `task-data-submit`(`skills/public/task-data-submit/`)调以下
接口完成入库,**对方系统无需调用**,此处仅供联调排查参考:
```
POST /api/task-analysis/data/submit
```
请求体:`{"task_id": "<source_task_id>", "block_key": "block_2", "data": {…JSON 对象…}}`。
响应 `200`:`{"source_task_id", "task_id", "block_key", "period_index", "updated_at", "keys"}`。
错误:`400` —— 块 key 非法 / payload 不是对象;`404` —— 任务不存在;`422` ——
请求体不是合法 JSON 对象。
## 5. 典型对接流程
```
对方系统创建任务
└─ POST /external/tasks ──► 保存 task_id(+ default_chain_id)
│
│ (DeerFlow 管理页配置:选业务链 + 执行频率 —— 无需开发)
▼
按 cron 自动执行(多轮并行,产出时间线版本)
├─ 详情页定期/手动 GET /external/tasks/{source_task_id}/detail ──► 渲染 blocks
└─ 数据交付(任务 6 块 JSON,见第 4 章)
├─ GET /external/tasks/{source_task_id}/periods ──► 当前数据状态(兼容路径)
└─ GET /external/tasks/{source_task_id}/periods/latest ──► 6 块完整 JSON
│
▼
详情页问答(可选)
├─ POST /tasks/{task_id}/qa/init ──► 保存 run_id + thread_ids
├─ POST /tasks/{task_id}/qa/stream(每轮,SSE 渲染对话与席位交付)
├─ (可选)POST /qa/{run_id}/apply-direction ──► 调整注入后续执行
└─ GET /external/runs/{run_id}/messages ──► 历史回放
对方系统删除任务
└─ DELETE /external/tasks/{source_task_id} ──► DeerFlow 侧级联清除
```
## 6. 错误码汇总
| 状态 | 场景 |
|---|---|
| 400 | 任务未绑定分析方案 / 链无席位 / 请求参数非法 / 数据块 key 非法 |
| 401 | 未带 token 或 token 失效 |
| 404 | 任务 / 会话 / 运行记录 / 期不存在 |
| 409 | `source_task_id` 重复创建;会话已收口或线程映射缺失;执行被跳过(业务链已删除/停用) |