agent-Specialization/docs/workflow_feature_plan.md
JOJO 4d9b709a9e feat(workflow): 实现工作流运行时并统一审核智能体配置
工作流运行时:
- 状态机与编排:modules/workflow_state_manager.py + server/workflow_flow.py
  (激活快照/阶段推进/审核节点/分支决策/柔性通知/max_stage_rounds 撞限询问)
- 五个工具(activate/report_stage/choose_branch/get_status/deactivate)
  与 REST API(server/workflow_runtime_api.py)
- 前端:QuickDock 工作流窗口(三段式进度,推进/驳回/完成/退出动画)、
  slash 菜单激活与退出、轮询事件消费、进入对话状态回填
- 审核:modules/workflow_review_agent.py(pass/reject 把关节点)

审核智能体统一配置:
- 个人空间新增「审核智能体」标签页:自动审批/目标/工作流三个审核智能体
  统一选择模型+思考模式+超时/轮次参数
- modules/review_agent_config.py 统一解析(复用子智能体模型库),
  废除独立 json 配置(auto_approval/goal_review/workflow_review)
- goal 审核接入 max_rounds 上限(原常量未接线);workflow 审核硬编码 6 轮改为可配

联调修复:
- /new 空对话激活:后端自动创建对话并完整继承模式参数
  (work_mode/permission/execution/reasoning_effort,修复思考模式丢失)
- 激活/通知消息 starts_work=True,恢复智能体回复头部与工作计时
- 节点目录改为从开始节点拓扑遍历(修复按保存顺序显示错乱)
- QuickDock 乐观掩码不再掩盖工作流实时状态(修复 /new 激活窗口瞬关+延迟瞬开);
  /new 路由不套用全局内容缓存(修复空对话展开空白数秒后收回)
- 工作流完成先广播完成态快照再摘牌,窗口播完落定+退出动画再收起
- 激活提示中的工具名修正为 report_workflow_stage
2026-08-21 16:50:35 +08:00

261 lines
18 KiB
Markdown
Raw 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.

