deerflow-code/docs/agentscope-多智能体报告协作工作台-前端对接指南.md
2026-09-07 18:24:55 +08:00

18 KiB
Raw Permalink Blame History

报告协作工作台 — 前端对接指南

适用版本: RC-BE-000~018 已落地(2026-09-06)
配套文档:

本文说明前端如何对接真实后端:环境配置、API 契约、用户流程、状态机、错误处理与联调验收。前端 API 客户端与页面已实现,通常无需再写一套 HTTP 层。


1. 结论速览

问题 答案
前端还要写接口吗? 不用。src/report-collaboration/api/ 已封装 REST + SSE,页面通过 getReportCollaborationDriver() 调用。
为什么调不通? 最常见:config.yaml 里 report_collaboration.enabled: false → 全部 503;或 worker_enabled: false → run 不入队执行。
Mock 和真后端怎么切? Mock 已移除。前端永远请求真实后端(deerflow.rc-mock / VITE_RC_MOCK 开关已删除);联调需 enabled: true。
字段会和 MySQL 对不上吗? 前端只认 JSON 契约(api/types.ts),不直连表。缺列表现为后端 500/SQL 错误,部署后需重启 Gateway 跑 create_all + 列同步。
从哪进页面? /page/workspace/report-collaboration(新会话)或 /page/workspace/report-collaboration/:sessionId。侧边栏入口默认注释,可直接 URL 访问。

2. 架构:前端已有什么

ReportCollaborationPage
  └─ useReportCollaborationSession(唯一数据入口)
       ├─ driver.getSnapshot()           ← REST 冷启动
       ├─ driver.openRunStream()          ← SSE 实时事件
       ├─ driver.sendMessage / createCommand / startRun …
       └─ event-reducer                   ← 事件 → UI 状态

ReportConversationPanel
  └─ MessageList(message-adapter 映射 CollaborationMessage → LangGraph Message)

2.1 目录结构

frontend-web/src/report-collaboration/
  api/
    types.ts          # 冻结契约(snake_case,与后端 Pydantic 一致)
    client.ts         # rcFetch:鉴权、幂等键、乐观锁、错误映射
    sessions.ts       # 会话 CRUD、消息
    plans.ts          # 方案请求 / 列表 / 选定
    runs.ts           # Run、SSE、命令、节点合同
    reports.ts        # 报告版本、改写、恢复
    driver.ts         # 真实后端统一门面(Mock 驱动已移除)
  state/
    event-normalizer.ts
    event-reducer.ts
    selectors.ts
    message-adapter.ts
  hooks/
    useReportCollaborationSession.ts   # 快照 → SSE → reducer → 动作
    useReportCollaborationStream.ts    # 断线重连、after_seq 续接
    useReportCollaborationMessages.ts
  components/ …
  pages/ReportCollaborationPage.tsx

2.2 事实源原则

  • 冷启动: GET /sessions/{id} 返回 SessionSnapshot(session、messages、plans、run、nodes、agent_runs、commands、report_versions、last_seq)。
  • 运行中: GET /runs/{id}/stream?after_seq=N 订阅 durable SSE。
  • 断线 / 序号缺口: GET /runs/{id}/events?after_seq=N REST 补拉。
  • 澄清 / 规划阶段(尚无 run): 每 2.5s 轮询快照(后端事件主要在 run 流上)。

纯展示状态(预览方案、聚焦成员、面板宽度)不写入服务器,仅存前端。


3. 后端启用与部署

3.1 必改配置

文件:offline-backend-20260512/backend/config.yaml

report_collaboration:
  enabled: false          # 联调必须改为 true
  worker_enabled: false   # 要看成员执行必须 true
  planner_model: null     # 建议填可用模型名
  coordinator_model: null
  research_model: null
  writer_model: null
  reviewer_model: null
  # … token_budget、max_concurrent_runs_per_user 等见同文件
配置 现象
enabled: false 所有路由 503,code: REPORT_COLLABORATION_DISABLED
enabled: true,worker_enabled: false REST/SSE 可用,run 入队但不自动执行(测 API 可用,无成员流式输出)
两者 true + 模型配置完整 完整联调

3.2 MySQL / 表结构

生产环境 Alembic 自动升级默认关闭,启动时走 create_all + _ensure_orm_columns_sync。

  • 迁移脚本(可选手动跑):20260905_01、20260906_01、20260907_01
  • ORM:packages/harness/deerflow/persistence/report_collaboration/model.py(13 张表)
  • 部署后务必重启 Gateway,观察日志是否有 Failed to auto-add column report_collaboration_*

