know-engine
项目实战2(know-engine)
生产级企业 RAG 知识引擎
57 篇 · 约 167 分钟项目整体架构与核心功能
本项目是一个基于 RAG 架构的企业知识管理与智能问答系统,实现从文档接入、智能切片、向量化存储到多源检索、意图路由、流式对话的全链路闭环。 整体架构分层 系统采用分层架构设计,自上而下分为 5 层: 知识入库流程 文档从上传到可检…
项目亮点与设计原则
项目亮点 🔥 本地 Reranking — 零外部依赖的精排方案 基于 ONNX Runtime 在 JVM 进程内直接运行 BGE RERANKER 模型,无需部署独立的 Reranking 微服务。采用双重检查锁单例模式,模型仅…
项目如何启动&快速开始
环境依赖 JDK 21+ MySQL 8.0+ Redis 7.0+ Elasticsearch 8.x(需开启 KNN 向量检索) Neo4j 5.x(需安装 APOC 插件) MinIO XXL Job Admin 2.4+ 配…
技术选型
Spring AI vs LangChain4J 前面我们介绍过Spring AI和LangChain4j了,同时也介绍过Spring AI Alibaba,在RAG这个章节中我们介绍了关于他们内置的一些分块器、文档处理器等等,也介…
为什么不用Java解析PDF文档
一般的知识库内容,通常由word、markdown、pdf以及在线文档这几种形式。其中比较难处理的就是pdf。 我们可以先试一下,用spring ai和langchain4j的话,处理一下pdf,看看什么效果。 先准备一份图文并茂的…
为什么选择MinerU解析文档?
我们选择使用python来解析文档,是因为他有很多成熟的库可以直接使用,目前,市面上比较常见的pdf处理的开源库有MinerU、Marker、PaddleOCR这几个。对比如下: 工具 MinerU PaddleOCR + PP S…
MinerU文档处理功能实现
前面我们介绍了如何使用MinerU的网页端进行文件的处理。但是我们总不能每次文档都去网页上处理吧,所以我们需要有工程化的手段来实现。介绍两种方案: 使用API服务 这种方式适合小团队,要处理的pdf不多,对处理速度要求不高的情况。个…
文档索引构建流程——文档上传
我们需要把一份PDF最终转化成向量数据库中的向量,需要经过以下步骤: 1、pdf文件上传 2、pdf文件存储在minio 3、将文件解析成markdown 4、基于markdown做分块 5、将分块后的数据做embedding 6、…
在Java代码中把MinerU解析文档功能集成进来
(MinerU相关的内容,虽然之前公司也在用,但是部署这块是算法同学搞的,这次从部署开始弄,我花了很多时间,前前后后搞了差不多三四个通宵吧,把一些过程中遇到的问题都整理出来了。网上这块的资料比较少,踩了很多坑,希望能给大家点帮助) …
解决MinerU解析无法获取图片的问题
前面我们介绍了,可以通过mineru的fast api,将一个pdf转成markdown。但是这个方案有个问题,那就是会丢失其中的图片内容,只会返回一个markdown,但是其中的图片都没有返回。 想要返回图片,直接用fast ap…
文档索引构建流程——文档切分
前面我们通过文档的上传,以及文档的转换处理,已经可以拿到一份markdown文档了,接着,我们就要针对这份文档做切分了,切片成多个chunk,用于embedding。 markdown标题切分 我们这里选择的切块方式,针对markd…
chunkSize和overlap设置成多少比较合适?
在RAG系统中,chunk size和overlap的设置没有绝对的“黄金标准”,但是我认为核心思想应该是:从通用推荐值出发,根据文档类型和语言特性进行调整,并通过实验验证找到最适合你特定场景的参数。(就像线程池的核心线程数的设置一…
接入ElasticSearch做向量存储
我们项目中选择使用ES做向量数据库,方便后面我们基于ES做混合检索。这一篇介绍下如何在LangChain4J中接入ES。 增加依赖 首先,langchain4j elasticsearch是一个针对langchain4j的es的包,…
文档索引构建流程——向量存储
这一步我们是把前面分段后的一个个segment保存在向量数据库中,那么我们就在KnowledgeDocumentService中定义一个embeddingAndStore:
向量维度如何设置?
在构建 RAG系统的索引时,向量维度的设置是一个非常关键的环节。简单来说,维度的选择并非一个可以随意调整的参数,而是由你所选用的 Embedding模型直接决定的。 在我们的项目中,我们的配置如下:
文档预处理阶段全流程讲解(事件驱动)
完整流程 1、多个流程之间,基于事件驱动。这样可以更好的解耦。 2、事件驱动如果处理失败了, 引入任务定时任务兜底。 文档上传 文档分段 文档向量保存 1、事件驱动 在DocumentEventListener中,接收Documen…
XXL-JOB部署及用任务驱动文档处理流程
XXL JOB部署 配置要求 CPU:1核 内存:2G 代码下载 https://github.com/xuxueli/xxl job 初始化数据库 找到文件/xxl job/doc/db/tables xxl job.sql ,然…
引入分布式锁解决文档处理的并发问题
在我们的课程中,有文档处理的过程,比如文档的转换、切分、嵌入和存储。因为我们为了解耦和提升吞吐量,我们做了基于事件驱动的方式做流程的串联。 因为有了事件驱动,而事件驱动有可能失败,所以我们引入了XXL JOB定时任务做兜底,那么在极…
分段批量插入性能优化
在我们的项目中,我们会针对一个文档做分段,分成多个segment之后,需要把他们都插入到数据库中。在最开始的代码中,我们是这么做的:
基于雪花算法生成唯一的chunkId
项目中,需要针对文档记录分段id,尤其是parentChunkId,需要保证唯一才行,不然会路由错误。我们选择使用雪花算法。 以下是ai帮我生成的雪花算法,基本上没啥问题,用了个双重校验锁的单例,还解决了时钟回拨的问题:
Excel文件如何处理?
一个优秀的rag系统,肯定要支持很多种类型的文件的处理,那么有一种常见的格式,即excel,我们要如何处理他呢? 我们前面介绍过pdf的处理,使用了mineru这个工具,然后市面上也有一些处理excel的方案,是这样的。会先通过Li…
项目中多种格式的文档处理?
PDF ✅MinerU文档处理功能实现 前面我们介绍了如何使用MinerU的网页端进行文件的处理。但是我们总不能每次文档都去网页上处理吧,所以我们需要有工程化的手段来实现。介绍两种方案: 使用API服务 这种方式适合小团队,要处理的…
表格&图片被拆分到多个分块如何解决?
在RAG智能客服中,比较常见的问题就是如果文档中包含了表格、或者图片,如何在分段的时候避免同一个图片、或者表格被切分到不同的分块中。 一旦表格被切分到不同分块,那么后面的分段就会丢失表头的信息,不仅会影响检索的效果,还会影响输出的结…
对话相关表结构设计
Chat 模块是知识引擎中的 AI 对话管理模块,负责管理用户与 AI 之间的对话会话和消息记录。该模块支持完整的对话生命周期管理,包括会话创建、消息存储、RAG 引用记录等功能。 核心实体设计 ChatConversation(会…
虚拟线程+flash模型生成对话标题摘要
在知识库对话系统中,当用户发起新会话时,需要为会话生成一个简洁的标题以便后续识别和管理。由于标题生成依赖 LLM 调用,耗时较长(通常 500ms 2s),为了不阻塞主对话流程,采用异步生成策略。 同步流程(主线程)
意图识别如何实现?如何优化?
意图识别是很多Agent中的核心任务,主要目的从用户输入中准确判断其背后的语义目标(如“查询订单”、“订机票”、“退货申请”等)。 往往很多智能体中,在意图识别之后,会把用户请求路由给不同的子agent来处理,所以意图识别至关重要,…
项目中意图识别提示词的优化
我们在项目中为了做意图识别,写了个提示词,最开始的提示词内容如下:
LangChain4J中的RAG执行流程
在下面这篇文章中,我们介绍过了关于RAG的模块化RAG的支持: ✅LangChain4J中的Modular RAG支持 除了Spring AI中提供了模块化RAG的支持,其实LangChain4J中也有,甚至功能更加强大。 Lang…
如何针对用户的问题做重写?
✅RAG优化技术:问题改写 在RAG的相似度检索中,检索效果的好坏,很大程度取决于用户问题的表达方式。用户输入的提问是不可控的,往往存在模糊、信息缺失、上下文依赖等问题,难以直接高效地匹配到高质量的相关文档块。因此需要在检索前对用户…
如何实现查询路由——检索器路由?
✅RAG优化技术:查询路由 RAG到这里,相信很多人都有了一些基本的了解了,但是其实我想说,还不够。 在回顾一下RAG的概念: RAG(Retrieval Augmented Generation,检索增强生成)从外部知识源中检索相…
混合检索如何实现?
因为我们采用了ElasticSearch来做知识的存储,而且ES同时支持向量检索和关键词检索,我们只需要依赖一个扩展包langchain4j elasticsearch的话,就能使用他的检索器做检索了。 为什么要做混合检索? 只所以…
自定义基于ElasticSearch的向量检索器
ES的语义相似度检索,采用的是KNN的方式,在ES的官网中(https://www.elastic.co/docs/solutions/search/vector/knn ) 提到,ES支持两种 kNN 搜索方法 分别是: 近似 k…
父子分段的切分和检索逻辑
传统固定长度切分会把一个完整的语义单元(如一段说明、一个步骤)切成两半,而我们为了解决这个问题,采用了标题分段+父子分段的方式。 先按 Markdown 标题层级切分,保证每个分段边界在标题处。超长分段保留完整父分段,用于展示时替换…
多级缓存实现chunk的快速检索
在项目中,我们用到了父子分块,来实现更加精准的rag检索。在父子分块的检索中,我们可能会在一起检索中检索到多个子分段,但是他们对应的父分段可能是同一个。 并且这种概率其实是比较高的,因为一般一整个段落的内容都是有关联的,这样就会导致…
使用BGE-ReRanker针对检索结果做重排序
我们之前讲过,LangChain4J中的ContentAggregator是有重排序的实现的,默认采用RRF算法做融合。 DefaultContentAggregator 它的主要工作是融合(Fusion)。当你的 RAG 流程中有…
根据不同的意图实现定制化提示词(单轮对话中版本)
在一个RAG系统中,根据用户的不同意图来定制提示词,是提升系统智能性、准确性和效率的关键。这相当于为系统装上了一个“大脑”,让它能理解用户到底想要什么,从而动态调整自己的行为。 简单来说,用户的提问千差万别,但一个固定的“检索→生成…
项目中问题回答全流程
以下是ChatController.send 方法的全流程介绍。 阶段一:会话管理 1、接收前端传入的 userId、content(用户问题)、conversationId(可选) 2、若 conversationId 为空,则创…
如何把RAG的过程内容返回给用户
我们见过的很多Agent都会要把执行过程返回给用户,而不是直接给出一个冷冰冰的最终答案,本质上是因为 Agent 的工作方式已经从“单次问答”进化到了“多步自主执行”。 把中间过程展示出来,主要有以下几个核心原因: 1. 建立信任与…
如何把引用文档内容返回给用户?
在RAG中,给问题回答增加参考来源是比较常见的做法,一方面可以增加回答的可信度,另外也能让用户直接查看完整文档,获取更多信息,如: 具体实现方式分两步,首先在分段时,需要在每一个分段中记录下来当前分段所属的文档的名称、以及对应的地址…
将模型返回的对话内容,保存在数据库中
前面,我们只是将用户的问题相关的内容保存在数据库了,但是LLM返回的结果我们是没有保存的,这个也需要保存。 1、对话开始时(ChatApplicationService chat),创建一条Assistant消息:
Chunk的metadata怎么设计的?怎么用?
metadata的作用,主要有两方面: 1、记录扩展信息 2、用于数据过滤(如权限控制) ✅RAG优化技术:元数据过滤 什么是元数据 在RAG中,元数据(Metadata) 是附加到文本块(Chunk)上的结构化信息,它是描述了该文…
如何解决模型json格式输出不稳定问题?
如果大家做大模型相关的开发做的早的话,会发现,在以前,模型很不听话,尤其是我们让他输出json格式的时候,经常错误,经常会出现缺少引号、逗号、括号不匹配、包含多余的解释性文字等。 随着模型的不断升级,很多模型已经在这方面做过很多优化…
基于langchain4j的多轮对话的实现
✅LangChain4J中实现持久化记忆 我们之前也介绍过LangChain4j中的记忆,但是也是介绍的基于内存短期记忆,利用LangChain4j也能做持久化的记忆,但是官方没给现成的实现,只能靠我们自己实现。 在LangChai…
根据不同的意图实现定制化提示词(多轮对话版本)
✅根据不同的意图实现定制化提示词(单轮对话中版本) 在一个RAG系统中,根据用户的不同意图来定制提示词,是提升系统智能性、准确性和效率的关键。这相当于为系统装上了一个“大脑”,让它能理解用户到底想要什么,从而动态调整自己的行为。 简…
问题重写支持多轮对话
✅如何针对用户的问题做重写? 我们之前介绍过很多问题重写的方案以及要解决的问题,包括分解、富化、多样化、回溯提示等等。都是很有用的方法,但是实际在应用时,我们并不会让每一个改写都处理一遍,至少不会每一个方案都调用一次LLM,那样就太…
支持多轮对话后的问题重写踩坑与LLM对比
✅基于langchain4j的多轮对话的实现 前面我们介绍过LangChain4J的持久化记忆的能力。基于langchain4j的能力,我们扩展一个自定义的DatabaseChatMemoryStore,采用 Redis 缓存 + …
RAG问题澄清——对话卡片的实现
我们在项目中实现了一个功能:当用户问题缺少必要信息(如车辆信息)时,通过卡片式UI引导用户补充选择,而非直接拒绝或猜测。 流程是:用户发问 → 意图识别 → 信息完备性检查 → 缺信息则返回卡片 → 前端渲染卡片 → 用户选择 → …
支持图片的召回和渲染
我们的RAG系统想要实现如下功能,即在页面上可以展示出图片,并且可以针对图片做召回。 基于我们之前的代码,需要做如下调整。 内容提示词修改 在我们的LLM的RAG的最终的生成的提示词中,增加关于markdown和图片的说明:
如何基于text2sql实现关系型数据查询?
在一个智能客服中,并不是所有的用户问题都是通过知识库做检索的,有一些情况,比如用户关于一些个人信息相关的东西,可能需要通过数据库查询。如以下情况,我问我的保险什么时候到期,这个问题肯定无法从知识库获得,而是应该查询数据库。 know…
如何基于text2cypher实现图数据库的查询
在一个智能客服中,并不是所有的用户问题都是通过知识库做检索的,有一些情况,比如用户关于一些个人信息相关的东西,可能需要通过图数据库查询。如以下情况,我问"哪些车配置了空气悬架系统?" 图关系如下: know engine 采用 三路…
文档如何做多版本管理?
know engine 的文档管理系统实现了一套完整的多版本管理方案,核心目标是:在不停机的前提下,支持知识文档的版本迭代、历史追溯与任意版本切换,同时保证 RAG 检索的向量数据与文档内容始终保持版本一致性。 PS:本章功能演示用…
文档如何实现不停机更新
RAG系统中,文档的更新也是个比较常见的操作。我们也支持文档的更新,支持以下这三种操作: 1、文档的基本信息更新,如名称、描述等。 2、指定分段的内容更新。 3、整个文档的更新 文档基本信息更新 更新范围限制 文档基本信息更新(PU…
钉钉机器人接入做客服答疑
如果你的RAG系统,要实现企业内部答疑,其实不需要单独弄一个网页,直接用办公软件集成进来就行了,比如说钉钉。(就像现在很火的openclaw一样,也是对接到各个IM上) 我们可以借助企业钉钉机器人来实现这样的功能,我们需要对话的时候…
文档检索权限体系实现
know engine 实现了基于角色的知识库检索权限管理,确保不同身份的用户只能检索到其权限范围内的知识文档。权限控制贯穿文档上传 → 切片元数据写入 → 检索过滤全链路,在 Elasticsearch 检索层进行硬过滤,无权文档…
接入登录,实现用户级对话隔离
KnowEngine 项目采用 sa token + Redis 实现双轨登录体系,分别服务于两类用户群体: 网页端客户:通过手机号+密码登录,用于车辆售前/售后咨询 钉钉员工(客服):不通过网页登录,直接通过钉钉机器人提问,系统自…
解决路由错误导致问答失败问题
查询路由,会根据用户的问题,路由到不同的存储类型中做检索,比如关系型数据库,图数据库,以及知识库。 但是,模型存在幻觉,有可能出现路由错的情况,比如应该路由到知识库,但是路由到了关系型数据库。 这种情况,我们通过兜底策略来解决,即我…
解决针对非向量检索导致重排序失败问题
在 RAG 混合检索场景中,系统同时使用多种检索器: 向量/全文检索:Elasticsearch(返回带相似度分数的文本片段) 结构化查询:SQL 检索器、Cypher 检索器(返回精确的表格数据) 当这些结果进入 KnowEngi…