# 工作流(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/` 页面 + `/api/workflows` CRUD) ### 3.3 运行时状态目录(待实现) ``` {workspace.data_dir}/workflow_states// ├── 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` 为 async(tools_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.rejectTo(stage 或 branch),工具返回带审核意见。 - **审核异常/超时** → 视为驳回(计入计数),返回中含「审核服务可能异常,**请告知用户**」。 - **撞 maxRejects** → status=failed(exit_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 | ### REST(3 个) - `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 导致主任务异常终止;柔性优先。