# 工作流Workflow功能设计与实施方案
> 状态:**设计定稿2026-08-21**。工作流库页与可视化编辑器已实现;本文档是运行时实施的最终依据。
> 调研依据:`workflow_research/` 三份报告(外部产品 / 范式要素 / 代码挂载点)。
> 历史说明:本文档前身是 2026-08-18 的讨论稿;当时「审核作为阶段属性」「兜底提醒轮询」「整体结束审核」等设想已在定稿中推翻,以本文档为准。
## 1. 功能定义与核心理念
用户把「一套既定流程:工作方式 → 验证方式 → 结束方式」存为一个**工作流**workflow之后在任何普通对话中激活它让主智能体复用现有循环与执行引擎按流程推进阶段间可由审核智能体软审核。
三条核心理念(定稿):
1. **结构在边上,自主在节点内**——画布拓扑(节点 + 路由是结构约束阶段内主智能体完全自主自由调工具、跑脚本。外部调研LangGraph / Dify / CrewAI / n8n一致验证的范式。
2. **工作流是智能体的辅助流程,不是宿主**——任何工作流异常/终态都不得掐断智能体工作。所有退出/失败/超限统一为**柔性通知**:摘牌(改状态)+ 一条 user 消息,处置权交回模型与用户。
3. **对话级持续状态**——工作流状态不随单次任务结束、模型停止输出、用户按停止按钮而结束。模型停下后用户可自由穿插讨论,说「继续」即接着推进。
## 2. 已拍板决策(定稿汇总)
| 决策点 | 结论 |
|---|---|
| 运行方式 | 不做独立模式/特殊 URL/新对话类型;在普通对话中激活 |
| 激活入口 | slash 菜单人工激活(仅智能体空闲可用)+ AI 工具 `activate_workflow` 自主激活 |
| 同时激活数 | **一个对话同时只有一个工作流处于激活**;重复激活同工作流幂等返回进度,激活另一个被拒绝 |
| 审核建模 | **独立 review 节点**(菱形,一等公民),非阶段属性;要结束审核就在 end 前显式放 review 节点 |
| 结束节点语义 | end 即终点,汇报到 end 即 completed**无隐藏的整体结束审核** |
| 分支节点语义 | 单出线 = 并线器(自动穿过,无需决策);多出线 = AI 决策点(等 `choose_workflow_branch` |
| 审核异常 | 视为驳回(计入 reject_counts工具返回中含「请告知用户」 |
| maxRejects 撞限 | 工作流 failed经工具返回告知模型已在场不另发 user 消息 |
| max_stage_rounds 撞限 | **不停工作流、不停智能体**;注入 user 消息让模型立刻停下、告知用户、询问是否继续 |
| deactivate用户/模型/撞限) | 一律柔性通知退出,见 §4.7 |
| 兜底提醒轮询 | **取消**。模型停止输出即停止,工作流挂起不断,期间可与用户讨论 |
| 停止任务联动 | **不做**(不仿 stop_goal_user_cancel |
| 版本快照 | 激活时把 WORKFLOW.md 复制进状态目录;运行期一切读取只读快照,库文件被改不影响运行中实例 |
| 前后端通信 | 轮询(复用 task 轮询 session_data 快照链路)+ 统一通知池轮询器user 消息) |
| 状态隔离 | 对话级状态目录,多对话互不惊扰 |
| 硬校验 | 不做步骤级硬校验;保存时做结构校验(对齐前后端 validate |
## 3. 数据模型与存储(已实现)
### 3.1 节点模型(对齐 `static/src/components/workflow/workflowModel.ts`
五种节点,串行边界(无并行语义):
| kind | 形态 | 语义 |
|---|---|---|
| `start` | 胶囊 | 入口,右 1 出,恰好 1 个 |
| `end` | 胶囊 | 终点,左 n 入,至少 1 个 |
| `stage` | 矩形 | AI 执行阶段:`goal` + `instructions` + `next`(单值,显式连接) |
| `review` | 菱形 | 审核把关:`prompt`(审核关注点)+ `next`(通过路由)+ `rejectTo`(驳回路由)+ `maxRejects`(连续驳回上限,超限 failed |
| `branch` | 虚线矩形 | 分线/并线器:`next[]` 路由数组,每条带 `condition`自然语言AI 决策依据;多出线必填) |
所有路径显式化(`next` 为 null 校验不通过);`position` 仅画布坐标,与执行解耦。
### 3.2 工作流库(已实现)
- WORKFLOW.md = YAML frontmatter上述结构+ markdown 正文(工作方式/验证方式/结束方式)
- 双源合并:源码树 `workflows/`(内置种子)+ 运行态用户库host`~/.astrion/astrion/host/workflows/`
- 模块:`modules/workflow_manager.py`CRUD + 校验 + camelCase↔snake_case
- REST`server/workflow_page.py``/workflows`、`/workflow/<name>` 页面 + `/api/workflows` CRUD
### 3.3 运行时状态目录(待实现)
```
{workspace.data_dir}/workflow_states/<conversation_id>/
├── state.json # 运行状态
└── WORKFLOW.md # 激活时刻的原样快照
```
`state.json` schema
```json
{
"workflow_name": "code-review-pipeline",
"status": "active | completed | stopped | failed",
"exit_reason": "user | model | max_rejects | round_limit_ack …",
"current_node_id": "review-target-stage",
"stage_rounds": 3,
"round_limit_notified": false,
"stage_start_msg_index": 142,
"reject_counts": {"review-gate": 1},
"history": [
{"node_id": "explore", "kind": "stage", "summary": "…", "rounds": 5, "completed_at": 169},
{"node_id": "review-gate", "kind": "review", "decision": "reject", "message": "…", "at": 169}
],
"pending_notices": [
{"type": "deactivated_by_user", "message": "完整文本", "created_at": 169}
],
"started_at": 169
}
```
要点:
- **`current_node_id` 只停 stage / branch / end**——review 是**瞬态节点**汇报时同步审完直接走到下一站review 只作为 history 记录。状态机与前端进度展示因此大幅简化。
- **`stage_start_msg_index`(消息游标)**:进入阶段时记录 conversation_history 长度,审核 payload 截取增量作为阶段工作痕迹§4.5)。
- **`pending_notices`**柔性通知池§4.7),落盘持久,取出即清除。
## 4. 运行时机制(待实现)
### 4.1 上下文注入:目录常存,详情跟走
| 信息 | 载体 | 时机 |
|---|---|---|
| 全景目录(工作流名/描述/正文三段/全部节点一句话清单/当前位置) | system 段(**不冻结**,每次 build_messages 现生成) | 激活期间恒在,压缩免疫 |
| 当前节点详情stage 的 goal + instructions 全文) | 工具返回tool 消息进历史) | 激活时、每次推进时 |
| 迷失自查 | `get_workflow_status` 工具 | 模型主动调 |
注意:主循环单次任务内 messages 只构建一次,阶段推进后同一任务后续迭代的 system 段会滞后。实施时二选一:推进时在工具 handler 内同步刷新 messages 中的工作流段;或 system 段注明「以最新工具返回/状态查询为准」。首选前者。
### 4.2 激活(两路入口,共享 `build_activation_text()`
**AI 自主激活**`activate_workflow(name)` 工具 → 加载定义 → 复制快照 → 初始化 state → 工具返回全景 + 入口阶段详情。重复激活规则:同工作流幂等返回当前进度;不同工作流拒绝(提示先退出)。
**slash 菜单激活**REST
```
POST /api/workflow/activate {conversation_id, name}
→ 检查该对话无运行中主任务(门闸/terminal 状态),忙则 409「智能体运行中无法激活」
→ 复制 WORKFLOW.md 快照 + 初始化 state
→ 构造完整 user 消息(含全景 + 入口详情 + 「请开始执行」),走正常消息链路:
持久化 + 广播 + metadata 齐全(正常 user 消息参数一个不少,
另打 auto_message_type: "workflow_activate" 标记供前端识别样式)
→ 创建主任务过门闸 → 模型收到消息直接开干(无需再调 activate_workflow
```
### 4.3 阶段推进矩阵(核心)
`report_workflow_stage(summary)` 仅在当前节点为 stage 时可调。引擎读当前 stage 的 `next`,按目标类型分派:
| 下一节点 | 引擎动作 | 工具返回 |
|---|---|---|
| `stage` | 直接推进 | 「已记录完成。下一阶段「X」goal + instructions」 |
| `review` | **同步 await 审核智能体**§4.5 | 通过 → 「审核通过。下一阶段「X」…」驳回 → reject_counts+1回到 rejectTo「审核未通过意见…。你已回到阶段「Y」整改」 |
| `branch`(多出线) | 不推进,停在 branch 等选择 | 「前方分支点:→ A条件→ B条件。请调 choose_workflow_branch」 |
| `branch`(单出线) | 自动穿过(并线器无需决策) | 同 stage |
| `end` | status=completed | 「工作流已完成。请输出总结后结束」(模型随后自然停止) |
`choose_workflow_branch(target_node_id)`:仅当前停在 branch 时可调;校验 target 在候选路由集;推进后返回新阶段详情。
技术可行性已验证:`handle_tool_call` 为 asynctools_execution.py L960`submit_plan` 已证明工具可长阻塞等待外部事件——审核在工具内同步 await 成立。
### 4.4 审核智能体
`modules/workflow_review_agent.py`fork `goal_review_agent.py`),内部工具 `report_workflow_review(decision: pass|reject, message)`(仿 `report_goal_status`:唯一结论出口 + 强制工具调用重试)。配置统一走个人空间「审核智能体」页(`modules/review_agent_config.py::resolve_review_agent_config`,模型复用子智能体模型库);`review_mode: active` 时注入只读 run_command 取证。
**payload 构建**(核心:让审核看证据而非听汇报):
```
【工作流】{name}{description}
【本次审核把关】{review 节点名}
审核关注点:{review.prompt}
【被审核阶段】{stage 名}
阶段目标:{stage.goal}
阶段要求:{stage.instructions}
【阶段执行痕迹】(消息游标 stage_start_msg_index 截取的对话增量,截断控长)
1. run_command: git diff --stat → …
2. read_file: server/chat.py L120-180 → …
【主智能体阶段汇报】{summary}
【历史审核意见】(若是重审,带上前几次驳回意见)
```
### 4.5 审核结果与边界
- **pass** → 推进到 review.next若为 branch 多出线 → 停在 branch 等选择,返回分支菜单)。
- **reject** → reject_counts[node]+1 → 回到 review.rejectTostage 或 branch工具返回带审核意见。
- **审核异常/超时** → 视为驳回(计入计数),返回中含「审核服务可能异常,**请告知用户**」。
- **撞 maxRejects** → status=failedexit_reason=max_rejects工具返回「连续驳回超限工作流已终止请告知用户」。模型在场同轮闭环不另发 user 消息。
### 4.6 max_stage_rounds 撞限(柔性询问)
- `stage_rounds` 跨任务累计:主循环**每轮迭代** +1挂点在主循环层不在工具循环内——遵守注入时序铁律进入新阶段清零。
- 撞限 → 注入 inline user 消息(`inject_runtime_user_message(inline=True)`,下轮模型即看到):
「工作流阶段「X」已进行 N 轮,达到上限。请立刻停下当前工作,告知用户已超过 N 轮,并询问是否还要继续。」
- **工作流不停**status 保持 active原地挂起等用户发话。
- 防重复:撞限后 `round_limit_notified=true`
- 清零时机:下一条真实用户消息到达、新任务开始时清零(视作用户已知情交互);之后若再跑 X 轮会再次询问——每超 X 轮问一次。
### 4.7 柔性退出与通知池
**模型自主 deactivate / completed**:工具返回同轮闭环,不需要 user 消息;前端 UI 走进度事件。
**用户 slash deactivate**REST随时可用不做空闲检查——摘牌不打断正在跑的任务
- 智能体**运行中** → 事件入 `pending_notices`;在 `execute_tool_calls` 末尾统一消费点注入 inline 通知(与 `process_sub_agent_updates` 同位置;遵守「循环内收集 → 循环后注入」铁律),模型下轮看到。
- 智能体**空闲** → REST 直接派发:预占主任务门闸 → 完整 user 消息(持久化+广播+metadata 齐全)→ 创建主任务。与 slash activate 共用派发函数。
- **兜底**:运行中模型在通知被消费前就停了 → 任务结尾轮询器 spawn 条件兜住(见下)。
**通知池 = 统一完成通知轮询器的第三路**`poll_completion_notifications`2026-06 实施、2026-08 门闸化),不新造轮子。改动点(均在 `server/chat_flow_task_main.py`
1. `_collect_pending_completion_notices`:增加 workflow 一路(与子智能体、后台命令按时间混排)。
2. `needs_completion_poll`L2478 附近):扩展条件 `or _has_pending_workflow_notices(...)`——否则无后台任务时工作流通知产生后轮询器不 spawn。
3. 轮询器主体零改动(门闸预占、批量预写+末条触发、新任务续轮询全复用)。
通知消息 metadata 新增 `message_source: "workflow"`(未识别时回落 "user")。
**摘牌后的工具行为**stopped/failed 后模型再调 `report_workflow_stage` / `choose_workflow_branch` → 返回 `success:false` + 「工作流已退出(原因),如需重新开始请重新激活」——返回错误但不炸任务。
### 4.8 与 goal 模式叠加
不互斥。工作流活跃时主循环尾部 no-tool-calls 分支不做任何工作流拦截兜底提醒已取消goal 审核照常。
## 5. 工具清单
### 主智能体5 个)
| 工具 | 参数 | 行为/返回 |
|---|---|---|
| `activate_workflow` | `name` | 加载+快照+初始化;返回全景目录+入口阶段详情。同工作流幂等;不同工作流拒绝 |
| `report_workflow_stage` | `summary` | 阶段汇报核心状态机,返回按 §4.3 矩阵分派 |
| `choose_workflow_branch` | `target_node_id` | 分支选择;校验候选集;返回新阶段详情 |
| `get_workflow_status` | — | 返回当前节点/已走路径/各阶段轮数/审核历史(迷失自查+用户问进度) |
| `deactivate_workflow` | `reason` | 柔性退出:摘牌+工具返回确认(模型自主退出无需 user 消息) |
### 审核智能体内部1 个)
| 工具 | 参数 | 说明 |
|---|---|---|
| `report_workflow_review` | `decision: pass\|reject`, `message` | 唯一结论出口,仿 report_goal_status |
### REST3 个)
- `POST /api/workflow/activate`仅智能体空闲409 检查);快照+初始化+派发完整 user 消息任务
- `POST /api/workflow/deactivate`:随时可用;忙入通知池、闲直发任务
- `GET /api/workflow/status?conversation_id=`:轮询/刷新恢复
## 6. 通信与前端
- **轮询事件**sender → session_data 快照 → REST 轮询,对齐 goal 链路):`workflow_progress`(推进/驳回)/ `workflow_review_progress`(审核进行中)/ `workflow_completed` / `workflow_stopped` / `workflow_failed`。快照自带 conversation_id。
- **slash 菜单**:新增 workflows 模式,数据用现成 `GET /api/workflows`
- **进度展示**:仿 goal 进度组件——当前阶段名 · 已走路径 · 审核状态 · 轮数。
- **刷新恢复**`GET /api/workflow/status`。
## 7. 已实现部分清单(编辑器期)
- `modules/workflow_manager.py`、`server/workflow_page.py`
- `static/src/components/workflow/``workflowModel.ts`(模型/校验/dagre 自动排版)、`WorkflowLibraryView.vue`、`WorkflowEditorView.vue`、四种节点组件
- `workflows/` 四个内置示例code-review-pipeline / bug-fix-triage / feature-development / research-report
## 8. 实施清单(文件级,按依赖顺序)
1. `modules/workflow_state_manager.py`(新增):状态目录读写、快照复制、计数、通知池、消息游标。
2. `modules/workflow_review_agent.py`新增fork goal_review_agent+ `prompts/workflow_review_agent.txt`(配置后改为统一审核智能体设置,见 `modules/review_agent_config.py`)。
3. `server/workflow_flow.py`(新增):编排——`build_activation_text`、system 段构建、推进矩阵、审核调用、通知文本构造、状态查询。
4. 工具注册:`core/main_terminal_parts/tools_definition/` 新增 5 个定义;`tools_execution.py` 注册 handler。
5. system 段注入:`core/main_terminal_parts/context/messages.py` 追加工作流段(不冻结)+ 推进时刷新机制。
6. 主循环挂点(`server/chat_flow_task_main.py`stage_rounds 计数与撞限注入;`needs_completion_poll` 扩展;`_collect_pending_completion_notices` 加 workflow 路;工具循环末尾消费工作流通知。
7. REST`server/tasks/workflows.py`新增activate / deactivate / status。
8. 前端slash 菜单 workflows 模式、进度组件、轮询事件消费(`taskPolling/lifecycle.ts`)、刷新恢复。
9. 验证:`python3 -m py_compile` 改动文件 + `python -m pytest test/test_server_refactor_smoke.py -q`
## 9. 硬约束(实施必须遵守)
- **单写者/门闸**:所有工作流逻辑发生在主任务内部(工具执行 + 主循环层不新增主任务入口REST 派发走门闸预占AGENTS.md §12
- **注入时序铁律**:工具循环内禁止直接 `inject_runtime_user_message`——一律「循环内收集 → 循环后注入」(记忆 `runtime_injected_message_convention`)。
- **运行期注入标记**:注入的 user 消息必须走 `inject_runtime_user_message`(自动带 `runtime_injected` 等标记),否则刷新恢复重建会重复显示。
- **不掐断智能体**:任何工作流路径不得 raise/return 导致主任务异常终止;柔性优先。