docs(asl): Upgrade Tool 3 architecture from Fan-out to Scatter+Aggregator (v2.0)
Architecture transformation: - Replace Fan-out (Manager->Child->Last Child Wins) with Scatter+Aggregator pattern - API layer directly dispatches N independent jobs (no Manager) - Worker only writes its own Result row, never touches Task table (zero row-lock) - Aggregator polls groupBy for completion + zombie cleanup (replaces Sweeper) - Reduce red lines from 13 to 9, eliminate distributed complexity Documents updated (10 files): - 08-Tool3 main architecture doc: v2.0 rewrite (schema, Task 2.3/2.4, red lines, risks) - 08d-Code patterns: rewrite sections 4.1-4.6 (API dispatch, SingleWorker, Aggregator) - 08a-M1 sprint: rewrite M1-3 core (Worker+Aggregator), red lines, acceptance criteria - 08b-M2 sprint: simplify SSE (NOTIFY/LISTEN downgraded to P2 optional) - 08c-M3 sprint: milestone table wording update - New: Scatter+Polling Aggregator pattern guide v1.1 (Level 2 cookbook) - New: V2.0 architecture deep review and gap-fix report - Updated: ASL module status, system status, capability layer index Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
> **所属:** 工具 3 全文智能提取工作台 V2.0
|
||||
> **架构总纲:** `08-工具3-全文智能提取工作台V2.0开发计划.md`
|
||||
> **代码手册:** `08d-工具3-代码模式与技术规范.md`(所有代码模式均在此手册中,开发时按需查阅)
|
||||
> **前置依赖:** M1 全部完成(Fan-out 管线已验证、PKB ACL 已通、纯文本提取可跑通)
|
||||
> **前置依赖:** M1 全部完成(散装管线 + Aggregator 已验证、PKB ACL 已通、纯文本提取可跑通)
|
||||
> **建议时间:** Week 2-3(8-9 天)
|
||||
> **核心目标:** 接入 MinerU 视觉大模型提升表格准确率,完成前端最复杂的 HITL 审核抽屉,交付一个"完全可用"的 V1 产品。
|
||||
|
||||
@@ -21,19 +21,18 @@
|
||||
|
||||
**做什么:**
|
||||
- `PdfProcessingPipeline.ts` 升级:M1 的纯文本降级 → 完整双引擎流水线
|
||||
- 从 PKB `storageKey` 下载 PDF Buffer → 调用 MinerU Cloud API → 返回结构化 HTML 表格
|
||||
- 从 PKB `snapshotStorageKey` 下载 PDF Buffer → 调用 MinerU Cloud API → 返回结构化 HTML 表格
|
||||
- **MinerU Clean Data OSS 缓存**(Cache-Aside):调用前先检查 `pkb/{kbId}/{docId}_mineru_clean.html`,命中则 <1 秒返回
|
||||
- 注册 `asl_mineru_extract` 子队列(`teamConcurrency: 2`)
|
||||
- Child Worker 内部通过 `pgBoss.send('asl_mineru_extract', ...)` 派发 MinerU 子任务
|
||||
- Worker 内部串行 `await mineruClient.extractTables()`(无需独立子队列,`teamConcurrency: 10` 即为 MinerU 隐式并发上限)
|
||||
|
||||
**不做什么:**
|
||||
- 不改 Fan-out 架构(M1 已稳定)
|
||||
- 不改散装架构(M1 已稳定)
|
||||
- 不做动态 Prompt(M3),继续用写死的 RCT Schema
|
||||
|
||||
**验收标准:**
|
||||
- [ ] MinerU 返回 HTML 表格,含 `<table>` + `colspan/rowspan`
|
||||
- [ ] OSS 缓存命中时跳过 MinerU 调用(日志可见 "Cache hit")
|
||||
- [ ] `asl_mineru_extract` 队列 `teamConcurrency: 2` 生效(3 Pod 环境下全局最多 2 个并行)
|
||||
- [ ] `teamConcurrency: 10` 全局并发控制生效(MinerU 调用受此限制)
|
||||
- [ ] MinerU 超时(>3min)自动降级到纯文本
|
||||
|
||||
> 📖 缓存代码模式见架构总纲 Task 2.2
|
||||
@@ -68,30 +67,30 @@
|
||||
|
||||
**做什么:**
|
||||
- `ExtractionController.ts` 新增 SSE 端点 `GET /tasks/:taskId/stream`
|
||||
- SSE 事件类型:`sync`(首帧)、`progress`、`log`、`complete`、`error`
|
||||
- SSE 事件类型:`sync`(首帧)、`log`、`error`
|
||||
- **首帧 sync 降级方案**:`recentLogs: []`(不依赖内存 logBuffer),前端检测到空日志时打印 "--- 监控已重新连接 ---"
|
||||
- `ProcessingTerminal.tsx` 组件:深色终端风格,来源颜色区分(MinerU 蓝 / DeepSeek 紫 / System 绿)
|
||||
- `useExtractionLogs.ts` Hook:仅驱动日志区,不影响主业务流
|
||||
- SSE 使用**本 Pod 内存事件**即可(Worker 和 API 在同一 Pod 时日志实时可达)
|
||||
|
||||
**M1 已完成的不动:**
|
||||
- `useTaskStatus.ts`(React Query 轮询)继续驱动进度条和步骤跳转
|
||||
- `useTaskStatus.ts`(React Query 轮询 + groupBy 进度)继续驱动进度条和步骤跳转
|
||||
- `complete` 检测完全由 React Query 轮询到 `status === 'completed'` 触发,不依赖 SSE
|
||||
|
||||
**[P2 可选] SSE 跨 Pod 广播 — NOTIFY/LISTEN:**
|
||||
> 散装架构下进度条由 React Query 轮询驱动,SSE 仅为日志增强。
|
||||
> 多 Pod 部署后若日志体验不佳,可后续实施 `SseNotifyBridge.ts`(代码见 08d §7.6)。
|
||||
> M2 阶段不强制实施。
|
||||
|
||||
**验收标准:**
|
||||
- [ ] SSE 连接后立即收到 `sync` 首帧
|
||||
- [ ] 日志实时打字机效果(`[MinerU]`、`[DeepSeek]`、`[System]` 分色)
|
||||
- [ ] SSE 断开后进度条不受影响(React Query 继续轮询)
|
||||
- [ ] 多 Pod 环境下 SSE 重连到其他 Pod → 显示 "监控已重新连接" 提示
|
||||
- [ ] **🆕 v1.5 NOTIFY/LISTEN 跨 Pod 实时日志:** Worker 在 Pod B 提取 → Pod A 的 SSE 客户端能实时收到日志
|
||||
|
||||
**🆕 v1.5 额外任务:SSE 跨 Pod 广播 — NOTIFY/LISTEN(含在 M2-3 工期内):**
|
||||
- `SseNotifyBridge.ts`:Pod 启动时创建独立 PgClient 长连接(不从连接池借),执行 `LISTEN asl_sse_channel`
|
||||
- 收到 NOTIFY 后检查本机是否有该 `taskId` 的 SSE 客户端,有则推送,无则静默忽略
|
||||
- `ExtractionChildWorker` 中替代 `sseEmitter.emit()`:改用 `prisma.$executeRawUnsafe('NOTIFY asl_sse_channel, ...')`
|
||||
- `complete` 事件同样走 NOTIFY 广播,确保"Last Child Wins"翻转后所有 Pod 收到
|
||||
- [ ] 多 Pod 环境下 SSE 重连到其他 Pod → 显示 "监控已重新连接" 提示(本 Pod 无历史日志时)
|
||||
|
||||
> 📖 双轨制架构见架构总纲 Task 4.1
|
||||
> 📖 SSE Hydration 降级见架构总纲 Task 2.4 补丁 2
|
||||
> 📖 NOTIFY/LISTEN 代码模式见 08d §7.6
|
||||
> 📖 SSE 降级方案见架构总纲 Task 2.4
|
||||
> 📖 [P2 可选] NOTIFY/LISTEN 代码模式见 08d §7.6
|
||||
|
||||
---
|
||||
|
||||
@@ -159,7 +158,7 @@
|
||||
- Step 1 → Step 2 → Step 3 完整流程走通(含 MinerU + 审核抽屉 + Excel)
|
||||
- fuzzyQuoteMatch 边界测试(连字符替换、空格差异、换行吞掉)
|
||||
- 断点恢复测试(关闭浏览器 → 重新打开 → 恢复正确步骤)
|
||||
- Fan-out 10 篇并发提取压力测试
|
||||
- 散装 10 篇并发提取压力测试
|
||||
|
||||
**验收标准:**
|
||||
- [ ] 8 篇测试 PDF 全链路跑通:PKB → MinerU + LLM → 抽屉审核 → Excel 导出
|
||||
@@ -172,12 +171,13 @@
|
||||
|
||||
```
|
||||
✅ M1 全部 +
|
||||
✅ MinerU 表格引擎 + OSS 缓存
|
||||
✅ MinerU 表格引擎 + OSS 缓存(Worker 内部串行调用)
|
||||
✅ XML 隔离 Prompt + 表格优先级
|
||||
✅ fuzzyQuoteMatch 三级置信度验证
|
||||
✅ SSE 终端日志(双轨制:React Query 主驱 + SSE 日志增强 + NOTIFY/LISTEN 跨 Pod 广播)
|
||||
✅ SSE 终端日志(双轨制:React Query 轮询主驱 + SSE 本 Pod 日志增强)
|
||||
✅ 完整审核抽屉(Collapse + Quote + HITL 解锁 + 签名 URL)
|
||||
✅ Excel 宽表导出
|
||||
⏳ [P2 可选] SSE NOTIFY/LISTEN 跨 Pod 广播(多 Pod 部署后按需实施)
|
||||
❌ 无自定义字段(仅系统基座模板)
|
||||
❌ 无 Prompt 注入防护(无用户输入,不需要)
|
||||
❌ 无 E2E 自动化测试
|
||||
|
||||
Reference in New Issue
Block a user