39 KiB
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 (知识库管理服务)
职责: 管理文档的上传、存储、检索和删除
接口:
@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模型生成文本向量
接口:
@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检索相关文档片段
接口:
@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模型生成报告和回答
接口:
@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调用
接口:
@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调用
接口:
@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文件夹,自动处理新文档
接口:
@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 (文档解析器)
职责: 解析不同格式的文档
接口:
@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 (文本分块器)
职责: 将长文本分割成适合向量化的块
接口:
@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 (提示词构建器)
职责: 构建发送给大模型的提示词
接口:
@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
接口:
@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
接口:
@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访问,数据格式如下:
// 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 文档信息
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 检索结果
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 生成结果
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报告请求
public class AIReportRequest {
private Map<String, Object> assessmentData; // 测评数据
private Map<String, Object> userProfile; // 用户档案
// getters and setters
}
2.5 AI问答请求
public class AIChatRequest {
private String question; // 问题
private String context; // 上下文(可选)
// getters and setters
}
2.6 系统状态响应
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 重建结果
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 嵌入请求
public class OllamaEmbedRequest {
private String model; // 模型名称
private String prompt; // 文本内容
// getters and setters
}
3.2 嵌入响应
public class OllamaEmbedResponse {
private float[] embedding; // 向量数组
// getters and setters
}
3.3 生成请求
public class OllamaGenerateRequest {
private String model; // 模型名称
private String prompt; // 提示词
private Boolean stream; // 是否流式输出
private Map<String, Object> options; // 生成选项
// getters and setters
}
3.4 生成响应
public class OllamaGenerateResponse {
private String response; // 生成的文本
private Boolean done; // 是否完成
// getters and setters
}
4. ChromaDB API Models
4.1 添加文档请求
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 查询请求
public class ChromaQueryRequest {
private float[] queryEmbeddings; // 查询向量
private Integer nResults; // 返回数量
private Map<String, Object> where; // 过滤条件
// getters and setters
}
4.3 查询响应
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
在编写具体属性之前,我们需要识别并消除冗余的属性:
识别的冗余情况:
- 属性3.1和4.1都测试向量维度为768,可以合并为一个通用的"向量化输出维度"属性
- 属性3.2和4.2都测试Top-K检索返回不超过5个结果,可以合并
- 属性3.6和4.5都测试返回格式包含内容和来源,可以合并为通用的"响应格式完整性"属性
- 属性1.1、1.2、1.3都测试文档解析,可以合并为一个"文档解析正确性"属性
- 属性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
错误分类
-
输入验证错误
- 无效文件格式
- 文件大小超限
- 缺少必需参数
- 响应: HTTP 400, 明确的错误消息
-
资源不存在错误
- 文档ID不存在
- 分类不存在
- 响应: HTTP 404, 资源标识信息
-
外部服务错误
- Ollama API不可用
- ChromaDB连接失败
- 响应: HTTP 503, 服务名称和错误详情
-
处理超时错误
- 文档解析超时
- AI生成超时
- 响应: HTTP 504, 超时操作描述
-
系统内部错误
- 未预期的异常
- 文件系统错误
- 响应: HTTP 500, 通用错误消息(不暴露内部细节)
错误处理策略
# 统一错误响应格式
{
"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: 测试提示词模板构建
示例测试:
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)
示例属性测试:
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)
测试组件之间的交互:
测试场景:
- 完整的文档上传流程(解析→分块→向量化→存储)
- 端到端的报告生成流程(查询→检索→生成→返回)
- Spring Boot与Flask AI服务的HTTP通信
- 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+
部署步骤
- 创建目录结构
mkdir D:\wwwroot\RAG\data\chroma_db
mkdir D:\wwwroot\RAG\uploads
mkdir D:\wwwroot\RAG\logs
- 启动Ollama服务
ollama serve
- 启动ChromaDB服务
# 方式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
- 配置Spring Boot
# 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
- 打包Spring Boot应用
mvn clean package -DskipTests
- 启动Spring Boot应用
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 内容:
@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天的备份
- 支持手动触发备份
安全考虑
-
访问控制:
- Spring Security权限控制
- 知识库管理需要管理员权限
- API接口需要登录认证
-
文件验证:
- 上传文件格式白名单(PDF、Word、TXT)
- 文件大小限制(默认50MB)
- 文件内容安全扫描
-
输入清理:
- 防止SQL注入
- 防止XSS攻击
- 参数验证和清理
-
日志脱敏:
- 日志中不记录敏感个人信息
- 自动脱敏身份证号、手机号等
-
数据安全:
- 所有数据本地存储
- 不依赖外网服务
- 可选文档加密存储
Future Enhancements
- 知识库版本管理: 支持文档的版本控制和回滚
- 多模型支持: 支持切换不同的嵌入模型和生成模型
- 增量更新: 支持文档的增量更新而非完全重新处理
- 缓存机制: 缓存常见查询的检索结果
- 批量处理: 支持批量上传和处理文档
- 知识图谱: 构建心理学概念的知识图谱
- 多语言支持: 支持英文等其他语言的文档
- 细粒度权限: 不同用户角色访问不同的知识库分类