14 KiB
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 知识库检索、多轮对话、结构化数据提取、知识库全生命周期管理。
构建与运行
# 编译
./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、ai_model_config 等表由 DatabaseInitConfig 自动创建,无需手动建表。
测试说明: 所有测试均为集成测试(@SpringBootTest),需要运行中的 PostgreSQL 和有效的 DashScope API Key。测试类:SupportBotApplicationTests(对话/RAG)、PgVectorVectorStoreConfigTest(向量存储)、QueryTransformerTests(查询重写策略)。无单元测试。
访问地址: 前端管理页面 http://localhost:9090/index.html,API 文档 http://localhost:9090/doc.html(Knife4j)
核心架构决策
主启动类排除了 PgVectorStoreAutoConfiguration
SupportBotApplication.java 中 @SpringBootApplication(exclude = PgVectorStoreAutoConfiguration.class),因为项目在 PgVectorStoreConfig 中手动配置 PgVectorStore Bean(标记 @Primary),不使用自动配置。另有一个 InMemoryVectorStoreConfig 作为开发备选。
Spring AI 集成模式
- ChatClient Builder: 所有对话通过
ChatClient.builder(chatModelFactory.getChatModel("CHAT"))构建,ChatModel 由ChatModelFactory按 DB 活跃配置动态创建 - Advisor 链:
MessageChatMemoryAdvisor(记忆) →MyLoggerAdvisor(日志) →QuestionAnswerAdvisor(RAG) - SSE 流式: 三种实现 — Flux<String>、Flux<ServerSentEvent>、SseEmitter
ChatMemory 持久化
当前使用 DatabaseChatMemory(PostgreSQL 持久化),FileBasedChatMemory(Kryo 序列化)已注释掉。
RAG 双模式
- QuestionAnswerAdvisor 模式(生产使用): 预检索优化 +
QuestionAnswerAdvisor - 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含 DashScope API Key,已被.gitignore排除- 模型名称、温度、最大 Token 等参数已全部迁移到前端「AI 大模型配置管理」页面,通过
ai_model_config表管理,不再在 yml 中配置(yml 仅保留api-key) - MyBatis Plus 逻辑删除字段:
isDelete,主键策略:assign_id(雪花算法) - 雪花 ID 精度问题:
KnowledgeDocument.id、categoryId和KnowledgeCategory.id、parentId已添加@JsonSerialize(using = ToStringSerializer.class),序列化为字符串避免前端 JS 精度丢失。新增 Long ID 字段时务必加上此注解 - PostgreSQL JSONB 字段使用自定义
PostgresJsonTypeHandler(期望 JSON 对象'{}',非数组'[]') - 向量维度: 由
knowledge.vector.dimension配置(默认 1024)。修改后需执行DROP TABLE IF EXISTS vector_store CASCADE重建向量表,并重新上传知识库文档。距离类型: COSINE_DISTANCE,索引: HNSW - 分块配置:
knowledge.chunk.*配置项(ChunkConfig),默认 chunkSize=200, overlap=100, minChunkSizeChars=10, maxNumChunks=5000, keepSeparator=true - 上传校验:
ALLOWED_EXTENSIONS白名单 + 50MB 大小限制(spring.servlet.multipart配置),前后端双重校验 - 文档去重:
KnowledgeDocument.contentHash字段(SHA-256),上传时自动计算并查重 - 数据库自动初始化:
DatabaseInitConfig在启动时检查并创建knowledge_category/knowledge_document/ai_model_config等表,对已存在的knowledge_document表会自动补加content_hash列。注意knowledge-base.sql脚本为早期版本,缺少此列,实际以DatabaseInitConfig为准
模型配置管理
- ai_model_config 表: 存储大模型配置,支持多套配置按 App 类型(CHAT / EMBEDDING / RAG_REWRITE)独立管理。所有模型参数(名称、温度、最大Token、API Key、Base URL 等)全部由此表管理,不再依赖 application.yml
- 激活互斥: 同一 App 类型只能有一个
is_active=true的配置,激活操作由 Service 层@Transactional保证 - 启动 seed: 首次启动时使用硬编码默认值写入 DB(
qwen-turbo/text-embedding-v2),用户可在前端修改。DashScope 自动配置已禁用(spring.ai.dashscope.enabled=false),api-key 可选——yml 与 DB 均未配置 api-key 不影响启动,实际调用 AI 功能前在前端「AI 大模型配置管理」页面配置即可 - 启动校验:
ModelConfigLoader在应用就绪后检查 DB 中每种 App 类型是否有活跃配置,并对 DashScope 提供商比较 DB 与 yml 的 API Key 一致性 - API Key 脱敏: 前端展示时只显示前 4 位 +
****+ 后 4 位 - ChatModel 运行时切换: 通过
ChatModelFactory按 DB 活跃配置动态创建/缓存 ChatModel(包括 DashScope,不再复用 yml 自动配置的 Bean),配置变更时立即生效(无需重启)。OpenAI 兼容路径使用自定义completionsPath(与 EmbeddingModelFactory 的 embeddingsPath 对应),baseUrl 已含版本段的厂商(moonshot/v1、volcengine/api/v3、zhipu/api/paas/v4)设为/chat/completions,其余使用默认/v1/chat/completions - EmbeddingModel 运行时切换: 通过
EmbeddingModelFactory+DynamicEmbeddingModel代理,按 DB 活跃配置动态创建/缓存 EmbeddingModel,PgVectorStoreConfig和InMemoryVectorStoreConfig注入DynamicEmbeddingModel,向量化模型配置变更后无需重启即可生效 - 多提供商支持: DashScope(通义千问)+ OpenAI 兼容提供商(DeepSeek / 豆包 / Kimi / 智谱 / OpenAI),ChatModel 和 EmbeddingModel 均通过对应 API 手动构建
- 缓存刷新: 配置增删改激活时 Controller 自动调用
ChatModelFactory.clearCache()+EmbeddingModelFactory.clearCache()+AssistantApp.clearCache()
依赖版本
- Spring AI BOM:
1.0.1,统一管理所有org.springframework.ai依赖版本 spring-ai-alibaba-starter-dashscope:1.0.0.4(新版 starter,替代老版spring-ai-alibaba-starterM6.1)spring-ai-openai: BOM 管理(OpenAI 兼容提供商支持)spring-ai-alibaba-starter(M6.1) 已移除,不再使用
EmbeddingModel 架构
- EmbeddingConfigFixer:
ApplicationListener<ApplicationReadyEvent>,启动时检查 EMBEDDING 配置合理性、校验 EmbeddingModel 实际维度与配置维度是否一致,不一致时 WARN 告警并给出修复步骤。不再强制修正非 DashScope 配置,尊重用户在 DB 中配置的提供商和模型 - EmbeddingModelFactory:按 DB 活跃配置动态创建/缓存 EmbeddingModel,支持多种提供商:
- DashScope(通义千问):
DashScopeEmbeddingModel - OpenAI 兼容提供商(DeepSeek / Kimi / 智谱 / OpenAI):通过
OpenAiEmbeddingModel+ 自定义 baseUrl +embeddingsPath创建 - 豆包文本模型(volcengine + 非 vision):通过
OpenAiEmbeddingModel,embeddingsPath=/embeddings - 豆包多模态模型(volcengine +
*vision*):通过VolcengineMultimodalEmbeddingModel,手写RestClient直调/embeddings/multimodal,适配{type, text}格式 - 各厂商 embeddingsPath 映射:
提供商 embeddingsPath 实现类 dashscope — DashScopeEmbeddingModel volcengine (vision) /embeddings/multimodalVolcengineMultimodalEmbeddingModel volcengine (text) /embeddingsOpenAiEmbeddingModel moonshot /embeddingsOpenAiEmbeddingModel zhipu /embeddingsOpenAiEmbeddingModel deepseek /v1/embeddingsOpenAiEmbeddingModel openai /v1/embeddingsOpenAiEmbeddingModel - 注意:各提供商的 embedding 端点兼容性由用户自行验证,向量维度需与 PgVectorStore 的
dimensions一致
- DashScope(通义千问):
- DynamicEmbeddingModel:代理类实现
EmbeddingModel接口,每次调用委托给 Factory,使 VectorStore 无需重建即可热切换 - 前端:
ModelConfigManager.js对 EMBEDDING 类型不再限制 provider,可自由选择任意提供商;EMBEDDING 类型弹窗增加「向量维度」输入框(写入extraConfig.dimensions)
前端架构
- 技术栈: Vue 3 CDN + ES Module(
importmap引入,无构建工具) - 入口:
src/main/resources/static/index.html→js/app.js - 组件化: 每个功能模块一个 JS 文件(
components/目录),导出 Vue 组件定义对象 - 状态管理:
js/store.js使用 Vue 3reactive,跨组件共享分类、统计、弹窗状态 - API 封装:
js/api.js统一封装所有后端调用,API 基址为空字符串(同源部署) - SSE 流式:
js/utils.js中readSSEStream()统一处理三种 SSE 接口 - 添加新功能: 在
components/下新建 JS 组件文件,在app.js中导入注册即可
API 路由约定
- AI 对话:
/ai/*(AiController) - 模型配置:
/model-config/*(AiModelConfigController) - 文档上传:
/upload/*(DocumentController) - 文档管理:
/document/*(DocumentController) - 批量操作:
/document/batch/*(DocumentController,用 POST 避免 DELETE+RequestBody 路径冲突) - 分类管理:
/category/*(DocumentController) - 消息反馈:
/feedback/*(MessageFeedbackController) - 敏感词管理:
/sensitive-word/*(SensitiveWordController) - FAQ 管理:
/faq/*(FaqController)
P0 阶段新增功能
内容安全过滤(P0-004)
- DFA 引擎:
ContentSafetyService使用字典树匹配敏感词,volatile+ copy-on-write 保证线程安全热加载 - ContentSafetyAdvisor: 实现
BaseAdvisor,getOrder()返回HIGHEST_PRECEDENCE(Advisor 链最外层),before 阶段检查用户输入、after 阶段检查 AI 输出 - 敏感词级别: level=1 仅脱敏(MASK),level=2 拦截(BLOCK)返回安全提示
- 审计日志:
content_audit_log表记录所有违规事件,不删除 - 前端:
SensitiveWordManager.js在系统设置 Tab,支持 CRUD + 批量导入 + 审计日志查看
用户反馈系统(P0-002)
- 反馈实体:
MessageFeedback,按message_id唯一索引,重复提交覆盖(upsert 语义) - 反馈类型: THUMBS_UP(有帮助)/ THUMBS_DOWN(没帮助),点踩可选原因分类 + 自由文本
- ChatPanel: 每条 AI 回复下方有 👍/👎 按钮,点击调用
POST /feedback - Chat SDK:
handleFeedback()已连接后端 API,同时保留 localStorage 作为乐观 UI 缓存 - 会话导出:
ConversationService.exportConversation()导出的 TXT 中包含反馈信息
意图识别 + FAQ 精准匹配(P0-003)
- IntentRouter: LLM 单次调用做意图分类(FAQ/RAG/CHITCHAT),解析失败降级为 RAG
- FaqMatchEngine: 三级匹配策略 — 精确匹配 → 关键词匹配 → 向量语义匹配(阈值
knowledge.faq.semantic-threshold,默认 0.85) - FAQ 向量化: 复用现有
DynamicEmbeddingModel,向量存入faq_embedding表,新增/修改 FAQ 时异步计算 - similar_questions 字段: 使用 String 类型存储 JSON 数组字符串(PostgresJsonTypeHandler 期望对象格式,故不用 typeHandler)
- 前端:
FaqManager.js在知识库文档管理 Tab,支持 CRUD + 批量 JSON 导入/导出 + 启用/禁用
混合检索 + 重排序引擎(P0-001)
- SearchMode: 枚举 VECTOR(默认)/ KEYWORD / HYBRID,向后兼容
- HybridSearchService: 多模式检索核心,KEYWORD 使用 PostgreSQL
tsvector全文检索,HYBRID 使用双路检索 + RRF 融合 - RrfFusion: RRF 融合算法
score = Σ 1/(k + rank_i),k=60 - RerankerService: 支持 DashScope + OpenAI 兼容提供商,通过
ai_model_config表 RERANK 类型配置,超时 3s 自动 fallback - vector_store 全文检索: 新增
content_tsvector列 + GIN 索引 + PostgreSQL 触发器自动维护 - 前端:
DocSearch.js增加检索模式下拉选择(向量/关键词/混合),结果标注来源模式
已知 TODO
AssistantApp.doChatWithRagEnhance():queryTransformers未生效DocumentService.updateDocumentMetadata(): Spring AI 无直接更新 vector_store metadata 的 API,向量元数据同步留后续DocumentService.searchDocuments(): Spring AI 1.0.1 的 filter 支持有限,分类过滤暂未实现CompressionQueryRewriter: 当前传入空历史列表- MyBatis Plus 3.5.12 的
mybatis-plus-spring-boot3-starter不含PaginationInnerInterceptor,分页通过 SQLLIMIT/OFFSET手动实现 PgVectorStoreConfig.dimensions(1024)硬编码了向量维度,切换非 1024 维的 Embedding 模型时需修改并重建 vector_store 表 → 已修复:维度由knowledge.vector.dimension配置,启动时自动检测不匹配并告警