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

39 KiB
Raw Permalink Blame History

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

在编写具体属性之前,我们需要识别并消除冗余的属性:

识别的冗余情况:

  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_dbValidates: 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, 通用错误消息(不暴露内部细节)

错误处理策略

# 统一错误响应格式
{
    "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)

测试组件之间的交互:

测试场景:

  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. 创建目录结构
mkdir D:\wwwroot\RAG\data\chroma_db
mkdir D:\wwwroot\RAG\uploads
mkdir D:\wwwroot\RAG\logs
  1. 启动Ollama服务
ollama serve
  1. 启动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
  1. 配置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
  1. 打包Spring Boot应用
mvn clean package -DskipTests
  1. 启动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天的备份
  • 支持手动触发备份

安全考虑

  1. 访问控制:

    • Spring Security权限控制
    • 知识库管理需要管理员权限
    • API接口需要登录认证
  2. 文件验证:

    • 上传文件格式白名单PDF、Word、TXT
    • 文件大小限制默认50MB
    • 文件内容安全扫描
  3. 输入清理:

    • 防止SQL注入
    • 防止XSS攻击
    • 参数验证和清理
  4. 日志脱敏:

    • 日志中不记录敏感个人信息
    • 自动脱敏身份证号、手机号等
  5. 数据安全:

    • 所有数据本地存储
    • 不依赖外网服务
    • 可选文档加密存储

Future Enhancements

  1. 知识库版本管理: 支持文档的版本控制和回滚
  2. 多模型支持: 支持切换不同的嵌入模型和生成模型
  3. 增量更新: 支持文档的增量更新而非完全重新处理
  4. 缓存机制: 缓存常见查询的检索结果
  5. 批量处理: 支持批量上传和处理文档
  6. 知识图谱: 构建心理学概念的知识图谱
  7. 多语言支持: 支持英文等其他语言的文档
  8. 细粒度权限: 不同用户角色访问不同的知识库分类