# LangHuan
**Repository Path**: orcadev/LangHuan
## Basic Information
- **Project Name**: LangHuan
- **Description**: LangHuan 是一个基于 Kotlin + Spring AI 的智能对话与知识检索系统,集成了 RAG 技术,为个人和小团队提供知识管理和智能问答的一站式解决方案。
"琅嬛福地",藏天下典籍。
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 5
- **Created**: 2026-08-16
- **Last Updated**: 2026-08-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# LangHuan(万卷琅嬛)
LangHuan 是一个基于 Kotlin + Spring AI 的智能对话与知识检索系统,集成了 RAG 技术,为个人和小团队提供知识管理和智能问答的一站式解决方案。
`琅嬛福地,藏天下典籍。`
## 功能特色
### 🤖 智能对话系统
- **个人知识空间**:为每个用户提供独立的知识库管理空间
- **对话记忆功能**:智能保存和管理对话上下文,提供连贯的交互体验
- **深度思考模式**:支持模型深度推理输出,提供更详细的分析过程
- **图片文档识别**:支持多模态模型,可识别图片和文档,提供更丰富的答案和体验
- **多专家模式对话**:支持多角色协作对话,模拟专家团队讨论
- **移动端适配**:响应式布局设计,自适应手机/平板等设备,移动端友好的界面交互
- **MCP支持**:支持stdio/streamable-http/sse协议MCP,更好的工具扩展性
### 📚 RAG知识检索
- **LightRAG 图增强检索**:基于知识图谱的双层检索(Low-level 精确实体匹配 + High-level 主题多跳聚合),作为向量+BM25之上的第四/第五召回路径,四路 RRF 融合,图检索失败自动降级
- **智能文档处理**:自动提取文档图片并进行存储,提供图文并茂的答案
- **混合检索技术**:结合向量检索、BM25全文检索,RRF(Reciprocal Rank Fusion)自适应融合,无需手动调参
- **查询预处理管线**:CompressionQueryTransformer(多轮指代消解)→ RewriteQueryTransformer(口语化改写)→ HyDE(假设性答案嵌入检索),三级预处理提升召回率
- **MMR多样性去重**:Maximal Marginal Relevance算法,避免同一文档多个chunk占据所有TopK位置
- **重排序机制**:支持ReRank模型,优化检索结果排序
- **BM25增量索引**:Lucene索引与向量存储实时同步,消除最长2天的数据不一致
- **多格式文档支持**:支持Md、Word、HTML(保留结构)、纯文本等多种文档格式
- **批量高效入库**:向量写入批次优化,入库速度提升10-50倍
- **Redis缓存**:统一缓存后端替代内存缓存,支持多实例部署和缓存持久化
- **召回测试工具**:提供可视化的检索效果测试和优化工具(含四路分路结果调试端点)
### 🗂️ 文件管理系统
- **文件组织管理**:支持文件分组、标签化管理
- **权限控制**:细粒度的文件访问权限控制,支持公开/私有设置
- **文件共享**:支持用户间文件组共享,便于协作
- **向量化管理**:支持单条向量的编辑、删除和优化
- **批量导入导出**:支持RAG文档的批量导入导出功能
### 👥 用户权限系统
- **角色权限管理**:接口级别,完整的RBAC权限控制体系
- **JWT认证**:安全的用户认证和授权机制
- **权限缓存优化**:高效的权限验证和缓存机制
- **多用户支持**:支持多用户并发使用,数据隔离
### 🔧 系统管理功能
- **提示词管理**:可配置的提示词模板和优化工具
- **模型配置**:支持多种OpenAI兼容模型的配置和切换
- **消息通知系统**:完整的系统消息推送和通知机制
- **使用统计仪表盘**:详细的系统使用情况统计和分析
- **MinIO对象存储**:集成对象存储,知识文件定期备份等功能
### 🐳 部署运维
- **轻量化部署**:适合个人和小团队快速部署使用
- **Docker容器化**:可选的完整的Docker部署方案
- **数据库备份**:自动化的数据备份和恢复机制
- **定时任务管理**:定时清理临时文件等维护任务
- **日志管理**:完善的系统日志记录和管理
## 部署
### 推荐使用
[Docker部署方案](./langhuan_docker_dist/README.md)
### 基于源码部署:
[前端本地部署](./langhuan-web/README.md) | [后端本地部署](./langhuan-server/README.md)
### 模型 Provider
对话模型默认走 OpenAI 兼容 API(默认 DashScope)。可选改用 [OrcaRouter](https://www.orcarouter.ai)(OpenAI 兼容 LLM 路由网关):源码运行加 `--spring.profiles.active=orcarouter`(并设置环境变量 `ORCAROUTER_API_KEY`);Docker 部署见 [部署文档](./langhuan_docker_dist/README.md)。
### 默认登陆账号
- 账号: admin
- 密码: asb#1234
`默认密码在 langhuan-server/src/main/kotlin/com/langhuan/common/Constant.kt 文件中调节后重新启动`
## 重点功能流程
### 对话流程
```mermaid
flowchart TD
Start([开始: ChatController.chat]) --> ParseOption[解析ChatRestOption
设置默认模型]
ParseOption --> CallChat[ChatService.chat]
%% 文件分类
CallChat --> FileCategorize[FileUtil.categorizeFiles
分类: images / documents]
FileCategorize --> CommandCheck{userMessage以
/add_personal_knowledge_space
开头?}
%% ====== 个人知识空间分支 ======
CommandCheck -->|是| ExtractContent[提取实际内容
移除命令前缀]
ExtractContent --> ImageCheck{有图片文件?}
ImageCheck -->|有| ImgToText[ImgService.chat_imageUnderstandingToText
多模态图片信息提取]
ImageCheck -->|无| ImgSkip[跳过图片处理]
ImgToText --> DocCheck{有文档文件?}
ImgSkip --> DocCheck
DocCheck -->|有| DocSplit["RagService.readAndSplitDocument
CompositeTextSplitter
(======分片 + 固定窗口overlap)"]
DocCheck -->|无| DocSkip[跳过文档处理]
DocSplit --> CollectAll[收集全部内容
用户文本 + 图片文本 + 文档文本]
DocSkip --> CollectAll
CollectAll --> FilterEmpty[过滤空内容]
FilterEmpty --> HasContent{有有效内容?}
HasContent -->|有| AddToMySpace["RagService.addDocumentToMySpace
创建/更新个人知识空间
写入向量库 + Lucene增量索引"]
AddToMySpace --> AddResult{添加结果}
AddResult -->|成功| ReturnSuccess[返回: 添加到个人知识空间成功]
AddResult -->|失败| ReturnFail[返回: 添加到个人知识空间失败]
HasContent -->|无| ReturnNoContent[返回: 未提取到知识信息]
%% ====== toChat 主对话分支 ======
CommandCheck -->|否| ToChat[toChat: 主对话处理]
ToChat --> RagCheck{ragGroupId
非空?}
%% --- RAG启用分支 ---
RagCheck -->|启用RAG| GetRAGPrompt[获取RAG提示词模板
优先缓存配置]
GetRAGPrompt --> QueryRewrite["QueryRewriteService.rewriteQuery
查询改写: 口语化→检索友好"]
QueryRewrite --> QueryCompress["QueryCompressionService.compressQuery
查询压缩: 多轮指代消解
(历史消息≥5条时触发)"]
QueryCompress --> HyDE["HydeService.generateHypotheticalDocument
HyDE: 生成假设性答案
(15s超时,失败返回null)"]
HyDE --> HyDECheck{hydeText
非null?}
HyDECheck -->|是| RagSearchHyde["RagCallBackService.ragSearchWithHyde
四路检索(向量+BM25+图Low+图High) + HyDE → RRF融合"]
HyDECheck -->|否| RagSearch["RagCallBackService.ragSearch
向量+BM25+图检索(Low/High) → 四路RRF融合 + 去重"]
RagSearchHyde --> BuildRAGContext[拼接检索文档内容]
RagSearch --> BuildRAGContext
BuildRAGContext --> ReplaceTemplate[替换提示词模板变量
构建RAG上下文]
ReplaceTemplate --> CallLLM
%% --- 普通对话分支 ---
RagCheck -->|未启用RAG| CallLLM[调用ChatClient]
CallLLM --> BuildResponse["构建ChatModelResult
chat=AI响应
rag=检索文档列表"]
BuildResponse --> End([结束])
%% 异常处理
AddToMySpace -.->|异常| CatchException
CallLLM -.->|异常| CatchException
CatchException[捕获异常] --> HandleException["返回友好错误消息
ChatModelResult(chat=错误信息)"]
HandleException --> End
%% 样式定义
classDef serviceClass fill:#e1f5fe,stroke:#01579b,stroke-width:2px
classDef preProcessClass fill:#e8eaf6,stroke:#283593,stroke-width:2px
classDef decisionClass fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef ragClass fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef resultClass fill:#fce4ec,stroke:#880e4f,stroke-width:2px
classDef errorClass fill:#ffebee,stroke:#c62828,stroke-width:2px
class ToChat,CallLLM serviceClass
class QueryRewrite,QueryCompress,HyDE preProcessClass
class CommandCheck,RagCheck,HyDECheck,ImageCheck,DocCheck,HasContent,AddResult decisionClass
class RagSearch,RagSearchHyde,BuildRAGContext,ReplaceTemplate,AddToMySpace ragClass
class ReturnSuccess,ReturnFail,ReturnNoContent,BuildResponse resultClass
class CatchException,HandleException errorClass
```
### 检索流程
```mermaid
flowchart TD
A([开始: ragSearch调用]) --> PARALLEL[阶段A: 三路立即并行
不互相依赖]
%% ====== 向量检索分支 ======
PARALLEL --> EMB[向量检索: embeddingCallBack]
EMB --> FILTER_CHECK{groupId/fileId
过滤条件?}
FILTER_CHECK -->|无过滤| GLOBAL_SEARCH["全局向量搜索
similaritySearch(query, topK, threshold)"]
FILTER_CHECK -->|有过滤| BUILD_FILTER["FilterExpressionValidator
构建安全的过滤表达式"]
BUILD_FILTER --> FILTERED_SEARCH["带过滤条件向量搜索
fileId == 'xxx'
或 groupId IN (...)"]
GLOBAL_SEARCH --> EMB_RESULT[向量检索结果
doc.score = 向量分数]
FILTERED_SEARCH --> EMB_RESULT
%% ====== BM25检索分支 ======
PARALLEL --> BM25["BM25全文检索: bm25CallBack
Lucene增量索引"]
BM25 --> LUCENE_SEARCH["LuceneIndexService.searchDocuments
全文索引搜索"]
LUCENE_SEARCH --> BM25_IDS[获取搜索结果ID列表 + BM25分数]
BM25_IDS --> DB_LOOKUP["vectorStoreRagDao.selectRagByIds
根据ID查询向量库获取内容"]
DB_LOOKUP --> BM25_RESULT["BM25检索结果
metadata.bm25Score = BM25分数"]
%% ====== 查询分析分支(阶段A第三路) ======
PARALLEL --> ANALYZE["QueryAnalyzer.analyze
LLM 抽取查询实体/主题/意图
超时/失败返回 null → 降级"]
ANALYZE --> ANALYSIS_RESULT{analysis
非null?}
%% ====== 阶段B: analysis 就绪后补启图检索两路 ======
ANALYSIS_RESULT -->|是| GRAPH_LOW["Graph-Low: DualLevelRetrievalService.lowLevelSearch
精确实体匹配 → 1-hop 关联 chunk"]
ANALYSIS_RESULT -->|是| GRAPH_HIGH["Graph-High: highLevelSearch
主题向量匹配 → 多-hop 聚合 chunk"]
ANALYSIS_RESULT -->|否| GRAPH_SKIP[图检索两路跳过
降级为两路]
GRAPH_LOW --> GRAPH_RESULT[图检索结果
metadata.graphLowScore/graphHighScore]
GRAPH_HIGH --> GRAPH_RESULT
GRAPH_SKIP --> MERGE
%% ====== 分数融合 ======
EMB_RESULT --> MERGE["mergeDocumentsWithScores
按ID合并向量+BM25两路结果"]
BM25_RESULT --> MERGE
MERGE --> MERGED[合并后的文档列表]
MERGED --> FUSION_CHECK{图检索路
有结果?}
GRAPH_RESULT --> FUSION_CHECK
FUSION_CHECK -->|四路| RRF4["rankRRF4Way: 四路 RRF 融合
score = Σ 1/(k+rank_i)
缺路自动跳过不加分"]
FUSION_CHECK -->|两路降级| RRF["rankRRF: 两路 RRF 融合
score = 1/(k+embRank) + 1/(k+bm25Rank)"]
RRF4 --> FUSED
RRF --> FUSED[Fused: 融合排序后文档列表]
%% ====== HyDE增强路径(ragSearchWithHyde) ======
FUSED -.->|如果启用HyDE| HYDE_PATH
HYDE_PATH["HyDE路径 (ragSearchWithHyde):
embeddingCallBack(hydeText, topK=hydeTopK)"]
HYDE_PATH --> RRF_HYDE["rankRRFForHyde: 二次RRF融合
hydeRrfScore = 1/(k+directRank) + 1/(k+hydeRank)"]
RRF_HYDE --> RERANK_CHECK
%% ====== ReRank vs 去重 分支选择 ======
FUSED --> RERANK_CHECK{是否启用ReRank?}
%% ReRank启用:跳过去重,全量候选交给cross-encoder
RERANK_CHECK -->|启用| RERANK_TOPK["取Top rerankTopK文档
(跳过去重,保留完整候选集)"]
RERANK_TOPK --> RERANK_CALL["ReRankProcessor.rerank
cross-encoder精排"]
RERANK_CALL --> FINAL_TOPN
%% ReRank未启用:用去重作为启发式兜底
RERANK_CHECK -->|未启用| DEDUP["DedupFactory.create().deduplicate()"]
DEDUP --> DEDUP_STRATEGY{去重策略
rag.dedup.strategy}
DEDUP_STRATEGY -->|none| NO_DEDUP[不去重: 直通]
DEDUP_STRATEGY -->|fileId-dedup| FILE_DEDUP["基于fileId父文档去重
同一文档最多N个chunk"]
DEDUP_STRATEGY -->|mmr| MMR_DEDUP["MMR语义多样性去重
λ=0.7 平衡相关性与多样性"]
DEDUP_STRATEGY -->|"mmr+fileId-dedup"| COMBO_DEDUP["先fileId去重
再MMR语义去重"]
NO_DEDUP --> FILTER_BRANCH
FILE_DEDUP --> FILTER_BRANCH
MMR_DEDUP --> FILTER_BRANCH
COMBO_DEDUP --> FILTER_BRANCH
FILTER_BRANCH{融合策略?}
FILTER_BRANCH -->|RRF| DIRECT_TOPN["直接取Top llmRagTopN"]
FILTER_BRANCH -->|Linear| THRESHOLD_FILTER["按weightedScore阈值过滤
≥ linearWeightingNum"]
THRESHOLD_FILTER --> FILTERED_TOPN["取Top llmRagTopN"]
DIRECT_TOPN --> FINAL_TOPN
FILTERED_TOPN --> FINAL_TOPN
%% ====== 最终结果 ======
FINAL_TOPN["限制最终结果数量
llmRagTopN (默认5)"] --> TT([结束: 返回搜索结果])
%% 样式定义
classDef searchMethod fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef fusionMethod fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef dedupMethod fill:#fff8e1,stroke:#f57f17,stroke-width:2px
classDef rerankMethod fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
classDef dataFlow fill:#fff3e0,stroke:#f57c00,stroke-width:2px
classDef decisionClass fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef hydeClass fill:#ede7f6,stroke:#4527a0,stroke-width:2px
classDef graphClass fill:#e0f7fa,stroke:#006064,stroke-width:2px
class EMB,BM25,LUCENE_SEARCH,DB_LOOKUP searchMethod
class MERGE,RRF4,RRF fusionMethod
class NO_DEDUP,FILE_DEDUP,MMR_DEDUP,COMBO_DEDUP dedupMethod
class RERANK_TOPK,RERANK_CALL rerankMethod
class EMB_RESULT,BM25_RESULT,MERGED,FUSED dataFlow
class FILTER_CHECK,FUSION_CHECK,RERANK_CHECK,DEDUP_STRATEGY,FILTER_BRANCH,ANALYSIS_RESULT decisionClass
class HYDE_PATH,RRF_HYDE hydeClass
class ANALYZE,GRAPH_LOW,GRAPH_HIGH,GRAPH_RESULT,GRAPH_SKIP graphClass
```
### 知识图谱构建流程
```mermaid
flowchart TD
A([文档上传/修改]) --> WRITE["写入 vector_store_rag
+ Lucene 索引"]
WRITE --> COMMIT{事务提交
afterCommit}
COMMIT -->|提交成功| BUILD_ASYNC["GraphBuilder.buildAsync
提交到 graphExecutor 线程池"]
COMMIT -->|提交失败| SKIP[跳过图谱构建]
BUILD_ASYNC --> REVERSE["反查 chunk
selectByFileIdForGraph"]
REVERSE --> EXTRACT["KnowledgeGraphExtractor.extractBatch
并行 LLM 抽取实体+关系三元组
并发度可配 batch-size"]
EXTRACT --> NORMALIZE["EntityNormalizer.normalize
规则精确/包含匹配 → LLM 批量同义判断"]
NORMALIZE --> UPSERT_ENTITY["kg_entity upsert
ON CONFLICT name,type,group_id
+ 批量 embedding 描述"]
UPSERT_ENTITY --> UPSERT_RELATION["kg_relation upsert
ON CONFLICT source,target,type
weight 累加 + 批量 embedding"]
UPSERT_RELATION --> LINK["kg_entity_chunk 关联
entity ↔ chunk"]
LINK --> DONE["kg_index_task 标记 DONE
实体数 + 关系数"]
BUILD_ASYNC -.->|异常| FAILED["标记 FAILED
记录错误信息"]
classDef buildClass fill:#e0f7fa,stroke:#006064,stroke-width:2px
classDef decisionClass fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef errorClass fill:#ffebee,stroke:#c62828,stroke-width:2px
class WRITE,REVERSE,EXTRACT,NORMALIZE,UPSERT_ENTITY,UPSERT_RELATION,LINK,DONE buildClass
class COMMIT decisionClass
class SKIP,FAILED errorClass
```
## 功能发展历程
### 核心功能建设期 (2024.12 - 2025.01)
- [x] 基础对话功能和记忆机制 (2024.12)
- [x] RAG检索问答系统 (2024.12)
- [x] 函数调用功能实现 (2024.12)
- [x] JWT用户认证授权 (2024.12)
- [x] 前端工程页面开发 (2024.12)
- [x] 用户角色权限体系 (2024.12)
- [x] 聊天记录管理 (2024.12)
- [x] OpenAI兼容模型接入 (2025.01)
### 功能扩展期 (2025.02 - 2025.03)
- [x] Spring AI框架升级优化 (2025.03)
- [x] 提示词配置管理 (2025.03)
- [x] 文件组和文件管理 (2025.03)
- [x] RAG召回测试工具 (2025.03)
- [x] Docker部署方案 (2025.03)
### 体验优化期 (2025.04 - 2025.05)
- [x] 提示词优化功能 (2025.03)
- [x] 文字向量化管理 (2025.04)
- [x] ReRank重排序机制 (2025.04)
- [x] Markdown格式支持 (2025.04)
- [x] 大文档处理优化 (2025.04)
- [x] 文档引用和反馈 (2025.04-05)
- [x] Spring AI 1.0正式版 (2025.05)
- [x] 权限控制完善 (2025.05)
- [x] RAG文件导出功能 (2025.05)
### 功能完善期 (2025.06 - 2025.08)
- [x] ReRank模型集成 (2025.06)
- [x] 深度思考模式 (2025.06)
- [x] 消息通知系统 (2025.06)
- [x] 权重计算优化 (2025.07)
- [x] 仪表盘统计功能 (2025.07)
- [x] 用户信息完善 (2025.07)
- [x] 文件组权限共享 (2025.07)
- [x] MinIO对象存储 (2025.08)
- [x] 多专家模式对话 (2025.08)
- [x] 个人知识空间 (2025.08)
- [x] 新增图片和文档的多模态识别 (2025.08)
- [x] 混合检索技术 (2025.10)
- [x] 移动端适配,更多的使用细节处理 (2025.12)
### RAG深度优化期 (2026.04)
- [x] Spring AI 1.1.4版本升级 (2026.04)
- [x] 向量写入批次优化,入库速度提升10-50倍 (2026.04)
- [x] BM25增量索引同步,消除数据不一致 (2026.04)
- [x] Redis缓存基础设施,替代内存缓存 (2026.04)
- [x] 查询压缩CompressionQueryTransformer,多轮指代消解 (2026.04)
- [x] 查询改写RewriteQueryTransformer,口语化→检索友好 (2026.04)
- [x] HyDE假设性答案嵌入检索 (2026.04)
- [x] RRF(Reciprocal Rank Fusion)融合替换线性加权 (2026.04)
- [x] MMR(Maximal Marginal Relevance)多样性去重 (2026.04)
- [x] FixedWindow滑动窗口overlap分块 (2026.04)
- [x] 网页解析保留Markdown结构 (2026.04)
- [x] filterExpression参数校验安全修复 (2026.04)
- [x] RAG参数全面外部化到application.yml (2026.04)
- [x] Streaming流式响应 (2026.05)
### LightRAG 图增强检索 (2026.07)
- [x] 知识图谱构建:LLM 抽取实体/关系三元组(8 类实体、12 类关系),文档入库自动异步构建
- [x] 实体归一化:规则匹配(精确/包含/别名表)+ LLM 批量同义判断,解决中文同义实体分裂
- [x] 双层图检索:Low-level(精确实体 1-hop)+ High-level(主题向量多跳聚合),纯 SQL 递归 CTE 图遍历
- [x] 四路 RRF 融合:向量 + BM25 + Graph-Low + Graph-High,缺路自动降级为两路
- [x] 三段式并行检索:Vector+BM25+分析立即并行,分析就绪后补启图检索,专用线程池隔离
- [x] 图谱生命周期:文档增删改自动维护图谱(afterCommit 触发),删除时清理关系+关联+孤立实体
- [x] DB 层 upsert 并发安全:实体/关系 ON CONFLICT DO UPDATE,避免并发写入竞态
- [x] 召回调试端点:/rag/recallTesting/detail 展示四路分路结果 + 指标
### 规划中功能
- [ ] Contextual Retrieval:chunk前置上下文,降低检索失败率
- [ ] 语义分块 + SummaryMetadataEnricher
- [ ] 多查询扩展MultiQueryExpander
- [ ] Embedding缓存,避免重复计算
- [ ] 移除function tool代码,转为全面对MCP的支持,实现MCP热插拔
- [ ] 计划开发与之配合的MCP服务
- [ ] 提供针对模型等信息的配置页面,可自由更换模型api,rag配置,权重等
- [ ] 添加更多的拆分文档方式(在全文中划线拆分chunk)
- [ ] 不满意的回答过滤文档后重新回答
- [ ] 在对话中标记文档,记录被调用次数多并且满意的文档,区分高低价值 便于维护
- [ ] 支持调用更多的服务解析文档
## 开源协议
本项目采用 **Apache License 2.0** 许可协议,详情见 `LICENSE` 文件。使用前请务必遵守协议条款。
## 特别声明
1. 作者不对因使用本项目代码引发的任何法律风险或技术问题承担责任。
2. 本项目与作者任职单位(如有)无关,非职务作品,未利用雇主资源、技术文档或商业信息。
## 联系与支持
如有问题,请联系开发团队或提交 Issue。