Files
AIclinicalresearch/docs/03-业务模块/ASL-AI智能文献/04-开发计划/07-Deep Research V2.0 开发计划.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

625 lines
26 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.
# Deep Research V2.0 开发计划
> **文档版本:** v1.0
> **创建日期:** 2026-02-22
> **维护者:** 开发团队
> **前置文档:** PRD V4.1 / 原型图 V4.2 / 技术设计 V4.1
> **预计工期:** 5 天
> **核心理念:** 单页瀑布流 + 自然语言需求扩写 + 异步执行 + 务实结果展示
---
## 1. 升级概述
### 1.1 V1.x → V2.0 变化总结
| 维度 | V1.x (当前) | V2.0 (目标) |
|------|------------|------------|
| **交互模式** | 单输入框 → 直接搜索 | 四步瀑布流 Landing → 配置 → HITL 确认 → 终端 → 结果 |
| **需求理解** | 用户原文直传 unifuncs | 内置 LLM 需求扩写 + 用户人工核验修改 |
| **API 协议** | OpenAI 兼容SSE 流式) | **Unifuncs 异步模式**create_task + query_task 轮询) |
| **执行展示** | 混合文字流(打字机效果) | 暗黑终端 + 分类结构化日志(每 3-5s 弹出一条) |
| **结果展示** | PubMed 链接列表 | 综合报告Markdown+ 文献清单表格 + Word 导出 |
| **可靠性** | 离开页面任务丢失 | pg-boss 队列,离开页面任务继续,回来可恢复 |
### 1.2 设计决策记录
| 决策 | 选择 | 理由 |
|------|------|------|
| SSE vs 异步 | **异步模式** | Deep Research 任务 3-10 分钟SSE 连接不稳定;异步模式用户可离开回来,可靠性远高于 SSE |
| 异步下的实时性 | **Worker 5s 轮询 + 前端 3s 轮询** | 用户每 3-5s 看到一条新日志,对分钟级 Agent 任务来说体验自然,比逐字流更适合终端 UI |
| 结果展示复杂度 | **报告 + 表格,不做图表看板** | 研究人员要的是内容本身(综合报告 + 文献清单图表是锦上添花非刚需MVP 不做 |
| Word 导出 | **复用 Pandoc** | Protocol Agent 已验证 Pandoc → Word 方案,零额外依赖 |
---
## 2. 系统数据流
```
┌──────────────────────────────────────────────────────────────────────┐
│ Step 1-2: 需求扩写(同步,本系统内部) │
│ │
│ 前端 Landing/Setup ──POST──→ Node.js ──LLMFactory──→ DeepSeek-V3 │
│ original_query "需求扩写Prompt" │
│ │
│ 返回taskId + generatedRequirement结构化自然语言检索指令书
│ 前端展示指令书,用户可编辑修改 │
└──────────────────────────────────────────────────────────────────────┘
↓ 用户确认
┌──────────────────────────────────────────────────────────────────────┐
│ Step 3: 异步执行pg-boss + Unifuncs 异步 API
│ │
│ 前端 ──PUT──→ Node.js ──pg-boss push──→ Worker │
│ confirmed_requirement │
│ │
│ Worker: │
│ 1. POST unifuncs/v1/create_task传入 confirmed_requirement
│ 2. 每 5s GET unifuncs/v1/query_task │
│ 3. 解析 reasoning_content → 增量日志写 DB (execution_logs) │
│ 4. 完成后解析 content → synthesis_report + result_list │
│ │
│ 前端每 3s GET /tasks/:id → 渲染 execution_logs 到暗黑终端 │
└──────────────────────────────────────────────────────────────────────┘
↓ status === 'completed'
┌──────────────────────────────────────────────────────────────────────┐
│ Step 4: 结果展示(读 DB 渲染) │
│ │
│ 终端折叠 → 白底结果区展开 │
│ ├── ✅ 完成横幅(一行 + 导出 Word 按钮) │
│ ├── 📄 AI 综合报告synthesis_report → Markdown 渲染) │
│ └── 📋 文献清单表格result_list → Ant Design Table
└──────────────────────────────────────────────────────────────────────┘
```
---
## 3. 数据库 Schema 变更
在现有 `AslResearchTask` 基础上**新增 6 个字段**,不删除任何现有字段(向后兼容)。
```prisma
model AslResearchTask {
// ── 现有字段(保留不动)──────────────────────────
id String @id @default(uuid())
projectId String @map("project_id")
userId String @map("user_id")
query String // 原始粗略输入Step 1
filters Json? // 高级筛选配置
externalTaskId String? @map("external_task_id") // unifuncs task_id
status String @default("pending")
errorMessage String? @map("error_message")
resultCount Int? @map("result_count")
rawResult String? @map("raw_result") @db.Text
reasoningContent String? @map("reasoning_content") @db.Text
literatures Json?
tokenUsage Json? @map("token_usage")
searchCount Int? @map("search_count")
readCount Int? @map("read_count")
iterations Int?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
completedAt DateTime? @map("completed_at")
// ── V2.0 新增字段 ──────────────────────────────
targetSources Json? @map("target_sources") // 选中的数据源 ["pubmed.ncbi.nlm.nih.gov", ...]
confirmedRequirement String? @map("confirmed_requirement") @db.Text // 用户核验后的自然语言检索指令书
aiIntentSummary Json? @map("ai_intent_summary") // AI提炼的结构化摘要左侧卡片用
executionLogs Json? @map("execution_logs") // 终端日志数组 [{type, title, text, timestamp}]
synthesisReport String? @map("synthesis_report") @db.Text // AI综合报告Markdown
resultList Json? @map("result_list") // 结构化文献元数据列表
// ── 索引(保留现有)────────────────────────────
@@index([projectId], map: "idx_research_tasks_project_id")
@@index([userId], map: "idx_research_tasks_user_id")
@@index([status], map: "idx_research_tasks_status")
@@index([createdAt], map: "idx_research_tasks_created_at")
@@map("research_tasks")
@@schema("asl_schema")
}
```
**Status 枚举扩展:**
| 状态 | 含义 | 触发时机 |
|------|------|---------|
| `draft` | 需求已扩写,等待用户确认 | POST /generate-requirement |
| `pending` | 用户已确认,等待 Worker 拾取 | PUT /tasks/:id/execute |
| `running` | Worker 已创建 unifuncs 任务,轮询中 | Worker 内部 |
| `completed` | unifuncs 完成,结果已解析入库 | Worker 内部 |
| `failed` | 执行失败 | Worker 内部 |
**迁移命令:**
```bash
npx prisma migrate dev --name add_deep_research_v2_fields
```
---
## 4. API 契约
### 4.1 需求扩写(同步)
**POST /api/v1/asl/research/generate-requirement**
```typescript
// 请求
{
originalQuery: string, // "他汀预防心血管疾病要能下载PDF的"
targetSources: string[], // ["pubmed.ncbi.nlm.nih.gov", "bmjopen.bmj.com"]
filters: {
yearRange?: string, // "2010至今" | "过去5年" | "不限"
targetCount?: string, // "~100篇" | "全面检索"
requireOpenAccess?: boolean // true
}
}
// 响应
{
success: true,
data: {
taskId: "uuid", // 已创建DB记录status=draft
generatedRequirement: "请帮我执行一次深度的医学文献检索...", // LLM扩写结果
intentSummary: { // 结构化摘要
objective: "为Meta分析构建测试语料库",
intervention: "他汀类药物 (Statins)",
condition: "心血管疾病 (CVD)",
literatureStandard: "高质量临床研究PDF全文可下载"
}
}
}
```
**实现要点:**
- 调用 `LLMFactory.getAdapter('deepseek-v3')` 进行需求扩写
- System Prompt 要求 LLM 输出结构化自然语言指令(非布尔检索式)
- 同时创建 DB 记录status = `draft`
### 4.2 启动执行(进入异步队列)
**PUT /api/v1/asl/research/tasks/:id/execute**
```typescript
// 请求
{
confirmedRequirement: string // 用户核验修改后的最终指令书
}
// 响应
{ success: true }
```
**实现要点:**
- 更新 DB 的 `confirmed_requirement``target_sources`
- `jobQueue.push('asl_deep_research_v2', { taskId })` 推入 pg-boss
- status 更新为 `pending`
### 4.3 任务状态与日志轮询
**GET /api/v1/asl/research/tasks/:id**
```typescript
// 响应
{
success: true,
data: {
taskId: "uuid",
status: "running", // draft/pending/running/completed/failed
executionLogs: [ // 终端日志(增量)
{ type: "think", title: "任务理解", text: "已收到检索需求...", ts: "..." },
{ type: "action", title: "Search", text: "executing search across PubMed...", ts: "..." },
{ type: "done", title: "搜索轮次完成", text: "", ts: "..." },
],
progress: { current: 60, total: 100 },
// 仅 completed 时有:
synthesisReport: "## 研究背景\n他汀类药物...",
resultList: [
{ title: "...", authors: "...", journal: "...", year: 2010, type: "Meta-analysis", pmid: "...", doi: "...", pdfStatus: "OA" },
],
resultCount: 103,
errorMessage: null
}
}
```
### 4.4 Word 导出
**GET /api/v1/asl/research/tasks/:id/export-word**
- 读取 DB 的 `synthesis_report`Markdown`result_list`JSON
- 拼接为完整 Markdown报告 + 文献清单表格)
- 调用 Pandoc 转 Word
- 返回 `.docx` 文件流
### 4.5 路由汇总
| 方法 | 路径 | 说明 | 新增/改造 |
|------|------|------|----------|
| POST | `/research/generate-requirement` | 需求扩写 | **新增** |
| PUT | `/research/tasks/:id/execute` | 启动执行 | **新增** |
| GET | `/research/tasks/:id` | 状态+日志+结果 | **改造** |
| GET | `/research/tasks/:id/export-word` | Word 导出 | **新增** |
| POST | `/research/stream` | V1 SSE保留兼容 | 不动 |
| POST | `/research/tasks` | V1 异步创建(保留) | 不动 |
---
## 5. 后台 Worker 逻辑
### 5.1 核心流程(伪代码)
```typescript
// backend/src/modules/asl/workers/deepResearchV2Worker.ts
export async function processDeepResearchV2(job: Job) {
const { taskId } = job.data;
const task = await prisma.aslResearchTask.findUnique({ where: { id: taskId } });
// 1. 调用 Unifuncs 创建异步任务
const unifuncsPayload = {
model: "s2",
messages: [{
role: "user",
content: `请根据以下详细检索需求执行深度研究:\n${task.confirmedRequirement}`
}],
introduction: buildIntroduction(),
max_depth: 25,
domain_scope: task.targetSources || ["https://pubmed.ncbi.nlm.nih.gov/"],
domain_blacklist: ["wanfang.com", "cnki.net"],
output_prompt: buildOutputPrompt(),
reference_style: "link",
generate_summary: true,
};
const createRes = await unifuncsClient.createTask(unifuncsPayload);
const unifuncsTaskId = createRes.data.task_id;
await prisma.aslResearchTask.update({
where: { id: taskId },
data: { externalTaskId: unifuncsTaskId, status: 'running' }
});
// 2. 轮询 Unifuncs 直到完成
let previousReasoning = '';
const MAX_POLLS = 180; // 最多 15 分钟180 × 5s
for (let i = 0; i < MAX_POLLS; i++) {
await sleep(5000);
const queryRes = await unifuncsClient.queryTask(unifuncsTaskId);
const data = queryRes.data;
// 解析增量日志
const currentReasoning = data.result?.reasoning_content || '';
if (currentReasoning.length > previousReasoning.length) {
const increment = currentReasoning.slice(previousReasoning.length);
const newLogs = parseReasoningToLogs(increment);
await appendExecutionLogs(taskId, newLogs);
previousReasoning = currentReasoning;
}
// 同步进度
if (data.progress) {
// progress 信息可通过 executionLogs 的最后一条体现
}
// 检查完成
if (data.status === 'completed') {
const content = data.result?.content || '';
const report = extractSection(content, 'REPORT_SECTION');
const jsonList = extractSection(content, 'JSON_LIST_SECTION');
const parsedList = safeParseJsonList(jsonList);
await prisma.aslResearchTask.update({
where: { id: taskId },
data: {
status: 'completed',
rawResult: content,
reasoningContent: currentReasoning,
synthesisReport: report || content,
resultList: parsedList,
resultCount: parsedList?.length || 0,
tokenUsage: data.statistics?.token_usage,
searchCount: data.statistics?.search_count,
readCount: data.statistics?.read_count,
iterations: data.statistics?.iterations,
completedAt: new Date(),
}
});
return;
}
if (data.status === 'failed') {
throw new Error(data.result?.content || 'Unifuncs 任务失败');
}
}
throw new Error('任务超时15分钟');
}
```
### 5.2 日志解析逻辑
```typescript
function parseReasoningToLogs(increment: string): LogEntry[] {
const logs: LogEntry[] = [];
const lines = increment.split('\n').filter(l => l.trim());
for (const line of lines) {
if (line.includes('搜索') || line.includes('search') || line.includes('Search')) {
logs.push({ type: 'action', title: 'Search', text: line.trim(), ts: new Date().toISOString() });
} else if (line.includes('阅读') || line.includes('read') || line.includes('Read')) {
logs.push({ type: 'action', title: 'Read', text: line.trim(), ts: new Date().toISOString() });
} else if (line.includes('完成') || line.includes('成功') || line.includes('OK')) {
logs.push({ type: 'done', title: '阶段完成', text: line.trim(), ts: new Date().toISOString() });
} else if (line.includes('汇总') || line.includes('总结') || line.includes('发现')) {
logs.push({ type: 'summary', title: '阶段总结', text: line.trim(), ts: new Date().toISOString() });
} else if (line.trim().length > 10) {
logs.push({ type: 'think', title: 'Thinking', text: line.trim(), ts: new Date().toISOString() });
}
}
return logs;
}
```
### 5.3 output_prompt 设计
```typescript
function buildOutputPrompt(): string {
return `请严格按照以下格式输出结果:
<REPORT_SECTION>
[此处撰写深度综合研究报告,使用 Markdown 格式,包括:
- 研究背景与目的
- 核心发现与共识
- 分歧点与研究空白
- 参考文献列表带编号和PubMed链接]
</REPORT_SECTION>
<JSON_LIST_SECTION>
[此处输出文献元数据的严格 JSON 数组,每条包含:
{"title":"...", "authors":"...", "journal":"...", "year":2024, "type":"RCT|Meta-analysis|Cohort|SR", "pmid":"...", "doi":"...", "pdfStatus":"OA|Restricted", "url":"https://pubmed.ncbi.nlm.nih.gov/..."}]
</JSON_LIST_SECTION>`;
}
```
---
## 6. 前端组件设计
### 6.1 页面结构
```
frontend-v2/src/modules/asl/pages/
└── DeepResearchPage.tsx # V2.0 主页面(替代 ResearchSearch.tsx
frontend-v2/src/modules/asl/components/
├── deep-research/
│ ├── LandingView.tsx # Landing 大搜索框
│ ├── SetupPanel.tsx # Step 1: 配置面板
│ ├── StrategyConfirm.tsx # Step 2: HITL 策略确认(左右分栏)
│ ├── AgentTerminal.tsx # Step 3: 暗黑执行终端
│ └── ResultsView.tsx # Step 4: 结果展示(报告+表格)
```
### 6.2 状态管理
```typescript
// 页面级状态useState 即可,无需 Zustand
interface DeepResearchState {
currentStep: 'landing' | 'setup' | 'strategy' | 'terminal' | 'results';
taskId: string | null;
originalQuery: string;
generatedRequirement: string;
intentSummary: IntentSummary | null;
isGenerating: boolean; // 需求扩写中
}
```
### 6.3 各组件核心逻辑
**LandingViewLanding 大搜索框)**
- 居中大输入框 + "开始研究"按钮 + 推荐预置词
- 点击后携带输入值,平滑过渡到 SetupPanel
- 参考原型图 V4.2 的 `#landing-view` 部分
**SetupPanelStep 1: 配置)**
- 继承 Landing 输入值到 textarea
- 数据源 CheckboxPubMed/PMC, BMJ Open, Cochrane
- 高级过滤年份下拉、目标数量、OA 强制)
- 点击"解析并生成检索需求书" → POST /generate-requirement
- Loading 后平滑展开 Step 2
**StrategyConfirmStep 2: HITL 确认)**
- 左侧 1/3AI 意图提炼卡片(只读,来自 `intentSummary`
- 右侧 2/3可编辑 textarea内容为 `generatedRequirement`
- 提示文案:"您可以像写邮件一样在这里补充任何大白话要求"
- 点击"确认需求,启动 Deep Research" → PUT /execute
**AgentTerminalStep 3: 暗黑终端)**
- 暗色背景bg-slate-900固定高度 550px内部滚动
- 顶部状态栏:红/黄/绿圆点 + "Running" 脉冲指示灯
- 日志渲染:
- `think` → 紫色 + 🧠 图标
- `action` → 蓝色 + 💻 图标
- `done` → 绿色 + ✅ 图标
- `summary` → 黄色 + 📋 图标
- 轮询逻辑:`useQuery` + refetchInterval: 3000running 时启用)
- 新日志出现时 auto-scroll 到底部
- 完成后状态灯变灰 "Finished",终端可折叠
**ResultsViewStep 4: 结果)**
- 白色背景,与终端形成视觉分界
- 完成横幅(一行):文献数 + 耗时 + "导出 Word" 按钮
- AI 综合报告区:`react-markdown` 渲染 `synthesisReport`,可折叠,默认展开
- 文献清单表格Ant Design Table
- 列:标题(可点击跳转 PubMed、期刊、年份、类型 Tag、PDF 状态
- 支持简单搜索过滤
- 分页(前端分页即可,数据量 ~100 条)
### 6.4 轮询 Hook
```typescript
// hooks/useDeepResearchTask.ts
function useDeepResearchTask(taskId: string | null) {
return useQuery({
queryKey: ['deep-research-task', taskId],
queryFn: () => apiClient.get(`/api/v1/asl/research/tasks/${taskId}`),
enabled: !!taskId,
refetchInterval: (query) => {
const status = query.state.data?.data?.status;
return (status === 'pending' || status === 'running') ? 3000 : false;
},
});
}
```
---
## 7. 复用清单(不重复造轮子)
| 能力 | 来源 | 用法 |
|------|------|------|
| LLM 调用 | `common/llm/LLMFactory` | DeepSeek-V3 需求扩写 |
| pg-boss 队列 | `common/jobs/jobQueue` | Worker 注册与任务推送 |
| 日志服务 | `common/logging/logger` | 全程结构化日志 |
| 认证中间件 | `common/auth/authenticate` | 所有 API 路由 |
| Prisma 全局实例 | `config/database` | 数据库操作 |
| Word 导出 | PandocPython 微服务) | 复用 Protocol Agent 验证的方案 |
| 前端 API Client | `common/api/axios` | 带认证的请求 |
| 前端布局 | `ASLLayout.tsx` | 左侧导航 |
---
## 8. 分阶段开发计划
### Phase 1: 数据库 + 需求扩写Day 1
**目标:** 用户输入粗略想法 → AI 扩写为结构化指令书 → 用户可编辑修改
| 任务 | 文件 | 说明 |
|------|------|------|
| Schema 迁移 | `prisma/schema.prisma` | 新增 6 个字段,`prisma migrate dev` |
| 需求扩写 Prompt | `services/requirementExpansionService.ts` | 新建服务,调用 DeepSeek-V3 扩写 |
| 扩写 API | `controllers/researchController.ts` | 新增 `POST /generate-requirement` |
| 启动 API | `controllers/researchController.ts` | 新增 `PUT /tasks/:id/execute` |
| 状态 API 改造 | `controllers/researchController.ts` | 改造 `GET /tasks/:id`,返回新字段 |
| 路由注册 | `routes/index.ts` | 注册新端点 |
**验收标准:**
- [ ] `POST /generate-requirement` 返回扩写后的指令书
- [ ] `PUT /tasks/:id/execute` 成功推入 pg-boss 队列
- [ ] `GET /tasks/:id` 返回含新字段的完整数据
### Phase 2: Worker 改造 — Unifuncs 异步模式Day 2
**目标:** Worker 使用 create_task + query_task 轮询,增量日志写入 DB
| 任务 | 文件 | 说明 |
|------|------|------|
| Unifuncs 异步客户端 | `services/unifuncsAsyncClient.ts` | 新建,封装 create_task / query_task |
| V2 Worker | `workers/deepResearchV2Worker.ts` | 新建,轮询 + 日志解析 + 结果切割 |
| 日志解析器 | `utils/reasoningParser.ts` | 新建reasoning_content → 结构化日志 |
| 结果解析器 | `utils/resultParser.ts` | 新建XML 标签切割报告与 JSON 列表 |
| Worker 注册 | `workers/researchWorker.ts` | 注册新 Worker `asl_deep_research_v2` |
**验收标准:**
- [ ] Worker 成功调用 unifuncs create_task
- [ ] 轮询期间 execution_logs 持续增量更新
- [ ] 完成后 synthesis_report 和 result_list 正确入库
- [ ] 超时保护15 分钟)和错误处理正常
### Phase 3: 前端 — Landing + 配置 + HITL 确认Day 3
**目标:** 完成 Step 1-2 的前端交互,瀑布流渐进展开
| 任务 | 文件 | 说明 |
|------|------|------|
| 主页面骨架 | `pages/DeepResearchPage.tsx` | 新建,管理瀑布流状态 |
| Landing 组件 | `components/deep-research/LandingView.tsx` | 大搜索框 + 推荐预置词 |
| 配置面板 | `components/deep-research/SetupPanel.tsx` | 数据源 + 高级过滤 + 生成按钮 |
| HITL 确认 | `components/deep-research/StrategyConfirm.tsx` | 左右分栏 + 可编辑 textarea |
| API 函数 | `api/index.ts` | 新增 generateRequirement / executeTask |
| 路由注册 | `pages/index.tsx` | 新增 V2 路由 |
**验收标准:**
- [ ] Landing 输入 → Step 1 配置面板流畅过渡
- [ ] 点击"生成需求书" → Loading → Step 2 展开
- [ ] Step 2 左侧摘要卡片正确展示,右侧 textarea 可编辑
- [ ] 点击"启动 Deep Research" → 进入 Step 3
### Phase 4: 前端 — 终端 + 结果展示Day 4
**目标:** 完成 Step 3-4终端实时日志 + 结果报告/表格
| 任务 | 文件 | 说明 |
|------|------|------|
| 暗黑终端 | `components/deep-research/AgentTerminal.tsx` | 日志渲染 + auto-scroll + 状态灯 |
| 结果视图 | `components/deep-research/ResultsView.tsx` | 横幅 + 报告 + 文献表格 |
| 轮询 Hook | `hooks/useDeepResearchTask.ts` | 3s 轮询running 时启用 |
| 终端样式 | CSS / Tailwind | 暗色主题 + 日志类型着色 |
**验收标准:**
- [ ] 终端日志按类型着色,新日志 auto-scroll
- [ ] 完成后终端折叠,结果区展开
- [ ] 综合报告 Markdown 渲染正确
- [ ] 文献清单表格展示(标题可点击跳转 PubMed
- [ ] 全流程端到端联调通过
### Phase 5: Word 导出 + 收尾Day 5
**目标:** Word 导出功能 + 全流程打磨 + 测试
| 任务 | 文件 | 说明 |
|------|------|------|
| Word 导出 API | `controllers/researchController.ts` | `GET /tasks/:id/export-word` |
| Markdown 拼接 | `services/wordExportService.ts` | 报告 + 文献表格 → 完整 Markdown |
| Pandoc 调用 | 复用 Python 微服务 | Markdown → .docx |
| 前端导出按钮 | `ResultsView.tsx` | 下载 Word 文件 |
| 全流程测试 | 手动 + 脚本 | 端到端验证 |
| 文档更新 | 模块状态文档 | 更新 ASL 模块当前状态 |
**验收标准:**
- [ ] 点击"导出 Word" → 下载包含报告和文献清单的 .docx
- [ ] 全流程Landing → 配置 → 扩写 → 确认 → 执行 → 日志 → 结果 → 导出
- [ ] 离开页面回来,能恢复查看正在执行/已完成的任务
- [ ] 错误情况处理unifuncs 超时、API 报错、网络中断)
---
## 9. 验收标准总览
### 功能验收
- [ ] **Landing 引导**:用户输入粗略想法 → 进入配置
- [ ] **需求扩写**AI 自动扩写为结构化自然语言指令书
- [ ] **HITL 核验**:用户可直接编辑修改指令书
- [ ] **异步执行**pg-boss 队列,离开页面任务不中断
- [ ] **终端日志**:每 3-5s 弹出一条结构化日志
- [ ] **综合报告**Markdown 渲染,内容来自 Unifuncs 输出
- [ ] **文献清单**:表格展示,标题可跳转 PubMed
- [ ] **Word 导出**:一键导出报告 + 文献清单
### 非功能验收
- [ ] V1.x SSE 端点保留不动(向后兼容)
- [ ] 所有 API 经过 authenticate 中间件
- [ ] 日志使用 `logger`(非 console.log
- [ ] 无硬编码配置API Key 来自环境变量)
- [ ] 数据库变更通过 Prisma migrate非 db push
---
## 10. 风险与应对
| 风险 | 概率 | 影响 | 应对措施 |
|------|------|------|---------|
| Unifuncs 异步模式下 reasoning_content 不增量更新 | 低 | 终端日志为空 | 降级方案:只显示 progress.message |
| output_prompt XML 标签分割不可靠 | 中 | 报告和列表无法分离 | 降级方案:整体作为报告展示,文献从 PubMed 链接提取 |
| Unifuncs 长任务超时 | 低 | 任务失败 | MAX_POLLS=18015分钟超时标记 failed用户可重试 |
| Pandoc Word 导出在 SAE 不可用 | 低 | 导出失败 | 降级方案:导出为 Markdown 文件 |
---
**文档维护者:** 开发团队
**最后更新:** 2026-02-22
**文档状态:** ✅ 方案确认,待开发启动