Files
AIclinicalresearch/docs/03-业务模块/ASL-AI智能文献/00-系统设计/V2.0 迭代升级/Deep Research MVP 技术设计文档V 4.1.md
HaHafeng b06daecacd feat(asl): Add Deep Research V2.0 development plan and Unifuncs API site coverage testing
Completed:
- Unifuncs DeepSearch API site coverage test (18 medical sites, 9 tier-1 available)
- ClinicalTrials.gov dedicated test (4 strategies, English query + depth>=10 works best)
- Deep Research V2.0 development plan (5-day phased delivery)
- DeepResearch engine capability guide (docs/02-common-capability/)
- Test scripts: test-unifuncs-site-coverage.ts, test-unifuncs-clinicaltrials.ts

Key findings:
- Tier-1 sites: PubMed(28), ClinicalTrials(38), NCBI(18), Scholar(10), Cochrane(4), CNKI(7), SinoMed(9), GeenMedical(5), VIP(1)
- Paid databases (WoS/Embase/Scopus/Ovid) cannot be accessed (no credential support)
- ClinicalTrials.gov requires English queries with max_depth>=10

Updated: ASL module status doc, system status doc, common capability list
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-22 22:44:41 +08:00

144 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# **技术设计文档 (TDD)ASL \- 智能文献检索 (Deep Research) MVP 版**
**文档版本:** v4.4-Tech (MVP 自然语言确认版)
**核心架构:** LLM Requirement Expansion (需求扩写) \+ Postgres-Only (pg-boss) \+ Unifuncs Async API
## **🏗️ 1\. 系统数据流向 (Data Flow)**
MVP 版本的架构最大程度降低了状态维护的成本,充分利用 Unifuncs 原生支持自然语言查询的能力。
1. Client 发送原始简短自然语言 \-\> Node.js 调用 DeepSeek-V3 \-\> 返回**结构化、扩写后的自然语言检索需求Search Requirements**(非布尔检索式)。
2. Client 展示该检索需求(普通文本/Markdown允许用户直接进行文字修改与补充 \-\> 用户点击执行,发送修改后的 Confirmed Requirement \-\> Node.js 创建 pg-boss 任务。
3. Worker 启动 \-\> 将用户确认的自然语言需求直接作为 content 传给 Unifuncs 创建任务 \-\> 每 5 秒轮询一次 Unifuncs \-\> 增量日志写入 PostgreSQL。
4. Client 每 3 秒轮询 Node.js 获取日志 \-\> 渲染 Terminal \-\> 任务完成,渲染结果。
## **🗄️ 2\. 数据库设计 (Prisma)**
极简表结构,去掉了复杂的澄清记录,只保留原始问题和最终执行的自然语言需求。
model AslResearchTask {
id String @id @default(uuid())
user\_id String
// Step 1 & 2
original\_query String @db.Text
target\_sources Json // 选中的数据源,如 \["pubmed.ncbi.nlm.nih.gov"\]
filters Json // 高级过滤条件
confirmed\_requirement String? @db.Text // 核心字段:用户复核并修改后的自然语言检索需求
// Step 3
status String // 'draft', 'pending', 'running', 'completed', 'failed'
unifuncs\_task\_id String? // 外部API的ID
execution\_logs Json? // 终端日志 \[{type: 'log', text: '...'}, ...\]
// Step 4
result\_list Json?
synthesis\_report String? @db.Text
created\_at DateTime @default(now())
updated\_at DateTime @updatedAt
}
## **🔌 3\. 核心 API 契约**
### **3.1 检索需求扩写接口 (同步, 无状态)**
* **POST /api/v1/asl/research/generate-requirement**
* **处理:** 拦截用户简短输入,拼装 System Prompt调用系统内置 LLMFactoryDeepSeek-V3
* *System Prompt 示例:* “你是一个医学检索辅助专家。请将用户简短的研究意图扩写并梳理成一份条理清晰的自然语言检索需求说明。内容包括1. 核心检索主题2. 建议包含的专业关键词中英文3. 目标人群及干预措施限定4. 文献类型建议(如 RCT。输出纯文本方便用户二次编辑。”
* *同时:* 创建数据库记录(状态为 draft
* **返回:** { taskId: "uuid", generatedRequirement: "研究主题:他汀类药物...\\n目标人群...\\n检索要求..." }
### **3.2 任务启动接口 (进入异步队列)**
* **PUT /api/v1/asl/research/tasks/:id/execute**
* **请求体:** { confirmedRequirement: string }
* **处理:** 1\. 更新 AslResearchTask 的 confirmed\_requirement 字段。
2\. jobQueue.createJob('deep-research-worker', { taskId: id })
3\. 更新状态为 pending。
* **返回:** { success: true }
### **3.3 任务状态与日志轮询接口**
* **GET /api/v1/asl/research/tasks/:id**
* **返回:** 包含 status, execution\_logs, 以及若完成synthesis\_report 和 result\_list。
## **⚙️ 4\. 后台 Worker 逻辑 (Unifuncs 集成)**
使用平台现有的 pg-boss 机制。
// backend/src/modules/asl/workers/DeepResearchWorker.ts
export async function processDeepResearch(job: Job) {
const taskId \= job.data.taskId;
const task \= await prisma.aslResearchTask.findUnique({ where: { id: taskId } });
// 1\. 发起 Unifuncs 创建任务请求
const unifuncsPayload \= {
model: "s2",
// 💡 核心变更:直接将用户确认的、详细的自然语言需求传给 Unifuncs由 Unifuncs 自己去理解和拆解检索词
messages: \[{
role: "user",
content: \`请根据以下详细检索需求执行深度研究:\\n${task.confirmed\_requirement}\`
}\],
introduction: "你是一名资深的循证医学研究员。请严格遵循用户的检索需求,在指定数据库中执行详尽的深度检索。",
max\_depth: 25,
domain\_scope: task.target\_sources,
// 强制输出格式以分离报告与文献JSON
output\_prompt: \`
\<REPORT\_SECTION\>
\[撰写综合报告\]
\</REPORT\_SECTION\>
\<JSON\_LIST\_SECTION\>
\[输出严格的文献JSON数组\]
\</JSON\_LIST\_SECTION\>
\`,
reference\_style: "link"
};
const createRes \= await unifuncsClient.createTask(unifuncsPayload);
const unifuncsId \= createRes.data.task\_id;
await prisma.aslResearchTask.update({
where: { id: taskId },
data: { unifuncs\_task\_id: unifuncsId, status: 'running' }
});
// 2\. 轮询 Unifuncs 状态 (防无限死循环,设置最大重试次数)
let isCompleted \= false;
let maxRetries \= 120; // 假设每5秒查一次最多查10分钟
while (\!isCompleted && maxRetries \> 0\) {
await sleep(5000);
const queryRes \= await unifuncsClient.queryTask(unifuncsId);
// 解析增量日志 reasoning\_content
const logs \= parseReasoningToLogs(queryRes.data.result?.reasoning\_content);
// 更新数据库日志 (覆盖或追加)
await prisma.aslResearchTask.update({
where: { id: taskId },
data: { execution\_logs: logs }
});
if (queryRes.data.status \=== 'completed') {
isCompleted \= true;
// 解析提取 \<REPORT\_SECTION\> 和 \<JSON\_LIST\_SECTION\>
const report \= extractReport(queryRes.data.result.content);
const list \= extractJsonList(queryRes.data.result.content);
await prisma.aslResearchTask.update({
where: { id: taskId },
data: { status: 'completed', synthesis\_report: report, result\_list: list }
});
}
maxRetries--;
}
}
## **🛡️ 5\. 技术优势**
1. **零学习成本**:去除了对医生来说晦涩难懂的“布尔逻辑检索式”,整个确认过程完全采用大白话(自然语言),用户审查和修改都极其自然。
2. **充分发挥 API 威力**:将“拆解关键词、发起搜索、阅读网页”的复杂动作全部下放给专业的 Unifuncs 引擎,本系统架构只做轻量级的“需求扩写”和“流式日志透传”,代码稳定性极高。
3. **极速上线**:前端页面仅需一个大文本框渲染扩写后的要求,没有任何复杂的 UI 组件开销,是名副其实的 MVP 最优解。