xinli/.kiro/specs/local-rag-knowledge-base/design.md
2025-12-19 14:03:43 +08:00

1275 lines
39 KiB
Markdown
Raw Permalink 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.

# Design Document
## Overview
本设计文档描述了基于Ollama本地大模型和ChromaDB向量数据库的RAG知识库系统。系统采用纯Java实现所有功能集成在Spring Boot应用中通过HTTP直接调用Ollama API。核心功能包括文档管理、向量检索、RAG增强生成和智能问答。系统支持监听指定文件夹自动加载文档部署时只需一个JAR包。
### 技术栈
- **后端框架**: Spring Boot 2.x
- **向量数据库**: ChromaDB (通过HTTP API调用)
- **嵌入模型**: nomic-embed-text (768维向量)
- **生成模型**: deepseek-r1:32b (32B参数)
- **文档解析**: Apache PDFBox (PDF), Apache POI (Word)
- **HTTP客户端**: OkHttp / RestTemplate
- **前端**: Vue.js (现有系统)
### 部署架构
```
[Vue.js前端]
↓ HTTP
[Spring Boot JAR包:8080]
├── 知识库管理模块
├── RAG检索模块
├── AI生成模块
└── 文件监听模块
↓ HTTP ↓ 文件系统
[Ollama:11434] [ChromaDB数据: D:\wwwroot\RAG\data\chroma_db]
[文档文件: D:\wwwroot\RAG\uploads]
```
## Architecture
### 系统分层架构
```
┌─────────────────────────────────────────────────────────────┐
│ Presentation Layer │
│ - Vue.js前端界面 │
│ - 知识库管理页面 │
│ - 报告展示页面 │
│ - 智能问答界面 │
└──────────────────────┬──────────────────────────────────────┘
│ REST API
┌──────────────────────▼──────────────────────────────────────┐
│ Spring Boot Application Layer │
│ Controllers: │
│ - PsyKnowledgeController (知识库管理) │
│ - PsyAIAnalysisController (AI分析) │
│ - PsyAIChatController (智能问答) │
└──────────────────────┬──────────────────────────────────────┘
┌──────────────────────▼──────────────────────────────────────┐
│ Service Layer │
│ - KnowledgeService (文档管理) │
│ - EmbeddingService (向量化) │
│ - RetrievalService (RAG检索) │
│ - GenerationService (AI生成) │
│ - OllamaClient (Ollama API调用) │
│ - ChromaDBClient (ChromaDB HTTP API调用) │
│ - FileWatcherService (文件夹监听) │
└──────────────────────┬──────────────────────────────────────┘
┌──────────────────────▼──────────────────────────────────────┐
│ Utility Layer │
│ - DocumentParser (文档解析: PDF, Word, TXT) │
│ - TextSplitter (文本分块) │
│ - PromptBuilder (提示词构建) │
│ - VectorUtils (向量计算工具) │
└──────────────┬────────────────────┬─────────────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ Ollama API │ │ ChromaDB │
│ (Port 11434) │ │ HTTP API │
│ - embed │ │ (Port 8000) │
│ - generate │ │ │
└──────────────────┘ └──────────────────┘
│ │
▼ ▼
┌──────────────────────────────────────┐
│ File System │
│ D:\wwwroot\RAG\ │
│ ├── data\chroma_db\ (向量数据) │
│ ├── uploads\ (文档文件) │
│ └── logs\ (日志文件) │
└──────────────────────────────────────┘
```
### 数据流
#### 文档上传流程
```
用户上传文档 → Spring Boot Controller接收
→ DocumentParser解析文档 → TextSplitter分块
→ OllamaClient调用nomic-embed-text向量化
→ ChromaDBClient存储向量 → 保存原文件到uploads目录
→ 返回成功响应
```
#### 文件夹自动加载流程
```
管理员放置文档到 D:\wwwroot\RAG\uploads
→ FileWatcherService检测到新文件
→ 自动触发文档解析流程 → 分块 → 向量化 → 存储
→ 记录处理日志
```
#### RAG报告生成流程
```
用户请求报告 → Spring Boot Controller接收
→ GenerationService构建查询(测评数据+用户档案)
→ EmbeddingService向量化查询
→ RetrievalService从ChromaDB语义检索(Top-5)
→ 过滤低相似度结果(threshold=0.7)
→ PromptBuilder构建提示词(检索知识+用户数据)
→ OllamaClient调用deepseek-r1生成报告
→ 存储报告到MySQL → 返回报告+引用来源
→ 前端展示报告
```
#### 智能问答流程
```
用户提问 → Spring Boot Controller接收
→ EmbeddingService向量化问题
→ RetrievalService从ChromaDB语义检索
→ PromptBuilder构建提示词
→ OllamaClient调用deepseek-r1生成回答
→ 返回回答+引用来源 → 前端展示
```
## Components and Interfaces
### 1. Service Layer (Spring Boot Services)
#### 1.1 KnowledgeService (知识库管理服务)
**职责**: 管理文档的上传、存储、检索和删除
**接口**:
```java
@Service
public class KnowledgeService {
/**
* 上传并处理文档
* @param file 上传的文件
* @param category 文档分类
* @param metadata 元数据
* @return 文档信息
*/
public DocumentInfo uploadDocument(MultipartFile file, String category, Map<String, Object> metadata);
/**
* 获取文档列表
* @param category 分类过滤(可选)
* @param page 页码
* @param size 每页大小
* @return 文档列表
*/
public PageResult<DocumentInfo> listDocuments(String category, int page, int size);
/**
* 获取文档详情
* @param docId 文档ID
* @return 文档详情
*/
public DocumentInfo getDocument(String docId);
/**
* 删除文档
* @param docId 文档ID
* @return 是否成功
*/
public boolean deleteDocument(String docId);
/**
* 搜索文档
* @param keyword 关键词
* @return 文档列表
*/
public List<DocumentInfo> searchDocuments(String keyword);
/**
* 重建索引
* @return 重建结果
*/
public RebuildResult rebuildIndex();
}
```
#### 1.2 EmbeddingService (向量化服务)
**职责**: 使用nomic-embed-text模型生成文本向量
**接口**:
```java
@Service
public class EmbeddingService {
private final OllamaClient ollamaClient;
private static final String MODEL_NAME = "nomic-embed-text";
/**
* 将单个文本转换为768维向量
* @param text 文本内容
* @return 768维向量数组
*/
public float[] embedText(String text);
/**
* 批量向量化
* @param texts 文本列表
* @return 向量列表
*/
public List<float[]> embedBatch(List<String> texts);
}
```
#### 1.3 RetrievalService (RAG检索服务)
**职责**: 从ChromaDB检索相关文档片段
**接口**:
```java
@Service
public class RetrievalService {
private final ChromaDBClient chromaDBClient;
private final EmbeddingService embeddingService;
private static final String COLLECTION_NAME = "psychology_knowledge";
/**
* 语义检索相关文档
* @param query 查询文本
* @param topK 返回结果数量
* @param threshold 相似度阈值
* @return 检索结果列表
*/
public List<RetrievalResult> retrieve(String query, int topK, double threshold);
/**
* 带分类过滤的检索
* @param query 查询文本
* @param category 分类
* @param topK 返回结果数量
* @return 检索结果列表
*/
public List<RetrievalResult> retrieveWithFilter(String query, String category, int topK);
}
```
#### 1.4 GenerationService (AI生成服务)
**职责**: 调用deepseek-r1模型生成报告和回答
**接口**:
```java
@Service
public class GenerationService {
private final OllamaClient ollamaClient;
private final RetrievalService retrievalService;
private static final String MODEL_NAME = "deepseek-r1:32b";
/**
* 生成综合分析报告
* @param assessmentData 测评数据
* @param userProfile 用户档案
* @return 生成结果(报告内容+来源引用)
*/
public GenerationResult generateReport(Map<String, Object> assessmentData, Map<String, Object> userProfile);
/**
* 回答问题
* @param question 问题
* @param context 上下文(可选)
* @return 生成结果(回答+来源引用)
*/
public GenerationResult answerQuestion(String question, String context);
/**
* 生成矫治建议
* @param userProfile 用户档案
* @param assessmentData 测评数据
* @return 生成结果(建议+来源引用)
*/
public GenerationResult generateSuggestions(Map<String, Object> userProfile, Map<String, Object> assessmentData);
}
```
#### 1.5 OllamaClient (Ollama API客户端)
**职责**: 封装Ollama HTTP API调用
**接口**:
```java
@Component
public class OllamaClient {
private final RestTemplate restTemplate;
private final String baseUrl = "http://localhost:11434";
/**
* 调用嵌入API
* @param model 模型名称
* @param text 文本内容
* @return 向量数组
*/
public float[] embed(String model, String text);
/**
* 调用生成API
* @param model 模型名称
* @param prompt 提示词
* @param options 生成选项
* @return 生成的文本
*/
public String generate(String model, String prompt, Map<String, Object> options);
/**
* 获取可用模型列表
* @return 模型列表
*/
public List<ModelInfo> listModels();
/**
* 检查连接状态
* @return 是否连接成功
*/
public boolean checkConnection();
}
```
#### 1.6 ChromaDBClient (ChromaDB HTTP API客户端)
**职责**: 封装ChromaDB HTTP API调用
**接口**:
```java
@Component
public class ChromaDBClient {
private final RestTemplate restTemplate;
private final String baseUrl = "http://localhost:8000";
/**
* 添加文档向量
* @param collectionName 集合名称
* @param documents 文档列表
* @param embeddings 向量列表
* @param metadatas 元数据列表
* @param ids ID列表
*/
public void addDocuments(String collectionName, List<String> documents,
List<float[]> embeddings, List<Map<String, Object>> metadatas, List<String> ids);
/**
* 查询相似文档
* @param collectionName 集合名称
* @param queryEmbedding 查询向量
* @param topK 返回数量
* @param filter 过滤条件
* @return 查询结果
*/
public QueryResult query(String collectionName, float[] queryEmbedding, int topK, Map<String, Object> filter);
/**
* 删除文档
* @param collectionName 集合名称
* @param ids ID列表
*/
public void deleteDocuments(String collectionName, List<String> ids);
/**
* 获取集合信息
* @param collectionName 集合名称
* @return 集合信息
*/
public CollectionInfo getCollection(String collectionName);
}
```
#### 1.7 FileWatcherService (文件夹监听服务)
**职责**: 监听uploads文件夹自动处理新文档
**接口**:
```java
@Service
public class FileWatcherService {
private final KnowledgeService knowledgeService;
private final String watchPath = "D:\\wwwroot\\RAG\\uploads";
/**
* 启动文件监听
*/
@PostConstruct
public void startWatching();
/**
* 处理新文件
* @param file 新文件
*/
private void processNewFile(File file);
/**
* 停止文件监听
*/
@PreDestroy
public void stopWatching();
}
```
### 2. Utility Components
#### 2.1 DocumentParser (文档解析器)
**职责**: 解析不同格式的文档
**接口**:
```java
@Component
public class DocumentParser {
/**
* 解析PDF文档
* @param filePath 文件路径
* @return 文本内容
*/
public String parsePdf(String filePath);
/**
* 解析Word文档
* @param filePath 文件路径
* @return 文本内容
*/
public String parseDocx(String filePath);
/**
* 解析TXT文档
* @param filePath 文件路径
* @return 文本内容
*/
public String parseTxt(String filePath);
/**
* 自动识别格式并解析
* @param filePath 文件路径
* @return 文本内容
*/
public String parse(String filePath);
}
```
#### 2.2 TextSplitter (文本分块器)
**职责**: 将长文本分割成适合向量化的块
**接口**:
```java
@Component
public class TextSplitter {
private int chunkSize = 800;
private int chunkOverlap = 200;
/**
* 按字符数分块
* @param text 文本内容
* @return 文本块列表
*/
public List<String> split(String text);
/**
* 按句子分块(保持语义完整)
* @param text 文本内容
* @return 文本块列表
*/
public List<String> splitBySentences(String text);
}
```
#### 2.3 PromptBuilder (提示词构建器)
**职责**: 构建发送给大模型的提示词
**接口**:
```java
@Component
public class PromptBuilder {
/**
* 构建报告生成提示词
* @param retrievedDocs 检索到的文档
* @param assessmentData 测评数据
* @param userProfile 用户档案
* @return 提示词
*/
public String buildReportPrompt(List<RetrievalResult> retrievedDocs,
Map<String, Object> assessmentData,
Map<String, Object> userProfile);
/**
* 构建问答提示词
* @param question 问题
* @param retrievedDocs 检索到的文档
* @return 提示词
*/
public String buildQAPrompt(String question, List<RetrievalResult> retrievedDocs);
/**
* 构建建议生成提示词
* @param userProfile 用户档案
* @param assessmentData 测评数据
* @param retrievedDocs 检索到的文档
* @return 提示词
*/
public String buildSuggestionPrompt(Map<String, Object> userProfile,
Map<String, Object> assessmentData,
List<RetrievalResult> retrievedDocs);
}
```
### 3. Controller Layer
#### 3.1 PsyKnowledgeController (知识库管理控制器)
**职责**: 提供知识库管理的REST API
**接口**:
```java
@RestController
@RequestMapping("/psychology/knowledge")
public class PsyKnowledgeController {
@PostMapping("/upload")
public AjaxResult uploadDocument(@RequestParam("file") MultipartFile file,
@RequestParam("category") String category);
@GetMapping("/list")
public TableDataInfo listDocuments(@RequestParam(required = false) String category,
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize);
@GetMapping("/{id}")
public AjaxResult getDocument(@PathVariable String id);
@DeleteMapping("/{id}")
public AjaxResult deleteDocument(@PathVariable String id);
@PostMapping("/search")
public AjaxResult searchDocuments(@RequestParam String keyword);
@PostMapping("/rebuild")
public AjaxResult rebuildIndex();
}
```
#### 3.2 PsyAIAnalysisController (AI分析控制器)
**职责**: 提供AI分析功能的REST API
**接口**:
```java
@RestController
@RequestMapping("/psychology/ai")
public class PsyAIAnalysisController {
@PostMapping("/generate-report")
public AjaxResult generateReport(@RequestBody AIReportRequest request);
@PostMapping("/chat")
public AjaxResult chat(@RequestBody AIChatRequest request);
@GetMapping("/system/status")
public AjaxResult getSystemStatus();
}
```
## Data Models
### 1. ChromaDB Collection Schema
ChromaDB通过HTTP API访问数据格式如下
```json
// Collection: psychology_knowledge
{
"name": "psychology_knowledge",
"metadata": {
"description": "监狱心理学知识库",
"embedding_model": "nomic-embed-text",
"dimension": 768
}
}
// Document Schema
{
"id": "doc_uuid_chunk_index",
"document": "文档内容文本...",
"embedding": [0.1, 0.2, ...],
"metadata": {
"doc_id": "doc_uuid",
"filename": "心理学教材.pdf",
"category": "人格心理学",
"chunk_index": 0,
"total_chunks": 10,
"upload_time": "2025-01-01 10:00:00",
"file_size": 1024000,
"page_number": 1
}
}
```
### 2. Java Domain Models
#### 2.1 文档信息
```java
public class DocumentInfo {
private String docId; // 文档唯一ID
private String filename; // 文件名
private String category; // 分类
private Integer totalChunks; // 总分块数
private Long fileSize; // 文件大小(字节)
private Date uploadTime; // 上传时间
private Map<String, Object> metadata; // 其他元数据
// getters and setters
}
```
#### 2.2 检索结果
```java
public class RetrievalResult {
private String docId; // 文档ID
private String filename; // 文件名
private Integer chunkIndex; // 分块索引
private Double similarity; // 相似度分数
private String content; // 文档片段内容
private Map<String, Object> metadata; // 元数据
// getters and setters
}
```
#### 2.3 生成结果
```java
public class GenerationResult {
private String content; // 生成的内容(报告/回答)
private List<SourceReference> sources; // 来源引用
private Double generationTime; // 生成耗时(秒)
// getters and setters
}
public class SourceReference {
private String docId; // 文档ID
private String filename; // 文件名
private Integer chunkIndex; // 分块索引
private Double similarity; // 相似度
private String content; // 引用片段
// getters and setters
}
```
#### 2.4 AI报告请求
```java
public class AIReportRequest {
private Map<String, Object> assessmentData; // 测评数据
private Map<String, Object> userProfile; // 用户档案
// getters and setters
}
```
#### 2.5 AI问答请求
```java
public class AIChatRequest {
private String question; // 问题
private String context; // 上下文(可选)
// getters and setters
}
```
#### 2.6 系统状态响应
```java
public class SystemStatusResponse {
private Boolean ollamaConnected; // Ollama连接状态
private Boolean chromaDBConnected; // ChromaDB连接状态
private List<String> availableModels; // 可用模型列表
private KnowledgeStats knowledgeStats; // 知识库统计
// getters and setters
}
public class KnowledgeStats {
private Integer totalDocuments; // 文档总数
private Integer totalChunks; // 向量总数
private Long storageSize; // 存储空间(字节)
// getters and setters
}
```
#### 2.7 重建结果
```java
public class RebuildResult {
private Boolean success; // 是否成功
private String message; // 消息
private Integer processedFiles; // 处理的文件数
private Integer totalChunks; // 生成的向量数
private Double elapsedTime; // 耗时(秒)
// getters and setters
}
```
### 3. Ollama API Models
#### 3.1 嵌入请求
```java
public class OllamaEmbedRequest {
private String model; // 模型名称
private String prompt; // 文本内容
// getters and setters
}
```
#### 3.2 嵌入响应
```java
public class OllamaEmbedResponse {
private float[] embedding; // 向量数组
// getters and setters
}
```
#### 3.3 生成请求
```java
public class OllamaGenerateRequest {
private String model; // 模型名称
private String prompt; // 提示词
private Boolean stream; // 是否流式输出
private Map<String, Object> options; // 生成选项
// getters and setters
}
```
#### 3.4 生成响应
```java
public class OllamaGenerateResponse {
private String response; // 生成的文本
private Boolean done; // 是否完成
// getters and setters
}
```
### 4. ChromaDB API Models
#### 4.1 添加文档请求
```java
public class ChromaAddRequest {
private List<String> ids; // ID列表
private List<String> documents; // 文档列表
private List<float[]> embeddings; // 向量列表
private List<Map<String, Object>> metadatas; // 元数据列表
// getters and setters
}
```
#### 4.2 查询请求
```java
public class ChromaQueryRequest {
private float[] queryEmbeddings; // 查询向量
private Integer nResults; // 返回数量
private Map<String, Object> where; // 过滤条件
// getters and setters
}
```
#### 4.3 查询响应
```java
public class ChromaQueryResponse {
private List<String> ids; // ID列表
private List<String> documents; // 文档列表
private List<Double> distances; // 距离列表
private List<Map<String, Object>> metadatas; // 元数据列表
// getters and setters
}
```
## Data Models
### ChromaDB存储路径
```
D:\wwwroot\RAG\
├── data\
│ └── chroma_db\ # ChromaDB数据目录
│ ├── chroma.sqlite3 # 元数据数据库
│ └── [向量数据文件]
├── uploads\ # 上传文件临时存储
│ └── [原始文档文件]
└── logs\ # 日志文件
└── ai_service.log
```
## Correctness Properties
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
### Property Reflection
在编写具体属性之前,我们需要识别并消除冗余的属性:
**识别的冗余情况**:
1. 属性3.1和4.1都测试向量维度为768可以合并为一个通用的"向量化输出维度"属性
2. 属性3.2和4.2都测试Top-K检索返回不超过5个结果可以合并
3. 属性3.6和4.5都测试返回格式包含内容和来源,可以合并为通用的"响应格式完整性"属性
4. 属性1.1、1.2、1.3都测试文档解析,可以合并为一个"文档解析正确性"属性
5. 属性1.6和8.5都测试数据持久化,可以合并为"数据持久化round-trip"属性
**合并后的核心属性集**:
- 文档处理: 解析、分块、向量化、存储
- 检索功能: Top-K检索、相似度过滤、分类过滤
- 生成功能: 报告生成、问答、响应格式
- 管理功能: CRUD操作、索引重建
- 系统功能: 错误处理、状态查询、数据持久化
### Core Properties
**Property 1: 文档解析正确性**
*For any* 支持格式的文档PDF、Word、TXT解析后提取的文本内容应该与文档中的实际文本内容一致
**Validates: Requirements 1.1, 1.2, 1.3**
**Property 2: 文档分块大小约束**
*For any* 文档分块后除最后一块外每个块的字符数应该在500到1000之间
**Validates: Requirements 1.4**
**Property 3: 向量维度一致性**
*For any* 文本输入文档块、查询、问题使用nomic-embed-text生成的向量维度应该恰好为768
**Validates: Requirements 1.5, 3.1, 4.1**
**Property 4: 数据持久化round-trip**
*For any* 文档及其向量和元数据存储到ChromaDB后应该能检索到完全相同的数据AI服务重启后数据应该保持完整
**Validates: Requirements 1.6, 8.5**
**Property 5: 上传失败状态不变性**
*For any* 导致上传失败的无效输入系统应该返回错误信息且ChromaDB中的文档数量保持不变
**Validates: Requirements 1.7**
**Property 6: 文档列表完整性**
*For any* 知识库状态上传N个新文档后文档列表的长度应该增加N
**Validates: Requirements 2.1**
**Property 7: 文档删除有效性**
*For any* 已存在的文档删除后该文档ID不应该出现在文档列表中且无法通过该ID检索到文档详情
**Validates: Requirements 2.3**
**Property 8: 分类过滤正确性**
*For any* 分类查询返回的所有文档的category字段都应该等于查询的分类值
**Validates: Requirements 2.4**
**Property 9: 文件名搜索匹配性**
*For any* 搜索关键词,返回的所有文档的文件名都应该包含该关键词(不区分大小写)
**Validates: Requirements 2.5**
**Property 10: Top-K检索数量约束**
*For any* 查询向量从ChromaDB检索时返回的结果数量应该不超过指定的top_k值默认5
**Validates: Requirements 3.2, 4.2**
**Property 11: 相似度阈值过滤**
*For any* 检索结果所有返回的文档片段的相似度分数都应该大于或等于0.7
**Validates: Requirements 3.3**
**Property 12: 上下文包含必要信息**
*For any* 报告生成请求,构建的上下文字符串应该同时包含检索到的知识片段、测评数据和用户档案信息
**Validates: Requirements 3.4**
**Property 13: 生成响应非空性**
*For any* 有效的上下文输入AI模型生成的报告或回答内容应该是非空字符串
**Validates: Requirements 3.5, 4.4**
**Property 14: 响应格式完整性**
*For any* 成功的生成请求(报告或问答),响应应该同时包含生成的内容字段和来源引用列表字段
**Validates: Requirements 3.6, 4.5**
**Property 15: 错误响应包含信息**
*For any* 导致失败的请求,响应应该包含非空的错误消息字段
**Validates: Requirements 3.7**
**Property 16: 提示词包含查询和知识**
*For any* 问答请求,构建的提示词应该同时包含用户问题和检索到的知识片段
**Validates: Requirements 4.3**
**Property 17: 系统状态响应完整性**
*For any* 系统状态查询响应应该包含Ollama连接状态、ChromaDB状态和可用模型列表这三个字段
**Validates: Requirements 5.1**
**Property 18: 连接测试返回明确状态**
*For any* Ollama连接测试响应应该明确指示连接成功或失败布尔值或状态码
**Validates: Requirements 5.2**
**Property 19: 统计数据准确性**
*For any* 知识库状态,统计查询返回的文档总数应该等于文档列表的长度
**Validates: Requirements 5.3**
**Property 20: 错误日志记录完整性**
*For any* 捕获的异常,日志文件应该包含该异常的时间戳和堆栈跟踪信息
**Validates: Requirements 5.4**
**Property 21: HTTP请求包含必要数据**
*For any* Spring Boot发起的报告生成请求HTTP请求体应该包含assessmentData和userProfile字段
**Validates: Requirements 6.1**
**Property 22: 报告持久化round-trip**
*For any* AI服务返回的报告存储到MySQL后应该能通过报告ID查询到相同的报告内容
**Validates: Requirements 6.2**
**Property 23: 错误处理日志记录**
*For any* AI服务返回的错误响应Spring Boot应该在日志中记录该错误
**Validates: Requirements 6.4**
**Property 24: 问答请求包含问题**
*For any* Spring Boot发起的问答请求HTTP请求体应该包含question字段
**Validates: Requirements 6.5**
**Property 25: API响应JSON格式有效性**
*For any* AI服务的HTTP响应响应体应该是有效的JSON格式
**Validates: Requirements 8.2**
**Property 26: 本地存储路径正确性**
*For any* 向量存储操作数据文件应该出现在配置的ChromaDB目录路径D:\wwwroot\RAG\data\chroma_db
**Validates: Requirements 9.3**
**Property 27: 文件本地存储验证**
*For any* 上传的文档原始文件应该存在于本地uploads目录中
**Validates: Requirements 9.5**
**Property 28: 索引重建后数据一致性**
*For any* 重建索引操作重建完成后ChromaDB中的文档数量应该等于uploads目录中的文档文件数量
**Validates: Requirements 10.1, 10.2, 10.3**
**Property 29: 重建进度范围有效性**
*For any* 重建过程中的进度查询返回的进度值应该在0到100之间包含边界
**Validates: Requirements 10.4**
**Property 30: 重建完成响应完整性**
*For any* 成功完成的重建操作,响应应该包含成功状态标志和统计信息(文档数、向量数)
**Validates: Requirements 10.5**
## Error Handling
### 错误分类
1. **输入验证错误**
- 无效文件格式
- 文件大小超限
- 缺少必需参数
- 响应: HTTP 400, 明确的错误消息
2. **资源不存在错误**
- 文档ID不存在
- 分类不存在
- 响应: HTTP 404, 资源标识信息
3. **外部服务错误**
- Ollama API不可用
- ChromaDB连接失败
- 响应: HTTP 503, 服务名称和错误详情
4. **处理超时错误**
- 文档解析超时
- AI生成超时
- 响应: HTTP 504, 超时操作描述
5. **系统内部错误**
- 未预期的异常
- 文件系统错误
- 响应: HTTP 500, 通用错误消息(不暴露内部细节)
### 错误处理策略
```python
# 统一错误响应格式
{
"code": 400, # HTTP状态码
"message": "文件格式不支持", # 用户友好消息
"error_type": "INVALID_FILE_FORMAT", # 错误类型代码
"details": { # 可选的详细信息
"supported_formats": ["pdf", "docx", "txt"]
},
"timestamp": "2025-01-01T10:00:00Z"
}
```
### 日志记录
- **INFO级别**: 正常操作(文档上传、报告生成)
- **WARNING级别**: 可恢复错误(相似度过滤、重试成功)
- **ERROR级别**: 需要关注的错误API调用失败、数据损坏
- **CRITICAL级别**: 系统级故障ChromaDB不可用、Ollama崩溃
日志格式:
```
[2025-01-01 10:00:00] [ERROR] [knowledge_service.py:123] 文档上传失败: doc_id=abc123, error=FileNotFoundError
Traceback: ...
```
## Testing Strategy
### 单元测试 (Unit Tests)
使用pytest框架测试各个组件的独立功能
**测试范围**:
- DocumentParser: 测试各种格式文档的解析
- TextSplitter: 测试分块算法的边界情况
- EmbeddingService: 测试向量化API调用使用mock
- RetrievalService: 测试检索逻辑使用内存ChromaDB
- PromptBuilder: 测试提示词模板构建
**示例测试**:
```python
def test_text_splitter_chunk_size():
"""测试分块大小约束"""
splitter = TextSplitter(chunk_size=800, chunk_overlap=200)
text = "a" * 5000
chunks = splitter.split(text)
for i, chunk in enumerate(chunks[:-1]): # 除最后一块
assert 500 <= len(chunk) <= 1000
```
### 属性测试 (Property-Based Tests)
使用Hypothesis库进行属性测试验证correctness properties
**配置**: 每个属性测试运行至少100次迭代
**测试库**: Hypothesis (Python)
**示例属性测试**:
```python
from hypothesis import given, strategies as st
@given(st.text(min_size=1000, max_size=10000))
def test_property_2_chunk_size_constraint(text):
"""
Feature: local-rag-knowledge-base, Property 2: 文档分块大小约束
"""
splitter = TextSplitter(chunk_size=800, chunk_overlap=200)
chunks = splitter.split(text)
# 除最后一块外每块应在500-1000字符之间
for chunk in chunks[:-1]:
assert 500 <= len(chunk) <= 1000
@given(st.text(min_size=10, max_size=1000))
def test_property_3_vector_dimension(text):
"""
Feature: local-rag-knowledge-base, Property 3: 向量维度一致性
"""
embedding_service = EmbeddingService()
vector = embedding_service.embed_text(text)
assert len(vector) == 768
```
### 集成测试 (Integration Tests)
测试组件之间的交互:
**测试场景**:
1. 完整的文档上传流程(解析→分块→向量化→存储)
2. 端到端的报告生成流程(查询→检索→生成→返回)
3. Spring Boot与Flask AI服务的HTTP通信
4. ChromaDB数据持久化和恢复
**测试环境**:
- 使用测试专用的ChromaDB实例
- 使用本地Ollama服务需要预先启动
- 使用测试数据库MySQL
### 测试数据
**文档测试数据**:
- 准备10-20个心理学相关的测试文档PDF、Word、TXT
- 包含不同长度1页、10页、100页
- 包含特殊字符、多语言内容
**测评数据测试数据**:
- 模拟MMPI、SCL-90等量表的答题数据
- 包含边界情况全选A、随机选择
### 性能测试
**基准指标**:
- 文档上传处理时间: <5秒/MB
- 向量检索时间: <1秒
- 报告生成时间: <30秒
- 并发请求支持: 10个并发用户
**测试工具**: pytest-benchmark, locust
### 测试覆盖率目标
- 代码覆盖率: >80%
- 属性覆盖率: 100%所有correctness properties都有对应测试
- API覆盖率: 100%所有API端点都有测试
## Deployment Considerations
### 环境要求
**硬件要求**:
- CPU: 8核以上推荐16核
- 内存: 32GB以上deepseek-r1:32b需要约20GB
- 存储: 100GB以上模型+知识库+日志)
- GPU: 可选,可加速推理
**软件要求**:
- Java 8+ (JDK)
- Ollama (已安装nomic-embed-text和deepseek-r1:32b)
- ChromaDB (通过Docker或直接安装)
- MySQL 5.7+
### 部署步骤
1. **创建目录结构**
```cmd
mkdir D:\wwwroot\RAG\data\chroma_db
mkdir D:\wwwroot\RAG\uploads
mkdir D:\wwwroot\RAG\logs
```
2. **启动Ollama服务**
```cmd
ollama serve
```
3. **启动ChromaDB服务**
```cmd
# 方式1: 使用Docker
docker run -p 8000:8000 chromadb/chroma
# 方式2: 使用Python安装
pip install chromadb
chroma run --path D:\wwwroot\RAG\data\chroma_db --port 8000
```
4. **配置Spring Boot**
```yaml
# application.yml
rag:
ollama:
url: http://localhost:11434
embed-model: nomic-embed-text
generate-model: deepseek-r1:32b
chromadb:
url: http://localhost:8000
collection: psychology_knowledge
storage:
upload-path: D:/wwwroot/RAG/uploads
log-path: D:/wwwroot/RAG/logs
file-watcher:
enabled: true
watch-path: D:/wwwroot/RAG/uploads
```
5. **打包Spring Boot应用**
```cmd
mvn clean package -DskipTests
```
6. **启动Spring Boot应用**
```cmd
java -jar ry-xinli-admin/target/xinli-admin.jar
```
### 一键部署方案
**部署包结构**:
```
xinli-rag-deploy/
├── xinli-admin.jar # Spring Boot应用
├── start.bat # 启动脚本
├── stop.bat # 停止脚本
├── config/
│ └── application.yml # 配置文件
├── data/ # 数据目录(自动创建)
├── uploads/ # 文档上传目录(自动创建)
└── logs/ # 日志目录(自动创建)
```
**start.bat 内容**:
```batch
@echo off
echo 正在启动心理评估系统...
REM 检查Ollama是否运行
curl -s http://localhost:11434/api/tags >nul 2>&1
if errorlevel 1 (
echo [错误] Ollama服务未启动请先启动Ollama
pause
exit /b 1
)
REM 检查ChromaDB是否运行
curl -s http://localhost:8000/api/v1/heartbeat >nul 2>&1
if errorlevel 1 (
echo [警告] ChromaDB服务未启动正在启动...
start /b chroma run --path D:\wwwroot\RAG\data\chroma_db --port 8000
timeout /t 5
)
REM 启动Spring Boot应用
echo 正在启动Spring Boot应用...
java -jar xinli-admin.jar
pause
```
### 监控和维护
**监控指标**:
- Spring Boot健康状态/actuator/health
- Ollama API响应时间
- ChromaDB存储空间使用率
- 请求成功率和错误率
- 文件监听服务状态
**日志管理**:
- 使用Logback按天切分日志
- 保留最近30天的日志
- 自动压缩归档旧日志
- 日志级别可配置INFO/DEBUG/ERROR
**备份策略**:
- 每天自动备份ChromaDB数据目录
- 每周备份uploads目录
- 保留最近7天的备份
- 支持手动触发备份
### 安全考虑
1. **访问控制**:
- Spring Security权限控制
- 知识库管理需要管理员权限
- API接口需要登录认证
2. **文件验证**:
- 上传文件格式白名单PDF、Word、TXT
- 文件大小限制默认50MB
- 文件内容安全扫描
3. **输入清理**:
- 防止SQL注入
- 防止XSS攻击
- 参数验证和清理
4. **日志脱敏**:
- 日志中不记录敏感个人信息
- 自动脱敏身份证号、手机号等
5. **数据安全**:
- 所有数据本地存储
- 不依赖外网服务
- 可选文档加密存储
## Future Enhancements
1. **知识库版本管理**: 支持文档的版本控制和回滚
2. **多模型支持**: 支持切换不同的嵌入模型和生成模型
3. **增量更新**: 支持文档的增量更新而非完全重新处理
4. **缓存机制**: 缓存常见查询的检索结果
5. **批量处理**: 支持批量上传和处理文档
6. **知识图谱**: 构建心理学概念的知识图谱
7. **多语言支持**: 支持英文等其他语言的文档
8. **细粒度权限**: 不同用户角色访问不同的知识库分类