已有 RC-003 时代旧表会通过列同步补上 template_snapshot_json、budget_snapshot_json、usage_json、budget_exhausted_reason 等可空列,并创建 rewrite_proposals、audits。

3.3 前端环境变量

变量 说明
VITE_BACKEND_BASE_URL Gateway 地址,默认 http://127.0.0.1:8001

请求经 apiFetch,自动携带登录 JWT(credentials: "include")。必须先登录 DeerFlow。


4. API 基址与请求约定

4.1 Base URL

{VITE_BACKEND_BASE_URL}/api/report-collaboration

代码常量:REPORT_COLLABORATION_BASE()(api/client.ts)。

4.2 请求头

Header 何时携带 说明
Authorization 全部 由 apiFetch 注入
X-Idempotency-Key 写操作 格式 rc-{uuid};重复提交返回首次结果
X-Expected-Revision 选方案、开 run、改会话等 会话 requirement_revision 或方案 revision
Accept: text/event-stream SSE openRunStream

4.3 错误响应格式

{
  "code": "REPORT_COLLABORATION_DISABLED",
  "message": "报告协作工作台未启用",
  "detail": { }
}

前端映射(api/client.ts):

HTTP 异常类 典型场景
409 ConflictError revision 过期、active run 冲突
422 ValidationError 参数/语义错误、缺幂等键
429 RateLimitError 预算耗尽、每用户并发 run 上限
5xx ServerError 可带同一幂等键重试
0 NetworkError fetch 失败

4.4 完整路由清单(与前端 client 对齐)

方法 路径 前端模块
POST /sessions sessions.createSession
GET /sessions sessions.listSessions
GET /sessions/{id} sessions.getSessionSnapshot
PATCH /sessions/{id} sessions.updateSession
DELETE /sessions/{id} sessions.deleteSession
GET /sessions/{id}/messages sessions.listMessages
POST /sessions/{id}/messages sessions.sendMessage
POST /sessions/{id}/plan-requests plans.requestPlans
GET /sessions/{id}/plans plans.listPlans
POST /sessions/{id}/plans/{planId}/select plans.selectPlan
POST /sessions/{id}/runs runs.startRun
GET /sessions/{id}/reports reports.listReportVersions
POST /sessions/{id}/report-rewrites reports.createRewrite
POST /sessions/{id}/report-rewrites/{id}/apply reports.applyRewrite
POST /sessions/{id}/report-versions/{id}/restore reports.restoreReportVersion
GET /runs/{id} runs.getRun
GET /runs/{id}/events runs.listRunEvents
GET /runs/{id}/stream runs.openRunStream
POST /runs/{id}/cancel runs.cancelRun
POST /runs/{id}/commands runs.createCommand
POST /runs/{id}/commands/{id}/confirm runs.confirmCommand
POST /runs/{id}/commands/{id}/cancel runs.cancelCommand
GET /runs/{id}/nodes/{nodeId}/contract runs.getNodeContract
GET /runs/{id}/artifacts (后端已暴露,前端按需接)
GET /runs/{id}/sources (后端已暴露,前端按需接)

5. 用户流程与 API 时序

sequenceDiagram
  participant U as 用户
  participant FE as 前端 RC
  participant API as Gateway
  participant W as Worker

  U->>FE: 输入需求
  FE->>API: POST /sessions
  FE->>API: POST /sessions/{id}/messages
  API-->>FE: 澄清(快照 messages)
  U->>FE: 回答澄清
  FE->>API: POST /messages
  FE->>API: POST /plan-requests
  API-->>FE: 候选方案(快照 plans)
  U->>FE: 采用方案
  FE->>API: POST /plans/{id}/select
  U->>FE: 开始协作
  FE->>API: POST /runs
  FE->>API: GET /runs/{id}/stream
  W-->>API: 持久化事件
  API-->>FE: SSE
  U->>FE: 运行中干预
  FE->>API: POST /commands → confirm

5.1 阶段 0:进入页面

路由 行为
/page/workspace/report-collaboration 空态;POST /sessions 后跳转带 sessionId
/page/workspace/report-collaboration/:sessionId 加载快照;有 location.state.rcInitialMessage 时自动发首条消息

路由注册:frontend-web/src/pages/WorkspaceRoutes.tsx。
侧边栏入口已在 workspace-nav-chat-list.tsx 中放开(「报告协作」项),也可直接访问 URL。

5.2 阶段 1:需求澄清(无 run)

