工作流运行时: - 状态机与编排: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
18 KiB
工作流(Workflow)功能设计与实施方案
状态:设计定稿(2026-08-21)。工作流库页与可视化编辑器已实现;本文档是运行时实施的最终依据。 调研依据:
workflow_research/三份报告(外部产品 / 范式要素 / 代码挂载点)。 历史说明:本文档前身是 2026-08-18 的讨论稿;当时「审核作为阶段属性」「兜底提醒轮询」「整体结束审核」等设想已在定稿中推翻,以本文档为准。
1. 功能定义与核心理念
用户把「一套既定流程:工作方式 → 验证方式 → 结束方式」存为一个工作流(workflow),之后在任何普通对话中激活它,让主智能体复用现有循环与执行引擎按流程推进;阶段间可由审核智能体软审核。
三条核心理念(定稿):
- 结构在边上,自主在节点内——画布拓扑(节点 + 路由)是结构约束;阶段内主智能体完全自主(自由调工具、跑脚本)。外部调研(LangGraph / Dify / CrewAI / n8n)一致验证的范式。
- 工作流是智能体的辅助流程,不是宿主——任何工作流异常/终态都不得掐断智能体工作。所有退出/失败/超限统一为柔性通知:摘牌(改状态)+ 一条 user 消息,处置权交回模型与用户。
- 对话级持续状态——工作流状态不随单次任务结束、模型停止输出、用户按停止按钮而结束。模型停下后用户可自由穿插讨论,说「继续」即接着推进。
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/workflowsCRUD)
3.3 运行时状态目录(待实现)
{workspace.data_dir}/workflow_states/<conversation_id>/
├── state.json # 运行状态
└── WORKFLOW.md # 激活时刻的原样快照
state.json schema:
{
"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):
_collect_pending_completion_notices:增加 workflow 一路(与子智能体、后台命令按时间混排)。needs_completion_poll(L2478 附近):扩展条件or _has_pending_workflow_notices(...)——否则无后台任务时工作流通知产生后轮询器不 spawn。- 轮询器主体零改动(门闸预占、批量预写+末条触发、新任务续轮询全复用)。
通知消息 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.pystatic/src/components/workflow/:workflowModel.ts(模型/校验/dagre 自动排版)、WorkflowLibraryView.vue、WorkflowEditorView.vue、四种节点组件workflows/四个内置示例(code-review-pipeline / bug-fix-triage / feature-development / research-report)
8. 实施清单(文件级,按依赖顺序)
modules/workflow_state_manager.py(新增):状态目录读写、快照复制、计数、通知池、消息游标。modules/workflow_review_agent.py(新增,fork goal_review_agent)+prompts/workflow_review_agent.txt(配置后改为统一审核智能体设置,见modules/review_agent_config.py)。server/workflow_flow.py(新增):编排——build_activation_text、system 段构建、推进矩阵、审核调用、通知文本构造、状态查询。- 工具注册:
core/main_terminal_parts/tools_definition/新增 5 个定义;tools_execution.py注册 handler。 - system 段注入:
core/main_terminal_parts/context/messages.py追加工作流段(不冻结)+ 推进时刷新机制。 - 主循环挂点(
server/chat_flow_task_main.py):stage_rounds 计数与撞限注入;needs_completion_poll扩展;_collect_pending_completion_notices加 workflow 路;工具循环末尾消费工作流通知。 - REST:
server/tasks/workflows.py(新增):activate / deactivate / status。 - 前端:slash 菜单 workflows 模式、进度组件、轮询事件消费(
taskPolling/lifecycle.ts)、刷新恢复。 - 验证:
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 导致主任务异常终止;柔性优先。