Files
deerflow-code/frontend-web/docs/microsoft-agent-framework-多智能体会商-实施计划.md
T
2026-08-03 19:27:54 +08:00

45 KiB
Raw Blame History

MAF 多智能体会商升级版实施计划(V2:保留原会商体验,替换底层编排)

文档状态:V2 重写,待按本计划重新实施 更新时间:2026-08-02 本轮决策:原 /page/maf/* 的「会话列表 + run 详情 + 前端轮询」原型不再作为目标产品继续扩展。 产品目标:新 MAF 会商是原多智能体会商页面的底层升级版,不是另造一套会商产品。


1. 本次重新确认的产品目标

用户认可的是现有多智能体会商的视觉语言和交互链路:左侧历史会话、中心对话流、输入框发问、意图理解、总控派活、席位发言、过程卡片、澄清与审批、最终结论。

本次升级只替换以下“看不见的发动机”:

  • 旧的前端驱动编排、多个前端可见线程和旧会商作业,替换为 MAF Workflow + DeerFlow Agent Adapter;
  • 浏览器定时轮询,替换为一条可恢复的 SSE 对话事件流;
  • 用户手动创建/管理多个智能体线程,收敛为服务端按需创建和持久化的内部执行线程;
  • 保留现有工具、技能、MCP、沙箱、WriteGuard、审批和审计能力,并让它们在原有会商体验中自然出现。

不能接受的结果: 新页面没有对话列表、没有输入框、让用户先创建 session/run、需要用户选择或理解多个内部线程、靠多个定时 GET 拼出实时效果,或把审批/流程图做成脱离聊天主链路的独立后台页。

1.1 必须保留的用户体验

原会商能力 升级版要求
左侧会商历史、新建会商 保留。一个条目就是一个用户可见会商,不暴露 MAF session/run/thread。
中央连续对话流 保留。用户消息、总控消息、席位发言、工具进度、澄清、审批、最终报告按时间顺序呈现。
底部对话输入框 保留。用户可在首轮发起任务、在澄清时回答、在会商结束后追问/继续会商。
意图理解 保留并服务端化。先识别“可直接会商 / 需要澄清 / 只回答问题 / 需要工具或写入”。
总控智能体派活 保留。总控是唯一能选择席位、分派任务、收束轮次和生成结论的主体。
业务链、席位与过程可视化 保留其信息架构和交互,不复用旧业务状态;数据改由 MAF 事件驱动。
澄清、取消、恢复、审批 保留,并成为对话流中的卡片,而不是跳转到 run 管理页。

1.2 明确不保留的实现方式

  • 不在浏览器端 setInterval 轮询 run、events、actions、approvals;
  • 不让浏览器创建或维护 seat thread、manager thread、thread map;
  • 不让用户先填写“经理、席位、模式、最大轮数”才能开始一次正常会商;
  • 不把 MafSessionsPage / MafRunDetailPage 当作新产品主界面继续堆功能;
  • 不调用旧的 /api/roundtable-*、/api/multi-agent/*、roundtable_jobs、旧草稿或旧会商状态;
  • 不修改旧 RoundtablePlanningPage 的业务状态机、历史数据和对外行为。

2. 总体架构与边界

flowchart LR
  U[用户:会商对话页] -->|POST 新建/发送消息| API[MAF Conversation API]
  API --> C[(MAF Conversation / Message)]
  API --> D[MAF Dispatcher]
  D --> W[MAF Workflow]
  W --> M[总控:意图、派活、收束]
  M --> S[服务端按需创建席位执行线程]
  S --> A[DeerFlow Agent Adapter]
  A --> T[工具 / 技能 / MCP / 沙箱]
  T --> G[WriteGuard + 审批]
  W --> E[(持久化会商事件)]
  E --> H[SSE Hub:重放 + 实时推送]
  H -->|一条 SSE 流| U

2.1 前后端职责

层 职责 禁止事项
前端 呈现会商、发送用户消息、消费 SSE、执行用户明确点击的取消/审批/重试 编排席位、决定下一位发言者、创建内部线程、轮询事件。
MAF Conversation Service 会话聚合、消息持久化、运行创建、SSE 重放、所有权校验 让浏览器传入 user_id、工具能力快照、目标键或内部幂等键。
MAF Workflow 意图判断、总控派活、席位协作、交叉审查、结论、恢复 把模型输出直接当作可写外部系统的授权。
DeerFlow Adapter 为总控/席位提供既有模型、工具、技能、MCP、沙箱和用户上下文 从 packages/harness/deerflow/** 导入 app.*。
WriteGuard 风险识别、审批、目标租约、一次执行、审计 将密钥、target_key、idempotency_key 回传给浏览器或模型。

2.2 新旧隔离规则

  1. 旧会商继续运行,旧路由、旧 API、旧数据表、旧任务深链全部不变。
  2. 新页面独立使用 /api/maf-roundtable/* 和 maf_roundtable_* 表;只允许参考旧页面的布局、文案、交互和通用视觉规范。
  3. 旧 roundtable-planning/** 中的业务 hook、草稿、Job、SSE 消费器和状态类型不能被新页面直接 import。
  4. 若需要复用旧组件的视觉效果,必须复制/迁移为 maf-roundtable/legacy-compatible/** 中的新组件,替换为 MAF view model;或抽到无业务依赖的公共展示组件。旧页面不得因此改变行为。
  5. 新旧页面都只能使用仓库本地依赖;UI 基础组件统一采用 tdesign-react,不接远程 UI、CDN 或外部运行时。

3. 用户可见的新版会商流程

3.1 首次进入

  1. 用户点击独立菜单“MAF 会商(升级版)”,进入与旧会商相同层级的页面壳。
  2. 左侧显示自己的 MAF 会商历史和“新建会商”。新建只创建一个用户可见会商,不显示 session/run/thread 表单。
  3. 中心区域显示欢迎语、业务链/任务上下文入口和对话输入框。
  4. 用户输入任务后,前端立即插入本地的用户气泡,调用一次 POST /messages,然后消费同一会商的 SSE 流。

3.2 一次会商轮次

  1. SSE 推送“正在理解任务”事件;页面以旧会商的过程卡/总控气泡表现。
  2. 若信息不足,推送 clarification.required,页面显示可回复的澄清卡;用户回答后仍通过输入框或卡片提交。
  3. 若可以执行,总控输出“派活计划”;页面以旧的席位条、派活卡和消息气泡展示。
  4. 每个席位的可见发言、工具进度、技能过程、交叉审查和总控收束都写入同一条时间线。
  5. 出现外部写操作时,SSE 推送审批卡。用户批准/拒绝后,后端恢复工作流,SSE 继续推送;前端不手工轮询 run 状态。
  6. 最终结论、事实账本、执行动作和报告作为对话流中的结果卡呈现;用户可以继续在同一会商输入追问。

3.3 “一个会商”与内部线程的关系

  • 用户只认识 conversation_id;左侧历史、URL 和前端状态都以它为主键。
  • 一个 conversation 可以有多轮用户消息,每轮消息产生一个内部 maf_run。
  • maf_session、manager/seat thread、seat run 都是服务端内部执行身份。服务端使用既有 ExecutionPrincipal 绑定当前用户,并在真正需要某席位执行时懒创建/复用线程。
  • 浏览器只收到经过脱敏的消息和事件,不会收到内部 thread id、能力快照、目标键、幂等键、密钥或原始工具结果。

3.4 总控质量闸门:派活不是“发出即完成”

当前旧会商的问题不是没有派活,而是席位只说一两句话、格式和证据都不合格时,总控仍把它当作完成并直接进入下一步。新版 MAF 必须把总控从“消息转发者”升级为每项席位交付的验收责任人。

每一个由总控发布的席位任务都必须有服务端持久化的 task_contract:

字段 含义
objective 本席位要回答的具体问题,不能只写泛泛角色描述。
expected_deliverable 交付类型和结构,例如“风险清单 + 依据 + 优先级 + 建议”。
acceptance_criteria 由总控给出的可验收标准:覆盖范围、最少关键点、证据/工具依据、格式与约束。
required 是否为本阶段必需交付;必需项不能被静默跳过。
max_rework_attempts 同一席位最多返工次数,默认 2(初稿之外最多两次返工),服务端配置且写入快照。
fallback_policy 到达返工上限后的策略:改派、请求用户澄清,或带缺口受控推进。

3.4.1 席位交付与总控验收状态机

stateDiagram-v2
  [*] --> assigned
  assigned --> delivering
  delivering --> submitted
  submitted --> manager_review
  manager_review --> accepted: 达到合同标准
  manager_review --> rework: 不合格且未到返工上限
  rework --> delivering: 带明确退回意见
  manager_review --> reassigned: 达到上限且可改派
  reassigned --> delivering
  manager_review --> exhausted: 达到上限且无合适改派
  exhausted --> controlled_gap: 记录缺口、风险与原因
  accepted --> [*]
  controlled_gap --> [*]

验收规则如下:

  1. 席位先提交结构化 delivery,至少包含结论、依据/证据、未解决项、自检结果;不能只输出“已完成”或一两句空泛结论。
  2. 进入 manager_review 前先执行确定性检查:空内容、最小有效长度、必须章节、必填字段、所需证据/工具引用、重复文本、错误 schema。确定性不通过时不允许直接 accepted。
  3. 总控随后根据 task_contract 做结构化审查,决策只能是 accept、return_for_rework、reassign、ask_user、controlled_gap,并必须写明 reason 和针对性修改要求。
  4. 总控的模型自评不是验收证据。 席位自评分只作为参考;验收由确定性规则 + 总控审查 + 必要时交叉审查共同决定。
  5. 对同一席位,默认最多两次返工。每次打回都必须把“缺什么、怎样补、哪些原结论不可用”带入下一次任务上下文。
  6. 到达上限后绝不把不合格结果伪装成合格:总控应优先改派给一个合适备用席位(默认最多一次改派);仍无法满足时生成 controlled_gap,明确标记未覆盖问题、风险和对最终结论的影响,再受控进入下一阶段。
  7. 一个阶段的所有 required 任务必须处于 accepted 或 controlled_gap 等明确终态,阶段闸门才可通过。总控不能因为“轮数到了”或“已有部分回答”跳过未决必需项。
  8. 最终报告不得将 controlled_gap 的内容写成已验证事实;它必须在结论中的风险/待补信息部分可追溯显示。

这既满足“打回几次后不要死循环”的要求,也避免“超过次数就把垃圾答案强行推进”的错误行为。

3.4.2 对话页必须可见的质量反馈

  • 总控派活卡展示任务目标、交付要求和当前第几次尝试;
  • 席位提交后显示“总控审核中”,而不是立即标为完成;
  • 打回时以总控消息卡显示具体退回理由和补充要求;
  • 改派时显示原席位未通过和新席位承接范围,但不羞辱性展示内部评分;
  • 受控降级时显示“存在未解决缺口”,并在最终结果卡中保留风险提示;
  • 右侧席位条区分“执行中、待返工、已验收、已改派、存在缺口”,不能只显示“发过言”。

4. API 与 SSE 契约(必须先定,前端不得猜测)

4.1 Conversation API

以下接口全部位于 /api/maf-roundtable,身份只从服务端鉴权上下文读取。

接口 用途 前端调用时机
GET /conversations 左侧历史列表(分页) 首次进入、用户显式刷新、创建/删除后失效刷新;无定时轮询。
POST /conversations 创建空白用户会商 点击“新建会商”。只接收 title、任务上下文等安全字段。
GET /conversations/{id} 获取会商快照、权限和当前状态 进入会商或浏览器刷新时。
GET /conversations/{id}/messages 获取历史消息分页 进入会商、向上滚动加载历史。
POST /conversations/{id}/messages 原子写入用户消息并启动 MAF run 用户点击发送或提交澄清。返回 message_id、run_id、conversation_id。
POST /conversations/{id}/cancel 取消当前活跃 run 用户显式点击取消。
POST /approvals/{id}/decision 批准/拒绝写入动作 审批卡点击;成功后由后端恢复 workflow。
POST /conversations/{id}/recover 显式恢复异常中断的活跃会商 仅在后端判定可恢复时展示。

不再让页面以“创建 session → 创建 run → GET events 循环”的方式驱动会商。原有低层 session/run 接口可以作为内部诊断 API 暂时保留,但从用户页面和导航移除。

4.2 SSE:唯一的实时通道

GET /api/maf-roundtable/conversations/{conversation_id}/stream?after_seq={last_seen_seq}
Accept: text/event-stream
Authorization: 与现有 fetch 客户端一致
  • 前端在进入一个 conversation 后只建立一条 fetch-reader SSE 连接;切换会商、卸载页面、权限失效时 Abort。
  • 浏览器不能用定时 GET 代替 SSE。连接断开后采用指数退避重连,并携带最后已确认的 after_seq;不产生全量重复气泡。
  • after_seq 是 conversation 维度、服务端单调递增的序号,不能复用每个 run 独立的 seq。
  • 首次连接先由 GET messages 加载历史,再从该历史的最大 seq 订阅 SSE;服务端也必须支持重放,避免“历史请求和订阅之间”丢事件。
  • SSE 使用 fetch + ReadableStream 解析,以复用项目鉴权头;响应必须带 Content-Type: text/event-stream、Cache-Control: no-cache、X-Accel-Buffering: no,并每 15 秒发送心跳。
  • 服务端负责等待和推送。单 worker 可用进程内 conversation event hub;生产多 worker 部署前必须接入 Redis Pub/Sub 或等价分布式广播,不能退回浏览器轮询。

4.3 SSE 事件信封

所有事件统一为:

{
  "seq": 42,
  "event_id": "evt_...",
  "conversation_id": "conv_...",
  "run_id": "run_...",
  "type": "agent.message.delta",
  "occurred_at": "2026-08-02T12:00:00Z",
  "data": {}
}

允许的首批 type:

类型 对话页表现
conversation.snapshot 首帧状态同步,不重复插入消息。
user.message.created 刷新/多标签同步时补齐用户气泡。
manager.intent 总控“正在理解/已理解”的过程卡。
clarification.required / clarification.resolved 澄清卡及其回答状态。
manager.dispatch 总控派活卡、席位条状态更新。
seat.delivery.submitted 席位提交交付,进入总控审核而非直接完成。
manager.review.decision 展示验收、打回、改派或受控降级及其安全摘要。
seat.rework.assigned / seat.reassigned 更新第几次返工、原/新席位和新的任务要求。
stage.quality_gate 阶段质量闸门通过、阻塞或带缺口推进。
agent.message.start / delta / complete 席位或总控流式气泡。
tool.started / tool.progress / tool.completed 现有步骤卡/工具过程,不显示敏感参数。
approval.required / approval.decided 嵌入对话流的审批卡。
fact.confirmed / review.completed 事实/交叉审查摘要卡。
run.status / run.error / run.completed 顶部状态、失败重试与最终结果。

事件 data 必须先经过现有 MAF 安全规范化和二次展示脱敏;前端不负责猜测工具风险或修复敏感数据。


5. 后端改造计划

MAF-R0:冻结错误原型并建立旧会商基线

难度:D2(中低)|负责人:前端/测试各 1 人|前置:无

  • 将现有 /page/maf/* 标记为“实验原型”,从正式菜单移除;不得在其上继续新增业务功能。
  • 记录旧会商的页面状态:空会商、发送后、意图澄清、总控派活、席位流式发言、审批、完成、失败恢复、历史切换。
  • 为每种状态保存可复现的测试数据与截图基线;截图只作为视觉验收参考,不作为数据契约。
  • 输出旧组件到新 MAF view-model 的映射清单,禁止直接搬旧 hook。

验收: 旧会商无行为回归;团队对“复制体验、替换编排”有书面映射表。

MAF-R1:Conversation 聚合与消息持久化

难度:D5(高)|负责人:后端资深 1 人|前置:R0

新增/迁移 MAF 专用持久化模型:

  • maf_roundtable_conversations:用户可见会商,至少包含 id、owner_user_id、title、task_context、安全状态、active_run_id、created_at、updated_at;
  • maf_roundtable_messages:用户消息、总控/席位消息、澄清/审批/结果卡的稳定历史表示;
  • maf_roundtable_conversation_events:conversation 维度严格递增的 seq、event_id、run_id、type、安全 data、created_at;
  • 现有 maf_roundtable_sessions/runs/events/seat_runs/actions/approvals 保留为底层执行与审计记录;conversation 与内部 session/run 显式关联。

要求:

  1. 发送用户消息、创建/占用 run、写入首个用户消息事件必须在清晰的事务边界内完成;失败不留“消息已显示但未运行”的孤儿状态。
  2. 消息历史必须可在刷新后重建对话;不能只依赖内存或 SSE 临时帧。
  3. 所有读写继续 owner-only;管理员诊断只读不扩大写权限。
  4. 新迁移必须 SQLite/PostgreSQL/MySQL 可重复执行;旧 MAF 原型数据可保留,不强制伪造为新对话历史。

验收: 会话创建、连续发消息、刷新恢复、并发发送冲突、跨用户隔离、迁移幂等都有 API 和存储测试。

MAF-R2:服务端 SSE Hub 与断线续传

难度:D5(高)|负责人:后端流式/并发经验者 1 人|前置:R1

  • 新增 conversation stream 路由和 ConversationEventHub;Workflow/Dispatcher 的规范化事件落库后再发布,顺序是“先持久化、后通知”。
  • SSE 连接先按 after_seq 重放,再订阅实时事件;重放和订阅切换期间必须有序、不丢帧、不重复。
  • workflow 终态、审批等待、审批恢复、取消、失败重试都必须通过同一流通知。
  • 不允许每个 SSE 客户端创建数据库轮询循环。服务端可以阻塞等待 hub 通知,事件重放只在连接/重连时发生。
  • 写出单 worker 与多 worker 的实现边界;若部署配置多 worker,未接入分布式广播时健康检查必须明确告警并禁止该模式上线。

验收: 测试覆盖慢客户端、断线重连、after_seq 重放、同时打开两个标签、切换会商、取消、审批后恢复、进程内 hub 异常和终态自动关流。

MAF-R3:总控意图理解与派活语义对齐

难度:D5(高)|负责人:MAF/Agent 负责人 1 人|前置:R1,可与 R2 并行

在现有 MAF Workflow 上增加用户对话入口状态,而不是让前端预先填 manager/seat/run:

  1. 总控首先进行意图判断:普通问答、需要澄清、单席位任务、并行专家会商、链式业务会商、需要工具/写入。
  2. 总控产出受 schema 校验的派活计划;只有服务端可将计划转成实际席位执行。
  3. 每个计划项必须生成并冻结 task_contract(目标、交付结构、验收标准、必需性、返工上限和降级策略),席位的发言不等于交付完成。
  4. 席位完成后先做确定性完整性检查,再由总控做结构化验收;总控可接受、打回同一席位、改派、请求用户补充或记录受控缺口。所有决策、次数和理由持久化到 checkpoint 与审计事件。
  5. 默认初稿后最多两次同席位返工;到达上限优先改派一次,仍失败才以带风险标记的 controlled_gap 结束。严禁自动把不合格交付推进为合格事实。
  6. 阶段迁移需经过质量闸门:所有必需任务均有 accepted 或受控缺口终态;最终总结只能消费已验收事实,缺口必须显式传入风险章节。
  7. 席位集合来自业务链、可信能力快照和上下文;前端可呈现“建议/已参与席位”,但不能提交任意工具权限或 thread id。
  8. 总控每轮应吸收已确认事实、验收结果、退回原因和用户追问;弱模型无效派活、重复派活、无收敛时走确定性纠偏/终止策略。
  9. 已有 structured/group_chat、事实账本、交叉审查、审批 checkpoint、执行阶段身份均继续复用;只重构其输入输出为 conversation event。

验收: 用同一任务对照旧会商的意图澄清、总控派活、席位协作、打回/改派和收束结论;弱模型的短答、空答、错误 schema、缺证据、重复派活、非法席位、超轮次、返工上限和受控降级都有确定性保护测试。

R3 当前实施记录(2026-08-03)

后端已先完成 R3 的服务端核心骨架,作为 R1/R2 Conversation API/SSE 的后续:

  • app/maf_roundtable/dispatch_contracts.py 提供确定性意图分类、服务端业务路线解析、schema 校验的 MafDispatchPlan 和弱模型防护;请求、模型输出都不能提供 agent id、thread id、tool metadata 或能力快照。
  • MafRoundtableConfig 增加 default_manager_agent_id、default_seat_agent_ids、business_routes 和 max_seats_per_run。仓库配置保持空路线;上线前必须由部署配置填入实际 agent catalog 中的精确 id,未知业务路线失败关闭。
  • 首条消息在同一事务内创建内部 session、服务端选定的 manager/seat participants 和冻结能力快照;澄清意图进入 waiting_input,不创建 run,用户补充信息后才允许重新 claim。
  • Conversation service 已接入现有 MafRunDispatcher/WorkflowRunner,持久化 manager.intent、manager.dispatch 和 run 状态桥接事件;现有结构化工作流的席位集合仍只来自服务端 participants,manager 文本不能扩席或改派非法席位。
  • V2 POST /conversations/{id}/messages 只返回 message_id、conversation_id、seq;run_id 仍是持久层/服务端内部关联字段,不返回给浏览器。
  • 新增 tests/test_maf_phase3_conversation_dispatch.py,覆盖未知业务路线、默认路线、澄清、完成状态桥接、重复/越权派发计划等确定性用例。R3 尚未整体验收完成:仍需完成新页面、完整真实 MAF Workflow E2E、质量门禁和与旧会商体验的浏览器对照验收。

MAF-R4:将审批和外部写入嵌回对话主链路

难度:D4(较高)|负责人:后端安全 + 前端各 1 人|前置:R2、R3

  • 保留 Phase 5 的 WriteGuard、能力快照、HMAC 目标键、租约、加密参数、一次执行和审计;不得为了 SSE 改弱任何安全边界。
  • approval.required 只携带白名单展示字段和安全摘要。审批决定后由后端自动续跑,前端只等待同一 SSE 流中的新事件。
  • 拒绝、过期、执行失败、unknown 均形成清晰对话卡和可恢复状态;不得把“未知结果”伪装成成功。
  • 行为审计可在最终结果区展开查看,但不能替代对话中的关键用户反馈。

验收: HTTP → MAF → ToolNode/outbox → 审批 → SSE → 前端卡片 的端到端测试;确保 target_key、idempotency_key、internal_canary、密钥和原始工具结果从不进入消息/API/SSE。


6. 前端改造计划:复刻体验,替换状态源

MAF-R5:新会商页面壳与历史列表

难度:D4(较高)|负责人:熟悉旧会商的前端 1 人|前置:R0、R1

新建 src/maf-roundtable/conversation/**,建议结构:

maf-roundtable/conversation/
  pages/MafRoundtableConversationPage.tsx
  components/
    ConversationSidebar.tsx
    ConversationTimeline.tsx
    ConversationComposer.tsx
    ManagerDispatchCard.tsx
    SeatMessageBubble.tsx
    ToolProgressCard.tsx
    ClarificationCard.tsx
    ApprovalMessageCard.tsx
    FinalResultCard.tsx
    ParticipantStrip.tsx
  hooks/
    use-maf-conversations.ts
    use-maf-conversation-stream.ts
    use-maf-conversation-reducer.ts
  api/conversations.ts
  lib/event-reducer.ts
  styles/maf-roundtable-legacy-compatible.css

页面要求:

  • 左侧 ConversationSidebar 的层级、历史列表、新建、激活态、删除/重命名交互对齐旧会商;
  • 中间 ConversationTimeline 使用连续消息流,保留旧会商的用户气泡、总控气泡、席位气泡和时间锚点;
  • ConversationComposer 常驻底部;发送、停止、澄清回答、追问都在该入口完成;
  • 右侧仅保留旧体验中真正有用的参与席位、当前阶段和业务链摘要,不再摆放 run/session 管理后台;
  • 使用本地 tdesign-react 组件实现按钮、输入、Dialog、Tag、Tabs 等基础交互,同时通过 scoped CSS 对齐旧视觉;
  • 视觉相似不等于 import 旧业务组件。旧组件仅作参考,数据类型、hook 和 API 必须是 MAF 专用实现。

验收: 不连接后端时,使用固定 MAF 事件样本可完整演示旧会商同等的 8 种关键状态;没有 session/run/thread 表单。

MAF-R6:SSE 客户端、事件 reducer 与刷新恢复

难度:D5(高)|负责人:前端流式经验者 1 人|前置:R2、R5

  • use-maf-conversation-stream 只维护一个连接、一个 cursor、一个 AbortController;不得含 setInterval、refetchInterval 或轮询 fallback。
  • reducer 以 (conversation_id, seq) 去重并排序,将原始事件转为稳定 view model;流式 delta 必须按 message_id 合并,不能用数组下标。
  • 切换会商时先 abort 旧流并增加 generation;旧 SSE 帧永远不能污染新会商。
  • 刷新时先加载消息历史,再以最后 seq 订阅;网络断开显示“正在重连”,重连成功不重复气泡。
  • 只有历史列表等非实时资源可在用户主动操作后调用 GET;不能靠后台刷新伪装实时性。

验收: 模拟 1 万条历史、跨页加载、慢旧流切换、新流先到、断线重连、重复帧、乱序帧、终态关流和多标签同步;所有案例必须组件级测试。

MAF-R7:意图/派活/审批卡的旧体验兼容

难度:D4(较高)|负责人:前端业务负责人 1 人|前置:R3、R4、R6

  • 用旧 IntentClarificationCard、MessageStepsCard、ParallelSeatStrip、MessageBubble 的交互作为视觉和信息架构参照,重新实现 MAF 版本。
  • 总控派活计划必须先显示“将由谁做什么”,席位开始/结束、工具过程和交叉审查要回到原有对话叙事中。
  • 席位“发言结束”只能显示为“已提交,待总控审核”;只有收到 manager.review.decision=accept 才能显示“已验收”。打回次数、改派和缺口必须清楚可见。
  • 审批卡需要同步防双击锁、二次脱敏、拒绝/通过后的“等待工作流继续”状态;不可另外跳转到 action 审计页。
  • 最终结论卡要区分“建议动作”“审批中动作”“已执行动作”“失败/未知动作”。
  • 继续追问时,页面不新建多个用户可见线程;后端根据 conversation 上下文决定是否创建新 run 或继续恢复。

验收: 产品人员可在不看技术术语的情况下完成“发起会商 → 澄清 → 观察派活 → 审批 → 查看结论 → 追问”全链路。


7. 测试、上线与回滚

7.1 必须新增的自动化测试

类别 核心用例
后端事务 发消息/创建 run 原子性、并发发送、跨用户隔离、迁移幂等。
SSE 服务端 重放、顺序、心跳、取消、断线、审批恢复、多订阅者、终态关流。
Workflow 意图澄清、总控派活、弱模型格式错误、重复派活、最大轮次、恢复。
质量闸门 短答/空答、缺少必填章节、无证据、总控打回、两次返工上限、一次改派、受控缺口、阶段阻塞和最终报告不把缺口伪装成事实。
安全 SSE/API/历史消息不泄露敏感键和值;审批和一次写入仍保持现有 Phase 5 保证。
前端 reducer delta 合并、去重、乱序、切换代次隔离、重连 cursor。
前端组件 输入发送、澄清、派活、审批锁、取消、失败恢复、历史切换、无轮询断言。
E2E 从用户输入到真实 MAF Workflow、ToolNode/outbox、审批、最终结果的 SSE 全链路。
回归 旧 roundtable-planning、旧 DeerFlow、AI 写作以及既有 MAF Phase 1–5 用例全部通过。

7.2 人工视觉验收

在同一浏览器尺寸下对照旧会商,至少核对:

  1. 空白页和新建会商;
  2. 左侧历史/当前会商切换;
  3. 用户输入、流式总控消息、席位消息;
  4. 意图澄清和总控派活;
  5. 工具过程、审批、取消、失败恢复;
  6. 最终结论和连续追问;
  7. 窄屏滚动、长内容、断线重连和页面刷新。

7.3 灰度与回滚

  • 新入口使用独立 feature flag,例如 maf_roundtable.conversation_ui_enabled;旧会商不受该开关影响。
  • 先仅向内部账号开放,记录连接数、重连率、事件延迟、工作流失败率、审批耗时和前端异常。
  • 出现问题时关闭新入口即可;不迁移或删除旧会商数据,也不需要回滚旧页面。
  • 当前错误原型可保留为仅开发者诊断路由,或在新版稳定后删除;它不应继续出现在用户菜单。

8. 分阶段任务分配、难度与交付顺序

本节是分工的唯一依据。难度定义:D1=很低(局部文案/样式),D2=低(明确边界的小模块),D3=中(跨 2–3 个模块),D4=较高(跨前后端或需回归),D5=高(并发、状态机、安全或 Agent 行为,必须由有经验者负责)。

阶段 0:冻结错误原型,提取旧会商交互基线(R0)

难度:D2|建议人员:1 名熟悉旧会商的前端 + 1 名测试|依赖:无

具体要做:

  1. 将现有 /page/maf/* 的 session/run 详情原型从正式菜单隐藏,标注为开发诊断原型,停止继续加功能。
  2. 逐一记录旧会商的 8 类页面状态:空白/新建、历史切换、用户提问、意图澄清、总控派活、席位发言、审批、完成/失败恢复。
  3. 给每种状态保留可复现 mock 数据、页面截图和操作步骤;梳理旧组件到新 MAF view-model 的映射。
  4. 明确哪些只能参考视觉和交互,哪些旧业务 hook/API/状态禁止复用。

交付物:旧会商交互地图、截图基线、组件映射表、被隐藏的原型入口说明。

验收:旧会商没有代码行为变化;任何人可以根据基线判断新版是否“像原页面”。

阶段 1:建立用户可见 Conversation 与消息历史(R1)

难度:D5|建议人员:1 名资深后端|依赖:阶段 0

具体要做:

  1. 新增 maf_roundtable_conversations、maf_roundtable_messages、maf_roundtable_conversation_events,设计 owner、标题、消息、conversation 全局序号、活跃 run 和安全状态字段。
  2. 建立 conversation 与现有 MAF session/run/seat-run 的内部关联;用户只得到 conversation id,不能看到内部 thread id。
  3. 实现会商历史列表、创建空白会商、读取会商快照、读取消息分页、发送用户消息五类 API。
  4. 发送消息时,用户消息持久化、run 创建/占用和首个事件必须有明确事务边界;并发发送、重复请求、失败回滚都要处理。
  5. 完成 SQLite/PostgreSQL/MySQL 迁移与 owner-only 权限测试。

交付物:迁移脚本、repository/service/router、API schema、后端事务与隔离测试。

验收:刷新后能从消息历史恢复完整会商;跨用户不可读写;失败不会留下“已显示但没有实际运行”的孤儿消息。

阶段 2:服务端 SSE 对话流、事件 Hub 与断线续传(R2)

难度:D5|建议人员:1 名熟悉 FastAPI 异步流与并发的后端|依赖:阶段 1

具体要做:

  1. 实现 GET /conversations/{id}/stream?after_seq=,按 conversation 全局 seq 先重放、后订阅实时事件。
  2. 新建 ConversationEventHub;所有 workflow 事件先安全落库,再按顺序广播。禁止 SSE 客户端通过定时查库等待更新。
  3. SSE 实现心跳、连接取消、权限校验、终态关流、异常帧和断线后的 cursor 续传。
  4. 明确多 worker 部署方案:单 worker 可进程内广播;多 worker 必须 Redis Pub/Sub 或等价方案,未满足时不能灰度上线。
  5. 把 run 状态、总控派活、席位消息 delta、工具过程、审批、质量审核、最终结论全部映射为统一事件信封。

交付物:SSE router/hub、事件发布适配器、集成测试、部署说明。

验收:慢连接、断线重连、乱序/重复防护、多标签订阅、审批后续跑、取消和终态均不丢事件;前端不需要轮询任何实时资源。

阶段 3:总控意图理解、业务链选择与服务端派活(R3)

难度:D5|建议人员:1 名 MAF/Agent 工程师|依赖:阶段 1;可与阶段 2 并行

具体要做:

  1. 将旧会商的意图理解能力迁到 MAF 总控入口:识别直接问答、需澄清、单席位、并行会商、链式业务会商、工具/写入请求。
  2. 总控根据业务链、用户上下文、可信能力快照选择席位,生成 schema 校验的派活计划;前端只展示,不参与编排。
  3. Dispatcher 在服务端按需创建/复用 manager 和 seat 的内部执行线程,并由 ExecutionPrincipal 绑定当前用户。
  4. 对弱模型增加确定性保护:非法席位、空派活、重复派活、无效 schema、超轮次、无法收束必须被拒绝、纠偏或终止。
  5. 保持既有工具、技能、MCP、沙箱、事实账本、交叉审查和 checkpoint 恢复可用。

交付物:总控状态 schema、workflow executor、派活事件、弱模型测试矩阵。

验收:用户只输入任务,就能看到“意图理解 → 总控派活 → 席位执行”;浏览器没有 thread map 和派活决策代码。

阶段 4:席位任务合同、总控验收、打回与强制收束(R3-Q)

难度:D5|建议人员:1 名 Agent/MAF 工程师 + 1 名后端状态机工程师|依赖:阶段 3

具体要做:

  1. 总控发布任务时冻结 task_contract:具体目标、交付格式、验收标准、必需性、返工次数、改派与降级策略。
  2. 为每项席位任务持久化状态机:assigned → delivering → submitted → manager_review → accepted/rework/reassigned/controlled_gap。
  3. 席位提交后先做确定性质量检查:空答、过短、必填章节缺失、格式错、无证据、重复内容等均不能自动完成。
  4. 总控必须生成结构化验收决定和原因;不合格时打回并带精确补充要求。默认最多两次同席位返工,之后最多一次改派。
  5. 改派仍失败时只能产生 controlled_gap,标记风险、缺失项和最终报告影响;严禁伪装为成功。
  6. 增加阶段质量闸门:所有必需任务处于 accepted 或 controlled_gap,才允许进入交叉审查/下一阶段/最终总结。
  7. 将尝试次数、退回理由、验收结果和缺口写入 checkpoint、审计和 SSE。

交付物:任务合同模型、持久化表/迁移、质量状态机、总控审查 prompt/schema、事件和测试。

验收:席位只说一两句话、无依据或内容垃圾时会被明确打回;达到上限不会死循环,也不会被当作合格产出;最终报告可追溯所有缺口。

阶段 5:审批、WriteGuard 与外部动作嵌入对话流(R4)

难度:D4|建议人员:1 名安全后端 + 1 名前端|依赖:阶段 2、3、4

具体要做:

  1. 保留现有 Phase 5 的可信能力快照、WriteGuard、目标租约、HMAC、加密参数、一次执行与审计,不允许为新页面降低安全性。
  2. 将工具开始、审批请求、批准/拒绝、执行成功/失败/unknown 变成安全 SSE 事件和对话卡。
  3. 审批点击只调用明确决策 API;后端负责恢复 checkpoint/workflow,浏览器只等待 SSE。
  4. 安全展示统一二次脱敏,禁止 target_key、idempotency_key、internal_canary、密钥、凭据和原始工具结果进入 API、消息、SSE 或 DOM。

交付物:事件映射、审批消息卡契约、端到端 ToolNode/outbox 测试。

验收:一次真实测试写入能在对话里经历“申请 → 审批 → 继续 → 结果”;重复点击或断线都不会重复外部写入。

阶段 6:复刻旧会商页面壳、历史列表和输入框(R5)

难度:D4|建议人员:1 名熟悉旧会商代码的前端|依赖:阶段 0、1

具体要做:

  1. 新建 MAF 专用 conversation 页面、路由和独立 feature flag;不修改旧 RoundtablePlanningPage。
  2. 依据阶段 0 的映射,复刻左侧历史会话、新建会商、中心时间线、常驻输入框、参与席位区和业务链摘要的视觉与交互层级。
  3. 基础组件使用本地 tdesign-react,旧页面仅参考;需要的视觉组件在 MAF 目录重写或抽无业务依赖公共组件。
  4. 接上 Conversation API:创建、历史、切换、消息分页。此阶段不允许先做任何轮询实时逻辑。
  5. 删除新页面中暴露给用户的 manager/seat/max round/session/run 创建表单。

交付物:新页面壳、MAF 专用 view model、静态/接口 mock 组件测试、视觉对照截图。

验收:即使 SSE 未接通,用户也能看到与旧会商同类的历史、对话与输入体验;新旧业务状态零耦合。

阶段 7:前端 SSE 消费、对话 reducer 与过程交互(R6 + R7)

难度:D5|建议人员:1 名前端流式工程师 + 1 名前端业务工程师|依赖:阶段 2、4、5、6

具体要做:

  1. 实现单连接 use-maf-conversation-stream:fetch-reader SSE、cursor、AbortController、指数退避重连和会商切换 generation 隔离。
  2. 实现 event reducer:按 conversation_id + seq 去重排序;按 message_id 合并 delta;刷新后历史与 SSE 无缝衔接。
  3. 重写旧会商对应的 MAF 版组件:总控意图卡、派活卡、席位条、席位气泡、工具步骤、澄清卡、审批卡、质量审核/打回卡、结果卡。
  4. 所有卡片在时间线内叙事,不另开 run/session 管理后台;继续追问仍使用同一输入框。
  5. 页面必须显示待审核、已验收、返工次数、改派、受控缺口和恢复状态,不能把“发过言”显示为“已完成”。
  6. 代码审查和测试中检查不存在 setInterval、refetchInterval 或事件轮询 fallback。

交付物:SSE hook、reducer、对话组件、组件/API mock 测试、无轮询静态检查。

验收:切换会商、断线重连、审批续跑、慢旧流回包、长会话翻页均不污染、不丢消息、不重复;整个会商过程只依赖 SSE 实时更新。

阶段 8:端到端验收、灰度和回滚演练(R8)

难度:D4|建议人员:1 名测试/集成人 + 各阶段负责人配合|依赖:阶段 1–7

具体要做:

  1. 跑完后端事务/SSE/Workflow/质量闸门/WriteGuard 测试、前端 reducer/组件测试、旧会商与 DeerFlow 回归。
  2. 在真实浏览器按阶段 0 截图基线逐项对照,并完成用户任务:发起、澄清、派活、短答打回、两次返工、改派、审批、受控缺口、结论和追问。
  3. 内部账号灰度,观测 SSE 建连/重连、事件时延、派活/验收/返工次数、workflow 失败率、审批耗时和前端错误。
  4. 验证关闭 feature flag 后立即回到旧会商入口,旧数据和旧任务不受影响。
  5. 若需生产外部写入,补齐 UAT 系统、最小权限凭据、核验 API、补偿联系人和生产 MAF_ACTION_SECRET_KEY。

交付物:自动化结果、人工验收记录、灰度指标面板、回滚演练记录、上线清单。

验收:满足第 9 节全部条件后才允许标记开发完成。

8.1 可并行边界

  • 阶段 2 与阶段 3 可在阶段 1 的 schema/API 定稿后并行,但二者必须共用同一事件信封。
  • 阶段 6 可在阶段 1 的 API mock 契约定稿后提前开始;不得自行发明事件字段。
  • 阶段 5 必须等待阶段 2、3、4 的安全事件与状态机定稿。
  • 阶段 7 必须等待阶段 2、4、6,不能以轮询临时替代 SSE。
  • 阶段 8 只做集成、验收和上线准备,不补写前面阶段缺失的核心设计。

建议主顺序:阶段 0 → 阶段 1 → (阶段 2 + 阶段 3 + 阶段 6) → 阶段 4 → 阶段 5 → 阶段 7 → 阶段 8。


9. 最终验收定义

只有同时满足以下条件,才可以说“本次 MAF 会商升级开发完成”:

  • 新页面在视觉和主交互上可被用户认作原多智能体会商的升级版;
  • 页面具备历史会话、连续对话流、输入框、意图理解、总控派活、席位协作、澄清、审批、结果和追问;
  • 每个必需席位任务都有任务合同、总控验收、有限返工和改派/受控缺口处理;席位短答或垃圾产出不能自动被当作完成;
  • 浏览器没有会商事件/run/approval 的定时轮询;实时交互通过可重连 SSE 完成;
  • 用户不需要创建或管理多个智能体线程,内部线程由服务端按用户身份安全创建和恢复;
  • 新页面未调用旧会商业务 API/状态,旧会商零回归;
  • 工具、技能、MCP、沙箱、审批、WriteGuard、一次写入和审计都仍可用;
  • 自动化测试、SSE 故障测试、真实浏览器人工验收和旧功能回归全部通过;
  • 真实 UAT 写入系统、最小权限凭据、外部核验 API、补偿协议及生产 MAF_ACTION_SECRET_KEY 已按 Phase 5 前置条件完成。

在这之前,任何“会话/run 原型页面通过构建或轮询测试”的结果,都只能算技术验证,不算产品升级验收。


阶段 3 实施记录(当前代码基线)

本轮已补齐阶段 3 的服务端安全路由与真实 MAF Workflow 入口,范围仅针对新 MAF 会商;旧 DeerFlow、旧 roundtable 和 AI 写作行为不变。

配置与入口闸门

  • 仓库默认 maf_roundtable.enabled: false。部署环境必须注入真实的 default_manager_agent_id、席位 ID 和业务路由后再开启,避免出现“入口显示正常但首条消息必然 503”的空配置。
  • 健康接口返回非敏感的 conversation_dispatch_ready 与 conversation_dispatch_status;新会商入口只有在配置路由可用且服务已启用时才开放。
  • 首条消息使用服务端可信能力快照校验 manager/seat 的可访问性;浏览器、会话请求和模型输出都不能提供或扩大 agent、thread、tool、capability 范围。
  • 配置模型会清理并校验 manager/seat ID,拒绝 manager 出现在 seat 列表、重复席位、超过 max_seats_per_run 的路由和非法业务 code。

受约束的总控派活

服务端先由业务链与可信 capability snapshot 生成候选席位集合。总控模型只能返回严格 JSON:intent_type、selected_seat_agent_ids、每席 task_goal/delivery_requirements、execution_mode、convergence_path 和 reason。Pydantic schema、服务端 allowlist 和顺序校验全部通过后,最终计划才会写入 checkpoint,并产生 manager.dispatch 审计/SSE 投影。

非法席位、重复席位、空任务、错误 schema、席位超限、缺少收敛路径或链式顺序错误,统一回退到服务端安全计划,不会扩大权限或启动越权席位。

四种结构化拓扑已固定为:

  • direct_answer:manager-only Workflow,不创建专家席位任务;
  • single_seat / tool_write:一个可信席位;
  • parallel_consultation:至少两个可信席位并行;
  • chain_consultation:按服务端业务链顺序串行。

阶段 3 验证状态

已覆盖配置校验、候选路由、非法总控计划回退、manager-only 真实 WorkflowBuilder 拓扑、线程/执行阶段回归、旧 DeerFlow 回归和会话 API 回归。当前仍不能据此标记整个 MAF 项目或阶段 5 为“验收完成”;真实 UAT 写入系统、最小权限凭据、外部核验 API、补偿协议和生产 MAF_ACTION_SECRET_KEY 仍按阶段 5/8 前置条件保持阻塞。

Stage 3 P0 dispatch correction

  • New MAF conversations no longer classify user text with server keyword rules. The server first freezes only the business-route candidate set and trusted, redacted capability summary; ManagerDispatchExecutor then returns the strict intent-and-dispatch JSON contract.
  • The final plan is Pydantic-validated and allowlisted before it is checkpointed. Invalid JSON, illegal intent or seat, missing convergence, manager failure, and timeout all finish on the clarification branch; they do not create expert threads or start expert/tool work.
  • A conversation initially persists and binds the manager only. After a valid decision, only selected_seat_agent_ids are added to the participant store and receive internal threads.
  • Every non-clarification route, including group_chat, starts at the same manager dispatch node. Group speakers are limited to the verified selected seats; static candidate configuration cannot bypass the plan.