docs(asl): Complete Tool 3 extraction workbench V2.0 development plan (v1.5)
ASL Tool 3 Development Plan: - Architecture blueprint v1.5 (6 rounds of architecture review, 13 red lines) - M1/M2/M3 sprint checklists (Skeleton Pipeline / HITL Workbench / Dynamic Template Engine) - Code patterns cookbook (9 chapters: Fan-out, Prompt engineering, ACL, SSE dual-track, etc.) - Key patterns: Fan-out with Last Child Wins, Optimistic Locking, teamConcurrency throttling - PKB ACL integration (anti-corruption layer), MinerU Cache-Aside, NOTIFY/LISTEN cross-pod SSE - Data consistency snapshot for long-running extraction tasks Platform capability: - Add distributed Fan-out task pattern development guide (7 patterns + 10 anti-patterns) - Add system-level async architecture risk analysis blueprint - Add PDF table extraction engine design and usage guide (MinerU integration) - Add table extraction source code (TableExtractionManager + MinerU engine) Documentation updates: - Update ASL module status with Tool 3 V2.0 plan readiness - Update system status document (v6.2) with latest milestones - Add V2.0 product requirements, prototypes, and data dictionary specs - Add architecture review documents (4 rounds of review feedback) - Add test PDF files for extraction validation Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
96
docs/03-业务模块/ASL-AI智能文献/06-技术文档/工具3终极架构审查与研发规范.md
Normal file
96
docs/03-业务模块/ASL-AI智能文献/06-技术文档/工具3终极架构审查与研发规范.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# **🎯 终极架构审查与研发红线规范:工具 3 全文智能提取 V2.0**
|
||||
|
||||
**文档性质:** 架构定稿与研发执行标准
|
||||
|
||||
**审查基准:** 《Postgres-Only 异步任务处理指南 (v1.1)》、《通用能力层清单 (v2.4)》
|
||||
|
||||
**适用对象:** 后端研发、前端研发、测试工程师
|
||||
|
||||
**核心宗旨:** 确保工具 3 在分布式环境下的高可用性,彻底对齐平台现有的 Postgres-Only 规范,消除并发死锁、状态撕裂与算力浪费。
|
||||
|
||||
## **🚨 核心研发红线 (Sprint 1 强制执行)**
|
||||
|
||||
在进入代码编写前,所有研发人员必须对齐以下三条底层红线:
|
||||
|
||||
1. **Payload 绝对轻量化:** pg-boss 的 Job Data 中,**绝对不允许**传入 PDF 文件的 Base64 或 extractedText 全文。只能传递 { taskId, resultId, pkbDocumentId }。所需的大文本必须在 Worker 启动后,通过 ID 实时从 DB 或 OSS 拉取。
|
||||
2. **严格的计算卸载:** Node.js 进程绝对不碰任何文档实体的解析计算(pymupdf4llm 或 MinerU)。所有解析动作必须通过 HTTP 路由给独立的 Python 微服务 (extraction\_service) 执行。
|
||||
3. **过期时间兜底:** 由于大模型提取长文本耗时较长,在推送 asl\_extraction\_child 任务时,expireInMinutes 强制设置为 **30 分钟**,防止任务被系统意外判死。
|
||||
|
||||
## **🛠️ 后端架构排雷与对齐方案**
|
||||
|
||||
### **1\. 废弃单机并发控制,拥抱全局队列限流**
|
||||
|
||||
* **❌ 错误做法:** 在 ExtractionService 内部使用 P-Queue 控制 MinerU 并发。在多实例(Pods)部署下,这会导致真实的 API 请求量翻倍,瞬间引发 429 熔断和重试风暴。
|
||||
* **✅ 标准解法:** 把并发控制权交还给数据库。针对昂贵的 MinerU 解析,单独拆分一个子队列 asl\_mineru\_extract,配置严格的全局并发数:
|
||||
// 全局只允许同时有 2 个 MinerU 解析任务在跑,跨所有 Node.js 实例生效
|
||||
jobQueue.process('asl\_mineru\_extract', { teamConcurrency: 2 }, async (job) \=\> { ... })
|
||||
|
||||
### **2\. Fan-out 扇出模式下的并发写入安全**
|
||||
|
||||
* **❌ 错误做法:** 查询父任务 \-\> successCount \+ 1 \-\> 更新父任务。100 个子任务并发完成时,会导致严重的计数丢失(Race Condition)。
|
||||
* **✅ 标准解法 (原子递增):** 所有聚合数据的回写,必须 100% 使用 Prisma 的原子操作,并结合**幂等性**检查:
|
||||
// 1\. 幂等性检查
|
||||
const existing \= await prisma.aslExtractionResult.findUnique({ where: { id: resultId }});
|
||||
if (existing.status \=== 'completed') return { success: true };
|
||||
|
||||
// 2\. 事务内的原子递增
|
||||
await prisma.$transaction(\[
|
||||
prisma.aslExtractionResult.update({ where: { id: resultId }, data: { status: 'completed' } }),
|
||||
prisma.aslExtractionTask.update({
|
||||
where: { id: taskId },
|
||||
data: { successCount: { increment: 1 }, totalTokens: { increment: tokens } }
|
||||
})
|
||||
\]);
|
||||
|
||||
### **3\. 错误处理边界:永久失败 vs 自动重试**
|
||||
|
||||
* **业务痛点:** 严格遵循《Postgres-Only 指南》规范1(直接 throw error),会导致在遇到“PKB源文件被删除”等不可逆错误时,pg-boss 盲目重试 3 次,白白消耗资源。
|
||||
* **✅ 标准解法 (异常分级路由):** 在 Worker 中必须明确区分“可恢复错误”与“致命错误”:
|
||||
try {
|
||||
await doExtraction();
|
||||
} catch (error) {
|
||||
if (error instanceof PkbDocumentNotFoundError || error.name \=== 'PdfCorruptedError') {
|
||||
// 致命错误:更新业务状态为 error,直接 return success 欺骗 pg-boss 停止重试
|
||||
await prisma.aslExtractionResult.update({
|
||||
where: { id: resultId }, data: { status: 'error', errorMessage: error.message }
|
||||
});
|
||||
return { success: false, reason: 'Permanent Failure, aborted retry.' };
|
||||
}
|
||||
// 临时错误 (429/网络抖动):直接 throw,让 pg-boss 自动指数退避重试
|
||||
throw error;
|
||||
}
|
||||
|
||||
### **4\. 极致落实 Clean Data 缓存机制**
|
||||
|
||||
* **业务痛点:** MinerU 表格解析极度昂贵且耗时。
|
||||
* **✅ 标准解法:** 必须前置检查 OSS 缓存,避免重复计算。
|
||||
const cleanDataKey \= \`pkb/${kbId}/${docId}\_mineru\_clean.html\`;
|
||||
try {
|
||||
const html \= await storage.download(cleanDataKey); // 优先读取缓存 (\<1秒)
|
||||
return html;
|
||||
} catch (e) {
|
||||
const html \= await callPythonMinerUService(pdfKey); // Fallback: 真正调用
|
||||
await storage.upload(cleanDataKey, Buffer.from(html)); // 同步存入 Clean Data
|
||||
return html;
|
||||
}
|
||||
|
||||
## **💻 前端架构排雷与对齐方案**
|
||||
|
||||
### **1\. 通信机制的优雅混合 (React Query \+ SSE)**
|
||||
|
||||
* **业务痛点:** 前端到底是采用 SSE 维持连接,还是用 React Query 轮询?混用会导致状态撕裂。
|
||||
* **✅ 标准解法:**
|
||||
* **主业务流控制 (Step 进度、成功/失败跳页):** 严格遵守《Postgres-Only 指南》步骤5。使用 useTaskStatus (React Query) 的 refetchInterval 进行串行稳健轮询。
|
||||
* **视觉反馈增强 (终端日志流):** 引入 SSE 单向通道,仅用于给 \<ProcessingTerminal /\> 组件灌入实时的打字机日志流。即使 SSE 意外断开,也不会阻断主线业务流。
|
||||
|
||||
### **2\. 人机协作 (HITL) 抽屉的死锁解套**
|
||||
|
||||
* **业务痛点:** 若 AI 提取的 Quote 模糊匹配失败(置信度 \< 0.8),前端标红警告。但如果医生强行认为 AI 提取的没错,系统没有提供放行的交互,导致数据卡在 Pending 状态。
|
||||
* **✅ 标准解法:** 抽屉内的错误警告框必须配套两个处理按钮:
|
||||
1. \[强制认可\]:消除警告,在 payload 中标记 quote\_force\_accepted: true。
|
||||
2. \[手动修改数值\]:医生直接修改 Input 框,系统自动给旧的错误 Quote 画上删除线,并提示“已转为人工干预,原文引用取消强绑定”。
|
||||
|
||||
### **3\. 规避签名 URL 过期导致的 403 报错**
|
||||
|
||||
* **业务痛点:** 医生复核 50 篇文献需要很长时间,预签名的 OSS PDF 链接容易过期。
|
||||
* **✅ 标准解法:** 绝对禁止在加载列表时批量生成并缓存签名 URL。采用**懒加载**:仅当医生点击某行文献的“复核提单”并展开右侧抽屉时,前端才实时请求获取一个有效期为 10 分钟的临时 URL 赋给 iframe。
|
||||
Reference in New Issue
Block a user