Summary: - Fix methodology score display issue in task list (show score instead of 'warn') - Add methodology_score field to database schema - Fix report display when only methodology agent is selected - Implement Word document export using docx library - Update documentation to v3.0/v3.1 Backend changes: - Add methodologyScore to Prisma schema and TaskSummary type - Update reviewWorker to save methodologyScore - Update getTaskList to return methodologyScore Frontend changes: - Install docx and file-saver libraries - Implement handleExportReport with Word generation - Fix activeTab auto-selection based on available data - Add proper imports for docx components Documentation: - Update RVW module status to 90% (Phase 1-5 complete) - Update system status document to v3.0 Tested: All review workflows verified, Word export functional
793 lines
21 KiB
Markdown
793 lines
21 KiB
Markdown
# PKB个人知识库功能审查报告 - 阶段0
|
||
|
||
> **审查日期:** 2026-01-06
|
||
> **审查人员:** AI助手
|
||
> **审查目标:** 深入理解PKB现有功能,为安全迁移做准备
|
||
> **状态:** ✅ 进行中
|
||
|
||
---
|
||
|
||
## 📋 执行摘要
|
||
|
||
### 关键发现
|
||
|
||
**🎯 PKB系统实际上是两个紧密关联的功能模块:**
|
||
|
||
```
|
||
Part 1: PKB知识库管理模块
|
||
├─ 位置:backend/src/legacy/controllers/knowledgeBaseController.ts
|
||
├─ 功能:创建、编辑、删除知识库;上传、管理文档
|
||
└─ 数据库:pkb_schema(独立Schema,无需迁移)
|
||
|
||
Part 2: AIA智能问答模块中的PKB应用
|
||
├─ 位置:backend/src/legacy/controllers/chatController.ts
|
||
├─ 功能:使用知识库进行智能问答(3种工作模式)
|
||
└─ 工作模式:
|
||
├─ 全文阅读模式(35-50篇文献综合分析)
|
||
├─ 逐篇精读模式(1-5篇文献深度分析)
|
||
└─ 批处理模式(3-50篇文献批量提取)
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Part 1: PKB知识库管理模块
|
||
|
||
### 1.1 文件结构
|
||
|
||
```
|
||
backend/src/legacy/
|
||
├─ controllers/
|
||
│ ├─ knowledgeBaseController.ts # API控制器(342行)
|
||
│ └─ documentController.ts # 文档上传控制器
|
||
├─ services/
|
||
│ ├─ knowledgeBaseService.ts # 业务逻辑(365行)
|
||
│ ├─ documentService.ts # 文档处理服务
|
||
│ └─ tokenService.ts # Token计算和文档选择
|
||
└─ routes/
|
||
└─ knowledgeBases.ts # 路由定义
|
||
```
|
||
|
||
### 1.2 核心API端点
|
||
|
||
#### 知识库管理API
|
||
```typescript
|
||
// 1. 创建知识库
|
||
POST /api/v1/knowledge/create
|
||
Body: { name: string, description?: string }
|
||
逻辑:
|
||
├─ 检查用户配额(kbQuota vs kbUsed)
|
||
├─ 在Dify创建Dataset
|
||
├─ 在数据库创建记录
|
||
└─ 更新用户配额计数
|
||
|
||
// 2. 获取知识库列表
|
||
GET /api/v1/knowledge/list
|
||
返回:用户所有知识库 + 文档数量统计
|
||
|
||
// 3. 获取知识库详情
|
||
GET /api/v1/knowledge/:id
|
||
返回:知识库信息 + 所有文档列表
|
||
|
||
// 4. 更新知识库
|
||
PUT /api/v1/knowledge/:id
|
||
Body: { name?: string, description?: string }
|
||
|
||
// 5. 删除知识库
|
||
DELETE /api/v1/knowledge/:id
|
||
逻辑:
|
||
├─ 删除Dify Dataset
|
||
├─ 级联删除数据库记录(documents自动删除)
|
||
└─ 减少用户配额计数
|
||
|
||
// 6. 检索知识库(RAG)
|
||
GET /api/v1/knowledge/:id/search?query=xxx&top_k=15
|
||
逻辑:
|
||
├─ 验证权限
|
||
├─ 调用Dify retrieveKnowledge API
|
||
└─ 返回检索结果(默认15个片段)
|
||
|
||
// 7. 获取知识库统计
|
||
GET /api/v1/knowledge/:id/stats
|
||
返回:文档数、完成数、处理中、错误数、总Token数
|
||
|
||
// 8. 获取文档选择(全文阅读模式)
|
||
GET /api/v1/knowledge/:id/document-selection?max_files=7&max_tokens=750000
|
||
返回:智能选择的文档列表(基于Token限制)
|
||
```
|
||
|
||
#### 文档管理API
|
||
```typescript
|
||
// 9. 上传文档
|
||
POST /api/v1/documents/upload
|
||
Multipart: { file, kbId }
|
||
逻辑:
|
||
├─ 上传文件到OSS
|
||
├─ 提取文本(PDF/Word/TXT/Markdown)
|
||
├─ 上传到Dify进行索引
|
||
└─ 创建数据库记录(状态:uploading→parsing→indexing→completed)
|
||
|
||
// 10. 获取文档详情
|
||
GET /api/v1/documents/:id
|
||
|
||
// 11. 删除文档
|
||
DELETE /api/v1/documents/:id
|
||
逻辑:
|
||
├─ 从Dify删除Document
|
||
├─ 从OSS删除文件
|
||
└─ 删除数据库记录
|
||
```
|
||
|
||
### 1.3 数据库Schema
|
||
|
||
#### 表结构(在pkb_schema中)
|
||
|
||
```sql
|
||
-- 知识库表
|
||
knowledge_bases
|
||
├─ id (UUID, PK)
|
||
├─ userId (String)
|
||
├─ name (String)
|
||
├─ description (String?)
|
||
├─ difyDatasetId (String, UNIQUE) -- Dify中的Dataset ID
|
||
├─ fileCount (Int, default: 0)
|
||
├─ totalSizeBytes (BigInt, default: 0)
|
||
├─ createdAt (DateTime)
|
||
└─ updatedAt (DateTime)
|
||
|
||
-- 文档表
|
||
documents
|
||
├─ id (UUID, PK)
|
||
├─ kbId (String, FK → knowledge_bases.id)
|
||
├─ userId (String)
|
||
├─ filename (String)
|
||
├─ fileType (String) -- pdf/docx/txt/md
|
||
├─ fileSizeBytes (BigInt)
|
||
├─ fileUrl (String) -- OSS URL
|
||
├─ difyDocumentId (String) -- Dify中的Document ID
|
||
├─ status (String) -- uploading/parsing/indexing/completed/error
|
||
├─ progress (Int, 0-100)
|
||
├─ errorMessage (String?)
|
||
├─ segmentsCount (Int?) -- Dify索引的片段数
|
||
├─ tokensCount (Int?) -- 总Token数
|
||
├─ charCount (Int?) -- 字符数
|
||
├─ language (String?)
|
||
├─ extractedText (String?) -- 提取的全文(用于全文阅读模式)
|
||
├─ extractionMethod (String?) -- marker/pymupdf/docx
|
||
├─ extractionQuality (Float?)
|
||
├─ uploadedAt (DateTime)
|
||
└─ processedAt (DateTime?)
|
||
|
||
-- 批处理任务表
|
||
batch_tasks
|
||
├─ id (UUID, PK)
|
||
├─ userId (String)
|
||
├─ kbId (String, FK → knowledge_bases.id)
|
||
├─ name (String)
|
||
├─ templateType (String)
|
||
├─ templateId (String?)
|
||
├─ prompt (String)
|
||
├─ status (String) -- pending/running/completed/failed
|
||
├─ totalDocuments (Int)
|
||
├─ completedCount (Int, default: 0)
|
||
├─ failedCount (Int, default: 0)
|
||
├─ modelType (String)
|
||
├─ concurrency (Int, default: 3)
|
||
├─ startedAt (DateTime?)
|
||
├─ completedAt (DateTime?)
|
||
├─ durationSeconds (Int?)
|
||
├─ createdAt (DateTime)
|
||
└─ updatedAt (DateTime)
|
||
|
||
-- 批处理结果表
|
||
batch_results
|
||
├─ id (UUID, PK)
|
||
├─ taskId (String, FK → batch_tasks.id)
|
||
├─ documentId (String, FK → documents.id)
|
||
├─ status (String) -- success/failed
|
||
├─ data (Json?) -- 提取的结构化数据
|
||
├─ rawOutput (String?) -- LLM原始输出
|
||
├─ errorMessage (String?)
|
||
├─ processingTimeMs (Int?)
|
||
├─ tokensUsed (Int?)
|
||
└─ createdAt (DateTime)
|
||
|
||
-- 任务模板表
|
||
task_templates
|
||
├─ id (UUID, PK)
|
||
├─ userId (String)
|
||
├─ name (String)
|
||
├─ description (String?)
|
||
├─ prompt (String)
|
||
├─ isPublic (Boolean, default: false)
|
||
├─ outputFields (Json) -- 期望的输出字段
|
||
├─ createdAt (DateTime)
|
||
└─ updatedAt (DateTime)
|
||
```
|
||
|
||
#### 索引
|
||
```sql
|
||
-- knowledge_bases
|
||
idx_pkb_knowledge_bases_user_id (userId)
|
||
idx_pkb_knowledge_bases_dify_dataset_id (difyDatasetId)
|
||
|
||
-- documents
|
||
idx_pkb_documents_kb_id (kbId)
|
||
idx_pkb_documents_user_id (userId)
|
||
idx_pkb_documents_status (status)
|
||
idx_pkb_documents_dify_document_id (difyDocumentId)
|
||
idx_pkb_documents_extraction_method (extractionMethod)
|
||
|
||
-- batch_tasks
|
||
idx_pkb_batch_tasks_kb_id (kbId)
|
||
idx_pkb_batch_tasks_user_id (userId)
|
||
idx_pkb_batch_tasks_status (status)
|
||
idx_pkb_batch_tasks_created_at (createdAt)
|
||
|
||
-- batch_results
|
||
idx_pkb_batch_results_task_id (taskId)
|
||
idx_pkb_batch_results_document_id (documentId)
|
||
idx_pkb_batch_results_status (status)
|
||
```
|
||
|
||
### 1.4 关键业务逻辑
|
||
|
||
#### 配额管理
|
||
```typescript
|
||
// 用户表(在platform_schema.users)中的字段
|
||
kbQuota: Int @default(3) // 知识库配额
|
||
kbUsed: Int @default(0) // 已使用数量
|
||
|
||
// 创建知识库时检查
|
||
if (user.kbUsed >= user.kbQuota) {
|
||
throw new Error('配额已满');
|
||
}
|
||
|
||
// 创建成功后增加计数
|
||
await prisma.user.update({
|
||
data: { kbUsed: { increment: 1 } }
|
||
});
|
||
|
||
// 删除知识库时减少计数
|
||
await prisma.user.update({
|
||
data: { kbUsed: { decrement: 1 } }
|
||
});
|
||
```
|
||
|
||
#### Dify集成
|
||
```typescript
|
||
// 创建知识库 → 创建Dify Dataset
|
||
const difyDataset = await difyClient.createDataset({
|
||
name: `${userId}_${name}_${Date.now()}`,
|
||
description,
|
||
indexing_technique: 'high_quality',
|
||
});
|
||
|
||
// 检索知识库 → 调用Dify RAG
|
||
const results = await difyClient.retrieveKnowledge(
|
||
difyDatasetId,
|
||
query,
|
||
{
|
||
retrieval_model: {
|
||
search_method: 'semantic_search',
|
||
top_k: 15,
|
||
},
|
||
}
|
||
);
|
||
```
|
||
|
||
#### 文档Token计算(tokenService.ts)
|
||
```typescript
|
||
// Token计算规则
|
||
const TOKEN_LIMITS = {
|
||
MAX_FILES: 7, // 最多7篇文献
|
||
MAX_TOTAL_TOKENS: 750000, // 总Token限制(Qwen-Long: 1M上下文 - 250K对话空间)
|
||
MAX_SINGLE_DOC_TOKENS: 200000, // 单篇文献最大Token数
|
||
};
|
||
|
||
// 智能选择算法
|
||
function selectDocumentsForFullText(
|
||
documentTokens,
|
||
maxFiles,
|
||
maxTokens
|
||
) {
|
||
// 按Token数升序排序
|
||
const sorted = documentTokens.sort((a, b) => a.tokens - b.tokens);
|
||
|
||
// 贪心算法选择
|
||
let totalTokens = 0;
|
||
let selectedCount = 0;
|
||
const selected = [];
|
||
|
||
for (const doc of sorted) {
|
||
if (selectedCount >= maxFiles) break;
|
||
if (totalTokens + doc.tokens > maxTokens) break;
|
||
if (doc.tokens > MAX_SINGLE_DOC_TOKENS) continue; // 跳过超大文档
|
||
|
||
selected.push(doc);
|
||
totalTokens += doc.tokens;
|
||
selectedCount++;
|
||
}
|
||
|
||
return { selected, totalTokens, excludedDocs };
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Part 2: AIA模块中的PKB应用
|
||
|
||
### 2.1 文件结构
|
||
|
||
```
|
||
backend/src/legacy/controllers/
|
||
└─ chatController.ts # 通用对话控制器(包含3种模式)
|
||
|
||
frontend/src/
|
||
├─ pages/ChatPage.tsx # 主对话页面
|
||
└─ components/
|
||
├─ FullTextMode.tsx # 全文阅读模式组件
|
||
├─ DeepReadMode.tsx # 逐篇精读模式组件
|
||
└─ BatchMode.tsx # 批处理模式组件
|
||
```
|
||
|
||
### 2.2 三种工作模式详解
|
||
|
||
#### 模式1:全文阅读模式(Full Text Mode)
|
||
|
||
**用途**:35-50篇文献的综合分析
|
||
|
||
**实现原理:**
|
||
```typescript
|
||
// 1. 前端:用户进入知识库模式 → 选择"全文阅读"
|
||
const modeState = {
|
||
baseMode: 'knowledge_base',
|
||
kbMode: 'full_text',
|
||
selectedKbId: 'xxx',
|
||
};
|
||
|
||
// 2. 前端:智能加载文献
|
||
const selection = await knowledgeBaseApi.getDocumentSelection(kbId, {
|
||
max_files: 7,
|
||
max_tokens: 750000,
|
||
});
|
||
// 返回:{ selectedDocuments[], excludedDocuments[], totalTokens }
|
||
|
||
// 3. 前端:自动切换到Qwen-Long模型
|
||
if (modeState.kbMode === 'full_text') {
|
||
setSelectedModel('qwen-long'); // 1M上下文
|
||
showToast('已自动切换到Qwen-Long模型(支持1M上下文)');
|
||
}
|
||
|
||
// 4. 前端:发送消息时传递文档ID列表
|
||
await chatApi.sendMessageStream({
|
||
content: userQuestion,
|
||
modelType: 'qwen-long',
|
||
fullTextDocumentIds: loadedDocs.map(d => d.id), // ✅ 关键参数
|
||
conversationId,
|
||
});
|
||
|
||
// 5. 后端:加载完整全文
|
||
if (fullTextDocumentIds && fullTextDocumentIds.length > 0) {
|
||
const documents = await prisma.document.findMany({
|
||
where: { id: { in: fullTextDocumentIds } },
|
||
select: { id, filename, extractedText, tokensCount },
|
||
});
|
||
|
||
// 6. 组装全文上下文
|
||
const fullTextParts = [];
|
||
for (let i = 0; i < documents.length; i++) {
|
||
const doc = documents[i];
|
||
const docNumber = i + 1;
|
||
|
||
// 格式:【文献N:文件名】\n全文内容
|
||
fullTextParts.push(
|
||
`【文献${docNumber}:${doc.filename}】\n\n${doc.extractedText}`
|
||
);
|
||
|
||
// 添加引用信息
|
||
allCitations.push({
|
||
id: docNumber,
|
||
fileName: doc.filename,
|
||
score: 1.0, // 全文相关度100%
|
||
content: doc.extractedText.substring(0, 200),
|
||
});
|
||
}
|
||
|
||
knowledgeBaseContext = fullTextParts.join('\n\n---\n\n');
|
||
}
|
||
|
||
// 7. 传递给LLM
|
||
const systemPrompt = '你是专业的学术文献分析助手。每篇文献用【文献N:文件名】标记。请认真阅读所有文献,进行深入的综合分析。在回答时请引用具体文献,使用【文献N】格式。';
|
||
|
||
const userContent = `${userQuestion}\n\n## 参考资料(文献全文)\n\n${knowledgeBaseContext}`;
|
||
|
||
const messages = [
|
||
{ role: 'system', content: systemPrompt },
|
||
...historyMessages, // 对话历史
|
||
{ role: 'user', content: userContent },
|
||
];
|
||
|
||
// 8. 调用Qwen-Long
|
||
const response = await LLMFactory.getAdapter('qwen-long').chatStream(messages, {
|
||
temperature: 0.7,
|
||
maxTokens: 6000, // 全文模式需要更长的回答空间
|
||
});
|
||
```
|
||
|
||
**关键特点:**
|
||
- ✅ 传递完整全文(不是RAG片段)
|
||
- ✅ 智能选择文献(基于Token限制)
|
||
- ✅ 文献来源标记:【文献N:文件名】
|
||
- ✅ 自动切换到Qwen-Long模型(1M上下文)
|
||
- ✅ 100%相关度(因为是全文)
|
||
- ✅ 适合跨文献比较、趋势分析、研究方法归纳
|
||
|
||
**Token使用:**
|
||
```
|
||
上下文:~750K tokens(7篇文献全文)
|
||
对话空间:~250K tokens
|
||
输出长度:6000 tokens(综合分析需要更长回答)
|
||
```
|
||
|
||
---
|
||
|
||
#### 模式2:逐篇精读模式(Deep Read Mode)
|
||
|
||
**用途**:1-5篇文献的深度分析
|
||
|
||
**实现原理:**
|
||
```typescript
|
||
// 1. 前端:用户选择"逐篇精读"
|
||
const modeState = {
|
||
baseMode: 'knowledge_base',
|
||
kbMode: 'deep_read',
|
||
selectedKbId: 'xxx',
|
||
};
|
||
|
||
// 2. 前端:用户选择要精读的文档
|
||
const selectedDocs = [doc1, doc2, doc3]; // 用户手动选择
|
||
|
||
// 3. 前端:切换到某个文档
|
||
const currentDoc = selectedDocs[0];
|
||
|
||
// 4. 前端:发送消息时传递当前文档ID(用于RAG过滤)
|
||
await chatApi.sendMessageStream({
|
||
content: userQuestion,
|
||
modelType: selectedModel,
|
||
knowledgeBaseIds: [kbId], // 知识库ID
|
||
documentIds: [currentDoc.id], // ✅ 关键:只检索当前文档
|
||
conversationId: currentDocConversationId, // 每个文档独立对话
|
||
});
|
||
|
||
// 5. 后端:RAG检索(限定在特定文档)
|
||
if (documentIds && documentIds.length > 0) {
|
||
// 调用Dify RAG,但会限定在指定文档范围
|
||
const results = await difyClient.retrieveKnowledge(
|
||
difyDatasetId,
|
||
query,
|
||
{
|
||
retrieval_model: {
|
||
search_method: 'semantic_search',
|
||
top_k: 15,
|
||
document_ids: documentIds, // ✅ Dify会只检索这些文档
|
||
},
|
||
}
|
||
);
|
||
}
|
||
```
|
||
|
||
**关键特点:**
|
||
- ✅ 基于RAG检索(不是全文)
|
||
- ✅ 限定在当前文档范围
|
||
- ✅ 每个文档有独立的对话历史
|
||
- ✅ 用户可以在文档间切换
|
||
- ✅ 适合深度理解单篇文献
|
||
|
||
---
|
||
|
||
#### 模式3:批处理模式(Batch Mode)
|
||
|
||
**用途**:3-50篇文献的批量信息提取
|
||
|
||
**实现原理:**
|
||
```typescript
|
||
// 1. 用户创建批处理任务
|
||
POST /api/v1/batch-tasks/create
|
||
Body: {
|
||
kbId: 'xxx',
|
||
name: '提取研究方法',
|
||
prompt: '请从这篇文献中提取:研究设计、样本量、统计方法',
|
||
templateType: 'custom' | 'preset',
|
||
modelType: 'deepseek-v3',
|
||
concurrency: 3, // 并发数
|
||
}
|
||
|
||
// 2. 后端:创建任务
|
||
const task = await prisma.batchTask.create({
|
||
data: {
|
||
userId,
|
||
kbId,
|
||
name,
|
||
prompt,
|
||
templateType,
|
||
modelType,
|
||
status: 'pending',
|
||
totalDocuments: documentsCount,
|
||
concurrency,
|
||
},
|
||
});
|
||
|
||
// 3. 后端:启动批处理Worker
|
||
async function processBatchTask(taskId) {
|
||
// 3.1 获取任务和文档列表
|
||
const task = await prisma.batchTask.findUnique({
|
||
where: { id: taskId },
|
||
include: { knowledgeBase: { include: { documents: true } } },
|
||
});
|
||
|
||
const documents = task.knowledgeBase.documents.filter(d => d.status === 'completed');
|
||
|
||
// 3.2 更新任务状态
|
||
await prisma.batchTask.update({
|
||
where: { id: taskId },
|
||
data: { status: 'running', startedAt: new Date() },
|
||
});
|
||
|
||
// 3.3 并发处理文档
|
||
const concurrency = task.concurrency || 3;
|
||
const chunks = chunkArray(documents, concurrency);
|
||
|
||
for (const chunk of chunks) {
|
||
await Promise.all(chunk.map(async (doc) => {
|
||
try {
|
||
// 3.3.1 对每个文档,使用其extractedText + prompt调用LLM
|
||
const llmPrompt = `${task.prompt}\n\n文献内容:\n${doc.extractedText}`;
|
||
|
||
const response = await LLMFactory.getAdapter(task.modelType).chat([
|
||
{ role: 'user', content: llmPrompt },
|
||
]);
|
||
|
||
// 3.3.2 解析LLM输出(期望JSON格式)
|
||
const data = parseJSONResponse(response.content);
|
||
|
||
// 3.3.3 保存结果
|
||
await prisma.batchResult.create({
|
||
data: {
|
||
taskId: task.id,
|
||
documentId: doc.id,
|
||
status: 'success',
|
||
data,
|
||
rawOutput: response.content,
|
||
tokensUsed: response.usage.totalTokens,
|
||
processingTimeMs: Date.now() - startTime,
|
||
},
|
||
});
|
||
|
||
// 3.3.4 更新任务进度
|
||
await prisma.batchTask.update({
|
||
where: { id: taskId },
|
||
data: { completedCount: { increment: 1 } },
|
||
});
|
||
|
||
} catch (error) {
|
||
// 3.3.5 处理失败
|
||
await prisma.batchResult.create({
|
||
data: {
|
||
taskId: task.id,
|
||
documentId: doc.id,
|
||
status: 'failed',
|
||
errorMessage: error.message,
|
||
},
|
||
});
|
||
|
||
await prisma.batchTask.update({
|
||
where: { id: taskId },
|
||
data: { failedCount: { increment: 1 } },
|
||
});
|
||
}
|
||
}));
|
||
}
|
||
|
||
// 3.4 任务完成
|
||
await prisma.batchTask.update({
|
||
where: { id: taskId },
|
||
data: {
|
||
status: 'completed',
|
||
completedAt: new Date(),
|
||
durationSeconds: Math.floor((Date.now() - task.startedAt) / 1000),
|
||
},
|
||
});
|
||
}
|
||
|
||
// 4. 前端:查看批处理结果
|
||
GET /api/v1/batch-tasks/:id/results
|
||
返回:
|
||
{
|
||
task: { /* 任务信息 */ },
|
||
results: [
|
||
{
|
||
documentId: 'xxx',
|
||
filename: 'paper1.pdf',
|
||
status: 'success',
|
||
data: {
|
||
研究设计: '随机对照试验',
|
||
样本量: '300人',
|
||
统计方法: 't检验、卡方检验',
|
||
},
|
||
},
|
||
// ...
|
||
],
|
||
}
|
||
|
||
// 5. 前端:导出结果(Excel/CSV)
|
||
```
|
||
|
||
**关键特点:**
|
||
- ✅ 批量处理多个文档
|
||
- ✅ 并发控制(默认3个并发)
|
||
- ✅ 结构化信息提取
|
||
- ✅ 进度实时更新
|
||
- ✅ 支持自定义模板
|
||
- ✅ 结果可导出(Excel/CSV)
|
||
- ✅ 错误处理和重试
|
||
|
||
---
|
||
|
||
### 2.3 三种模式的对比
|
||
|
||
| 维度 | 全文阅读 | 逐篇精读 | 批处理 |
|
||
|------|---------|---------|--------|
|
||
| **文档数量** | 7篇左右 | 1-5篇 | 3-50篇 |
|
||
| **数据来源** | 完整全文 | RAG检索片段 | 完整全文 |
|
||
| **LLM调用** | 对话式(多轮) | 对话式(多轮) | 批量(单次) |
|
||
| **上下文** | ~750K tokens | ~15K tokens | 单篇全文 |
|
||
| **输出方式** | 流式(SSE) | 流式(SSE) | 批量保存 |
|
||
| **适用场景** | 综合分析、跨文献比较 | 深度理解单篇 | 信息提取、数据表格 |
|
||
| **用户交互** | 实时问答 | 实时问答 | 后台处理 |
|
||
| **对话历史** | 全局共享 | 每篇独立 | 无对话 |
|
||
|
||
---
|
||
|
||
## 📋 API端点完整清单
|
||
|
||
### PKB管理模块API
|
||
|
||
```
|
||
POST /api/v1/knowledge/create # 创建知识库
|
||
GET /api/v1/knowledge/list # 获取知识库列表
|
||
GET /api/v1/knowledge/:id # 获取知识库详情
|
||
PUT /api/v1/knowledge/:id # 更新知识库
|
||
DELETE /api/v1/knowledge/:id # 删除知识库
|
||
GET /api/v1/knowledge/:id/search # RAG检索
|
||
GET /api/v1/knowledge/:id/stats # 统计信息
|
||
GET /api/v1/knowledge/:id/document-selection # 文档选择(全文模式)
|
||
|
||
POST /api/v1/documents/upload # 上传文档
|
||
GET /api/v1/documents/:id # 获取文档详情
|
||
DELETE /api/v1/documents/:id # 删除文档
|
||
GET /api/v1/documents/:id/content # 获取文档内容(全文)
|
||
|
||
POST /api/v1/batch-tasks/create # 创建批处理任务
|
||
GET /api/v1/batch-tasks/list # 获取批处理任务列表
|
||
GET /api/v1/batch-tasks/:id # 获取任务详情
|
||
GET /api/v1/batch-tasks/:id/results # 获取任务结果
|
||
DELETE /api/v1/batch-tasks/:id # 删除任务
|
||
|
||
GET /api/v1/task-templates/list # 获取模板列表
|
||
POST /api/v1/task-templates/create # 创建模板
|
||
DELETE /api/v1/task-templates/:id # 删除模板
|
||
```
|
||
|
||
### AIA对话模块API(含PKB集成)
|
||
|
||
```
|
||
POST /api/v1/chat/send-message-stream # 发送消息(流式)
|
||
参数:
|
||
- content: string
|
||
- modelType: 'deepseek-v3' | 'qwen3-72b' | 'qwen-long'
|
||
- knowledgeBaseIds?: string[] # RAG模式
|
||
- documentIds?: string[] # 逐篇精读模式(限定文档)
|
||
- fullTextDocumentIds?: string[] # 全文阅读模式(传递全文)
|
||
- conversationId?: string
|
||
|
||
GET /api/v1/chat/conversations # 获取对话列表
|
||
GET /api/v1/chat/conversations/:id # 获取对话历史
|
||
DELETE /api/v1/chat/conversations/:id # 删除对话
|
||
```
|
||
|
||
---
|
||
|
||
## 🔗 模块间依赖关系
|
||
|
||
```
|
||
AIA智能问答模块
|
||
│
|
||
├─ 依赖 PKB知识库管理模块
|
||
│ ├─ 获取知识库列表(选择知识库)
|
||
│ ├─ 获取文档列表(选择文档)
|
||
│ ├─ 获取文档全文(全文阅读)
|
||
│ ├─ RAG检索(逐篇精读)
|
||
│ └─ 文档智能选择(全文阅读)
|
||
│
|
||
├─ 依赖 LLM网关
|
||
│ ├─ DeepSeek V3
|
||
│ ├─ Qwen3-72B
|
||
│ └─ Qwen-Long
|
||
│
|
||
└─ 依赖 Dify RAG引擎
|
||
└─ retrieveKnowledge API
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 迁移关键点
|
||
|
||
### 1. PKB模块迁移
|
||
```
|
||
✅ 简单:
|
||
- 数据库已在pkb_schema,无需迁移
|
||
- API端点清晰,易于复制
|
||
- 业务逻辑独立
|
||
|
||
⚠️ 注意:
|
||
- Dify集成需要保持
|
||
- OSS文件上传需要保持
|
||
- 配额管理需要保持
|
||
```
|
||
|
||
### 2. AIA模块中的PKB集成迁移
|
||
```
|
||
✅ 简单:
|
||
- 接口清晰(fullTextDocumentIds/documentIds)
|
||
- 三种模式逻辑独立
|
||
|
||
⚠️ 注意:
|
||
- chatController.ts需要同时迁移
|
||
- 前端3个模式组件需要迁移
|
||
- 对话历史管理需要保持
|
||
```
|
||
|
||
### 3. 测试要点
|
||
```
|
||
必须测试:
|
||
✅ PKB CRUD功能
|
||
✅ 文档上传和提取
|
||
✅ RAG检索功能
|
||
✅ 全文阅读模式(7篇文献)
|
||
✅ 逐篇精读模式(文档切换)
|
||
✅ 批处理模式(并发处理)
|
||
✅ 配额管理
|
||
✅ 对话历史管理
|
||
✅ 模型切换
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 阶段0完成标准
|
||
|
||
- [x] 深入理解PKB的两个部分
|
||
- [x] 列出所有API端点
|
||
- [x] 理解数据库Schema
|
||
- [x] 理解三种工作模式
|
||
- [x] 理解模块间依赖
|
||
- [ ] 创建测试用例清单
|
||
- [ ] 准备测试数据
|
||
|
||
---
|
||
|
||
## 📊 下一步:创建测试用例
|
||
|
||
即将创建详细的测试用例清单,覆盖所有功能点...
|
||
|
||
---
|
||
|
||
**审查状态:** 🟡 进行中(90%完成)
|
||
**下一步:** 创建测试用例清单和测试数据准备方案
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|