# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## 项目概述 AI 智能客服系统,基于 Spring AI Alibaba + 通义千问 + PGVector,支持 RAG 知识库检索、多轮对话、结构化数据提取、知识库全生命周期管理。 ## 构建与运行 ```bash # 编译 ./mvnw compile # 运行(端口 9090) ./mvnw spring-boot:run # 运行测试 ./mvnw test # 运行单个测试类 ./mvnw test -Dtest=SupportBotApplicationTests # 运行单个测试方法 ./mvnw test -Dtest=SupportBotApplicationTests#testRag ``` **前提条件**: PostgreSQL 12+ 需运行且安装 PGVector 扩展,数据库 `support_bot` 需存在。`knowledge_category` 和 `knowledge_document` 表由 `DatabaseInitConfig` 自动创建,无需手动建表。 ## 核心架构决策 ### 主启动类排除了 PgVectorStoreAutoConfiguration `SupportBotApplication.java` 中 `@SpringBootApplication(exclude = PgVectorStoreAutoConfiguration.class)`,因为项目在 `PgVectorStoreConfig` 中手动配置 PgVectorStore Bean(标记 `@Primary`),不使用自动配置。另有一个 `InMemoryVectorStoreConfig` 作为开发备选。 ### Spring AI 集成模式 - **ChatClient Builder**: 所有对话通过 `ChatClient.builder(dashscopeChatModel)` 构建 - **Advisor 链**: `MessageChatMemoryAdvisor`(记忆) → `MyLoggerAdvisor`(日志) → `QuestionAnswerAdvisor`(RAG) - **结构化输出**: `ProductInfoApp` 使用 `.entity(ProductInfo.class)` 提取结构化数据 - **SSE 流式**: 三种实现 — Flux\、Flux\、SseEmitter ### ChatMemory 持久化 当前使用 `DatabaseChatMemory`(PostgreSQL 持久化),`FileBasedChatMemory`(Kryo 序列化)已注释掉。`ProductInfoApp` 单独使用 `InMemoryChatMemory`。 ### RAG 双模式 1. **QuestionAnswerAdvisor 模式**(生产使用): 预检索优化 + `QuestionAnswerAdvisor` 2. **RetrievalAugmentationAdvisor 模式**(实验性): `doChatWithRagEnhance()` 中 `queryTransformers` 和 `multiQueryExpander` 未生效 ### 文档处理管道 `DocumentService.uploadDocument()` 统一流程:文档提取 → `MyTokenTextSplitter` 分块 → `MyKeywordEnricher` AI 关键词提取 → `pgVectorVectorStore.add()` 向量化存储。每个分块的 metadata 中注入 `documentId`、`chunkIndex`、`sourceName`、`title` 以关联 `knowledge_document` 表。 ### 预检索查询优化 四种策略在 `rag/preretrieval/` 下,由 `AssistantApp.doChatWithRagStrategy()` 根据 `strategy` 参数动态选择:REWRITE / TRANSLATION / COMPRESSION / MULTI_QUERY。另存在 Bean 配置版本(`QueryTransformerConfig`、`QueryExpanderConfig`),但实际使用自定义 Rewriter 组件。 ## 关键配置 - `application.yml` 含 API Key,已被 `.gitignore` 排除 - MyBatis Plus 逻辑删除字段: `isDelete`,主键策略: `assign_id`(雪花算法) - **雪花 ID 精度问题**: `KnowledgeDocument.id`、`categoryId` 和 `KnowledgeCategory.id`、`parentId` 已添加 `@JsonSerialize(using = ToStringSerializer.class)`,序列化为字符串避免前端 JS 精度丢失 - PostgreSQL JSONB 字段使用自定义 `PostgresJsonTypeHandler`(期望 JSON 对象 `'{}'`,非数组 `'[]'`) - 向量维度: 1536,距离类型: COSINE_DISTANCE,索引: HNSW - **分块配置**: `knowledge.chunk.*` 配置项(`ChunkConfig`),默认 chunkSize=200, overlap=100 - **上传校验**: `ALLOWED_EXTENSIONS` 白名单 + 50MB 大小限制,前后端双重校验 - **文档去重**: `KnowledgeDocument.contentHash` 字段(SHA-256),上传时自动计算并查重 ## 前端架构 - **技术栈**: Vue 3 CDN + ES Module(`importmap` 引入,无构建工具) - **入口**: `src/main/resources/static/index.html` → `js/app.js` - **组件化**: 每个功能模块一个 JS 文件(`components/` 目录),导出 Vue 组件定义对象 - **状态管理**: `js/store.js` 使用 Vue 3 `reactive`,跨组件共享分类、统计、弹窗状态 - **API 封装**: `js/api.js` 统一封装所有后端调用,API 基址为空字符串(同源部署) - **SSE 流式**: `js/utils.js` 中 `readSSEStream()` 统一处理三种 SSE 接口 - **添加新功能**: 在 `components/` 下新建 JS 组件文件,在 `app.js` 中导入注册即可 ## API 路由约定 - AI 对话: `/ai/*`(`AiController`) - 文档上传: `/upload/*`(`DocumentController`) - 文档管理: `/document/*`(`DocumentController`) - 批量操作: `/document/batch/*`(`DocumentController`,用 POST 避免 DELETE+RequestBody 路径冲突) - 分类管理: `/category/*`(`DocumentController`) ## 已知 TODO - `AssistantApp.doChatWithRagEnhance()`: `queryTransformers` 未生效 - `DocumentService.updateDocumentMetadata()`: Spring AI 无直接更新 vector_store metadata 的 API,向量元数据同步留后续 - `DocumentService.searchDocuments()`: Spring AI 1.0.0-M6 的 filter 支持有限,分类过滤暂未实现 - `CompressionQueryRewriter`: 当前传入空历史列表 - MyBatis Plus 3.5.12 的 `mybatis-plus-spring-boot3-starter` 不含 `PaginationInnerInterceptor`,分页通过 SQL `LIMIT/OFFSET` 手动实现