POST /api/report-collaboration/sessions
POST /api/report-collaboration/sessions/{sessionId}/messages
Content-Type: application/json

{ "text": "请写一份…", "target_node_id": null, "agent_run_id": null }
  • useReportCollaborationSession.send():当 session.status 不是 running / awaiting_input / reviewing 时走 sendMessage。
  • 会话状态:empty → clarifying → planning → proposal_ready。
  • 澄清问题以 CollaborationMessage 进入时间线;业务卡通过 MessageList 的 businessCardSlot 渲染(additional_kwargs.report_collaboration_card)。

5.3 阶段 2:候选方案

POST /api/report-collaboration/sessions/{sessionId}/plan-requests
POST /api/report-collaboration/sessions/{sessionId}/plans/{planId}/select
  • 预览方案(previewPlanId):纯前端,不调 API。
  • 采用方案:select 写 selected_plan_id,不创建 run。
  • 409:方案 revision 过期 → 前端 refreshSnapshot,提示用户重选。
  • 右栏 ReportFlowCanvas 使用 PlanNode / PlanEdge 渲染 DAG。

5.4 阶段 3:开始执行与 SSE

POST /api/report-collaboration/sessions/{sessionId}/runs
{ "plan_id": "plan-xxx" }

GET /api/report-collaboration/runs/{runId}/stream?after_seq=0
Accept: text/event-stream

SSE 每条 data: 为 JSON:

interface CollaborationEvent {
  eventId: string;
  sessionId: string;
  runId?: string | null;
  seq: number;
  type: CollaborationEventType;
  timestamp: string;
  data: unknown;
}

常用 type(完整列表见 api/types.ts):

类型 含义
message.created / message.delta / message.completed 对话镜像流式
tool_call.* / tool_result.* 工具调用与返回
team_message.* 成员 / 协调者广播
plan.proposed / plan.selected 方案生命周期
run.status.changed Run 状态
node.status.changed / node.progress 节点执行
command.confirmation.required 需用户确认的干预
report.version.created 报告版本落盘
heartbeat 保活

5.5 阶段 4:运行中干预

POST /api/report-collaboration/runs/{runId}/commands
POST /api/report-collaboration/runs/{runId}/commands/{commandId}/confirm
POST /api/report-collaboration/runs/{runId}/commands/{commandId}/cancel
POST /api/report-collaboration/runs/{runId}/cancel
  • Run 活跃时 send() 自动走 createCommand(而非 sendMessage)。
  • 可从节点抽屉 / AgentStageSelector 传入 target_node_id、agent_run_id。
  • InterventionCard 展示 confirmation_required 命令;确认后调 confirmCommand。

CommandIntent 枚举(后端分类,前端展示 reason/impact):answer_question、update_requirements、research_again、rewrite_section、rerun_node、replan、cancel 等。

5.6 阶段 5:报告版本与改写

GET  /api/report-collaboration/sessions/{sessionId}/reports
POST /api/report-collaboration/sessions/{sessionId}/report-rewrites
POST /api/report-collaboration/sessions/{sessionId}/report-rewrites/{rewriteId}/apply
POST /api/report-collaboration/sessions/{sessionId}/report-versions/{versionId}/restore
  • createRewrite 只生成候选,不直接覆盖正式版本。
  • applyRewrite / restoreReportVersion 产生新的 head 版本,历史保留。
  • ReportPreviewDialog 展示 ReportVersion.markdown。

6. 前端状态机(接入方须知)

不要在页面里用零散 REST 字段拼 UI 状态。统一路径:

SessionSnapshot → applySessionSnapshot()
CollaborationEvent[] → normalizeCollaborationEvent() → applyCollaborationEvents()
→ selectors(derivePagePhase、selectPlanForCanvas、…)

6.1 核心 Selector

Selector 用途
derivePagePhase Composer 占位、方案卡、空态
selectPlanForCanvas 画布 DAG(含预览方案)
selectAgentTabs 并行成员 Tab
selectNodeStatusMap 节点颜色 / 状态
selectPendingConfirmationCommands 干预确认卡
selectHeadReportVersion 报告预览入口
selectStreamingAgentRunIds 流式成员指示

6.2 SSE 连接策略(useReportCollaborationStream)

  • Run 非终态时连接;completed / failed / cancelled 后关流并 REST 最终补拉。
  • 断线:指数退避重连(1s~30s),after_seq 取 reducer 内 lastSeq。
  • hasSeqGap:暂停 live 应用,先 listRunEvents 回填。

6.3 乐观消息

用户发送时插入 metadata.optimistic: true 的 pending 消息;服务端镜像带相同 idempotency_key 时 reducer 原地替换。


7. 消息与 MessageList 复用

useReportCollaborationMessages 将 CollaborationMessage[] 转为 @langchain/langgraph-sdk 的 Message[],并构造合成 BaseStream 供 MessageList 消费。

来源 渲染
human / ai 文本 普通气泡
tool_calls + tool 现有工具卡
team_message 事件 带 name 的成员发言
业务卡 businessCardSlot(方案组、命令确认、报告可用)

分组键:core/messages/utils.ts 中 assistant:task-report-import 同级扩展 assistant:business-card,判据 additional_kwargs.report_collaboration_card。

7.1 在其他页面嵌入 RC(最小集)

  1. useReportCollaborationSession(sessionId)
  2. ThreadContext.Provider + MessageList + businessCardSlot
  3. 引入 report-collaboration/styles/report-collaboration.css

8. 单测

Mock 驱动(原 api/mock.ts)与 deerflow.rc-mock / VITE_RC_MOCK 开关已移除,前端只请求真实后端;本地演示请直接联调后端。

单测:

cd frontend-web
pnpm test:report-collaboration

9. 联调验收清单

9.1 准备

  • report_collaboration.enabled: true
  • report_collaboration.worker_enabled: true
  • 五个 *_model 已配置且可用
  • Gateway 已重启(MySQL 表/列就绪)
  • 前端已登录(JWT 有效)

9.2 探活

curl -s -H "Authorization: Bearer <token>" \
  http://127.0.0.1:8001/api/report-collaboration/sessions

期望:200 + { "sessions": [...] },而非 503。

9.3 页面流程(浏览器 Network)

  1. 打开 /#/page/workspace/report-collaboration
  2. 输入需求 → POST .../sessions 200
  3. 跳转 → GET .../sessions/{id} 200,响应含 SessionSnapshot
  4. 首条消息 → POST .../messages 200
  5. 请求方案 → POST .../plan-requests 200
  6. 采用方案 → POST .../plans/{id}/select 200
  7. 开始协作 → POST .../runs 200
  8. GET .../runs/{id}/stream 持续收到 SSE(message.delta、node.status.changed 等)
  9. 刷新页面 → 消息与 last_seq 续接正确
  10. 运行中输入「重新检索」→ POST .../commands → 确认卡 → confirm 200

9.4 常见失败

现象 原因 处理
全部 503 enabled: false 改配置并重启
run 一直 queued worker_enabled: false 改为 true
409 选方案 revision 过期 刷新后重选(前端已自动 refresh)
429 预算/并发上限 调大配置或取消其他 run
500 + SQL 表缺列 重启 Gateway,查列同步日志

10. 契约与类型维护

  • 单一事实源: frontend-web/src/report-collaboration/api/types.ts
  • 后端镜像: offline-backend-20260512/backend/app/report_collaboration/contracts/
  • 修改字段须同步两份实施计划与本指南,并跑前后端相关测试。

SessionSnapshot 形状(摘要):

interface SessionSnapshot {
  session: ReportSession;
  messages: CollaborationMessage[];
  plans: ReportPlanCandidate[];
  run: ReportRun | null;
  nodes: CollaborationNodeState[];
  agent_runs: AgentRun[];
  commands: CollaborationCommand[];
  report_versions: ReportVersion[];
  last_seq: number;
}

ReportRun 可选字段(RC-BE-016):usage、budget_exhausted_reason。


11. 后续工作(非对接阻塞)

项 说明
RC-BE-019 灰度发布与离线部署文档
侧边栏入口 已放开(workspace-nav-chat-list.tsx 的「报告协作」项)
iframe 嵌入 RC 页尚未专门适配 embed=1,可参考现有深链模式扩展
真人盲评 RC-BE-018 为确定性评测集,上线前仍需计划 §11.4 人工评审

12. 相关代码索引

用途 路径
API 客户端 frontend-web/src/report-collaboration/api/
会话 Hook frontend-web/src/report-collaboration/hooks/useReportCollaborationSession.ts
页面 frontend-web/src/report-collaboration/pages/ReportCollaborationPage.tsx
路由 frontend-web/src/pages/WorkspaceRoutes.tsx
后端路由 offline-backend-20260512/backend/app/gateway/routers/report_collaboration.py
配置 offline-backend-20260512/backend/config.yaml → report_collaboration
持久化 offline-backend-20260512/backend/packages/harness/deerflow/persistence/report_collaboration/