diff --git a/_posts/rag/torchv/2024-07-03-torchv-think.md b/_posts/rag/torchv/2024-07-03-torchv-think.md new file mode 100644 index 0000000..db14bce --- /dev/null +++ b/_posts/rag/torchv/2024-07-03-torchv-think.md @@ -0,0 +1,152 @@ +--- +layout: post +title: 我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈 +description: 我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈 +keywords: TorchV实践,RAG,大模型开发思考 +categories: +- 大模型 +- RAG实践 +- TorchV +tags: +- RAG概述 +- RAG +- 大模型 +- LLM +sidebar_position: 4 +author: 八一菜刀 +data: 2024年07月03日 +--- + + +## 1、前言 + +在6.28/29的稀土掘金开发者大会RAG专场上,我们公司CEO员外代表TorchV分享了我们在《RAG在企业应用中落地的难点与创新》 + +其中最后分享了两个观点: + +- **AI在应用场景落地时有三个特点:功能小、质量高、价值大** +- ![image-20240701143924758](/assets/images/rag/torchv/rag-4/image-20240701143924758.png) +- **如果说做产品是把一横做好的话,那么去做企业落地服务就是一竖,从需求和方案,再到 POC,和最后交付。** +- ![image-20240701143941791](/assets/images/rag/torchv/rag-4/image-20240701143941791.png) + +对于AI应用的三个特点,我们在落地的时候,其实碰到的问题蛮多的,但是用过大模型或者AI产品的人应该都知道,目前基于大模型应用开发的C端产品其实在整体给人的感觉都是相对较小的工具居多,在帮助人类提效这件事上,借助于AI工具,能很好的完成日常繁杂的工作和学习任务。比如**AI翻译**、**网页总结**插件等等。这类产品更多的是偏C端为主,借助于互联网的生态以及开源技术的发展,只要功能/交互满足用户的要求,很快就能打动C端用户进行尝鲜试用甚至付费。 + +但是做B端类的产品,整个交付的过程就明显和C端不一样,在B端我们除了产品本身需要功能足够强大之外,我们还需要做AI的落地交付,这里面包含**私有化定制**/**客户培训**/**私有化部署**/**软硬件适配**等等繁杂的工作,整个交付周期漫长的多。这明显是和上面第二个观点相呼应的,**产品+服务**才能综合服务好B端的客户。 + +本篇是结合我们公司在B端RAG/大模型应用产品的落地交付的场景考虑,以实际场景出发,谈谈我对知识库类产品的技术架构的思考总结。 + +## 2、业务功能/技术组件拆解抽象 + +![image-20240703085452132](/assets/images/rag/torchv/rag-4/image-20240703085452132.png) + +在文章的标题中,我已经标注了范围: **RAG**、**大模型**、**非结构化数据** + +我们从这三个方面出发,在软件层面,我们如何来考虑这些新型的技术名词,将他们从技术/产品功能的角度进行拆解,实现对应的功能交付给我们的客户。 + +从业务的功能诉求来看,主要有几个方面: + +- **知识库**:客户需要将业务数据统一收集处理,形成知识库,以便提供给LLM进行使用 +- **应用中心**:B端客户需要开箱即用的产品,解决实际工作业务中碰到的问题 +- **用户权限**:系统提供企业级灵活可控的权限管理,方便企业客户进行统一管理授权。 +- **多租户**:多租户体系架构是必不可少的,可以保证数据以Schema级别进行隔离,保障数据安全以及上层应用的灵活输出支撑。 +- ... + +而从技术侧考虑,技术人员需要关注的是: + +- **非结构化数据的处理**:平台需要支持多种多样的非结构化数据的提取处理工作,将整个文档内容进行chunking、embedding进入数据库,以便进行搜索 + - **文件类型广度**:提供众多的非结构化数据文档(PDF/PPT/WORD等)的提取支持,是打动B端客户的有利吸引点, + - **文件解析精度**:以PDF/PPT/Word为首的文档解析工作困难重重,如何在解析的工作上更进一步,从根源上减少模型在利用已知数据的幻觉问题 + - **任务调度**:数据的处理依靠稳定的任务调度平台,保证数据处理的最终有序执行。 +- **模型服务**:从LLM大语言模型、Reranker模型、embedding、OCR模型、视觉模型等等,**保证模型的幂等输出**,为上层应用提供稳定可靠的服务支撑。 + - **LLM模型**:提供一系列**Agent服务**,保证上层业务能够灵活调用大模型获取满意的结果 + - **ReRanker模型**:重排序模型是问答二阶段召回提高准确率的关键手段,不可忽虑 + - **Embedding模型**:向量化嵌入,提供对知识文本的表征提取向量工作,不可忽虑 + - **OCR/视觉模型**:辅助非结构化数据提取在规则提取不满足的情况下,启动OCR及视觉模型,增强非结构化数据的提供效果 +- **向量数据库(VectorDB)**: 需要结合实际业务诉求,从性能/空间/生态等多方面考量VectorDB等选型 + +技术的角度拆分,其实技术人员关注的点非常的多,每一项工作其实都可以是独立的中间件产品,要把这些全部整合到一块,并非易事。 + +## 3、微服务/分布式/云原生? + +写过Java的估计对上面这三个名词都已经滚瓜乱熟了,我记得很早之前,说面试你如果不会微服务,那都找不到工作(PS:现在好像不管你会什么,也同样都找不到)😂。 + +对于AI应用,可能更多的软件生态是由Python带动起来的,包括一些工具库LangChain、LlamaIndex等都是Python,虽然Java中也不乏有一些,比如LangChain4j、Spring-AI等组件,都是后起之秀,在整个生态稳定性等方面确实是落后了一节。 + +但可能很多人都在用过LangChain等框架后有一个共识,那就是当作工具用没有问题,但是上生产?问题太多了。我觉得主要的几个点: + +- LangChain的过度封装,对于应用层而言,不管是Agent,还是RAG,其实蛮简单的一件事情,和大模型API接口对接就好了,但是你去看LangChain的源码,整个调用链路封装的极其复杂,改都没法改。 +- 上层的业务需求变化太大了,有时候是需要结合自己公司的实际业务情况来进行处理的,这种情况下,还不如自己写来的快,其实调用的链路并不复杂 +- 就稳定性/事务/数据一致性而言,Python作为企业服务接口主语言是否合适呢? + +而我们今天讨论的是整个产品的技术架构的选择,其实在上面业务功能/技术组件抽象那一节,我们已经拆分了功能和技术点,从技术点去看,这已经是一个集众多服务于一体的综合技术解决方案了。在应用层面的功能,我们是否还需要像以前那样,整一套微服务架构出来来开发业务功能? + +我的个人看法是:**根据团队配置,微服务可用可不用。但是应用程序必须天然分布式,支持横向扩展集群,弹性伸缩。** + +> 目前这个环境,项目搞微服务,最后的困境可能就是所有服务都是你一个人负责,写完a服务写b服务,再来个rpc调用,还要考虑数据熔断、可用性等等,小团队我觉得完全没必要折腾! + +主要考虑的点: + +**1、海量非结构化数据处理的提效** + +在处理RAG产品类中,非结构化数据的处理除了快速解析之外,还需要将文本进行向量化,而我们在技术架构中需要能够快速的处理这些文件,通过Pipeline的方式,将非结构化数据最终存储到向量数据库中,这里面传统的做法不得不用消息中间件MQ,而应用层面的程序则可以通过考虑弹性伸缩的方式,扩充消费节点,以提高整体的处理效率 + +**2、海量向量数据的存储/计算召回效率** + +当我们对非结构化数据进行提取后,需要经过Embedding模型进行向量化,这里面还涉及到文本的Chunking分块,所以底层向量数据的存储和计算必然是一个需要更全面的考虑向量数据库中间件,这其中包括:向量召回的性能、数据的存储/备份、多租户Schema级别数据权限等等 + +**3、数据最终一致性** + +数据的Embedding处理、大模型调度扣费、缓存等等,在目前已经众多服务组件拆分的情况下,整个数据的处理任务我觉得需要保证数据的最终一致性,在分布式场景下,多节点处理时需要特别注意。 + +**4、应用功能原子性(云原生)** + +整个应用层的功能,我觉得需要**保持独立,并且保障稳定性**,这点其实我觉得在私有化部署/交付的环节比较奏效。如果你是一名运维或者主力开发者,在一个完全内网隔离的环境下部署时,你会体会到这种便捷。 + +总之,我觉得在应用层面服务,服务端应该做的是:**减少配置、轻量化、稳定** + +## 4、编程语言/中间件选择? + +我们团队目前的开发语言是Java+Python的组合,主要有职责分工: + +- Java:上层业务应用的API接口,任务调度、数据处理等等 +- Python:和模型、数据处理、NLP等相关任务以接口的形式开放出来,API接口是无状态的,所有的数据状态流转都在Java端实现 + +这里面很多开发可能会有一些担忧,对于Java语言的选择,是否在目前的RAG/大模型领域合适?其实最困惑的就是非结构化数据的处理,可能很多开发者看到目前开源的众多组件或者平台,都是Python的主技术栈,认为Java处理不了,其实这是完全有误区的,对于最难处理的PDF文件提取,**Apache PDFBox**绝对是值得你深挖的一个组件,当然Python本来就擅长数据处理/分析,可以根据团队的配置进行执行选择,这里面我觉得主要考虑的几个点: + +**1、团队人员配置** + +根据团队当前的主流编程语言去做技术架构上的选型和决策,并没有绝对意义上的以哪个编程语言为主,Java、Python、Go、NodeJS、TypeScript等等都可以。 + +**2、软件生态&技术成熟度** + +上层应用产品的开发,肯定首先要考虑有哪些成熟的中间件和组件,来开发完成这一众多的需求,总不能从0到1造轮子,造轮子固然能提升开发人员的水平技能,但是在AI日益发展的今天,为公司产品尽早的找到PMF才是首要任务。需要综合考虑。 + +其他的编程语言我不了解,就非结构化数据的解析这一块,其实Python和Java都相对更加丰富和稳 定。 + +Java语言中比较好用的包括:Apache PDFBox、POI、Tika + +Python中包括:PyMuPDF、pdfplumber、pypdf、camelot、python-docx等等 + +**3、稳定性/集群/高可用** + +> 嗯,这里没有高并发,因为大家都没卡😂 + +大模型的产品相比较传统的业务在这点上并没有 太多的区别,稳定性/集群等特点也是需要的,技术人员在选择中间件时,也应当考虑这一点。 + +例如MQ消息中间件、缓存Redis等等 + +**4、部署实施/交付** + +没错,最后一步部署实施这个环节也需要考虑,Docker确实能带来极大的便利,但是成本也是需要考量的,目前的Python生态打包整个Docker,压缩包动辄2、3G起步,其实也是蛮头疼的,如果你是使用K8s调度来部署,k8s拉取一个10G的镜像也不是那么快的😂 + +## 5、总结 + +AI应用是一个需要快速试错、功能强大的某一个点去突破,技术架构上,也应当考虑整体的开发效率、生态等等。 + +这让我想起来十几年前的jQuery,一经面世,得到众多开发者的喜爱,经典名言: + +```shell +Write Less, Do More!!! +``` + +在大模型日益健壮发展的同时,我们的技术架构,是否也应该做一次瘦身呢? \ No newline at end of file diff --git a/_posts/rag/torchv/2024-07-08-torchv-pdf-01.md b/_posts/rag/torchv/2024-07-08-torchv-pdf-01.md new file mode 100644 index 0000000..21816e5 --- /dev/null +++ b/_posts/rag/torchv/2024-07-08-torchv-pdf-01.md @@ -0,0 +1,140 @@ +--- +layout: post +title: RAG工程实践拦路虎之一:PDF格式解析杂谈 +description: RAG工程实践拦路虎之一:PDF格式解析杂谈 +keywords: TorchV实践,RAG,PDF格式解析杂谈 +categories: +- 大模型 +- RAG实践 +- TorchV +tags: +- RAG概述 +- RAG +- 大模型 +- LLM +sidebar_position: 4 +author: 八一菜刀 +data: 2024年07月08日 +--- + +## 背景 + +PDF(Portable Document Format)是一种广泛用于文档交换的文件格式,由Adobe Systems开发。它具有跨平台性、固定布局和易于打印等特点,因此在商业、学术和个人领域广泛应用。然而,PDF文件的解析一直是一个具有挑战性的问题,因为其内部结构的复杂性和多样性,使得提取其中的文本、图片和表格等内容并不是一件容易的事情。 + +## 技术方案 + +在目前的PDF文件解析领域中,我们可以将其大致分为以下几类技术方案: + +- **LLM/视觉大模型解析**:LLM(Large Language Model)大型语言模型在近年来的发展中,展现出了强大的语言理解和生成能力。通过训练大规模的神经网络,可以实现对PDF文件中文字内容的理解和提取,这种方法尤其适用于那些布局复杂、内容丰富的PDF文件。 +- **OCR模型**:光学字符识别(OCR)模型专门设计用于将PDF文件中的图像转换为可编辑的文本。这种技术在处理扫描版或图像化的PDF文档时尤其有用。 +- **传统规则提取**:传统的PDF解析方式可能包括基于规则的文本提取、图像处理和表格识别等方法。虽然这些方法可能不如深度学习模型那样灵活,但在某些情况下仍然是有效的选择。 + +各个解决方案目前可能需要配合使用,因为PDF格式本身的复杂程度,一项技术方案可能是**无法100%满足业务需求**的,这里面需要考虑的是: + +- **文档提取还原度**:通过技术手段,能够完整的提取PDF中的各项元素,包括文本、表格、图片、链接、图形、目录等等信息 +- **高效/💰成本**:在RAG知识库问答的产品中,考虑到文本还需要Embedding的过程,因此在提取过程中如何更高效,成本更低也是需要着重考虑到事项。 +- **稳定/幂等**:我们知道大模型可能是出现幻觉的,如果用大模型来提取PDF中的内容,是否能足够保证稳定性。 + +当我们处理解析PDF时,我们需要可以讲每一项的难点都进行拆分,从需求出发,逐一进行攻破,找到解决方案。 + +其实我觉得技术人员如果能**通过技术手段确定PDF中的Block(块)以及阅读顺序,按Block(块)进行输出转换(Markdown/Html等),这里面包括的Block块元素:文本、图片、表格等等。那么这个提取的效果就会达到我们的最优**。 + +而这个目标是我们接下来要重点讨论的。 + +## 技术难点 + +在考虑解析PDF文件时,我们需要根据当前的技术栈发展情况,并结合实际的业务诉求,综合考量这其中的技术难点,因为每一项技术难点所涉及的技术方案都会需要一个算法/或者技术手段去突破。 + +而开发者从解析的效果去考虑,可以从简单的做起,逐步突破难点,这对于开发人员自身的自信心提升也是一种正向的导向。在整个PDF解析过程中,我觉得以下几项是比较难处理的: + +- **布局解析困难**:PDF文件的布局可能会因为不同的作者、工具或用途而有所不同,因此解析其布局是一个具有挑战性的任务。 +- **格式错综复杂**:PDF文件中可能包含各种格式的内容,包括**文字**、**图像**、**表格**等,因此解析其内容需要考虑到这种多样性和复杂性。 +- **复合表格**:纵向/横向合并的复杂表格,在PDF中进行抽象还原是最难处理的问题之一 +- **文本、图片、表格顺序提取**:提取PDF文件中的文本、图片和表格,并确保它们的顺序正确性,是一个需要解决的重要问题。 +- **文档结构还原**:还原PDF文件的文档结构,包括标题、目录等信息,是实现自动化文档处理和理解的关键步骤之一。 +- **元素重叠**:从PDF100%效果还原的角度考虑,图片/文本之间的重叠,图片合并,合并后不失真等,也是需要考虑的事项之一 +- **元数据提取**:在PDF中隐藏的元数据信息是RAG产品的关键数据,比如链接、目录、字体等等 +- **扫描件**:PDF中如果是扫描件,依靠OCR模型可能是无法有效的提取,这里面包含了清晰度、模型的稳定性等等问题 +- **Latex公式提取**:在一些特殊领域,PDF文本中包含了Latex等数学公式。通过完整的提取和转换是对RAG问答的有效补充 + +## 技术可行性 + +我们从解析PDF的技术可行性角度,考虑哪些方面值得我们重点关注和突破: + +- **文字提取能力,逐行提取**:确保能够准确地提取PDF文件中的文字内容,并按照正确的顺序进行排列和输出,避免文字乱码(字体)。 +- **简单/复杂表格完整提取**:对PDF文件中的表格进行完整提取,包括表格内的内容和格式。 +- **图片提取/合并**:提取PDF文件中的图片,并保留其原始质量和格式。 +- **文档布局(Block块的标识)识别**:识别PDF文件的布局,包括页面的排列方式、文本和图片的位置等信息。 +- **文档结构识别(标题、目录),内容顺序输出**:识别PDF文件的结构,包括标题、目录等信息,并确保输出内容的顺序正确。 +- **转换为Markdown格式**:将解析后的PDF文件内容转换为Markdown格式,以便于后续的处理和分享。 + +## 开源技术方案 + +结合上面的技术难点/方案及可行性上去分析,我们可以看看目前开源的技术组件中,有哪些是我们可以考虑进行结合的。 + +因为目前TorchV系统主要以Java+Python双语作为底层的应用开发语言,接下来我们可以看看在这两个编程语言中,有哪些开源的方案可以使用。 + +### Java生态 + +在Java生态中,对于PDF组件处理的开源方案不多见,Apache PDFBOX是当前最强的,也是最好的 + +| 名称 | 地址 | 说明 | +| ------------- | ---------------------------------------- | ------------------------------------------------------------ | +| Apache PDFBox | [https://github.com/apache/pdfbox](https://github.com/apache/pdfbox) | 提供开箱即用的文本、图片内容提取方式,并且可以基于Stream接口重写各项元素的解析实现,**并能输出元素的坐标信息**。开发者可以根据元素的坐标信息结合算法进行内容的高度还原。唯一的缺点是没有表格组件提取的API供开发人员使用。 | +| tabula-java | [https://github.com/tabulapdf/tabula-java](https://github.com/tabulapdf/tabula-java) | 基于Apache PDFBOx组件的表格提取实现 | + +### Python生态 + +Python生态的PDF提取组件还是蛮多的,不过也是有不同的侧重,比如pdfplumber、camelot等都专注在表格的提取上,提供了开箱即用的方案。 + +| 名称 | 地址 | 说明 | +| :----------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------ | +| pypdf | [https://github.com/py-pdf/pypdf](https://github.com/py-pdf/pypdf) | 一个纯Python PDF库,能够分割、合并、裁剪和转换PDF文件的页面 | +| PyMuPDF(AGPL) | [https://github.com/pymupdf/PyMuPDF](https://github.com/pymupdf/PyMuPDF) | 高性能 Python 库,用于 PDF(和其他)文档的数据提取、分析、转换和操作。 | +| **[pdfplumber](https://github.com/jsvine/pdfplumber)**(MIT) | [https://github.com/jsvine/pdfplumber](https://github.com/jsvine/pdfplumber) | 查看 PDF 以获取有关每个字符、矩形、线条等的详细信息,并轻松提取文本和表格。 | +| **[camelot](https://github.com/camelot-dev/camelot)**(MIT) | [https://github.com/camelot-dev/camelot](https://github.com/camelot-dev/camelot) | 专注于PDF中表格的提取,包括复杂的表格 | + +### OCR生态/大模型 + +在上面Python和Java生态库的开源组件,基本都是针对文字的PDF处理为主,当我们的PDF是扫描件时,那上面的组件统统失效,都提取不出来文本信息。 + +此时就需要用到OCR的模型进行提取。 + +考虑到如果是OCR提取,那么最终的目的是将PDF文件Page页码内容提取出完成的图片Image,所以本质上是对图片内容的理解 + +可以考虑的开源组件如下: + +| 名称 | 地址 | 说明 | +| ------------------- | ------------------------------------------ | ------------------------------------------------------------ | +| marker(GPL) | https://github.com/VikParuchuri/marker | 基于模型将PDF文件内容提取为Markdown格式 | +| surya(GPL) | https://github.com/VikParuchuri/surya | OCR、布局分析、阅读顺序、线条检测(支持90 多种语言) | +| tesseract(Apache 2) | https://github.com/tesseract-ocr/tesseract | 老牌OCR组件,支持100多种语言 | +| RapidOCR(Apache) | https://github.com/RapidAI/RapidOCR | 基于 ONNXRuntime、OpenVION 和 PaddlePaddle 的出色 OCR 多种编程语言工具包。 | +| PaddleOCR(Apache) | https://github.com/PaddlePaddle/PaddleOCR | 基于飞桨的出色多语言OCR工具包(实用的超轻量级OCR系统,支持80+语言识别) | +| EasyOCR(Apache ) | https://github.com/JaidedAI/EasyOCR | Python\C++开发,支持80多种语言OCR识别 | + +## 技术准备/细节 + +在解析PDF时,我们也会有一些其他方面的知识储备,以便我们快速应对不同的业务需求及应用产品形态。 + +**1、图形类API**:不管是Java还是Python里面,对于处理PDF中间件的部分,都需要对图形类的API/算法熟悉和掌握,这里面包含图形的转换、缩放、矩阵坐标、截取等等,都会在PDF提取的过程中使用到。 + +**2、PDF标准**:在处理PDF中,结合开源的技术中间件,对于PDF的ISO标准,我们也是需要了解的,这样更加有利于开发人员理解中间件的代码写法及含义。 + +**3、边/线/矩阵算法等**:对于文本/边框的聚类算法等,在根据元素坐标高效还原时,利用高效的算法可以提高解析速度以及内容还原度 + +**4、OCR/LLM模型等**:了解学习在用OCR/LLM模型分析布局、边界检测等等技术上的一些算法及数据工程上的实践 + +5、**PDF页面旋转**:有时候原PDF可能会有旋转(0、90、180、270度),需先校正后,再次提取内容 + +6、**字体/乱码**:系统/服务器中缺失PDF中的字体,导致文本提取乱码 + +## 最后 + +本文从大的方面简单概括了在PDF解析处理过程中的技术方案/难点/开源技术方案等内容,后面我会从一些细节方面来逐一分享我们在构建TorchV产品时,解析PDF文件过程中的一些问题及技术实践,包括对表格的提取,感兴趣的可以关注我们😁。 + +另外,我们团队提供了一个PDF解析的Demo地址,针对文本类的PDF(暂时不支持扫描件),可以进行试用体验。 + +地址:[http://tabletest.torchv.com:8010/](http://tabletest.torchv.com:8010/) + +![image-20240706170720200](/assets/images/rag/torchv/pdf-01/image-20240706170720200.png) \ No newline at end of file diff --git a/_site/2024/04/01/torchv-summary-01/index.html b/_site/2024/04/01/torchv-summary-01/index.html index d7b4ce2..b275dfa 100644 --- a/_site/2024/04/01/torchv-summary-01/index.html +++ b/_site/2024/04/01/torchv-summary-01/index.html @@ -117,9 +117,9 @@

创业:大模型RAG系统三个月的开发心

1. 前言

-

自从和员外从上家公司离职后,我们就自己搞公司投入到了RAG大模型的AI产品应用的开发中,这中间有一个春节,前后的总时间大概是三个月左右,在这三个月期间,基本是昼夜兼程啊,到今天3月底结束,产品目前看是有了一个基础的雏形。

+

自从和员外上家公司离职后,我们就自己搞公司投入到了RAG大模型的AI产品应用的开发中,这中间有一个春节,前后的总时间大概是三个月左右,在这三个月期间,基本是昼夜兼程啊,到今天3月底结束,产品目前看是有了一个基础的雏形。

-

在这期间,员外负责整个产品的营销、商业客户的洽谈等方面的内容,我和阿包负责整体的技术架构搭建,代码从0-1的编写,我们是1月初的样子,产品初步上线了一个版本,开始接受企业客户的试用,这让我们接受到了大量的需求,以及我们产品在目前的市场环境中还存在哪些竞争力不足需要改进的地方。

+

在这期间,员外负责整个产品的营销、商业客户的洽谈等方面的内容,我和阿包负责整体的技术架构搭建,代码从0-1的编写,我们是在24年1月26,产品初步上线了一个版本,开始接受企业客户的试用,这让我们接受到了大量的需求,以及我们产品在目前的市场环境中还存在哪些竞争力不足需要改进的地方。

三个月时间过去了,在我们的TorchV AI 产品初步成型之际,和大家分享一下开发RAG、LLM系统以来的一些心得和经验。

@@ -240,14 +240,14 @@

3.2 检索生成

4. 技术&产品领导驱动商业的发展

-

做RAG这类AI应用开发以来,感受最深的是和之前做项目并不相同,一方面是技术栈发展较新,新技术带来的技术变革,需求层出不穷,另外,目前的AI应用,我觉得更多的是技术&产品来领导驱动商业的发展,这和普通软件企业的开发流程或许有所不同。很多做项目集成的公司,做的项目未必是有价值的,可能销售人员只需要搞定某个项目非常重要的人,项目就拿下了,这时软件开发人员只需要按功能清单进行开发即可。但是软件功能未必是有价值的。

+

做RAG这类AI应用开发以来,感受最深的是和之前做产品/项目并不相同,一方面是技术栈发展较新,新技术带来的技术变革存在非常大的挑战,有了大模型之后,需求&想法也是五花八门,另外,目前的AI应用,我觉得更多的是技术&产品来领导驱动商业的发展,这和普通软件企业的开发流程或许有所不同。

这里我觉得几点非常重要:

我们团队内部经过这段时间的迭代,也碰了很多客户的需求,团队的方向也是在发展中不断的进行调整。

@@ -346,6 +346,13 @@

6. 总结

TorchV.AI目前是刚起步阶段,也欢迎更多的企业客户试用,合作!!!

+
+

如果您有商务合作需求:

+ +

请扫码添加以下微信(员外🔥TorchV),并请您告知您的称呼 和 企业名称 。 +

+
+

我们的官网地址:https://www.torchv.com

7. References

diff --git a/_site/2024/07/03/torchv-think/index.html b/_site/2024/07/03/torchv-think/index.html new file mode 100644 index 0000000..710380d --- /dev/null +++ b/_site/2024/07/03/torchv-think/index.html @@ -0,0 +1,439 @@ + + + + + + + 我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈 — 八一菜刀 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+

我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈

+
+ + + 2024/07/03 + + + + + + 大模型 + + + + + RAG实践 + + + + + TorchV + + + + + 浏览 + +
+
+
+
+
+
+ +
+
+
+
+

1、前言

+ +

在6.28/29的稀土掘金开发者大会RAG专场上,我们公司CEO员外代表TorchV分享了我们在《RAG在企业应用中落地的难点与创新》

+ +

其中最后分享了两个观点:

+ +
    +
  • AI在应用场景落地时有三个特点:功能小、质量高、价值大
  • +
  • image-20240701143924758
  • +
  • 如果说做产品是把一横做好的话,那么去做企业落地服务就是一竖,从需求和方案,再到 POC,和最后交付。
  • +
  • image-20240701143941791
  • +
+ +

对于AI应用的三个特点,我们在落地的时候,其实碰到的问题蛮多的,但是用过大模型或者AI产品的人应该都知道,目前基于大模型应用开发的C端产品其实在整体给人的感觉都是相对较小的工具居多,在帮助人类提效这件事上,借助于AI工具,能很好的完成日常繁杂的工作和学习任务。比如AI翻译网页总结插件等等。这类产品更多的是偏C端为主,借助于互联网的生态以及开源技术的发展,只要功能/交互满足用户的要求,很快就能打动C端用户进行尝鲜试用甚至付费。

+ +

但是做B端类的产品,整个交付的过程就明显和C端不一样,在B端我们除了产品本身需要功能足够强大之外,我们还需要做AI的落地交付,这里面包含私有化定制/客户培训/私有化部署/软硬件适配等等繁杂的工作,整个交付周期漫长的多。这明显是和上面第二个观点相呼应的,产品+服务才能综合服务好B端的客户。

+ +

本篇是结合我们公司在B端RAG/大模型应用产品的落地交付的场景考虑,以实际场景出发,谈谈我对知识库类产品的技术架构的思考总结。

+ +

2、业务功能/技术组件拆解抽象

+ +

image-20240703085452132

+ +

在文章的标题中,我已经标注了范围: RAG大模型非结构化数据

+ +

我们从这三个方面出发,在软件层面,我们如何来考虑这些新型的技术名词,将他们从技术/产品功能的角度进行拆解,实现对应的功能交付给我们的客户。

+ +

从业务的功能诉求来看,主要有几个方面:

+ +
    +
  • 知识库:客户需要将业务数据统一收集处理,形成知识库,以便提供给LLM进行使用
  • +
  • 应用中心:B端客户需要开箱即用的产品,解决实际工作业务中碰到的问题
  • +
  • 用户权限:系统提供企业级灵活可控的权限管理,方便企业客户进行统一管理授权。
  • +
  • 多租户:多租户体系架构是必不可少的,可以保证数据以Schema级别进行隔离,保障数据安全以及上层应用的灵活输出支撑。
  • +
  • +
+ +

而从技术侧考虑,技术人员需要关注的是:

+ +
    +
  • 非结构化数据的处理:平台需要支持多种多样的非结构化数据的提取处理工作,将整个文档内容进行chunking、embedding进入数据库,以便进行搜索 +
      +
    • 文件类型广度:提供众多的非结构化数据文档(PDF/PPT/WORD等)的提取支持,是打动B端客户的有利吸引点,
    • +
    • 文件解析精度:以PDF/PPT/Word为首的文档解析工作困难重重,如何在解析的工作上更进一步,从根源上减少模型在利用已知数据的幻觉问题
    • +
    • 任务调度:数据的处理依靠稳定的任务调度平台,保证数据处理的最终有序执行。
    • +
    +
  • +
  • 模型服务:从LLM大语言模型、Reranker模型、embedding、OCR模型、视觉模型等等,保证模型的幂等输出,为上层应用提供稳定可靠的服务支撑。 +
      +
    • LLM模型:提供一系列Agent服务,保证上层业务能够灵活调用大模型获取满意的结果
    • +
    • ReRanker模型:重排序模型是问答二阶段召回提高准确率的关键手段,不可忽虑
    • +
    • Embedding模型:向量化嵌入,提供对知识文本的表征提取向量工作,不可忽虑
    • +
    • OCR/视觉模型:辅助非结构化数据提取在规则提取不满足的情况下,启动OCR及视觉模型,增强非结构化数据的提供效果
    • +
    +
  • +
  • 向量数据库(VectorDB): 需要结合实际业务诉求,从性能/空间/生态等多方面考量VectorDB等选型
  • +
+ +

技术的角度拆分,其实技术人员关注的点非常的多,每一项工作其实都可以是独立的中间件产品,要把这些全部整合到一块,并非易事。

+ +

3、微服务/分布式/云原生?

+ +

写过Java的估计对上面这三个名词都已经滚瓜乱熟了,我记得很早之前,说面试你如果不会微服务,那都找不到工作(PS:现在好像不管你会什么,也同样都找不到)😂。

+ +

对于AI应用,可能更多的软件生态是由Python带动起来的,包括一些工具库LangChain、LlamaIndex等都是Python,虽然Java中也不乏有一些,比如LangChain4j、Spring-AI等组件,都是后起之秀,在整个生态稳定性等方面确实是落后了一节。

+ +

但可能很多人都在用过LangChain等框架后有一个共识,那就是当作工具用没有问题,但是上生产?问题太多了。我觉得主要的几个点:

+ +
    +
  • LangChain的过度封装,对于应用层而言,不管是Agent,还是RAG,其实蛮简单的一件事情,和大模型API接口对接就好了,但是你去看LangChain的源码,整个调用链路封装的极其复杂,改都没法改。
  • +
  • 上层的业务需求变化太大了,有时候是需要结合自己公司的实际业务情况来进行处理的,这种情况下,还不如自己写来的快,其实调用的链路并不复杂
  • +
  • 就稳定性/事务/数据一致性而言,Python作为企业服务接口主语言是否合适呢?
  • +
+ +

而我们今天讨论的是整个产品的技术架构的选择,其实在上面业务功能/技术组件抽象那一节,我们已经拆分了功能和技术点,从技术点去看,这已经是一个集众多服务于一体的综合技术解决方案了。在应用层面的功能,我们是否还需要像以前那样,整一套微服务架构出来来开发业务功能?

+ +

我的个人看法是:根据团队配置,微服务可用可不用。但是应用程序必须天然分布式,支持横向扩展集群,弹性伸缩。

+ +
+

目前这个环境,项目搞微服务,最后的困境可能就是所有服务都是你一个人负责,写完a服务写b服务,再来个rpc调用,还要考虑数据熔断、可用性等等,小团队我觉得完全没必要折腾!

+
+ +

主要考虑的点:

+ +

1、海量非结构化数据处理的提效

+ +

在处理RAG产品类中,非结构化数据的处理除了快速解析之外,还需要将文本进行向量化,而我们在技术架构中需要能够快速的处理这些文件,通过Pipeline的方式,将非结构化数据最终存储到向量数据库中,这里面传统的做法不得不用消息中间件MQ,而应用层面的程序则可以通过考虑弹性伸缩的方式,扩充消费节点,以提高整体的处理效率

+ +

2、海量向量数据的存储/计算召回效率

+ +

当我们对非结构化数据进行提取后,需要经过Embedding模型进行向量化,这里面还涉及到文本的Chunking分块,所以底层向量数据的存储和计算必然是一个需要更全面的考虑向量数据库中间件,这其中包括:向量召回的性能、数据的存储/备份、多租户Schema级别数据权限等等

+ +

3、数据最终一致性

+ +

数据的Embedding处理、大模型调度扣费、缓存等等,在目前已经众多服务组件拆分的情况下,整个数据的处理任务我觉得需要保证数据的最终一致性,在分布式场景下,多节点处理时需要特别注意。

+ +

4、应用功能原子性(云原生)

+ +

整个应用层的功能,我觉得需要保持独立,并且保障稳定性,这点其实我觉得在私有化部署/交付的环节比较奏效。如果你是一名运维或者主力开发者,在一个完全内网隔离的环境下部署时,你会体会到这种便捷。

+ +

总之,我觉得在应用层面服务,服务端应该做的是:减少配置、轻量化、稳定

+ +

4、编程语言/中间件选择?

+ +

我们团队目前的开发语言是Java+Python的组合,主要有职责分工:

+ +
    +
  • Java:上层业务应用的API接口,任务调度、数据处理等等
  • +
  • Python:和模型、数据处理、NLP等相关任务以接口的形式开放出来,API接口是无状态的,所有的数据状态流转都在Java端实现
  • +
+ +

这里面很多开发可能会有一些担忧,对于Java语言的选择,是否在目前的RAG/大模型领域合适?其实最困惑的就是非结构化数据的处理,可能很多开发者看到目前开源的众多组件或者平台,都是Python的主技术栈,认为Java处理不了,其实这是完全有误区的,对于最难处理的PDF文件提取,Apache PDFBox绝对是值得你深挖的一个组件,当然Python本来就擅长数据处理/分析,可以根据团队的配置进行执行选择,这里面我觉得主要考虑的几个点:

+ +

1、团队人员配置

+ +

根据团队当前的主流编程语言去做技术架构上的选型和决策,并没有绝对意义上的以哪个编程语言为主,Java、Python、Go、NodeJS、TypeScript等等都可以。

+ +

2、软件生态&技术成熟度

+ +

上层应用产品的开发,肯定首先要考虑有哪些成熟的中间件和组件,来开发完成这一众多的需求,总不能从0到1造轮子,造轮子固然能提升开发人员的水平技能,但是在AI日益发展的今天,为公司产品尽早的找到PMF才是首要任务。需要综合考虑。

+ +

其他的编程语言我不了解,就非结构化数据的解析这一块,其实Python和Java都相对更加丰富和稳 定。

+ +

Java语言中比较好用的包括:Apache PDFBox、POI、Tika

+ +

Python中包括:PyMuPDF、pdfplumber、pypdf、camelot、python-docx等等

+ +

3、稳定性/集群/高可用

+ +
+

嗯,这里没有高并发,因为大家都没卡😂

+
+ +

大模型的产品相比较传统的业务在这点上并没有 太多的区别,稳定性/集群等特点也是需要的,技术人员在选择中间件时,也应当考虑这一点。

+ +

例如MQ消息中间件、缓存Redis等等

+ +

4、部署实施/交付

+ +

没错,最后一步部署实施这个环节也需要考虑,Docker确实能带来极大的便利,但是成本也是需要考量的,目前的Python生态打包整个Docker,压缩包动辄2、3G起步,其实也是蛮头疼的,如果你是使用K8s调度来部署,k8s拉取一个10G的镜像也不是那么快的😂

+ +

5、总结

+ +

AI应用是一个需要快速试错、功能强大的某一个点去突破,技术架构上,也应当考虑整体的开发效率、生态等等。

+ +

这让我想起来十几年前的jQuery,一经面世,得到众多开发者的喜爱,经典名言:

+ +
Write Less, Do More!!!
+
+ +

在大模型日益健壮发展的同时,我们的技术架构,是否也应该做一次瘦身呢?

+ +
+ +
+ + + + + +
+ + + + + + +
+
+
+ +

站内搜索

+ + +
    + + + + + + + + + +
    +
    +

    TorchV Bot开放试用中......

    +
    +
    + +
    +
    +
    +
    +

    最新内容,关注“八一菜刀”公众号

    +
    +
    +
    + +

    Table of Contents

    +
    +
    + + +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    + + + + + + + + + + + + + + + + + + diff --git a/_site/2024/07/08/torchv-pdf-01/index.html b/_site/2024/07/08/torchv-pdf-01/index.html new file mode 100644 index 0000000..9d87633 --- /dev/null +++ b/_site/2024/07/08/torchv-pdf-01/index.html @@ -0,0 +1,492 @@ + + + + + + + RAG工程实践拦路虎之一:PDF格式解析杂谈 — 八一菜刀 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +
    +

    RAG工程实践拦路虎之一:PDF格式解析杂谈

    +
    + + + 2024/07/08 + + + + + + 大模型 + + + + + RAG实践 + + + + + TorchV + + + + + 浏览 + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +

    背景

    + +

    PDF(Portable Document Format)是一种广泛用于文档交换的文件格式,由Adobe Systems开发。它具有跨平台性、固定布局和易于打印等特点,因此在商业、学术和个人领域广泛应用。然而,PDF文件的解析一直是一个具有挑战性的问题,因为其内部结构的复杂性和多样性,使得提取其中的文本、图片和表格等内容并不是一件容易的事情。

    + +

    技术方案

    + +

    在目前的PDF文件解析领域中,我们可以将其大致分为以下几类技术方案:

    + +
      +
    • LLM/视觉大模型解析:LLM(Large Language Model)大型语言模型在近年来的发展中,展现出了强大的语言理解和生成能力。通过训练大规模的神经网络,可以实现对PDF文件中文字内容的理解和提取,这种方法尤其适用于那些布局复杂、内容丰富的PDF文件。
    • +
    • OCR模型:光学字符识别(OCR)模型专门设计用于将PDF文件中的图像转换为可编辑的文本。这种技术在处理扫描版或图像化的PDF文档时尤其有用。
    • +
    • 传统规则提取:传统的PDF解析方式可能包括基于规则的文本提取、图像处理和表格识别等方法。虽然这些方法可能不如深度学习模型那样灵活,但在某些情况下仍然是有效的选择。
    • +
    + +

    各个解决方案目前可能需要配合使用,因为PDF格式本身的复杂程度,一项技术方案可能是无法100%满足业务需求的,这里面需要考虑的是:

    + +
      +
    • 文档提取还原度:通过技术手段,能够完整的提取PDF中的各项元素,包括文本、表格、图片、链接、图形、目录等等信息
    • +
    • 高效/💰成本:在RAG知识库问答的产品中,考虑到文本还需要Embedding的过程,因此在提取过程中如何更高效,成本更低也是需要着重考虑到事项。
    • +
    • 稳定/幂等:我们知道大模型可能是出现幻觉的,如果用大模型来提取PDF中的内容,是否能足够保证稳定性。
    • +
    + +

    当我们处理解析PDF时,我们需要可以讲每一项的难点都进行拆分,从需求出发,逐一进行攻破,找到解决方案。

    + +

    其实我觉得技术人员如果能通过技术手段确定PDF中的Block(块)以及阅读顺序,按Block(块)进行输出转换(Markdown/Html等),这里面包括的Block块元素:文本、图片、表格等等。那么这个提取的效果就会达到我们的最优

    + +

    而这个目标是我们接下来要重点讨论的。

    + +

    技术难点

    + +

    在考虑解析PDF文件时,我们需要根据当前的技术栈发展情况,并结合实际的业务诉求,综合考量这其中的技术难点,因为每一项技术难点所涉及的技术方案都会需要一个算法/或者技术手段去突破。

    + +

    而开发者从解析的效果去考虑,可以从简单的做起,逐步突破难点,这对于开发人员自身的自信心提升也是一种正向的导向。在整个PDF解析过程中,我觉得以下几项是比较难处理的:

    + +
      +
    • 布局解析困难:PDF文件的布局可能会因为不同的作者、工具或用途而有所不同,因此解析其布局是一个具有挑战性的任务。
    • +
    • 格式错综复杂:PDF文件中可能包含各种格式的内容,包括文字图像表格等,因此解析其内容需要考虑到这种多样性和复杂性。
    • +
    • 复合表格:纵向/横向合并的复杂表格,在PDF中进行抽象还原是最难处理的问题之一
    • +
    • 文本、图片、表格顺序提取:提取PDF文件中的文本、图片和表格,并确保它们的顺序正确性,是一个需要解决的重要问题。
    • +
    • 文档结构还原:还原PDF文件的文档结构,包括标题、目录等信息,是实现自动化文档处理和理解的关键步骤之一。
    • +
    • 元素重叠:从PDF100%效果还原的角度考虑,图片/文本之间的重叠,图片合并,合并后不失真等,也是需要考虑的事项之一
    • +
    • 元数据提取:在PDF中隐藏的元数据信息是RAG产品的关键数据,比如链接、目录、字体等等
    • +
    • 扫描件:PDF中如果是扫描件,依靠OCR模型可能是无法有效的提取,这里面包含了清晰度、模型的稳定性等等问题
    • +
    • Latex公式提取:在一些特殊领域,PDF文本中包含了Latex等数学公式。通过完整的提取和转换是对RAG问答的有效补充
    • +
    + +

    技术可行性

    + +

    我们从解析PDF的技术可行性角度,考虑哪些方面值得我们重点关注和突破:

    + +
      +
    • 文字提取能力,逐行提取:确保能够准确地提取PDF文件中的文字内容,并按照正确的顺序进行排列和输出,避免文字乱码(字体)。
    • +
    • 简单/复杂表格完整提取:对PDF文件中的表格进行完整提取,包括表格内的内容和格式。
    • +
    • 图片提取/合并:提取PDF文件中的图片,并保留其原始质量和格式。
    • +
    • 文档布局(Block块的标识)识别:识别PDF文件的布局,包括页面的排列方式、文本和图片的位置等信息。
    • +
    • 文档结构识别(标题、目录),内容顺序输出:识别PDF文件的结构,包括标题、目录等信息,并确保输出内容的顺序正确。
    • +
    • 转换为Markdown格式:将解析后的PDF文件内容转换为Markdown格式,以便于后续的处理和分享。
    • +
    + +

    开源技术方案

    + +

    结合上面的技术难点/方案及可行性上去分析,我们可以看看目前开源的技术组件中,有哪些是我们可以考虑进行结合的。

    + +

    因为目前TorchV系统主要以Java+Python双语作为底层的应用开发语言,接下来我们可以看看在这两个编程语言中,有哪些开源的方案可以使用。

    + +

    Java生态

    + +

    在Java生态中,对于PDF组件处理的开源方案不多见,Apache PDFBOX是当前最强的,也是最好的

    + + + + + + + + + + + + + + + + + + + + + +
    名称地址说明
    Apache PDFBoxhttps://github.com/apache/pdfbox提供开箱即用的文本、图片内容提取方式,并且可以基于Stream接口重写各项元素的解析实现,并能输出元素的坐标信息。开发者可以根据元素的坐标信息结合算法进行内容的高度还原。唯一的缺点是没有表格组件提取的API供开发人员使用。
    tabula-javahttps://github.com/tabulapdf/tabula-java基于Apache PDFBOx组件的表格提取实现
    + +

    Python生态

    + +

    Python生态的PDF提取组件还是蛮多的,不过也是有不同的侧重,比如pdfplumber、camelot等都专注在表格的提取上,提供了开箱即用的方案。

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    名称地址说明
    pypdfhttps://github.com/py-pdf/pypdf一个纯Python PDF库,能够分割、合并、裁剪和转换PDF文件的页面
    PyMuPDF(AGPL)https://github.com/pymupdf/PyMuPDF高性能 Python 库,用于 PDF(和其他)文档的数据提取、分析、转换和操作。
    pdfplumber(MIT)https://github.com/jsvine/pdfplumber查看 PDF 以获取有关每个字符、矩形、线条等的详细信息,并轻松提取文本和表格。
    camelot(MIT)https://github.com/camelot-dev/camelot专注于PDF中表格的提取,包括复杂的表格
    + +

    OCR生态/大模型

    + +

    在上面Python和Java生态库的开源组件,基本都是针对文字的PDF处理为主,当我们的PDF是扫描件时,那上面的组件统统失效,都提取不出来文本信息。

    + +

    此时就需要用到OCR的模型进行提取。

    + +

    考虑到如果是OCR提取,那么最终的目的是将PDF文件Page页码内容提取出完成的图片Image,所以本质上是对图片内容的理解

    + +

    可以考虑的开源组件如下:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    名称地址说明
    marker(GPL)https://github.com/VikParuchuri/marker基于模型将PDF文件内容提取为Markdown格式
    surya(GPL)https://github.com/VikParuchuri/suryaOCR、布局分析、阅读顺序、线条检测(支持90 多种语言)
    tesseract(Apache 2)https://github.com/tesseract-ocr/tesseract老牌OCR组件,支持100多种语言
    RapidOCR(Apache)https://github.com/RapidAI/RapidOCR基于 ONNXRuntime、OpenVION 和 PaddlePaddle 的出色 OCR 多种编程语言工具包。
    PaddleOCR(Apache)https://github.com/PaddlePaddle/PaddleOCR基于飞桨的出色多语言OCR工具包(实用的超轻量级OCR系统,支持80+语言识别)
    EasyOCR(Apache )https://github.com/JaidedAI/EasyOCRPython\C++开发,支持80多种语言OCR识别
    + +

    技术准备/细节

    + +

    在解析PDF时,我们也会有一些其他方面的知识储备,以便我们快速应对不同的业务需求及应用产品形态。

    + +

    1、图形类API:不管是Java还是Python里面,对于处理PDF中间件的部分,都需要对图形类的API/算法熟悉和掌握,这里面包含图形的转换、缩放、矩阵坐标、截取等等,都会在PDF提取的过程中使用到。

    + +

    2、PDF标准:在处理PDF中,结合开源的技术中间件,对于PDF的ISO标准,我们也是需要了解的,这样更加有利于开发人员理解中间件的代码写法及含义。

    + +

    3、边/线/矩阵算法等:对于文本/边框的聚类算法等,在根据元素坐标高效还原时,利用高效的算法可以提高解析速度以及内容还原度

    + +

    4、OCR/LLM模型等:了解学习在用OCR/LLM模型分析布局、边界检测等等技术上的一些算法及数据工程上的实践

    + +

    5、PDF页面旋转:有时候原PDF可能会有旋转(0、90、180、270度),需先校正后,再次提取内容

    + +

    6、字体/乱码:系统/服务器中缺失PDF中的字体,导致文本提取乱码

    + +

    最后

    + +

    本文从大的方面简单概括了在PDF解析处理过程中的技术方案/难点/开源技术方案等内容,后面我会从一些细节方面来逐一分享我们在构建TorchV产品时,解析PDF文件过程中的一些问题及技术实践,包括对表格的提取,感兴趣的可以关注我们😁。

    + +

    另外,我们团队提供了一个PDF解析的Demo地址,针对文本类的PDF(暂时不支持扫描件),可以进行试用体验。

    + +

    地址:http://tabletest.torchv.com:8010/

    + +

    image-20240706170720200

    + +
    + +
    + + + + + +
    + + + + + + +
    +
    +
    + +

    站内搜索

    + + +
      + + + + + + + + + +
      +
      +

      TorchV Bot开放试用中......

      +
      +
      + +
      +
      +
      +
      +

      最新内容,关注“八一菜刀”公众号

      +
      +
      +
      + +

      Table of Contents

      +
      +
      + + +
      +
      +
      + + + +
      +
      +
      + + + +
      + +
      + + + + + + + + + + + + + + + + + + diff --git a/_site/404.html b/_site/404.html index 48e3a62..44d6624 100644 --- a/_site/404.html +++ b/_site/404.html @@ -192,7 +192,7 @@

      标签

      - RAG实践(3) + RAG实践(5) @@ -208,7 +208,7 @@

      标签

      - TorchV(3) + TorchV(5) @@ -220,7 +220,7 @@

      标签

      - 大模型(9) + 大模型(11) diff --git a/_site/README.en/index.html b/_site/README.en/index.html index 4ad3294..cbd5216 100644 --- a/_site/README.en/index.html +++ b/_site/README.en/index.html @@ -251,7 +251,7 @@

      标签

      - RAG实践(3) + RAG实践(5) @@ -267,7 +267,7 @@

      标签

      - TorchV(3) + TorchV(5) @@ -279,7 +279,7 @@

      标签

      - 大模型(9) + 大模型(11) diff --git a/_site/about/index.html b/_site/about/index.html index 8a983c4..b6ef006 100644 --- a/_site/about/index.html +++ b/_site/about/index.html @@ -219,7 +219,7 @@

      标签

      - RAG实践(3) + RAG实践(5) @@ -235,7 +235,7 @@

      标签

      - TorchV(3) + TorchV(5) @@ -247,7 +247,7 @@

      标签

      - 大模型(9) + 大模型(11) diff --git a/_site/archives/index.html b/_site/archives/index.html index 69c8f32..954a91c 100644 --- a/_site/archives/index.html +++ b/_site/archives/index.html @@ -97,11 +97,27 @@

      归档

      -

      2024 (2)

      +

      2024 (4)

        +
      1. +07-08 +RAG工程实践拦路虎之一:PDF格式解析杂谈 +
      2. + + + + +
      3. +07-03 +我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈 +
      4. + + + +
      5. 04-01 创业:大模型RAG系统三个月的开发心得和思考 @@ -1628,7 +1644,7 @@

        标签

        - RAG实践(3) + RAG实践(5) @@ -1644,7 +1660,7 @@

        标签

        - TorchV(3) + TorchV(5) @@ -1656,7 +1672,7 @@

        标签

        - 大模型(9) + 大模型(11) diff --git a/_site/assets/images/rag/torchv/pdf-01/image-20240706170720200.png b/_site/assets/images/rag/torchv/pdf-01/image-20240706170720200.png new file mode 100644 index 0000000..7fc9e86 Binary files /dev/null and b/_site/assets/images/rag/torchv/pdf-01/image-20240706170720200.png differ diff --git a/_site/assets/images/rag/torchv/rag-4/image-20240701143924758.png b/_site/assets/images/rag/torchv/rag-4/image-20240701143924758.png new file mode 100644 index 0000000..c182b58 Binary files /dev/null and b/_site/assets/images/rag/torchv/rag-4/image-20240701143924758.png differ diff --git a/_site/assets/images/rag/torchv/rag-4/image-20240701143941791.png b/_site/assets/images/rag/torchv/rag-4/image-20240701143941791.png new file mode 100644 index 0000000..bc41fe5 Binary files /dev/null and b/_site/assets/images/rag/torchv/rag-4/image-20240701143941791.png differ diff --git a/_site/assets/images/rag/torchv/rag-4/image-20240703085452132.png b/_site/assets/images/rag/torchv/rag-4/image-20240703085452132.png new file mode 100644 index 0000000..7197ffb Binary files /dev/null and b/_site/assets/images/rag/torchv/rag-4/image-20240703085452132.png differ diff --git a/_site/assets/search_data.json b/_site/assets/search_data.json index 8af775a..2d3b166 100644 --- a/_site/assets/search_data.json +++ b/_site/assets/search_data.json @@ -1311,6 +1311,20 @@ "url" : "http://localhost:4000/2024/04/01/torchv-summary-01/" } , + { + "title" : "我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈", + "category" : "大模型", + + "url" : "http://localhost:4000/2024/07/03/torchv-think/" + } , + + { + "title" : "RAG工程实践拦路虎之一:PDF格式解析杂谈", + "category" : "大模型", + + "url" : "http://localhost:4000/2024/07/08/torchv-pdf-01/" + } , + { "title" : "Android Studio", "category" : "Android", diff --git a/_site/categories/index.html b/_site/categories/index.html index 6d51653..7014941 100644 --- a/_site/categories/index.html +++ b/_site/categories/index.html @@ -462,6 +462,16 @@

        Python

        RAG实践

          +
        1. +2024-07-08 +RAG工程实践拦路虎之一:PDF格式解析杂谈 +
        2. + +
        3. +2024-07-03 +我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈 +
        4. +
        5. 2024-04-01 创业:大模型RAG系统三个月的开发心得和思考 @@ -542,6 +552,16 @@

          SpringBoot

          TorchV

            +
          1. +2024-07-08 +RAG工程实践拦路虎之一:PDF格式解析杂谈 +
          2. + +
          3. +2024-07-03 +我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈 +
          4. +
          5. 2024-04-01 创业:大模型RAG系统三个月的开发心得和思考 @@ -732,6 +752,16 @@

            springfox

            大模型

              +
            1. +2024-07-08 +RAG工程实践拦路虎之一:PDF格式解析杂谈 +
            2. + +
            3. +2024-07-03 +我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈 +
            4. +
            5. 2024-04-01 创业:大模型RAG系统三个月的开发心得和思考 @@ -1175,7 +1205,7 @@

              Blog Categories

            6. RAG实践 - 3 + 5
            7. @@ -1195,7 +1225,7 @@

              Blog Categories

            8. TorchV - 3 + 5
            9. @@ -1210,7 +1240,7 @@

              Blog Categories

            10. 大模型 - 9 + 11
            11. diff --git a/_site/feed.xml b/_site/feed.xml index 5402489..714b0f6 100644 --- a/_site/feed.xml +++ b/_site/feed.xml @@ -1,8 +1,361 @@ -Jekyll2024-04-01T20:37:58+08:00http://localhost:4000/feed.xml八一菜刀八一菜刀的个人博客肖玉民创业:大模型RAG系统三个月的开发心得和思考2024-04-01T00:00:00+08:002024-04-01T00:00:00+08:00http://localhost:4000/2024/04/01/torchv-summary-01<h1 id="1-前言">1. 前言</h1> +Jekyll2024-07-08T09:52:22+08:00http://localhost:4000/feed.xml八一菜刀八一菜刀的个人博客肖玉民RAG工程实践拦路虎之一:PDF格式解析杂谈2024-07-08T00:00:00+08:002024-07-08T00:00:00+08:00http://localhost:4000/2024/07/08/torchv-pdf-01<h2 id="背景">背景</h2> -<p>自从和<a href="https://www.luxiangdong.com/">员外</a>从上家公司离职后,我们就自己搞公司投入到了RAG大模型的AI产品应用的开发中,这中间有一个春节,前后的总时间大概是三个月左右,在这三个月期间,基本是昼夜兼程啊,到今天3月底结束,产品目前看是有了一个基础的雏形。</p> +<p>PDF(Portable Document Format)是一种广泛用于文档交换的文件格式,由Adobe Systems开发。它具有跨平台性、固定布局和易于打印等特点,因此在商业、学术和个人领域广泛应用。然而,PDF文件的解析一直是一个具有挑战性的问题,因为其内部结构的复杂性和多样性,使得提取其中的文本、图片和表格等内容并不是一件容易的事情。</p> -<p>在这期间,员外负责整个产品的营销、商业客户的洽谈等方面的内容,我和阿包负责整体的技术架构搭建,代码从0-1的编写,我们是1月初的样子,产品初步上线了一个版本,开始接受企业客户的试用,这让我们接受到了大量的需求,以及我们产品在目前的市场环境中还存在哪些竞争力不足需要改进的地方。</p> +<h2 id="技术方案">技术方案</h2> + +<p>在目前的PDF文件解析领域中,我们可以将其大致分为以下几类技术方案:</p> + +<ul> + <li><strong>LLM/视觉大模型解析</strong>:LLM(Large Language Model)大型语言模型在近年来的发展中,展现出了强大的语言理解和生成能力。通过训练大规模的神经网络,可以实现对PDF文件中文字内容的理解和提取,这种方法尤其适用于那些布局复杂、内容丰富的PDF文件。</li> + <li><strong>OCR模型</strong>:光学字符识别(OCR)模型专门设计用于将PDF文件中的图像转换为可编辑的文本。这种技术在处理扫描版或图像化的PDF文档时尤其有用。</li> + <li><strong>传统规则提取</strong>:传统的PDF解析方式可能包括基于规则的文本提取、图像处理和表格识别等方法。虽然这些方法可能不如深度学习模型那样灵活,但在某些情况下仍然是有效的选择。</li> +</ul> + +<p>各个解决方案目前可能需要配合使用,因为PDF格式本身的复杂程度,一项技术方案可能是<strong>无法100%满足业务需求</strong>的,这里面需要考虑的是:</p> + +<ul> + <li><strong>文档提取还原度</strong>:通过技术手段,能够完整的提取PDF中的各项元素,包括文本、表格、图片、链接、图形、目录等等信息</li> + <li><strong>高效/💰成本</strong>:在RAG知识库问答的产品中,考虑到文本还需要Embedding的过程,因此在提取过程中如何更高效,成本更低也是需要着重考虑到事项。</li> + <li><strong>稳定/幂等</strong>:我们知道大模型可能是出现幻觉的,如果用大模型来提取PDF中的内容,是否能足够保证稳定性。</li> +</ul> + +<p>当我们处理解析PDF时,我们需要可以讲每一项的难点都进行拆分,从需求出发,逐一进行攻破,找到解决方案。</p> + +<p>其实我觉得技术人员如果能<strong>通过技术手段确定PDF中的Block(块)以及阅读顺序,按Block(块)进行输出转换(Markdown/Html等),这里面包括的Block块元素:文本、图片、表格等等。那么这个提取的效果就会达到我们的最优</strong>。</p> + +<p>而这个目标是我们接下来要重点讨论的。</p> + +<h2 id="技术难点">技术难点</h2> + +<p>在考虑解析PDF文件时,我们需要根据当前的技术栈发展情况,并结合实际的业务诉求,综合考量这其中的技术难点,因为每一项技术难点所涉及的技术方案都会需要一个算法/或者技术手段去突破。</p> + +<p>而开发者从解析的效果去考虑,可以从简单的做起,逐步突破难点,这对于开发人员自身的自信心提升也是一种正向的导向。在整个PDF解析过程中,我觉得以下几项是比较难处理的:</p> + +<ul> + <li><strong>布局解析困难</strong>:PDF文件的布局可能会因为不同的作者、工具或用途而有所不同,因此解析其布局是一个具有挑战性的任务。</li> + <li><strong>格式错综复杂</strong>:PDF文件中可能包含各种格式的内容,包括<strong>文字</strong>、<strong>图像</strong>、<strong>表格</strong>等,因此解析其内容需要考虑到这种多样性和复杂性。</li> + <li><strong>复合表格</strong>:纵向/横向合并的复杂表格,在PDF中进行抽象还原是最难处理的问题之一</li> + <li><strong>文本、图片、表格顺序提取</strong>:提取PDF文件中的文本、图片和表格,并确保它们的顺序正确性,是一个需要解决的重要问题。</li> + <li><strong>文档结构还原</strong>:还原PDF文件的文档结构,包括标题、目录等信息,是实现自动化文档处理和理解的关键步骤之一。</li> + <li><strong>元素重叠</strong>:从PDF100%效果还原的角度考虑,图片/文本之间的重叠,图片合并,合并后不失真等,也是需要考虑的事项之一</li> + <li><strong>元数据提取</strong>:在PDF中隐藏的元数据信息是RAG产品的关键数据,比如链接、目录、字体等等</li> + <li><strong>扫描件</strong>:PDF中如果是扫描件,依靠OCR模型可能是无法有效的提取,这里面包含了清晰度、模型的稳定性等等问题</li> + <li><strong>Latex公式提取</strong>:在一些特殊领域,PDF文本中包含了Latex等数学公式。通过完整的提取和转换是对RAG问答的有效补充</li> +</ul> + +<h2 id="技术可行性">技术可行性</h2> + +<p>我们从解析PDF的技术可行性角度,考虑哪些方面值得我们重点关注和突破:</p> + +<ul> + <li><strong>文字提取能力,逐行提取</strong>:确保能够准确地提取PDF文件中的文字内容,并按照正确的顺序进行排列和输出,避免文字乱码(字体)。</li> + <li><strong>简单/复杂表格完整提取</strong>:对PDF文件中的表格进行完整提取,包括表格内的内容和格式。</li> + <li><strong>图片提取/合并</strong>:提取PDF文件中的图片,并保留其原始质量和格式。</li> + <li><strong>文档布局(Block块的标识)识别</strong>:识别PDF文件的布局,包括页面的排列方式、文本和图片的位置等信息。</li> + <li><strong>文档结构识别(标题、目录),内容顺序输出</strong>:识别PDF文件的结构,包括标题、目录等信息,并确保输出内容的顺序正确。</li> + <li><strong>转换为Markdown格式</strong>:将解析后的PDF文件内容转换为Markdown格式,以便于后续的处理和分享。</li> +</ul> + +<h2 id="开源技术方案">开源技术方案</h2> + +<p>结合上面的技术难点/方案及可行性上去分析,我们可以看看目前开源的技术组件中,有哪些是我们可以考虑进行结合的。</p> + +<p>因为目前TorchV系统主要以Java+Python双语作为底层的应用开发语言,接下来我们可以看看在这两个编程语言中,有哪些开源的方案可以使用。</p> + +<h3 id="java生态">Java生态</h3> + +<p>在Java生态中,对于PDF组件处理的开源方案不多见,Apache PDFBOX是当前最强的,也是最好的</p> + +<table> + <thead> + <tr> + <th>名称</th> + <th>地址</th> + <th>说明</th> + </tr> + </thead> + <tbody> + <tr> + <td>Apache PDFBox</td> + <td><a href="https://github.com/apache/pdfbox">https://github.com/apache/pdfbox</a></td> + <td>提供开箱即用的文本、图片内容提取方式,并且可以基于Stream接口重写各项元素的解析实现,<strong>并能输出元素的坐标信息</strong>。开发者可以根据元素的坐标信息结合算法进行内容的高度还原。唯一的缺点是没有表格组件提取的API供开发人员使用。</td> + </tr> + <tr> + <td>tabula-java</td> + <td><a href="https://github.com/tabulapdf/tabula-java">https://github.com/tabulapdf/tabula-java</a></td> + <td>基于Apache PDFBOx组件的表格提取实现</td> + </tr> + </tbody> +</table> + +<h3 id="python生态">Python生态</h3> + +<p>Python生态的PDF提取组件还是蛮多的,不过也是有不同的侧重,比如pdfplumber、camelot等都专注在表格的提取上,提供了开箱即用的方案。</p> + +<table> + <thead> + <tr> + <th style="text-align: left">名称</th> + <th>地址</th> + <th>说明</th> + </tr> + </thead> + <tbody> + <tr> + <td style="text-align: left">pypdf</td> + <td><a href="https://github.com/py-pdf/pypdf">https://github.com/py-pdf/pypdf</a></td> + <td>一个纯Python PDF库,能够分割、合并、裁剪和转换PDF文件的页面</td> + </tr> + <tr> + <td style="text-align: left">PyMuPDF(AGPL)</td> + <td><a href="https://github.com/pymupdf/PyMuPDF">https://github.com/pymupdf/PyMuPDF</a></td> + <td>高性能 Python 库,用于 PDF(和其他)文档的数据提取、分析、转换和操作。</td> + </tr> + <tr> + <td style="text-align: left"><strong><a href="https://github.com/jsvine/pdfplumber">pdfplumber</a></strong>(MIT)</td> + <td><a href="https://github.com/jsvine/pdfplumber">https://github.com/jsvine/pdfplumber</a></td> + <td>查看 PDF 以获取有关每个字符、矩形、线条等的详细信息,并轻松提取文本和表格。</td> + </tr> + <tr> + <td style="text-align: left"><strong><a href="https://github.com/camelot-dev/camelot">camelot</a></strong>(MIT)</td> + <td><a href="https://github.com/camelot-dev/camelot">https://github.com/camelot-dev/camelot</a></td> + <td>专注于PDF中表格的提取,包括复杂的表格</td> + </tr> + </tbody> +</table> + +<h3 id="ocr生态大模型">OCR生态/大模型</h3> + +<p>在上面Python和Java生态库的开源组件,基本都是针对文字的PDF处理为主,当我们的PDF是扫描件时,那上面的组件统统失效,都提取不出来文本信息。</p> + +<p>此时就需要用到OCR的模型进行提取。</p> + +<p>考虑到如果是OCR提取,那么最终的目的是将PDF文件Page页码内容提取出完成的图片Image,所以本质上是对图片内容的理解</p> + +<p>可以考虑的开源组件如下:</p> + +<table> + <thead> + <tr> + <th>名称</th> + <th>地址</th> + <th>说明</th> + </tr> + </thead> + <tbody> + <tr> + <td>marker(GPL)</td> + <td>https://github.com/VikParuchuri/marker</td> + <td>基于模型将PDF文件内容提取为Markdown格式</td> + </tr> + <tr> + <td>surya(GPL)</td> + <td>https://github.com/VikParuchuri/surya</td> + <td>OCR、布局分析、阅读顺序、线条检测(支持90 多种语言)</td> + </tr> + <tr> + <td>tesseract(Apache 2)</td> + <td>https://github.com/tesseract-ocr/tesseract</td> + <td>老牌OCR组件,支持100多种语言</td> + </tr> + <tr> + <td>RapidOCR(Apache)</td> + <td>https://github.com/RapidAI/RapidOCR</td> + <td>基于 ONNXRuntime、OpenVION 和 PaddlePaddle 的出色 OCR 多种编程语言工具包。</td> + </tr> + <tr> + <td>PaddleOCR(Apache)</td> + <td>https://github.com/PaddlePaddle/PaddleOCR</td> + <td>基于飞桨的出色多语言OCR工具包(实用的超轻量级OCR系统,支持80+语言识别)</td> + </tr> + <tr> + <td>EasyOCR(Apache )</td> + <td>https://github.com/JaidedAI/EasyOCR</td> + <td>Python\C++开发,支持80多种语言OCR识别</td> + </tr> + </tbody> +</table> + +<h2 id="技术准备细节">技术准备/细节</h2> + +<p>在解析PDF时,我们也会有一些其他方面的知识储备,以便我们快速应对不同的业务需求及应用产品形态。</p> + +<p><strong>1、图形类API</strong>:不管是Java还是Python里面,对于处理PDF中间件的部分,都需要对图形类的API/算法熟悉和掌握,这里面包含图形的转换、缩放、矩阵坐标、截取等等,都会在PDF提取的过程中使用到。</p> + +<p><strong>2、PDF标准</strong>:在处理PDF中,结合开源的技术中间件,对于PDF的ISO标准,我们也是需要了解的,这样更加有利于开发人员理解中间件的代码写法及含义。</p> + +<p><strong>3、边/线/矩阵算法等</strong>:对于文本/边框的聚类算法等,在根据元素坐标高效还原时,利用高效的算法可以提高解析速度以及内容还原度</p> + +<p><strong>4、OCR/LLM模型等</strong>:了解学习在用OCR/LLM模型分析布局、边界检测等等技术上的一些算法及数据工程上的实践</p> + +<p>5、<strong>PDF页面旋转</strong>:有时候原PDF可能会有旋转(0、90、180、270度),需先校正后,再次提取内容</p> + +<p>6、<strong>字体/乱码</strong>:系统/服务器中缺失PDF中的字体,导致文本提取乱码</p> + +<h2 id="最后">最后</h2> + +<p>本文从大的方面简单概括了在PDF解析处理过程中的技术方案/难点/开源技术方案等内容,后面我会从一些细节方面来逐一分享我们在构建TorchV产品时,解析PDF文件过程中的一些问题及技术实践,包括对表格的提取,感兴趣的可以关注我们😁。</p> + +<p>另外,我们团队提供了一个PDF解析的Demo地址,针对文本类的PDF(暂时不支持扫描件),可以进行试用体验。</p> + +<p>地址:<a href="http://tabletest.torchv.com:8010/">http://tabletest.torchv.com:8010/</a></p> + +<p><img src="/assets/images/rag/torchv/pdf-01/image-20240706170720200.png" alt="image-20240706170720200" /></p>八一菜刀背景我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈2024-07-03T00:00:00+08:002024-07-03T00:00:00+08:00http://localhost:4000/2024/07/03/torchv-think<h2 id="1前言">1、前言</h2> + +<p>在6.28/29的稀土掘金开发者大会RAG专场上,我们公司CEO员外代表TorchV分享了我们在《RAG在企业应用中落地的难点与创新》</p> + +<p>其中最后分享了两个观点:</p> + +<ul> + <li><strong>AI在应用场景落地时有三个特点:功能小、质量高、价值大</strong></li> + <li><img src="/assets/images/rag/torchv/rag-4/image-20240701143924758.png" alt="image-20240701143924758" /></li> + <li><strong>如果说做产品是把一横做好的话,那么去做企业落地服务就是一竖,从需求和方案,再到 POC,和最后交付。</strong></li> + <li><img src="/assets/images/rag/torchv/rag-4/image-20240701143941791.png" alt="image-20240701143941791" /></li> +</ul> + +<p>对于AI应用的三个特点,我们在落地的时候,其实碰到的问题蛮多的,但是用过大模型或者AI产品的人应该都知道,目前基于大模型应用开发的C端产品其实在整体给人的感觉都是相对较小的工具居多,在帮助人类提效这件事上,借助于AI工具,能很好的完成日常繁杂的工作和学习任务。比如<strong>AI翻译</strong>、<strong>网页总结</strong>插件等等。这类产品更多的是偏C端为主,借助于互联网的生态以及开源技术的发展,只要功能/交互满足用户的要求,很快就能打动C端用户进行尝鲜试用甚至付费。</p> + +<p>但是做B端类的产品,整个交付的过程就明显和C端不一样,在B端我们除了产品本身需要功能足够强大之外,我们还需要做AI的落地交付,这里面包含<strong>私有化定制</strong>/<strong>客户培训</strong>/<strong>私有化部署</strong>/<strong>软硬件适配</strong>等等繁杂的工作,整个交付周期漫长的多。这明显是和上面第二个观点相呼应的,<strong>产品+服务</strong>才能综合服务好B端的客户。</p> + +<p>本篇是结合我们公司在B端RAG/大模型应用产品的落地交付的场景考虑,以实际场景出发,谈谈我对知识库类产品的技术架构的思考总结。</p> + +<h2 id="2业务功能技术组件拆解抽象">2、业务功能/技术组件拆解抽象</h2> + +<p><img src="/assets/images/rag/torchv/rag-4/image-20240703085452132.png" alt="image-20240703085452132" /></p> + +<p>在文章的标题中,我已经标注了范围: <strong>RAG</strong>、<strong>大模型</strong>、<strong>非结构化数据</strong></p> + +<p>我们从这三个方面出发,在软件层面,我们如何来考虑这些新型的技术名词,将他们从技术/产品功能的角度进行拆解,实现对应的功能交付给我们的客户。</p> + +<p>从业务的功能诉求来看,主要有几个方面:</p> + +<ul> + <li><strong>知识库</strong>:客户需要将业务数据统一收集处理,形成知识库,以便提供给LLM进行使用</li> + <li><strong>应用中心</strong>:B端客户需要开箱即用的产品,解决实际工作业务中碰到的问题</li> + <li><strong>用户权限</strong>:系统提供企业级灵活可控的权限管理,方便企业客户进行统一管理授权。</li> + <li><strong>多租户</strong>:多租户体系架构是必不可少的,可以保证数据以Schema级别进行隔离,保障数据安全以及上层应用的灵活输出支撑。</li> + <li>…</li> +</ul> + +<p>而从技术侧考虑,技术人员需要关注的是:</p> + +<ul> + <li><strong>非结构化数据的处理</strong>:平台需要支持多种多样的非结构化数据的提取处理工作,将整个文档内容进行chunking、embedding进入数据库,以便进行搜索 + <ul> + <li><strong>文件类型广度</strong>:提供众多的非结构化数据文档(PDF/PPT/WORD等)的提取支持,是打动B端客户的有利吸引点,</li> + <li><strong>文件解析精度</strong>:以PDF/PPT/Word为首的文档解析工作困难重重,如何在解析的工作上更进一步,从根源上减少模型在利用已知数据的幻觉问题</li> + <li><strong>任务调度</strong>:数据的处理依靠稳定的任务调度平台,保证数据处理的最终有序执行。</li> + </ul> + </li> + <li><strong>模型服务</strong>:从LLM大语言模型、Reranker模型、embedding、OCR模型、视觉模型等等,<strong>保证模型的幂等输出</strong>,为上层应用提供稳定可靠的服务支撑。 + <ul> + <li><strong>LLM模型</strong>:提供一系列<strong>Agent服务</strong>,保证上层业务能够灵活调用大模型获取满意的结果</li> + <li><strong>ReRanker模型</strong>:重排序模型是问答二阶段召回提高准确率的关键手段,不可忽虑</li> + <li><strong>Embedding模型</strong>:向量化嵌入,提供对知识文本的表征提取向量工作,不可忽虑</li> + <li><strong>OCR/视觉模型</strong>:辅助非结构化数据提取在规则提取不满足的情况下,启动OCR及视觉模型,增强非结构化数据的提供效果</li> + </ul> + </li> + <li><strong>向量数据库(VectorDB)</strong>: 需要结合实际业务诉求,从性能/空间/生态等多方面考量VectorDB等选型</li> +</ul> + +<p>技术的角度拆分,其实技术人员关注的点非常的多,每一项工作其实都可以是独立的中间件产品,要把这些全部整合到一块,并非易事。</p> + +<h2 id="3微服务分布式云原生">3、微服务/分布式/云原生?</h2> + +<p>写过Java的估计对上面这三个名词都已经滚瓜乱熟了,我记得很早之前,说面试你如果不会微服务,那都找不到工作(PS:现在好像不管你会什么,也同样都找不到)😂。</p> + +<p>对于AI应用,可能更多的软件生态是由Python带动起来的,包括一些工具库LangChain、LlamaIndex等都是Python,虽然Java中也不乏有一些,比如LangChain4j、Spring-AI等组件,都是后起之秀,在整个生态稳定性等方面确实是落后了一节。</p> + +<p>但可能很多人都在用过LangChain等框架后有一个共识,那就是当作工具用没有问题,但是上生产?问题太多了。我觉得主要的几个点:</p> + +<ul> + <li>LangChain的过度封装,对于应用层而言,不管是Agent,还是RAG,其实蛮简单的一件事情,和大模型API接口对接就好了,但是你去看LangChain的源码,整个调用链路封装的极其复杂,改都没法改。</li> + <li>上层的业务需求变化太大了,有时候是需要结合自己公司的实际业务情况来进行处理的,这种情况下,还不如自己写来的快,其实调用的链路并不复杂</li> + <li>就稳定性/事务/数据一致性而言,Python作为企业服务接口主语言是否合适呢?</li> +</ul> + +<p>而我们今天讨论的是整个产品的技术架构的选择,其实在上面业务功能/技术组件抽象那一节,我们已经拆分了功能和技术点,从技术点去看,这已经是一个集众多服务于一体的综合技术解决方案了。在应用层面的功能,我们是否还需要像以前那样,整一套微服务架构出来来开发业务功能?</p> + +<p>我的个人看法是:<strong>根据团队配置,微服务可用可不用。但是应用程序必须天然分布式,支持横向扩展集群,弹性伸缩。</strong></p> + +<blockquote> + <p>目前这个环境,项目搞微服务,最后的困境可能就是所有服务都是你一个人负责,写完a服务写b服务,再来个rpc调用,还要考虑数据熔断、可用性等等,小团队我觉得完全没必要折腾!</p> +</blockquote> + +<p>主要考虑的点:</p> + +<p><strong>1、海量非结构化数据处理的提效</strong></p> + +<p>在处理RAG产品类中,非结构化数据的处理除了快速解析之外,还需要将文本进行向量化,而我们在技术架构中需要能够快速的处理这些文件,通过Pipeline的方式,将非结构化数据最终存储到向量数据库中,这里面传统的做法不得不用消息中间件MQ,而应用层面的程序则可以通过考虑弹性伸缩的方式,扩充消费节点,以提高整体的处理效率</p> + +<p><strong>2、海量向量数据的存储/计算召回效率</strong></p> + +<p>当我们对非结构化数据进行提取后,需要经过Embedding模型进行向量化,这里面还涉及到文本的Chunking分块,所以底层向量数据的存储和计算必然是一个需要更全面的考虑向量数据库中间件,这其中包括:向量召回的性能、数据的存储/备份、多租户Schema级别数据权限等等</p> + +<p><strong>3、数据最终一致性</strong></p> + +<p>数据的Embedding处理、大模型调度扣费、缓存等等,在目前已经众多服务组件拆分的情况下,整个数据的处理任务我觉得需要保证数据的最终一致性,在分布式场景下,多节点处理时需要特别注意。</p> + +<p><strong>4、应用功能原子性(云原生)</strong></p> + +<p>整个应用层的功能,我觉得需要<strong>保持独立,并且保障稳定性</strong>,这点其实我觉得在私有化部署/交付的环节比较奏效。如果你是一名运维或者主力开发者,在一个完全内网隔离的环境下部署时,你会体会到这种便捷。</p> + +<p>总之,我觉得在应用层面服务,服务端应该做的是:<strong>减少配置、轻量化、稳定</strong></p> + +<h2 id="4编程语言中间件选择">4、编程语言/中间件选择?</h2> + +<p>我们团队目前的开发语言是Java+Python的组合,主要有职责分工:</p> + +<ul> + <li>Java:上层业务应用的API接口,任务调度、数据处理等等</li> + <li>Python:和模型、数据处理、NLP等相关任务以接口的形式开放出来,API接口是无状态的,所有的数据状态流转都在Java端实现</li> +</ul> + +<p>这里面很多开发可能会有一些担忧,对于Java语言的选择,是否在目前的RAG/大模型领域合适?其实最困惑的就是非结构化数据的处理,可能很多开发者看到目前开源的众多组件或者平台,都是Python的主技术栈,认为Java处理不了,其实这是完全有误区的,对于最难处理的PDF文件提取,<strong>Apache PDFBox</strong>绝对是值得你深挖的一个组件,当然Python本来就擅长数据处理/分析,可以根据团队的配置进行执行选择,这里面我觉得主要考虑的几个点:</p> + +<p><strong>1、团队人员配置</strong></p> + +<p>根据团队当前的主流编程语言去做技术架构上的选型和决策,并没有绝对意义上的以哪个编程语言为主,Java、Python、Go、NodeJS、TypeScript等等都可以。</p> + +<p><strong>2、软件生态&amp;技术成熟度</strong></p> + +<p>上层应用产品的开发,肯定首先要考虑有哪些成熟的中间件和组件,来开发完成这一众多的需求,总不能从0到1造轮子,造轮子固然能提升开发人员的水平技能,但是在AI日益发展的今天,为公司产品尽早的找到PMF才是首要任务。需要综合考虑。</p> + +<p>其他的编程语言我不了解,就非结构化数据的解析这一块,其实Python和Java都相对更加丰富和稳 定。</p> + +<p>Java语言中比较好用的包括:Apache PDFBox、POI、Tika</p> + +<p>Python中包括:PyMuPDF、pdfplumber、pypdf、camelot、python-docx等等</p> + +<p><strong>3、稳定性/集群/高可用</strong></p> + +<blockquote> + <p>嗯,这里没有高并发,因为大家都没卡😂</p> +</blockquote> + +<p>大模型的产品相比较传统的业务在这点上并没有 太多的区别,稳定性/集群等特点也是需要的,技术人员在选择中间件时,也应当考虑这一点。</p> + +<p>例如MQ消息中间件、缓存Redis等等</p> + +<p><strong>4、部署实施/交付</strong></p> + +<p>没错,最后一步部署实施这个环节也需要考虑,Docker确实能带来极大的便利,但是成本也是需要考量的,目前的Python生态打包整个Docker,压缩包动辄2、3G起步,其实也是蛮头疼的,如果你是使用K8s调度来部署,k8s拉取一个10G的镜像也不是那么快的😂</p> + +<h2 id="5总结">5、总结</h2> + +<p>AI应用是一个需要快速试错、功能强大的某一个点去突破,技术架构上,也应当考虑整体的开发效率、生态等等。</p> + +<p>这让我想起来十几年前的jQuery,一经面世,得到众多开发者的喜爱,经典名言:</p> + +<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Write Less, Do More!!! +</code></pre></div></div> + +<p>在大模型日益健壮发展的同时,我们的技术架构,是否也应该做一次瘦身呢?</p>八一菜刀1、前言创业:大模型RAG系统三个月的开发心得和思考2024-04-01T00:00:00+08:002024-04-01T00:00:00+08:00http://localhost:4000/2024/04/01/torchv-summary-01<h1 id="1-前言">1. 前言</h1> + +<p>自从和<a href="https://www.luxiangdong.com/">员外</a>上家公司离职后,我们就自己搞公司投入到了RAG大模型的AI产品应用的开发中,这中间有一个春节,前后的总时间大概是三个月左右,在这三个月期间,基本是昼夜兼程啊,到今天3月底结束,产品目前看是有了一个基础的雏形。</p> + +<p>在这期间,员外负责整个产品的营销、商业客户的洽谈等方面的内容,我和阿包负责整体的技术架构搭建,代码从0-1的编写,我们是在24年1月26,产品初步上线了一个版本,开始接受企业客户的试用,这让我们接受到了大量的需求,以及我们产品在目前的市场环境中还存在哪些竞争力不足需要改进的地方。</p> <p>三个月时间过去了,在我们的TorchV AI 产品初步成型之际,和大家分享一下开发RAG、LLM系统以来的一些心得和经验。</p> @@ -123,14 +476,14 @@ <h1 id="4-技术产品领导驱动商业的发展">4. 技术&amp;产品领导驱动商业的发展</h1> -<p>做RAG这类AI应用开发以来,感受最深的是和之前做项目并不相同,一方面是技术栈发展较新,新技术带来的技术变革,需求层出不穷,另外,目前的AI应用,我觉得更多的是<strong>技术&amp;产品来领导驱动商业的发展</strong>,这和普通软件企业的开发流程或许有所不同。很多做项目集成的公司,做的项目未必是有价值的,可能销售人员只需要搞定某个项目非常重要的人,项目就拿下了,这时软件开发人员只需要按功能清单进行开发即可。但是软件功能未必是有价值的。</p> +<p>做RAG这类AI应用开发以来,感受最深的是和之前做产品/项目并不相同,一方面是技术栈发展较新,新技术带来的技术变革存在非常大的挑战,有了大模型之后,需求&amp;想法也是五花八门,另外,目前的AI应用,我觉得更多的是<strong>技术&amp;产品来领导驱动商业的发展</strong>,这和普通软件企业的开发流程或许有所不同。</p> <p>这里我觉得几点非常重要:</p> <ul> - <li>新AI技术的迅速发展必然革新之前的软件流程和开发过程,在思想是必须转变。</li> + <li>新AI技术的迅速发展必然革新之前的软件流程和开发过程,在思想层面是必须转变。</li> <li>大模型幻觉很严重,通过RAG技术解决幻觉<strong>做60分很容易</strong>,但是把底层的能力提升到80分甚至90分,是非常难的事情,这需要一个长期累积迭代的过程。</li> - <li>企业客户不会为了一个只有60-70分的技术产品买单付费,对待软件编码、技术架构实现,开发人员在思想上也是需要转变的。</li> + <li>企业客户不会为了一个只有60-70分的技术产品买单付费,对待软件编码、技术架构、产品交互等方面,产研人员需要对自己要求更高,追求完美</li> </ul> <p>我们团队内部经过这段时间的迭代,也碰了很多客户的需求,团队的方向也是在发展中不断的进行调整。</p> @@ -229,6 +582,13 @@ <p>TorchV.AI目前是刚起步阶段,也欢迎更多的企业客户试用,合作!!!</p> +<blockquote> + <p>如果您有商务合作需求:</p> + + <p>请扫码添加以下微信(员外🔥TorchV),并请您告知您的称呼 和 企业名称 。 +<img src="https://www.torchv.com/img/consociation/yuanwai.png" alt="" /></p> +</blockquote> + <p>我们的官网地址:<a href="https://www.torchv.com">https://www.torchv.com</a></p> <h1 id="7-references">7. References</h1> @@ -1680,611 +2040,4 @@ OpenSSL 1.1.1q 5 Jul 2022 <ul> <li><a href="https://www.luxiangdong.com/2023/08/08/prompt/">一文讲清楚实用Prompt工程</a></li> <li><a href="https://www.luxiangdong.com/2023/08/08/advprompt/">高级prompt工程讲解</a></li> -</ul>八一菜刀前言实战0-1,Java开发者也能看懂的大模型应用RAG开发实践2023-10-12T00:00:00+08:002023-10-12T00:00:00+08:00http://localhost:4000/2023/10/12/rag-inaction-java<h2 id="前言">前言</h2> - -<p>在前几天的文章中,我分享说在RAG领域,很多都是工程上的实践,做AI大模型应用的开发其实Java也能写,那么本文就一个Java开发者的立场,构建实现一个最基础的大模型应用系统。</p> - -<p>而大模型应用系统其实在目前阶段,可能应用最广的还是RAG领域,因此,本文也是通过在RAG领域的基础架构下,来实现应用的开发,主要需求点:<strong>让大模型理解文本(知识库)内容,基于知识库范围内的内容进行回答对话</strong></p> - -<p>而基于知识库的回答会帮助我们解决哪些问题呢?</p> - -<ul> - <li>✅ <strong>节省大模型训练成本:</strong>我们知道ChatGPT的知识内容停留在2021年,最新的知识它并不知道,而检索增强生成则可以解决大模型无法快速学习的问题,训练大模型代价是非常昂贵的,不仅仅只是金钱,还包括时间,随着模型的参数大小成本成正相关。</li> - <li>✅ <strong>让大模型更聪明:</strong>很多企业内部的私有数据大模型并没有学习,而通过RAG的方式可以让大模型在知识库范围的领域进行回答,避免胡说八道,基于底层大模型的基座,可以让我们的应用系统看上去更加的聪明。</li> -</ul> - -<p>在本文中,你将学习到:</p> - -<ul> - <li>✅ RAG工程的基本处理框架流程(基于Java)</li> - <li>✅ 向量数据库的基础使用及了解</li> -</ul> - -<h2 id="技术栈">技术栈</h2> - -<p>考虑到作者也是Java开发者,因此本文所选择的技术栈以及中间件也是Java人员都耳熟能详的,主要技术栈如下:</p> - -<p><strong>1、开发框架:</strong><code class="language-plaintext highlighter-rouge">Spring Boot</code>、<code class="language-plaintext highlighter-rouge">Spring Shell</code>(命令行对话)</p> - -<p>Java开发者对于<strong>Spring Boot</strong>的生态应该是非常熟悉的,而选择<code class="language-plaintext highlighter-rouge">Spring Shell</code>工具包主要是为了演示命令行的交互问答效果,和本次的技术无太大关系,算是一个最小雏形的产品交互体验。</p> - -<p><strong>2、HTTP组件:</strong><code class="language-plaintext highlighter-rouge">OkHTTP</code>、<code class="language-plaintext highlighter-rouge">OkHTTP-SSE</code></p> - -<p>此次我们选择的大模型是以智谱AI开放的ChatGLM系列为主,因此我们需要HTTP组件和商业大模型的API进行接口的对接,当然开发者如果有足够的条件,也是可以在本地部署开源大模型并且开放API接口进行调试的,这个并不冲突,本文只是为了方便演示效果,所以使用了智谱的大模型API接口,而智谱AI注册后,默认提供了一个18元的免费Token消费额度,因此接口的API-Key只需要注册一个即可快速获取。</p> - -<p><strong>3、工具包:</strong><code class="language-plaintext highlighter-rouge">Hutool</code></p> - -<p>非常好用的一个基础工具包组件,封装了很多工具类方法,包含字符、文件、时间、集合等等</p> - -<p>本文会使用到<code class="language-plaintext highlighter-rouge">Hutool</code>包的文本读取和切割方法。</p> - -<p><strong>4、向量数据库:</strong><code class="language-plaintext highlighter-rouge">ElasticSearch</code></p> - -<p>向量数据库是RAG应用程序的基础中间件,所有的文本Embedding向量都需要存储在向量数据库中间件中进行召回计算,当然在Java领域并没有类似Python中<code class="language-plaintext highlighter-rouge">numpy</code>这类本地化工具组件包,即可快速实现矩阵计算等需求(<code class="language-plaintext highlighter-rouge">PS:最近Java21的发布中,不仅仅只是虚拟线程等新特性,提供的向量API相信在未来AI领域,Java也会有一席之地的</code>),所以选择了独立部署的中间件。</p> - -<p>本文选择<strong>ElasticSearch</strong>可能对于Java开发人员也是比较熟悉的一个组件,毕竟ES在Java领域用途还是非常广的,只是可能很多开发者并不知道ElasticSearch居然还有存储向量数据的功能?</p> - -<p>对于向量数据库中间件的选择,目前市面上有非常多的向量数据库,包括:<code class="language-plaintext highlighter-rouge">Milvus</code>、<code class="language-plaintext highlighter-rouge">Qdrant</code>、<code class="language-plaintext highlighter-rouge">Postgres(pgvector)</code>、<code class="language-plaintext highlighter-rouge">Chroma</code> 等等,Java开发者可以在熟悉当前流程后,根据自己的实际需求,选择符合企业生产环境的向量数据库。</p> - -<p><strong>5、LLM大模型</strong>:<code class="language-plaintext highlighter-rouge">ChatGLM-Std</code></p> - -<p>为了演示方便,本文直接使用开放API接口的商业大模型,智谱AI提供的<code class="language-plaintext highlighter-rouge">ChatGLM-Std</code></p> - -<h2 id="rag工程的基本处理流程">RAG工程的基本处理流程</h2> - -<p>在RAG检索增强生成领域中,最简单的核心处理流程架构图如下:</p> - -<blockquote> - <p>该架构图图是一个非常简单的流程图,在RAG领域中其实有非常多的处理细节,当我们深入了解后就会知道</p> - - <p>我们后续根据该图来进行Java编码实现。</p> -</blockquote> - -<p><img src="/assets/images/llm/rag-java-action/001.png" alt="图1-RAG通用框架流程架构示意图" /></p> - -<p>在RAG应用工程领域,其实整个程序的处理包含两部分:</p> - -<ul> - <li><strong>问答:</strong>对用户提问的问题通过向量<code class="language-plaintext highlighter-rouge">Embedding</code>模型处理,然后通过查询向量数据库(<code class="language-plaintext highlighter-rouge">ElasticSearch</code>)进行相似度计算获取和用户问题最相似的知识库段落内容,获取成功后,构建<code class="language-plaintext highlighter-rouge">Prompt</code>,最终发送给大模型获取最终的答案。</li> - <li><strong>数据处理:</strong>数据的处理是将用户私有的数据进行提取,包括各种结构化及非结构化数据(例如<code class="language-plaintext highlighter-rouge">PDF</code>/<code class="language-plaintext highlighter-rouge">Word</code>/<code class="language-plaintext highlighter-rouge">Text</code>等等),提取文本数据后进行分割处理,最终通过向量<code class="language-plaintext highlighter-rouge">Embedding</code>模型将这些分割后的段落进行向量化,最终向量数据存储在基础设施向量数据库组件中,以供后续的问答流程使用。</li> -</ul> - -<p>从图中我们可以知道,在我们所需要的大模型处于什么位置,以及它的作用,主要是<strong>两个模型</strong>的应用:</p> - -<ul> - <li><strong>向量Embedding模型:</strong>对我们本地知识的向量表征处理,将文本内容转化为便于计算机理解的向量表示</li> - <li><strong>LLM问答大模型:</strong>大模型负责将我们通过语义召回的段落+用户的问题结合,构建的<code class="language-plaintext highlighter-rouge">Prompt</code>送给大模型以获取最终的答案,问答大模型在这里充当的角色是理解我们送给他的内容,然后进行精准回答</li> -</ul> - -<h2 id="java编码实践">Java编码实践</h2> - -<p>我们理解了基础的架构流程,接下来就是编码实现了</p> - -<h3 id="环境准备">环境准备</h3> - -<p><strong>Java:</strong>JDK 1.8</p> - -<p><strong>ElasticSearch:</strong>7.16.1</p> - -<p>对于<code class="language-plaintext highlighter-rouge">ElasticSearch</code>的安装,可以通过<code class="language-plaintext highlighter-rouge">docker-compose</code>在本地快速部署一个</p> - -<p>编写<code class="language-plaintext highlighter-rouge">docker-compose.yml</code>配置文件,当前部署目录建<code class="language-plaintext highlighter-rouge">data</code>文件夹挂载数据目录</p> - -<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">version</span><span class="pi">:</span> <span class="s2">"</span><span class="s">3"</span> -<span class="na">services</span><span class="pi">:</span> - <span class="na">elasticsearch</span><span class="pi">:</span> - <span class="na">image</span><span class="pi">:</span> <span class="s">elasticsearch:7.16.1</span> - <span class="na">ports</span><span class="pi">:</span> - <span class="pi">-</span> <span class="s2">"</span><span class="s">9200:9200"</span> - <span class="pi">-</span> <span class="s2">"</span><span class="s">9300:9300"</span> - <span class="na">environment</span><span class="pi">:</span> - <span class="s">node.name</span><span class="pi">:</span> <span class="s">es</span> - <span class="s">cluster.name</span><span class="pi">:</span> <span class="s">elasticsearch</span> - <span class="s">discovery.type</span><span class="pi">:</span> <span class="s">single-node</span> - <span class="na">ES_JAVA_OPTS</span><span class="pi">:</span> <span class="s">-Xms4096m -Xmx4096m</span> - <span class="na">volumes</span><span class="pi">:</span> - <span class="pi">-</span> <span class="s">./data:/usr/share/elasticsearch/data</span> - <span class="na">deploy</span><span class="pi">:</span> - <span class="na">resources</span><span class="pi">:</span> - <span class="na">limits</span><span class="pi">:</span> - <span class="na">cpus</span><span class="pi">:</span> <span class="s2">"</span><span class="s">4"</span> - <span class="na">memory</span><span class="pi">:</span> <span class="s">5G</span> - <span class="na">reservations</span><span class="pi">:</span> - <span class="na">cpus</span><span class="pi">:</span> <span class="s2">"</span><span class="s">1"</span> - <span class="na">memory</span><span class="pi">:</span> <span class="s">2G</span> - <span class="na">restart</span><span class="pi">:</span> <span class="s">always</span> -</code></pre></div></div> - -<p>启动Es:<code class="language-plaintext highlighter-rouge">docker-compose up -d</code></p> - -<h2 id="应用初体验">应用初体验</h2> - -<p>先来看整个程序的应用效果,通过Spring Shell环境下,程序启动后,如下图所示:</p> - -<p><img src="/assets/images/llm/rag-java-action/image-20231011223529653.png" alt="图3-程序启动效果" /></p> - -<p>程序启动后,在命令行终端,我们可以看到一个可交互的命令行,此时,我们可以通过<code class="language-plaintext highlighter-rouge">add</code>和<code class="language-plaintext highlighter-rouge">chat</code>两个命令完成图1中的整个流程</p> - -<p>先使用<code class="language-plaintext highlighter-rouge">add</code>命令加载文档,在<code class="language-plaintext highlighter-rouge">data</code>目录下分别存储了<code class="language-plaintext highlighter-rouge">001.txt</code>、<code class="language-plaintext highlighter-rouge">002.txt</code>两个文件,通过命令加载向量处理,如下图:</p> - -<p><img src="/assets/images/llm/rag-java-action/image-20231011223800438.png" alt="图4-ADD命令加载文件" /></p> - -<p>当日志显示保存向量成功后,此时,我们即可以通过<code class="language-plaintext highlighter-rouge">chat</code>命令进行对话了,我们先来看看<code class="language-plaintext highlighter-rouge">002.txt</code>的文本主要说了什么内容?</p> - -<blockquote> - <p>data目录下的文本,开发者在调试时可以自己随意添加,网上随便找的文章都可以</p> -</blockquote> - -<p><img src="/assets/image-20231011223914297.png" alt="图5-知识文本内容" /></p> - -<p>文章内容是一篇非常具有代表性的时政人物介绍新闻,那么我们就根据该文章的内容进行问答!</p> - -<p><strong>问题1:苏州2022年全市的GDP是多少?</strong></p> - -<p><img src="/assets/images/llm/rag-java-action/image-20231011224157706.png" alt="图6-问答调试" /></p> - -<p><strong>问题2:吉林省宣传部部长现在是谁?</strong></p> - -<p><img src="/assets/images/llm/rag-java-action/image-20231011224356744.png" alt="图7-问答调试1" /></p> - -<p>通过第一个问题,你是否可以发现问题呢?,如果你问ChatGPT一样的问题,它能准确回答吗?</p> - -<p>以下是<code class="language-plaintext highlighter-rouge">ChatGPT</code>的回答</p> - -<p><img src="/assets/images/llm/rag-java-action/image-20231012074115652.png" alt="图8-ChatGPT回答内容" /></p> - -<p>通过对比<code class="language-plaintext highlighter-rouge">ChatGPT</code>,开发者应该能看到一个基础的对比效果,主要体现:</p> - -<ul> - <li>我们都知道ChatGPT大模型的内容日期截止到2021年,之后世界发生了什么,它并不知道,同类的GPT大模型也会出现一样的问题,因为训练大模型的代价是非常昂贵的,不可能按周、月,甚至是年的频率去更新大模型。</li> - <li>基于现有的知识回答内容(RAG),能够有效的<strong>避免大模型胡说八道</strong>,而且<strong>回答的更精准</strong></li> -</ul> - -<h2 id="技术实现">技术实现</h2> - -<p>进行问答体验后,我们来看具体的Java代码实现。</p> - -<p>新建<strong>Spring Boot</strong>项目,工程目录如下:</p> - -<p><strong>GitHub</strong>:<a href="https://github.com/xiaoymin/LlmInAction/tree/master/llm_chat_java_hello">https://github.com/xiaoymin/LlmInAction/tree/master/llm_chat_java_hello</a></p> - -<p><img src="/assets/images/llm/rag-java-action/image-20231011222852231.png" alt="图2-Java代码目录结构" /></p> - -<p>从上文的RAG流程图中,我们知道了主要分两个步骤来实现,分别是<strong>数据的向量处理</strong>和<strong>问答</strong></p> - -<p>由于是通过<code class="language-plaintext highlighter-rouge">Spring Shell</code>进行实现,因此这里我也分开,主要实现了两个<code class="language-plaintext highlighter-rouge">Command</code>命令:</p> - -<ul> - <li><strong>add</strong>:在data目录下,为了演示需要,存放了两个txt内容,可以通过<code class="language-plaintext highlighter-rouge">add file名称</code>来实现文档的向量化流程加载处理,数据的处理开发者在实际的生产过程中可以通过定时任务、MQ消息等方式进行异步处理。</li> - <li><strong>chat:</strong>通过命令<code class="language-plaintext highlighter-rouge">chat 问题</code>即可在Spring Shell的命令行终端进行对话,可以问<strong>data</strong>目录下相关的问题</li> -</ul> - -<p>为了方便后续的处理,程序启动时即会自动构建向量数据库的索引集合,代码如下:</p> - -<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/** - * 初始化向量数据库index - * @param collectionName 名称 - * @param dim 维度 - */</span> - <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">initCollection</span><span class="o">(</span><span class="nc">String</span> <span class="n">collectionName</span><span class="o">,</span><span class="kt">int</span> <span class="n">dim</span><span class="o">){</span> - <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"collection:{}"</span><span class="o">,</span> <span class="n">collectionName</span><span class="o">);</span> - <span class="c1">// 查看向量索引是否存在,此方法为固定默认索引字段</span> - <span class="nc">IndexOperations</span> <span class="n">indexOperations</span> <span class="o">=</span> <span class="n">elasticsearchRestTemplate</span><span class="o">.</span><span class="na">indexOps</span><span class="o">(</span><span class="nc">IndexCoordinates</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="n">collectionName</span><span class="o">));</span> - <span class="k">if</span> <span class="o">(!</span><span class="n">indexOperations</span><span class="o">.</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span> - <span class="c1">// 索引不存在,直接创建</span> - <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"index not exists,create"</span><span class="o">);</span> - <span class="c1">//创建es的结构,简化处理</span> - <span class="nc">Document</span> <span class="n">document</span> <span class="o">=</span> <span class="nc">Document</span><span class="o">.</span><span class="na">from</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">elasticMapping</span><span class="o">(</span><span class="n">dim</span><span class="o">));</span> - <span class="c1">// 创建</span> - <span class="n">indexOperations</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;&gt;(),</span> <span class="n">document</span><span class="o">);</span> - <span class="k">return</span> <span class="kc">true</span><span class="o">;</span> - <span class="o">}</span> - <span class="k">return</span> <span class="kc">true</span><span class="o">;</span> - <span class="o">}</span> -</code></pre></div></div> - -<p>Es中的Index的Mapping结构如下:</p> - -<p><img src="/assets/images/llm/rag-java-action/image-20231011230453855.png" alt="图9-ES向量Index-Mapping结构" /></p> - -<p><strong>开发者需要注意vector字段,字段类型时<code class="language-plaintext highlighter-rouge">dense_vector</code>,并且指定向量维度为1024</strong></p> - -<blockquote> - <p>向量维度的长度指定是和最终向量Embedding模型息息相关的,不同的模型有不同的维度,比如ChatGPT的向量模型维度是1536,百度文心一言也有368的,因此根据实际情况进行选择。</p> - - <p><strong>而这里因为我们选择的是智谱AI的向量模型,该模型返回的维度为1024,那么我们在向量数据库的维度就设置为1024</strong></p> -</blockquote> - -<p>首先是<code class="language-plaintext highlighter-rouge">add</code>命令实现文档的向量化过程处理,代码如下:</p> - -<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Slf4j</span> -<span class="nd">@AllArgsConstructor</span> -<span class="nd">@ShellComponent</span> -<span class="kd">public</span> <span class="kd">class</span> <span class="nc">AddTxtCommand</span> <span class="o">{</span> - - <span class="kd">final</span> <span class="nc">TxtChunk</span> <span class="n">txtChunk</span><span class="o">;</span> - <span class="kd">final</span> <span class="nc">VectorStorage</span> <span class="n">vectorStorage</span><span class="o">;</span> - <span class="kd">final</span> <span class="nc">ZhipuAI</span> <span class="n">zhipuAI</span><span class="o">;</span> - - <span class="nd">@ShellMethod</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="s">"add local txt data"</span><span class="o">)</span> - <span class="kd">public</span> <span class="nc">String</span> <span class="nf">add</span><span class="o">(</span><span class="nc">String</span> <span class="n">doc</span><span class="o">){</span> - <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"start add doc."</span><span class="o">);</span> - <span class="c1">// 加载</span> - <span class="nc">List</span><span class="o">&lt;</span><span class="nc">ChunkResult</span><span class="o">&gt;</span> <span class="n">chunkResults</span><span class="o">=</span> <span class="n">txtChunk</span><span class="o">.</span><span class="na">chunk</span><span class="o">(</span><span class="n">doc</span><span class="o">);</span> - <span class="c1">// embedding</span> - <span class="nc">List</span><span class="o">&lt;</span><span class="nc">EmbeddingResult</span><span class="o">&gt;</span> <span class="n">embeddingResults</span><span class="o">=</span><span class="n">zhipuAI</span><span class="o">.</span><span class="na">embedding</span><span class="o">(</span><span class="n">chunkResults</span><span class="o">);</span> - <span class="c1">// store vector</span> - <span class="nc">String</span> <span class="n">collection</span><span class="o">=</span> <span class="n">vectorStorage</span><span class="o">.</span><span class="na">getCollectionName</span><span class="o">();</span> - <span class="n">vectorStorage</span><span class="o">.</span><span class="na">store</span><span class="o">(</span><span class="n">collection</span><span class="o">,</span><span class="n">embeddingResults</span><span class="o">);</span> - <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"finished"</span><span class="o">);</span> - <span class="k">return</span> <span class="s">"finished docId:{}"</span><span class="o">+</span><span class="n">doc</span><span class="o">;</span> - <span class="o">}</span> -<span class="o">}</span> -</code></pre></div></div> - -<p>我们完全按照图1RAG的流程架构图进行代码的变现,主要的步骤:</p> - -<p>1、加载指定的文档,并且将文档内容进行分割处理(按固定size大小进行分割处理),得到分割集合<code class="language-plaintext highlighter-rouge">chunkResults</code>,代码如下:</p> - -<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Slf4j</span> -<span class="nd">@Component</span> -<span class="nd">@AllArgsConstructor</span> -<span class="kd">public</span> <span class="kd">class</span> <span class="nc">TxtChunk</span> <span class="o">{</span> - - <span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">ChunkResult</span><span class="o">&gt;</span> <span class="nf">chunk</span><span class="o">(</span><span class="nc">String</span> <span class="n">docId</span><span class="o">){</span> - <span class="nc">String</span> <span class="n">path</span><span class="o">=</span><span class="s">"data/"</span><span class="o">+</span><span class="n">docId</span><span class="o">+</span><span class="s">".txt"</span><span class="o">;</span> - <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"start chunk---&gt; docId:{},path:{}"</span><span class="o">,</span><span class="n">docId</span><span class="o">,</span><span class="n">path</span><span class="o">);</span> - <span class="c1">// 读取data目录下的文件流</span> - <span class="nc">ClassPathResource</span> <span class="n">classPathResource</span><span class="o">=</span><span class="k">new</span> <span class="nc">ClassPathResource</span><span class="o">(</span><span class="n">path</span><span class="o">);</span> - <span class="k">try</span> <span class="o">{</span> - <span class="c1">// 读取为文本</span> - <span class="nc">String</span> <span class="n">txt</span><span class="o">=</span><span class="nc">IoUtil</span><span class="o">.</span><span class="na">read</span><span class="o">(</span><span class="n">classPathResource</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">(),</span> <span class="nc">StandardCharsets</span><span class="o">.</span><span class="na">UTF_8</span><span class="o">);</span> - <span class="c1">//按固定字数分割,256</span> - <span class="nc">String</span><span class="o">[]</span> <span class="n">lines</span><span class="o">=</span><span class="nc">StrUtil</span><span class="o">.</span><span class="na">split</span><span class="o">(</span><span class="n">txt</span><span class="o">,</span><span class="mi">256</span><span class="o">);</span> - <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"chunk size:{}"</span><span class="o">,</span> <span class="nc">ArrayUtil</span><span class="o">.</span><span class="na">length</span><span class="o">(</span><span class="n">lines</span><span class="o">));</span> - <span class="nc">List</span><span class="o">&lt;</span><span class="nc">ChunkResult</span><span class="o">&gt;</span> <span class="n">results</span><span class="o">=</span><span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span> - <span class="c1">//此处给每个文档一个固定的chunkId</span> - <span class="nc">AtomicInteger</span> <span class="n">atomicInteger</span><span class="o">=</span><span class="k">new</span> <span class="nc">AtomicInteger</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span> - <span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="nl">line:</span><span class="n">lines</span><span class="o">){</span> - <span class="nc">ChunkResult</span> <span class="n">chunkResult</span><span class="o">=</span><span class="k">new</span> <span class="nc">ChunkResult</span><span class="o">();</span> - <span class="n">chunkResult</span><span class="o">.</span><span class="na">setDocId</span><span class="o">(</span><span class="n">docId</span><span class="o">);</span> - <span class="n">chunkResult</span><span class="o">.</span><span class="na">setContent</span><span class="o">(</span><span class="n">line</span><span class="o">);</span> - <span class="n">chunkResult</span><span class="o">.</span><span class="na">setChunkId</span><span class="o">(</span><span class="n">atomicInteger</span><span class="o">.</span><span class="na">incrementAndGet</span><span class="o">());</span> - <span class="n">results</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">chunkResult</span><span class="o">);</span> - <span class="o">}</span> - <span class="k">return</span> <span class="n">results</span><span class="o">;</span> - <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span> - <span class="n">log</span><span class="o">.</span><span class="na">error</span><span class="o">(</span><span class="n">e</span><span class="o">.</span><span class="na">getMessage</span><span class="o">());</span> - <span class="o">}</span> - <span class="k">return</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span> - <span class="o">}</span> - -<span class="o">}</span> -</code></pre></div></div> - -<p>2、将分块的集合通过智谱AI提供的向量<code class="language-plaintext highlighter-rouge">Embedding</code>模型进行向量化处理,代码实现如下:</p> - -<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/** - * 批量 - * @param chunkResults 批量文本 - * @return 向量 - */</span> - <span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">EmbeddingResult</span><span class="o">&gt;</span> <span class="nf">embedding</span><span class="o">(</span><span class="nc">List</span><span class="o">&lt;</span><span class="nc">ChunkResult</span><span class="o">&gt;</span> <span class="n">chunkResults</span><span class="o">){</span> - <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"start embedding,size:{}"</span><span class="o">,</span><span class="nc">CollectionUtil</span><span class="o">.</span><span class="na">size</span><span class="o">(</span><span class="n">chunkResults</span><span class="o">));</span> - <span class="k">if</span> <span class="o">(</span><span class="nc">CollectionUtil</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">(</span><span class="n">chunkResults</span><span class="o">)){</span> - <span class="k">return</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span> - <span class="o">}</span> - <span class="nc">List</span><span class="o">&lt;</span><span class="nc">EmbeddingResult</span><span class="o">&gt;</span> <span class="n">embeddingResults</span><span class="o">=</span><span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span> - <span class="k">for</span> <span class="o">(</span><span class="nc">ChunkResult</span> <span class="nl">chunkResult:</span><span class="n">chunkResults</span><span class="o">){</span> - <span class="c1">//分别处理</span> - <span class="n">embeddingResults</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">embedding</span><span class="o">(</span><span class="n">chunkResult</span><span class="o">));</span> - <span class="o">}</span> - <span class="k">return</span> <span class="n">embeddingResults</span><span class="o">;</span> - <span class="o">}</span> - - <span class="kd">public</span> <span class="nc">EmbeddingResult</span> <span class="nf">embedding</span><span class="o">(</span><span class="nc">ChunkResult</span> <span class="n">chunkResult</span><span class="o">){</span> - <span class="c1">//获取智谱AI的开发Key</span> - <span class="nc">String</span> <span class="n">apiKey</span><span class="o">=</span> <span class="k">this</span><span class="o">.</span><span class="na">getApiKey</span><span class="o">();</span> - <span class="c1">// 初始化http客户端</span> - <span class="nc">OkHttpClient</span><span class="o">.</span><span class="na">Builder</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">OkHttpClient</span><span class="o">.</span><span class="na">Builder</span><span class="o">()</span> - <span class="o">.</span><span class="na">connectTimeout</span><span class="o">(</span><span class="mi">20000</span><span class="o">,</span> <span class="nc">TimeUnit</span><span class="o">.</span><span class="na">MILLISECONDS</span><span class="o">)</span> - <span class="o">.</span><span class="na">readTimeout</span><span class="o">(</span><span class="mi">20000</span><span class="o">,</span> <span class="nc">TimeUnit</span><span class="o">.</span><span class="na">MILLISECONDS</span><span class="o">)</span> - <span class="o">.</span><span class="na">writeTimeout</span><span class="o">(</span><span class="mi">20000</span><span class="o">,</span> <span class="nc">TimeUnit</span><span class="o">.</span><span class="na">MILLISECONDS</span><span class="o">)</span> - <span class="o">.</span><span class="na">addInterceptor</span><span class="o">(</span><span class="k">new</span> <span class="nc">ZhipuHeaderInterceptor</span><span class="o">(</span><span class="n">apiKey</span><span class="o">));</span> - <span class="nc">OkHttpClient</span> <span class="n">okHttpClient</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">build</span><span class="o">();</span> - <span class="nc">EmbeddingResult</span> <span class="n">embedRequest</span><span class="o">=</span><span class="k">new</span> <span class="nc">EmbeddingResult</span><span class="o">();</span> - <span class="n">embedRequest</span><span class="o">.</span><span class="na">setPrompt</span><span class="o">(</span><span class="n">chunkResult</span><span class="o">.</span><span class="na">getContent</span><span class="o">());</span> - <span class="n">embedRequest</span><span class="o">.</span><span class="na">setRequestId</span><span class="o">(</span><span class="nc">Objects</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">chunkResult</span><span class="o">.</span><span class="na">getChunkId</span><span class="o">()));</span> - <span class="c1">// 智谱embedding模型接口</span> - <span class="nc">Request</span> <span class="n">request</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Request</span><span class="o">.</span><span class="na">Builder</span><span class="o">()</span> - <span class="o">.</span><span class="na">url</span><span class="o">(</span><span class="s">"https://open.bigmodel.cn/api/paas/v3/model-api/text_embedding/invoke"</span><span class="o">)</span> - <span class="o">.</span><span class="na">post</span><span class="o">(</span><span class="nc">RequestBody</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="nc">MediaType</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="nc">ContentType</span><span class="o">.</span><span class="na">JSON</span><span class="o">.</span><span class="na">getValue</span><span class="o">()),</span> <span class="no">GSON</span><span class="o">.</span><span class="na">toJson</span><span class="o">(</span><span class="n">embedRequest</span><span class="o">)))</span> - <span class="o">.</span><span class="na">build</span><span class="o">();</span> - <span class="k">try</span> <span class="o">{</span> - <span class="nc">Response</span> <span class="n">response</span><span class="o">=</span> <span class="n">okHttpClient</span><span class="o">.</span><span class="na">newCall</span><span class="o">(</span><span class="n">request</span><span class="o">).</span><span class="na">execute</span><span class="o">();</span> - <span class="nc">String</span> <span class="n">result</span><span class="o">=</span><span class="n">response</span><span class="o">.</span><span class="na">body</span><span class="o">().</span><span class="na">string</span><span class="o">();</span> - <span class="nc">ZhipuResult</span> <span class="n">zhipuResult</span><span class="o">=</span> <span class="no">GSON</span><span class="o">.</span><span class="na">fromJson</span><span class="o">(</span><span class="n">result</span><span class="o">,</span> <span class="nc">ZhipuResult</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> - <span class="nc">EmbeddingResult</span> <span class="n">ret</span><span class="o">=</span> <span class="n">zhipuResult</span><span class="o">.</span><span class="na">getData</span><span class="o">();</span> - <span class="n">ret</span><span class="o">.</span><span class="na">setPrompt</span><span class="o">(</span><span class="n">embedRequest</span><span class="o">.</span><span class="na">getPrompt</span><span class="o">());</span> - <span class="n">ret</span><span class="o">.</span><span class="na">setRequestId</span><span class="o">(</span><span class="n">embedRequest</span><span class="o">.</span><span class="na">getRequestId</span><span class="o">());</span> - <span class="k">return</span> <span class="n">ret</span><span class="o">;</span> - <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span> - <span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="n">e</span><span class="o">);</span> - <span class="o">}</span> - - <span class="o">}</span> -</code></pre></div></div> - -<p>3、向量处理成功后,我们即可将向量数据存储在向量数据库中间件(<code class="language-plaintext highlighter-rouge">ElasticSearch</code>)中,调用<code class="language-plaintext highlighter-rouge">vectorStorage.store</code>处理,代码如下:</p> - -<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">public void store(String collectionName,List&lt;EmbeddingResult&gt; embeddingResults){</span> - <span class="s">//保存向量</span> - <span class="s">log.info("save vector,collection:{},size:{}",collectionName, CollectionUtil.size(embeddingResults));</span> - - <span class="s">List&lt;IndexQuery&gt; results = new ArrayList&lt;&gt;();</span> - <span class="s">for (EmbeddingResult embeddingResult</span> <span class="pi">:</span> <span class="s">embeddingResults) {</span> - <span class="s">ElasticVectorData ele = new ElasticVectorData();</span> - <span class="s">ele.setVector(embeddingResult.getEmbedding());</span> - <span class="s">ele.setChunkId(embeddingResult.getRequestId());</span> - <span class="s">ele.setContent(embeddingResult.getPrompt());</span> - <span class="s">results.add(new IndexQueryBuilder().withObject(ele).build());</span> - <span class="s">}</span> - <span class="s">// 构建数据包</span> - <span class="s">List&lt;IndexedObjectInformation&gt; bulkedResult = elasticsearchRestTemplate.bulkIndex(results, IndexCoordinates.of(collectionName));</span> - <span class="s">int size = CollectionUtil.size(bulkedResult);</span> - <span class="s">log.info("保存向量成功-size:{}", size);</span> - <span class="s">}</span> -</code></pre></div></div> - -<p>至此,整个文本数据的Embedding处理就完成了。</p> - -<p>数据处理完成后,接下来我们需要实现问答<code class="language-plaintext highlighter-rouge">chat</code>命令,来看代码实现:</p> - -<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@AllArgsConstructor</span> -<span class="nd">@Slf4j</span> -<span class="nd">@ShellComponent</span> -<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ChatCommand</span> <span class="o">{</span> - - <span class="kd">final</span> <span class="nc">VectorStorage</span> <span class="n">vectorStorage</span><span class="o">;</span> - <span class="kd">final</span> <span class="nc">ZhipuAI</span> <span class="n">zhipuAI</span><span class="o">;</span> - - <span class="nd">@ShellMethod</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="s">"chat with files"</span><span class="o">)</span> - <span class="kd">public</span> <span class="nc">String</span> <span class="nf">chat</span><span class="o">(</span><span class="nc">String</span> <span class="n">question</span><span class="o">){</span> - <span class="k">if</span> <span class="o">(</span><span class="nc">StrUtil</span><span class="o">.</span><span class="na">isBlank</span><span class="o">(</span><span class="n">question</span><span class="o">)){</span> - <span class="k">return</span> <span class="s">"You must send a question"</span><span class="o">;</span> - <span class="o">}</span> - <span class="c1">//句子转向量</span> - <span class="kt">double</span><span class="o">[]</span> <span class="n">vector</span><span class="o">=</span><span class="n">zhipuAI</span><span class="o">.</span><span class="na">sentence</span><span class="o">(</span><span class="n">question</span><span class="o">);</span> - <span class="c1">// 向量召回</span> - <span class="nc">String</span> <span class="n">collection</span><span class="o">=</span> <span class="n">vectorStorage</span><span class="o">.</span><span class="na">getCollectionName</span><span class="o">();</span> - <span class="nc">String</span> <span class="n">vectorData</span><span class="o">=</span><span class="n">vectorStorage</span><span class="o">.</span><span class="na">retrieval</span><span class="o">(</span><span class="n">collection</span><span class="o">,</span><span class="n">vector</span><span class="o">);</span> - <span class="k">if</span> <span class="o">(</span><span class="nc">StrUtil</span><span class="o">.</span><span class="na">isBlank</span><span class="o">(</span><span class="n">vectorData</span><span class="o">)){</span> - <span class="k">return</span> <span class="s">"No Answer!"</span><span class="o">;</span> - <span class="o">}</span> - <span class="c1">// 构建Prompt</span> - <span class="nc">String</span> <span class="n">prompt</span><span class="o">=</span> <span class="nc">LLMUtils</span><span class="o">.</span><span class="na">buildPrompt</span><span class="o">(</span><span class="n">question</span><span class="o">,</span><span class="n">vectorData</span><span class="o">);</span> - <span class="n">zhipuAI</span><span class="o">.</span><span class="na">chat</span><span class="o">(</span><span class="n">prompt</span><span class="o">);</span> - <span class="c1">// 大模型对话</span> - <span class="c1">//return "you question:{}"+question+"finished.";</span> - <span class="k">return</span> <span class="nc">StrUtil</span><span class="o">.</span><span class="na">EMPTY</span><span class="o">;</span> - <span class="o">}</span> - -<span class="o">}</span> -</code></pre></div></div> - -<p><code class="language-plaintext highlighter-rouge">Chat</code>命令主要包含的步骤如下:</p> - -<p>1、将用户的问句首先通过向量Embedding模型转化得到一个多维的浮点型向量数组,代码如下:</p> - -<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/** - * 获取句子的向量 - * @param sentence 句子 - * @return 向量 - */</span> - <span class="kd">public</span> <span class="kt">double</span><span class="o">[]</span> <span class="nf">sentence</span><span class="o">(</span><span class="nc">String</span> <span class="n">sentence</span><span class="o">){</span> - <span class="nc">ChunkResult</span> <span class="n">chunkResult</span><span class="o">=</span><span class="k">new</span> <span class="nc">ChunkResult</span><span class="o">();</span> - <span class="n">chunkResult</span><span class="o">.</span><span class="na">setContent</span><span class="o">(</span><span class="n">sentence</span><span class="o">);</span> - <span class="n">chunkResult</span><span class="o">.</span><span class="na">setChunkId</span><span class="o">(</span><span class="nc">RandomUtil</span><span class="o">.</span><span class="na">randomInt</span><span class="o">());</span> - <span class="nc">EmbeddingResult</span> <span class="n">embeddingResult</span><span class="o">=</span><span class="k">this</span><span class="o">.</span><span class="na">embedding</span><span class="o">(</span><span class="n">chunkResult</span><span class="o">);</span> - <span class="k">return</span> <span class="n">embeddingResult</span><span class="o">.</span><span class="na">getEmbedding</span><span class="o">();</span> - <span class="o">}</span> -</code></pre></div></div> - -<p>2、根据向量数据查询向量数据库召回相似的段落内容,<code class="language-plaintext highlighter-rouge">vectorStorage.retrieval</code>方法代码如下:</p> - -<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nc">String</span> <span class="nf">retrieval</span><span class="o">(</span><span class="nc">String</span> <span class="n">collectionName</span><span class="o">,</span><span class="kt">double</span><span class="o">[]</span> <span class="n">vector</span><span class="o">){</span> - <span class="c1">// Build the script,查询向量</span> - <span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Object</span><span class="o">&gt;</span> <span class="n">params</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;&gt;();</span> - <span class="n">params</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"query_vector"</span><span class="o">,</span> <span class="n">vector</span><span class="o">);</span> - <span class="c1">// 计算cos值+1,避免出现负数的情况,得到结果后,实际score值在减1再计算</span> - <span class="nc">Script</span> <span class="n">script</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Script</span><span class="o">(</span><span class="nc">ScriptType</span><span class="o">.</span><span class="na">INLINE</span><span class="o">,</span> <span class="nc">Script</span><span class="o">.</span><span class="na">DEFAULT_SCRIPT_LANG</span><span class="o">,</span> <span class="s">"cosineSimilarity(params.query_vector, 'vector')+1"</span><span class="o">,</span> <span class="n">params</span><span class="o">);</span> - <span class="nc">ScriptScoreQueryBuilder</span> <span class="n">scriptScoreQueryBuilder</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ScriptScoreQueryBuilder</span><span class="o">(</span><span class="nc">QueryBuilders</span><span class="o">.</span><span class="na">boolQuery</span><span class="o">(),</span> <span class="n">script</span><span class="o">);</span> - <span class="c1">// 构建请求</span> - <span class="nc">NativeSearchQuery</span> <span class="n">nativeSearchQuery</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">NativeSearchQueryBuilder</span><span class="o">()</span> - <span class="o">.</span><span class="na">withQuery</span><span class="o">(</span><span class="n">scriptScoreQueryBuilder</span><span class="o">)</span> - <span class="o">.</span><span class="na">withPageable</span><span class="o">(</span><span class="nc">Pageable</span><span class="o">.</span><span class="na">ofSize</span><span class="o">(</span><span class="mi">3</span><span class="o">)).</span><span class="na">build</span><span class="o">();</span> - <span class="nc">SearchHits</span><span class="o">&lt;</span><span class="nc">ElasticVectorData</span><span class="o">&gt;</span> <span class="n">dataSearchHits</span> <span class="o">=</span> <span class="k">this</span><span class="o">.</span><span class="na">elasticsearchRestTemplate</span><span class="o">.</span><span class="na">search</span><span class="o">(</span><span class="n">nativeSearchQuery</span><span class="o">,</span> <span class="nc">ElasticVectorData</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="nc">IndexCoordinates</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="n">collectionName</span><span class="o">));</span> - <span class="c1">//log.info("检索成功,size:{}", dataSearchHits.getTotalHits());</span> - <span class="nc">List</span><span class="o">&lt;</span><span class="nc">SearchHit</span><span class="o">&lt;</span><span class="nc">ElasticVectorData</span><span class="o">&gt;&gt;</span> <span class="n">data</span> <span class="o">=</span> <span class="n">dataSearchHits</span><span class="o">.</span><span class="na">getSearchHits</span><span class="o">();</span> - <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">results</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">LinkedList</span><span class="o">&lt;&gt;();</span> - <span class="k">for</span> <span class="o">(</span><span class="nc">SearchHit</span><span class="o">&lt;</span><span class="nc">ElasticVectorData</span><span class="o">&gt;</span> <span class="n">ele</span> <span class="o">:</span> <span class="n">data</span><span class="o">)</span> <span class="o">{</span> - <span class="n">results</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">ele</span><span class="o">.</span><span class="na">getContent</span><span class="o">().</span><span class="na">getContent</span><span class="o">());</span> - <span class="o">}</span> - <span class="k">return</span> <span class="nc">CollectionUtil</span><span class="o">.</span><span class="na">join</span><span class="o">(</span><span class="n">results</span><span class="o">,</span><span class="s">""</span><span class="o">);</span> - <span class="o">}</span> -</code></pre></div></div> - -<p>这里主要利用了<code class="language-plaintext highlighter-rouge">ElasticSearch</code>提供的<code class="language-plaintext highlighter-rouge">cosineSimilarity</code>余弦相似性函数,计算向量得到相似度的分值,<strong>分值会在区间[0,1]之间,如果无限趋近于1那么代表用户输入的句子和之前我们存储在向量中的句子是非常相似的,越相似代表我们找到了语义相近的文档内容,可以作为最终构建大模型Prompt的基础内容。</strong></p> - -<blockquote> - <p>向量矩阵的计算除了余弦相似性,还有IP点积、欧几里得距离等等,根据实际情况选择不同的算法实现。</p> -</blockquote> - -<p>3、向量召回Top3得到相似的语义文本内容后,我们就可以构建<code class="language-plaintext highlighter-rouge">Prompt</code>了,并且发送给大模型,<code class="language-plaintext highlighter-rouge">Prompt</code>如下:</p> - -<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="nc">String</span> <span class="nf">buildPrompt</span><span class="o">(</span><span class="nc">String</span> <span class="n">question</span><span class="o">,</span><span class="nc">String</span> <span class="n">context</span><span class="o">){</span> - <span class="k">return</span> <span class="s">"请利用如下上下文的信息回答问题:"</span> <span class="o">+</span> <span class="s">"\n"</span> <span class="o">+</span> - <span class="n">question</span> <span class="o">+</span> <span class="s">"\n"</span> <span class="o">+</span> - <span class="s">"上下文信息如下:"</span> <span class="o">+</span> <span class="s">"\n"</span> <span class="o">+</span> - <span class="n">context</span> <span class="o">+</span> <span class="s">"\n"</span> <span class="o">+</span> - <span class="s">"如果上下文信息中没有帮助,则不允许胡乱回答!"</span><span class="o">;</span> - <span class="o">}</span> -</code></pre></div></div> - -<p>而在构建<code class="language-plaintext highlighter-rouge">Prompt</code>时,我们可以遵循一个最简单的框架范式,<strong>RTF框架(Role-Task-Format)</strong>:</p> - -<ul> - <li><strong>R-Role</strong>:指定GPT大模型担任特定的角色</li> - <li><strong>T-Task</strong>:任务,需要大模型做的事情</li> - <li><strong>F-Format</strong>:大模型返回的内容格式(常规情况下可以忽略)</li> -</ul> - -<p>4、最后是调用大模型,实现sse流式调用输出,代码如下:</p> - -<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">chat</span><span class="o">(</span><span class="nc">String</span> <span class="n">prompt</span><span class="o">){</span> - <span class="k">try</span> <span class="o">{</span> - <span class="nc">OkHttpClient</span><span class="o">.</span><span class="na">Builder</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">OkHttpClient</span><span class="o">.</span><span class="na">Builder</span><span class="o">()</span> - <span class="o">.</span><span class="na">connectTimeout</span><span class="o">(</span><span class="mi">20000</span><span class="o">,</span> <span class="nc">TimeUnit</span><span class="o">.</span><span class="na">MILLISECONDS</span><span class="o">)</span> - <span class="o">.</span><span class="na">readTimeout</span><span class="o">(</span><span class="mi">20000</span><span class="o">,</span> <span class="nc">TimeUnit</span><span class="o">.</span><span class="na">MILLISECONDS</span><span class="o">)</span> - <span class="o">.</span><span class="na">writeTimeout</span><span class="o">(</span><span class="mi">20000</span><span class="o">,</span> <span class="nc">TimeUnit</span><span class="o">.</span><span class="na">MILLISECONDS</span><span class="o">)</span> - <span class="o">.</span><span class="na">addInterceptor</span><span class="o">(</span><span class="k">new</span> <span class="nc">ZhipuHeaderInterceptor</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getApiKey</span><span class="o">()));</span> - <span class="nc">OkHttpClient</span> <span class="n">okHttpClient</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="na">build</span><span class="o">();</span> - - <span class="nc">ZhipuChatCompletion</span> <span class="n">zhipuChatCompletion</span><span class="o">=</span><span class="k">new</span> <span class="nc">ZhipuChatCompletion</span><span class="o">();</span> - <span class="n">zhipuChatCompletion</span><span class="o">.</span><span class="na">addPrompt</span><span class="o">(</span><span class="n">prompt</span><span class="o">);</span> - <span class="c1">// 采样温度,控制输出的随机性,必须为正数</span> - <span class="c1">// 值越大,会使输出更随机,更具创造性;值越小,输出会更加稳定或确定</span> - <span class="n">zhipuChatCompletion</span><span class="o">.</span><span class="na">setTemperature</span><span class="o">(</span><span class="mf">0.7f</span><span class="o">);</span> - <span class="n">zhipuChatCompletion</span><span class="o">.</span><span class="na">setTop_p</span><span class="o">(</span><span class="mf">0.7f</span><span class="o">);</span> - - <span class="nc">EventSource</span><span class="o">.</span><span class="na">Factory</span> <span class="n">factory</span> <span class="o">=</span> <span class="nc">EventSources</span><span class="o">.</span><span class="na">createFactory</span><span class="o">(</span><span class="n">okHttpClient</span><span class="o">);</span> - <span class="nc">ObjectMapper</span> <span class="n">mapper</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ObjectMapper</span><span class="o">();</span> - <span class="nc">String</span> <span class="n">requestBody</span> <span class="o">=</span> <span class="n">mapper</span><span class="o">.</span><span class="na">writeValueAsString</span><span class="o">(</span><span class="n">zhipuChatCompletion</span><span class="o">);</span> - <span class="nc">Request</span> <span class="n">request</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Request</span><span class="o">.</span><span class="na">Builder</span><span class="o">()</span> - <span class="o">.</span><span class="na">url</span><span class="o">(</span><span class="s">"https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_std/sse-invoke"</span><span class="o">)</span> - <span class="o">.</span><span class="na">post</span><span class="o">(</span><span class="nc">RequestBody</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="nc">MediaType</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="nc">ContentType</span><span class="o">.</span><span class="na">JSON</span><span class="o">.</span><span class="na">getValue</span><span class="o">()),</span> <span class="n">requestBody</span><span class="o">))</span> - <span class="o">.</span><span class="na">build</span><span class="o">();</span> - <span class="nc">CountDownLatch</span> <span class="n">countDownLatch</span><span class="o">=</span><span class="k">new</span> <span class="nc">CountDownLatch</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span> - <span class="c1">// 创建事件,控制台输出</span> - <span class="nc">EventSource</span> <span class="n">eventSource</span> <span class="o">=</span> <span class="n">factory</span><span class="o">.</span><span class="na">newEventSource</span><span class="o">(</span><span class="n">request</span><span class="o">,</span> <span class="k">new</span> <span class="nc">ConsoleEventSourceListener</span><span class="o">(</span><span class="n">countDownLatch</span><span class="o">));</span> - <span class="n">countDownLatch</span><span class="o">.</span><span class="na">await</span><span class="o">();</span> - - <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span> - <span class="n">log</span><span class="o">.</span><span class="na">error</span><span class="o">(</span><span class="s">"llm-chat异常:{}"</span><span class="o">,</span> <span class="n">e</span><span class="o">.</span><span class="na">getMessage</span><span class="o">());</span> - <span class="o">}</span> - <span class="o">}</span> -</code></pre></div></div> - -<p>SSE流式的调用我们使用了<code class="language-plaintext highlighter-rouge">okhttp-sse</code>组件提供的功能快速实现。</p> - -<p>好了,整个工程层面的Java代码实现就已经全部完成了。</p> - -<h2 id="最后">最后</h2> - -<p>以上就是本片分享的全部内容了,通过Java开发语言,实现一个最小可用级别的RAG大模型应用!相信你看完本文后,也能够对AI大模型应用的开发有一个基本的了解。</p> - -<p>如果你也在关注大模型、RAG检索增强生成技术,欢迎关注我,一起探索学习、成长~!</p> - -<h2 id="附录">附录</h2> - -<p>本文代码Github:<a href="https://github.com/xiaoymin/LlmInAction">https://github.com/xiaoymin/LlmInAction</a></p> - -<p>智谱AI:<a href="https://open.bigmodel.cn/">https://open.bigmodel.cn/</a></p>八一菜刀前言全面进击AI大模型、RAG领域2023-10-10T00:00:00+08:002023-10-10T00:00:00+08:00http://localhost:4000/2023/10/10/llm-start<h2 id="写在前面">写在前面</h2> - -<p>首先,<strong>非常感谢关注Knife4j项目的朋友</strong>,该公众号应该是今年开始,对于开源项目Knife4j的更新都在此公众号进行了第一时间的发布更新,包括该项目的迭代、想法、实践等等内容,包括最近Knife4j的付费产品Knife4jInsight的推出,虽然更新的不是很频繁,但对于还是要给自己一直坚持的事情做输出点赞的(感动了自己😹)。对于写公众号而言,对于文章的发表,如果有人持续关注的话,会是一种正向的鼓励~!</p> - -<p>而现在,考虑到我实际工作中的内容,目前工作核心是在做<strong>大模型RAG(检索增强生成)方面</strong>的开发工作,主要还是以Java技术栈进行产品的功能迭代开发,Python语言则更多的偏向底层大模型方面,包括大模型(LLM)的训练、微调、数据标注、向量Embedding等领域,工程上,业务产品测的逻辑实现、编排,接口开发等等功能还是以Java语言实现为主,并非使用当下最火的LangChain、LlaMaIndex等Python框架,我在昨天看一本书<strong>《Java开发之道》</strong>里面提到,开发者在实际开发过程中,<strong>在产品或项目开发周期结束后,需要善于总结自己的工作内容</strong>,我觉得以Blog或者视频的形式进行输出最好,这样才能更快速的成长。</p> - -<p>我回想起这么多年的工作,对于一个领域,<strong>不管是技术层面,或者是业务层面,似乎一直是缺少总结性的输出的,或者说做的都不是太深入</strong>。在早些时候,我和我的老大哥员外说,这么多年做的东西不管是产品、还是项目,都不太能拿的出手,而<strong>随着时间越久,这种深深的挫败感</strong>就从内心油然而生,每每想起,都自感恼火😫。主要原因还是我们做的东西都太表面了,在技术层面,我们很多技术都是浮于表面,并<strong>没有做持续深度的精进</strong>,产品层面,一个像样的<strong>产品是经过千锤百炼的打磨</strong>的,细扣每一个细节,把同类竞品比下去,也许产品上面一个看似不起眼的优点,都能把同类的竞品给比下去,而要做到产品上的优势体现,技术人员的投入是成正相关的。项目就更不用说了,<strong>交钥匙工程(内部代号,意指项目做完就验收了,至于使用如何,功能好不好用从来没care过,业主也不care)</strong>的项目做的已经数都数不过来了。</p> - -<p>而最近我和我的老伙计员外已经一头扎进了AI大模型、RAG(Retrieval Augmented Generation-检索增强生成)这个赛道,每天讨论的都是大模型、RAG等相关内容,然后产品的技术栈开发又是Java为主,Python为辅,在Java语言这个领域开发AI应用,好像目前在RAG这个领域并没有相关的技术文档、博客输出,基本80%都是Python,我在看了<strong>LangChain</strong>、<strong>LlaMaIndex</strong>等Python框架处理开发大模型应用(主要是RAG)时,除了在本地加载大模型外,很多其实都是工程方面的知识,并非一定要使用Python语言来进行开发,而我最近实际工作中又在做这个,因此,希望能够通过以Java+Python两种语言的形式,通过学习大模型、RAG等新型领域的知识,甚至是学习Python语言,将自己学到的内容以及一些工作中的实践通过文章的方式进行输出分享,更多的还是会将内容应用的实际的产品中,也希望在这个领域做一个深耕,不管是技术上还是业务领域,大模型这一波,我觉得每一个开发者都应该持续保持关注。</p> - -<p>在AI大模型、RAG这个赛道,我们要做的事情:</p> - -<ul> - <li> - <p><strong>技术:</strong>深挖AI大模型、RAG领域的技术细节(应用工程领域),从思想、代码、架构等领域都需要<strong>花120%的投入</strong>,知其所以然!</p> - - <blockquote> - <p>☑️ 考虑到我并非搞算法的人员,底层的大模型算法等内容,我觉得对于我自己的要求而言,做到知道、了解即可,甚至有必要的话,搞一张4090(太贵了,还没舍得买)的卡跑跑预训练的模型也是有必要的!</p> - - <p>☑️ RAG领域在工程层面的知识所涉及的面也是足够广的,对于做应用开发者而言,也并非一朝一夕就能全盘了解其中的细节,需要做的就是两字:<strong>“深耕”</strong></p> - - <p>☑️ 技术层面有时候是需要较真一下的,解决关键的核心技术问题是对竞对产品的致命打击</p> - </blockquote> - </li> - <li> - <p><strong>产品</strong>:<strong>坚持价值输出导向,倾听客户的意见,坚决反对交钥匙工程</strong></p> - - <blockquote> - <p>☑️ 技术上输出最终都会落地到实际应用产品的开发上,而产品需要坚持的事情则是要尊重用户,技术测则需要尊重产品</p> - - <p>☑️ 价值输出导向是永恒的真理,客户付费买单,最终看中的也是这个产品所带来的价值,或者说能够给客户带来收益(赚钱才是硬道理)</p> - - <p>☑️ 做顺势而为的事情,而大模型这一波技术浪潮,我觉得做这方面相关的内容或者产品技术探索,就是顺势了</p> - </blockquote> - </li> -</ul> - -<h2 id="-新名称">🆕 新名称</h2> - -<p>这个公众号之前都是以Swagger/OpenAPI/Knife4j等领域相关的名称,因为一直在维护开源项目Knife4j,主要还是和接口相关的,就一直用了这些名称!思来想去,公众号的性质也是个人性质,以后更多的还是以个人的一些想法、工作实践等内容为主进行输出,就干脆换回之前一直用的网络昵称名称吧:<strong>八一菜刀</strong></p> - -<blockquote> - <p>🆕 名称含义(该公众号之前注册时也是用的这个名称,相当于恢复出厂设置了)</p> - - <p><strong>八一</strong>:字面意思一致</p> - - <p><strong>菜刀</strong>:作者故乡来自湖南省桑植县,贺龙元帅故乡,贺老总两把菜刀闹革命是旗帜,以此纪念,同时也有时刻思念故乡之意!</p> -</blockquote> - -<h2 id="️-要写一些什么呢">✍️ 要写一些什么呢?</h2> - -<p>目前看来,主要两个方面:</p> - -<ul> - <li><strong>开源</strong>:开源项目<strong>Knife4j并没有停更</strong>,所以和这个项目相关的内容、资讯等,也会同步发布在这个公众号里面,这个项目作者有精力的情况下还是会持续更新下去的。</li> - <li><strong>RAG</strong>:以学习者的心态,学习大模型领域相关的技术,特别是RAG领域,这块领域我觉得哪怕你不是一个算法人员,而仅仅只是一个普通的开发者(Java/Python/.Net等),是可以触控可及的,而我的工作中目前正在做这类产品的开发迭代,不管是学习或者工作中,必然会碰到很多棘手的问题,那么就会将自己的思考以及实践总结分享出来。</li> -</ul> - -<p>结合我最近的工作内容,我总结了一部分的大纲内容(后面随着学习的深入可能会扩展更多),如下图:</p> - -<p><img src="/assets/images/llm/llm-start/image-20231010104036526.png" alt="image-20231010104036526" /></p> - -<p>在技术层面,我愿称这方面的技术合集为”<strong>大模型应用工程技术</strong>“。</p> - -<p>为什么这么说呢?主要几个方面:</p> - -<ul> - <li>主要还是基于应用层面的技术围绕展开,而底层的<strong>大模型训练</strong>、<strong>数据标注</strong>、<strong>基于预训练模型的微调(Fine-turn)</strong>等领域,我觉得那是专业算法人员干的事情,比如基于企业的私有数据调整开源预训练大模型的权重,通过SFT手段进行微调,或者从0到1基于数据语料构建一个全新的垂直领域的Embedding模型,这已经属于更便底层的领域了,相信很多和我一样的Java开发人员其实像接触到这方面的知识,哪怕是学习都是很吃力的,就做到了解和知道吧,看个人兴趣。</li> - <li>而RAG领域的知识点,更多的是偏工程应用技术,包括<strong>数据的处理</strong>、<strong>存储</strong>、<strong>逻辑编排</strong>等等对于非算法领域的人员,对于业务开发人员来说我们是擅长的,虽然也是和AI大模型挂钩,但LLM作为底层的基础设施,我们更多的是使用大模型的能力,在大模型基础之上,构建上层的应用烟囱,所以作为开发人员,是可以尝试去学习、了解的,我认为是触手可及的。</li> -</ul> - -<p>而在”<strong>大模型应用工程技术</strong>“,我初步列了一个大纲(后面随着学习的深入可能会扩展更多)</p> - -<p>目前包含的几个方面:</p> - -<ul> - <li><strong>向量Embedding</strong>:在RAG领域中,将多模态数据(文本、图像、视频、音频等数据)进行向量Embedding的嵌入转化,通过向量计算召回Top k,可以解决很多实际生产中的问题,比如:文本相似度计算、以图搜图、以文搜图等等,这方面都会涉及到向量的知识。</li> - <li><strong>LLM语言模型</strong>:LLM大模型(Large Language Model)作为基础设施,是上层应用的基石,但是在应用领域中,对大模型的了解也是很有必要的,包括Prompt的构建优化、模型参数的差异以及不同效果体现、模型的部署和训练微调、开源模型以及商业模型等等</li> - <li><strong>多模态数据</strong>:RAG相关的AI应用,离不开数据的处理,在很多LLM大模型中,也标注为多模态大模型,包括文生图、图生图等等,但在应用领域,文本(pdf/word/html/text等)、图片、视频、音频等等格式的数据处理是无可避免的,还包括市面上很多非结构化的数据处理等内容,工程层面的技术可以说是如星辰大海般辽阔,技术人员学习之路无穷无尽。</li> - <li><strong>基础知识:</strong>在做应用层面的开发上,当然离不开基础知识点的学习,常用的包括HTTP SSE协议、向量等等知识点。</li> - <li><strong>基础工具包</strong>:工欲善其事,必先利其器,在当下的开源大环境下,有非常多的优秀的工具辅助开发者开发生产级别的应用,以Python、Java这两大语言生态为标杆,生态及其丰富,而我们在做应用成技术的开发离不开这些优秀的组件,掌握组件的用法也是必须的。</li> - <li><strong>基础算法:</strong>虽然是做应用层面的开发,基础的常用算法,该学习的还是需要去了解的,像贝叶斯、KNN、决策树等等,了解算法的原理实践,对于生产环境的代码编写时非常有指导思想的,否则你都不知道这段代码为何这么写,而每个算法解决的都是非常实际的问题。</li> - <li><strong>应用场景:</strong>技术人员在开发产品时,也应该关注应用场景及市场,开发出来的产品解决了什么问题,有什么价值作为技术人员也应该学会思考。在大模型领域,以RAG赛道来看,触及的场景其实也是非常多的,比如:智能客服、以图搜图/视频等等,要关注实际的产品需求,然后转化为技术输出,这样我们作为开发人员所写的代码才是有价值的。</li> - <li><strong>RAG:</strong>RAG全称<strong>Retrieval Augmented Generation(检索增强生成)</strong>,是属于AI生成式技术领域范围,解决大模型的幻觉(胡说八道)、数据不及时(数据未更新)等领域的问题,通过将企业自己的数据通过传统的工程技术结合向量Embeding进行处理,然后通过检索的方式将企业内部数据构建送给大模型进行内容的回答生成,这种方式有效的避免了大模型胡说八道和数据不准确的问题,在企业不同的领域中有非常宽广的应用领域,当然这里面所涵盖的面以及问题也是非常的广,比如: - <ul> - <li>大模型出现幻觉(送给LLM的Context不准,导致大模型胡说八道)如何解决?</li> - <li>按固定size进行分割,出现上下文语义丢失,核心信息检索问答生成失败,回答不准确</li> - <li>千万级数据量文档检索效率问题</li> - <li>大模型Token限制问题导致在一个文档中出现多段落讲解同一个事情的情况下会回答不完整如何处理</li> - <li>……</li> - </ul> - </li> -</ul> - -<p>这些都只是AI大模型、RAG等领域的冰山一角,千里之行,始于足下,作为技术人员,那么就从现在开始,一步步学起来吧~</p> - -<h2 id="最后">最后</h2> - -<p>如果你最近也在做RAG领域相关的技术研究或者产品开发,欢迎关注、沟通交流合作!!!</p>八一菜刀写在前面 \ No newline at end of file +</ul>八一菜刀前言 \ No newline at end of file diff --git a/_site/index.html b/_site/index.html index e16a835..20ae062 100644 --- a/_site/index.html +++ b/_site/index.html @@ -97,14 +97,14 @@

              士不可以不弘毅,任重
            12. - 创业:大模型RAG系统三个月的开发心得和思考 + RAG工程实践拦路虎之一:PDF格式解析杂谈

              - 1. 前言 + 背景

              - 2024/04/01 + 2024/07/08 @@ -127,14 +127,14 @@

            13. - TorchV的RAG实践分享(三):解析llama_index的数据存储结构和召回策略过程 + 我对《RAG/大模型/非结构化数据知识库类产品》技术架构的思考、杂谈

              - 1.前言 + 1、前言

              - 2024/01/14 + 2024/07/03 @@ -157,14 +157,14 @@

            14. - TorchV的RAG实践分享(二):基于ElasticSearch的混合检索实战&原理分析 + 创业:大模型RAG系统三个月的开发心得和思考

              - 概述 + 1. 前言

              - 2023/12/27 + 2024/04/01 @@ -187,14 +187,14 @@

            15. - RAG的概述 + TorchV的RAG实践分享(三):解析llama_index的数据存储结构和召回策略过程

              - 待续… + 1.前言

              - 2023/12/23 + 2024/01/14 @@ -202,19 +202,29 @@

              大模型 + + + RAG实践 + + + + + TorchV + +

            16. - 基于Apple MLX框架的M1设备上大模型微调实践 + TorchV的RAG实践分享(二):基于ElasticSearch的混合检索实战&原理分析

              - 前言 + 概述

              - 2023/12/17 + 2023/12/27 @@ -222,29 +232,34 @@

              大模型 + + + RAG实践 + + + + + TorchV + +

            17. - Python3.11在CentOS7环境下的安装指定OpenSSL + RAG的概述

              - 如果你是在CentOS7 上面源码安装Python3.11版本,你可能会碰到和我一样的问题,那就是OpenSSL模块太低了。 + 待续…

              - 2023/11/07 - - - - - Blog + 2023/12/23 - Python + 大模型

              @@ -252,19 +267,19 @@

            18. - 超赞的博客主题分享,值得一看 + 基于Apple MLX框架的M1设备上大模型微调实践

              - 最近在学习RAG、大模型等领域方面的技术,想在学习的过程中做总结性的输出,因此就想把自己之前弄的博客重新整理一番,主要有几个原因: + 前言

              - 2023/10/16 + 2023/12/17 - Blog + 大模型

              @@ -272,19 +287,24 @@

            19. - 用好大模型?这5种实用的Prompt框架你一定要看看! + Python3.11在CentOS7环境下的安装指定OpenSSL

              - 前言 + 如果你是在CentOS7 上面源码安装Python3.11版本,你可能会碰到和我一样的问题,那就是OpenSSL模块太低了。

              - 2023/10/15 + 2023/11/07 - 大模型 + Blog + + + + + Python

              @@ -385,7 +405,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -401,7 +421,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -413,7 +433,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/links/index.html b/_site/links/index.html index 800f9dc..3b78890 100644 --- a/_site/links/index.html +++ b/_site/links/index.html @@ -224,7 +224,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -240,7 +240,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -252,7 +252,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page10/index.html b/_site/page10/index.html index cb07c73..910535d 100644 --- a/_site/page10/index.html +++ b/_site/page10/index.html @@ -97,19 +97,19 @@

              士不可以不弘毅,任重
            20. - springfox 源码分析(二十一) 忽略参数Class类型 + swagger-bootstrap-ui 1.9.4 发布,扩展支持动态字段注释

              - 我们在前面的源码过程中,了解了springfox的基本工作原理,接下来,我们可以通过使用springfox给我们提供的外部接口,来处理一些我们工作中碰到的问题,或者进行自定义扩展 + swagger-bootstrap-ui 1.9.4 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿

              - 2019/06/03 + 2019/06/10 - springfox + 开源资讯

              @@ -117,7 +117,7 @@

            21. - springfox 源码分析(二十) 自定义扩展实现Map、JSONObject等动态字段显示 + springfox 源码分析(二十二) 总结

              待续… @@ -137,14 +137,14 @@

            22. - springfox 源码分析(十九) guava库学习 + springfox 源码分析(二十一) 忽略参数Class类型

              - 我们在研究springfox的过程中,发现springfox大量使用了guava这个库的一些方法和类,针对我们在研究源码的学习过程中,将涉及到的guava库中的类进行归纳总结,后期在工作中我们也可以熟练运用guava库为我们提供的简介api + 我们在前面的源码过程中,了解了springfox的基本工作原理,接下来,我们可以通过使用springfox给我们提供的外部接口,来处理一些我们工作中碰到的问题,或者进行自定义扩展

              - 2019/06/02 + 2019/06/03 @@ -157,14 +157,14 @@

            23. - springfox 源码分析(十八) 自定义扩展实现分组的排序 + springfox 源码分析(二十) 自定义扩展实现Map、JSONObject等动态字段显示

              - 既然我们对springfox提供的接口已经有了一个初步的了解,那么针对我们在分组接口文章中提的需求,如果自定义扩展实现分组的排序如何做呢? + 待续…

              - 2019/06/02 + 2019/06/03 @@ -177,14 +177,14 @@

            24. - springfox 源码分析(十七) Swagger2接口文档示例接口api-docs + springfox 源码分析(十九) guava库学习

              - 前面已经获取得到了swagger的分组接口信息了,接下来就是根据分组名称获取每个分组的Swagger资源详细信息,在springfox中提供了/v2/api-docs接口来进行获取 + 我们在研究springfox的过程中,发现springfox大量使用了guava这个库的一些方法和类,针对我们在研究源码的学习过程中,将涉及到的guava库中的类进行归纳总结,后期在工作中我们也可以熟练运用guava库为我们提供的简介api

              - 2019/06/01 + 2019/06/02 @@ -197,14 +197,14 @@

            25. - springfox 源码分析(十六) 分组接口swagger-resouces + springfox 源码分析(十八) 自定义扩展实现分组的排序

              - 通过前面的分析,我们最终得到了springfox的Documentation文档对象,将我们的RESTful接口最终转换为了文档对象,文档对象是包含了接口列表、分组信息等属性的 + 既然我们对springfox提供的接口已经有了一个初步的了解,那么针对我们在分组接口文章中提的需求,如果自定义扩展实现分组的排序如何做呢?

              - 2019/06/01 + 2019/06/02 @@ -217,14 +217,14 @@

            26. - springfox 源码分析(十五) 归档得到Documentation文档对象 + springfox 源码分析(十七) Swagger2接口文档示例接口api-docs

              - 通过上篇的分析,我们已经得到了ApiListing的map集合,接下来最终做文档归档,得到Documentation对象 + 前面已经获取得到了swagger的分组接口信息了,接下来就是根据分组名称获取每个分组的Swagger资源详细信息,在springfox中提供了/v2/api-docs接口来进行获取

              - 2019/05/31 + 2019/06/01 @@ -237,14 +237,14 @@

            27. - springfox 源码分析(十四) 归档得到ApiListing接口集合 + springfox 源码分析(十六) 分组接口swagger-resouces

              - 在前面我们拿到了接口的Model类型集合,然后还获取到了该接口的ApiDescription描述信息 + 通过前面的分析,我们最终得到了springfox的Documentation文档对象,将我们的RESTful接口最终转换为了文档对象,文档对象是包含了接口列表、分组信息等属性的

              - 2019/05/30 + 2019/06/01 @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page11/index.html b/_site/page11/index.html index 7ad05b8..ef032f9 100644 --- a/_site/page11/index.html +++ b/_site/page11/index.html @@ -97,14 +97,14 @@

              士不可以不弘毅,任重
            28. - springfox 源码分析(十三) 自定义扩展实现接口的排序 + springfox 源码分析(十五) 归档得到Documentation文档对象

              - 很多时候,Swagger定义的标准并不能满足我们实际的需求,比如拿分组后的接口来说,有适合我们希望我们的接口能够排序,假如我们当前有一个注册的需求实现,那么他的接口可能是这样的: + 通过上篇的分析,我们已经得到了ApiListing的map集合,接下来最终做文档归档,得到Documentation对象

              - 2019/05/29 + 2019/05/31 @@ -117,14 +117,14 @@

            29. - springfox 源码分析(十二) 遍历接口获取ApiDescription集合 + springfox 源码分析(十四) 归档得到ApiListing接口集合

              - ApiDescription是springfox提供的接口描述信息类,在springfox 源码分析(十) 遍历接口获取Model对象中我们拿到了接口的类型Model集合信息,但除了Model信息,接口还有更多的信息 + 在前面我们拿到了接口的Model类型集合,然后还获取到了该接口的ApiDescription描述信息

              - 2019/05/28 + 2019/05/30 @@ -137,14 +137,14 @@

            30. - springfox 源码分析(十一) 自定义添加Swagger Models功能实现 + springfox 源码分析(十三) 自定义扩展实现接口的排序

              - 在springfox 源码分析(十) 遍历接口获取Model对象这一篇中,我们其实已经大致了解了Springfox针对接口中涉及到的Model类进行解析初始化的过程 + 很多时候,Swagger定义的标准并不能满足我们实际的需求,比如拿分组后的接口来说,有适合我们希望我们的接口能够排序,假如我们当前有一个注册的需求实现,那么他的接口可能是这样的:

              - 2019/05/27 + 2019/05/29 @@ -157,14 +157,14 @@

            31. - springfox 源码分析(十) 遍历接口获取Model对象 + springfox 源码分析(十二) 遍历接口获取ApiDescription集合

              - 在上一篇中,我们了解到了springfox通过groupName的过滤,拿到了所有的接口,并且通过guava库的ArrayListMultimap对接口的Controller进一步进行了分组,接下来就是解析每个接口的操作了 + ApiDescription是springfox提供的接口描述信息类,在springfox 源码分析(十) 遍历接口获取Model对象中我们拿到了接口的类型Model集合信息,但除了Model信息,接口还有更多的信息

              - 2019/05/26 + 2019/05/28 @@ -177,14 +177,14 @@

            32. - springfox 源码分析(九) 文档初始化-分组 + springfox 源码分析(十一) 自定义添加Swagger Models功能实现

              - 在前面我们了解了DocumennationContext的初始化过程,包括一系列的默认属性的赋值,接下来,开始真正的文档解析操作 + 在springfox 源码分析(十) 遍历接口获取Model对象这一篇中,我们其实已经大致了解了Springfox针对接口中涉及到的Model类进行解析初始化的过程

              - 2019/05/25 + 2019/05/27 @@ -197,14 +197,14 @@

            33. - springfox 源码分析(八) 遍历接口获取Model对象 + springfox 源码分析(十) 遍历接口获取Model对象

              - 我们通过读DocumentationPluginsBootstrapper代码中的start方法,了解到springfox根据我们外部提供的Docket对象进行初始化时,会通过Docket对象构建DocumentationContext对象来进行初始化操作 + 在上一篇中,我们了解到了springfox通过groupName的过滤,拿到了所有的接口,并且通过guava库的ArrayListMultimap对接口的Controller进一步进行了分组,接下来就是解析每个接口的操作了

              - 2019/05/24 + 2019/05/26 @@ -217,14 +217,14 @@

            34. - springfox 源码分析(七) 文档初始化 + springfox 源码分析(九) 文档初始化-分组

              - 时间:2019-5-23 20:12:04 + 在前面我们了解了DocumennationContext的初始化过程,包括一系列的默认属性的赋值,接下来,开始真正的文档解析操作

              - 2019/05/23 + 2019/05/25 @@ -237,14 +237,14 @@

            35. - springfox 源码分析(六) web配置类扫描包作用探索 + springfox 源码分析(八) 遍历接口获取Model对象

              - 时间:2019-5-23 18:46:50 + 我们通过读DocumentationPluginsBootstrapper代码中的start方法,了解到springfox根据我们外部提供的Docket对象进行初始化时,会通过Docket对象构建DocumentationContext对象来进行初始化操作

              - 2019/05/23 + 2019/05/24 @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page12/index.html b/_site/page12/index.html index e6f227a..88516cd 100644 --- a/_site/page12/index.html +++ b/_site/page12/index.html @@ -97,10 +97,10 @@

              士不可以不弘毅,任重
            36. - springfox 源码分析(五) web配置类Plugin插件的使用 + springfox 源码分析(七) 文档初始化

              - 时间:2019-5-23 14:46:50 + 时间:2019-5-23 20:12:04

              @@ -117,10 +117,10 @@

            37. - springfox 源码分析(四) 配置类初始化 + springfox 源码分析(六) web配置类扫描包作用探索

              - 时间:2019-5-23 12:46:50 + 时间:2019-5-23 18:46:50

              @@ -137,14 +137,14 @@

            38. - springfox 源码分析(三) 初探Spring Plugin插件系统 + springfox 源码分析(五) web配置类Plugin插件的使用

              - 时间:2019-5-22 12:46:50 + 时间:2019-5-23 14:46:50

              - 2019/05/22 + 2019/05/23 @@ -157,14 +157,14 @@

            39. - springfox 源码分析(二) 初探mapstruct + springfox 源码分析(四) 配置类初始化

              - 时间:2019-5-22 12:40:21 + 时间:2019-5-23 12:46:50

              - 2019/05/22 + 2019/05/23 @@ -177,14 +177,14 @@

            40. - springfox 源码分析(一) 程序入口 + springfox 源码分析(三) 初探Spring Plugin插件系统

              - 日期:2019-5-21 21:05:15 + 时间:2019-5-22 12:46:50

              - 2019/05/21 + 2019/05/22 @@ -197,14 +197,14 @@

            41. - springfox 源码系列 + springfox 源码分析(二) 初探mapstruct

              - 最近闲来无事,之前在开发过程中一直在用到springfox来生成swagger的文档,但一直对springfox的源码尚未研究,所以决定对源码进行探究一番. + 时间:2019-5-22 12:40:21

              - 2019/05/20 + 2019/05/22 @@ -217,19 +217,19 @@

            42. - mybatis 源码系列(八) Java基础之wait()、notify()、notifyAll()方法 + springfox 源码分析(一) 程序入口

              - 在研究mybatis的连接池数据源源码时,我们看到了wait()、notifyAll()方法的使用,工作中因为很少使用到这类方法的调用,所以,其中概念也有些模糊了,写一遍博客记录一下. + 日期:2019-5-21 21:05:15

              - 2019/05/19 + 2019/05/21 - mybatis + springfox

              @@ -237,19 +237,19 @@

            43. - mybatis 源码系列(七) Java基础之数据库事务隔离级别 + springfox 源码系列

              - 正确设置数据库的事务访问级别,有助于我们的应用程序达到预期的效果 + 最近闲来无事,之前在开发过程中一直在用到springfox来生成swagger的文档,但一直对springfox的源码尚未研究,所以决定对源码进行探究一番.

              - 2019/05/18 + 2019/05/20 - mybatis + springfox

              @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page13/index.html b/_site/page13/index.html index ce47ca2..33461ff 100644 --- a/_site/page13/index.html +++ b/_site/page13/index.html @@ -97,14 +97,14 @@

              士不可以不弘毅,任重
            44. - mybatis 源码系列(六) 设计模式 + mybatis 源码系列(八) Java基础之wait()、notify()、notifyAll()方法

              - 以前我们在学习Java的时候,都会将Java中的设计模式,记忆中用的比较多的好像有23种吧,但是这些设计模式其实自己在工作中除了那么几种几乎很少用到. + 在研究mybatis的连接池数据源源码时,我们看到了wait()、notifyAll()方法的使用,工作中因为很少使用到这类方法的调用,所以,其中概念也有些模糊了,写一遍博客记录一下.

              - 2019/05/17 + 2019/05/19 @@ -117,14 +117,14 @@

            45. - mybatis 源码系列(五) 数据源DataSource + mybatis 源码系列(七) Java基础之数据库事务隔离级别

              - 在第四章节中,我们分析里数据库驱动Driver的加载方式,其中有提到mybatis的数据源,我们都知道,Java中的SQL规范java.sql.DataSource是一个接口,而我们在生产环境中一般都是基于数据库的连接池技术来获取数据库连接以操作数据库的. + 正确设置数据库的事务访问级别,有助于我们的应用程序达到预期的效果

              - 2019/05/16 + 2019/05/18 @@ -137,14 +137,14 @@

            46. - mybatis 源码系列(四) 数据库驱动Driver加载方式 + mybatis 源码系列(六) 设计模式

              - 不管是mysql或者oracle等等数据库的连接,在我们Java程序中,都需要将相应的数据库驱动jar包加入到Java应用程序中 + 以前我们在学习Java的时候,都会将Java中的设计模式,记忆中用的比较多的好像有23种吧,但是这些设计模式其实自己在工作中除了那么几种几乎很少用到.

              - 2019/05/14 + 2019/05/17 @@ -157,14 +157,14 @@

            47. - mybatis 源码系列(三) 配置之环境变量Environment + mybatis 源码系列(五) 数据源DataSource

              - 通过初始化的章节,我们知道了mybatis的核心配置类Configuration,那么,接下来我们逐一查看该配置的属性 + 在第四章节中,我们分析里数据库驱动Driver的加载方式,其中有提到mybatis的数据源,我们都知道,Java中的SQL规范java.sql.DataSource是一个接口,而我们在生产环境中一般都是基于数据库的连接池技术来获取数据库连接以操作数据库的.

              - 2019/05/13 + 2019/05/16 @@ -177,14 +177,14 @@

            48. - mybatis 源码系列(二) 配置类Configuration + mybatis 源码系列(四) 数据库驱动Driver加载方式

              - 我们在第一章初始化中知道了mybatis的核心配置类为org.apache.ibatis.session.Configuration.java + 不管是mysql或者oracle等等数据库的连接,在我们Java程序中,都需要将相应的数据库驱动jar包加入到Java应用程序中

              - 2019/05/12 + 2019/05/14 @@ -197,14 +197,14 @@

            49. - mybatis 源码系列(一) 初始化 + mybatis 源码系列(三) 配置之环境变量Environment

              - 通过阅读mybatis的官方文档,我们知道了初始化mybatis的方法有以下两种方法: + 通过初始化的章节,我们知道了mybatis的核心配置类Configuration,那么,接下来我们逐一查看该配置的属性

              - 2019/05/11 + 2019/05/13 @@ -217,14 +217,14 @@

            50. - mybatis 源码系列 + mybatis 源码系列(二) 配置类Configuration

              - 最近闲来无事,之前在开发过程中一直在使用mybatis这个技术框架,但是一直没有认真的好好读一下mybatis的源码,所以,决定把mybatis的源码通读一遍,在对mybatis的基础使用上,巩固自己的技术积累,也想通过这个优秀的开源ORM框架中学到一些程序设计理念.并且通过博客记录的方式,加深自己的印象. + 我们在第一章初始化中知道了mybatis的核心配置类为org.apache.ibatis.session.Configuration.java

              - 2019/05/10 + 2019/05/12 @@ -237,19 +237,19 @@

            51. - 免费给网站配置SSL证书(https) + mybatis 源码系列(一) 初始化

              - 这几天一直在看小程序的开发指南,其中读到小程序调用的RESTful Api接口的网站都必须是HTTPS的,为了后面学习小程序开发先给我的swagger-bootstrap-ui的文档地址配置一个SSL证书.就权当练习吧. + 通过阅读mybatis的官方文档,我们知道了初始化mybatis的方法有以下两种方法:

              - 2019/05/07 + 2019/05/11 - Blog + mybatis

              @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page14/index.html b/_site/page14/index.html index 12740a7..50748b2 100644 --- a/_site/page14/index.html +++ b/_site/page14/index.html @@ -97,19 +97,19 @@

              士不可以不弘毅,任重
            52. - swagger-bootstrap-ui 1.9.3 发布,i18n及自定义文档支持 + mybatis 源码系列

              - swagger-bootstrap-ui 1.9.3 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿 + 最近闲来无事,之前在开发过程中一直在使用mybatis这个技术框架,但是一直没有认真的好好读一下mybatis的源码,所以,决定把mybatis的源码通读一遍,在对mybatis的基础使用上,巩固自己的技术积累,也想通过这个优秀的开源ORM框架中学到一些程序设计理念.并且通过博客记录的方式,加深自己的印象.

              - 2019/04/23 + 2019/05/10 - 开源资讯 + mybatis

              @@ -117,19 +117,19 @@

            53. - swagger-bootstrap-ui 1.9.2 发布,提供前后端分离解决方案 + 免费给网站配置SSL证书(https)

              - swagger-bootstrap-ui 1.9.2 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿 + 这几天一直在看小程序的开发指南,其中读到小程序调用的RESTful Api接口的网站都必须是HTTPS的,为了后面学习小程序开发先给我的swagger-bootstrap-ui的文档地址配置一个SSL证书.就权当练习吧.

              - 2019/04/08 + 2019/05/07 - 开源资讯 + Blog

              @@ -137,14 +137,14 @@

            54. - swagger-bootstrap-ui 1.9.1 发布,优化大数据响应接口 + swagger-bootstrap-ui 1.9.3 发布,i18n及自定义文档支持

              - swagger-bootstrap-ui 1.9.1 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿 + swagger-bootstrap-ui 1.9.3 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿

              - 2019/03/11 + 2019/04/23 @@ -157,14 +157,14 @@

            55. - swagger-bootstrap-ui 1.9.0 发布,提供Swagger资源保护 + swagger-bootstrap-ui 1.9.2 发布,提供前后端分离解决方案

              - SwaggerBootstrapUi 1.9.0 发布了。SwaggerBootstrapUi是 Swagger 的增强UI 实现,使文档更友好一点儿 + swagger-bootstrap-ui 1.9.2 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿

              - 2019/02/25 + 2019/04/08 @@ -177,14 +177,14 @@

            56. - swagger-bootstrap-ui 1.8.9 发布,Swagger增强UI 实现 + swagger-bootstrap-ui 1.9.1 发布,优化大数据响应接口

              - Swagger-Bootstrap-Ui 1.8.9 发布了。Swagger-Bootstrap-Ui是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.9.1 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿

              - 2019/01/11 + 2019/03/11 @@ -197,14 +197,14 @@

            57. - swagger-bootstrap-ui 1.8.8 发布,Swagger增强UI 实现 + swagger-bootstrap-ui 1.9.0 发布,提供Swagger资源保护

              - Swagger-Bootstrap-Ui 1.8.8 发布了。Swagger-Bootstrap-Ui是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + SwaggerBootstrapUi 1.9.0 发布了。SwaggerBootstrapUi是 Swagger 的增强UI 实现,使文档更友好一点儿

              - 2018/12/17 + 2019/02/25 @@ -217,14 +217,14 @@

            58. - swagger-bootstrap-ui 1.8.7 发布,Swagger增强UI 实现 + swagger-bootstrap-ui 1.8.9 发布,Swagger增强UI 实现

              - Swagger-Bootstrap-Ui 1.8.7 发布了。Swagger-Bootstrap-Ui是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + Swagger-Bootstrap-Ui 1.8.9 发布了。Swagger-Bootstrap-Ui是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/11/12 + 2019/01/11 @@ -237,14 +237,14 @@

            59. - swagger-bootstrap-ui 1.8.6 发布,Swagger增强UI 实现 + swagger-bootstrap-ui 1.8.8 发布,Swagger增强UI 实现

              - swagger-bootstrap-ui 1.8.6 发布了。swagger-bootstrap-ui 是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + Swagger-Bootstrap-Ui 1.8.8 发布了。Swagger-Bootstrap-Ui是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/10/31 + 2018/12/17 @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page15/index.html b/_site/page15/index.html index f0b8e74..b6db02c 100644 --- a/_site/page15/index.html +++ b/_site/page15/index.html @@ -97,14 +97,14 @@

              士不可以不弘毅,任重
            60. - swagger-bootstrap-ui 1.8.5 发布,Swagger增强UI 实现 + swagger-bootstrap-ui 1.8.7 发布,Swagger增强UI 实现

              - swagger-bootstrap-ui 1.8.5 发布了。swagger-bootstrap-ui 是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + Swagger-Bootstrap-Ui 1.8.7 发布了。Swagger-Bootstrap-Ui是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/10/16 + 2018/11/12 @@ -117,14 +117,14 @@

            61. - swagger-bootstrap-ui 1.8.4 发布,前端 UI 实现 + swagger-bootstrap-ui 1.8.6 发布,Swagger增强UI 实现

              - swagger-bootstrap-ui 1.8.4 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.8.6 发布了。swagger-bootstrap-ui 是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/09/25 + 2018/10/31 @@ -137,14 +137,14 @@

            62. - swagger-bootstrap-ui 1.8.3 发布,前端 UI 实现 + swagger-bootstrap-ui 1.8.5 发布,Swagger增强UI 实现

              - swagger-bootstrap-ui 1.8.3 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.8.5 发布了。swagger-bootstrap-ui 是 Swagger 的增强UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/09/17 + 2018/10/16 @@ -157,19 +157,19 @@

            63. - swagger-bootstrap-ui详解 + swagger-bootstrap-ui 1.8.4 发布,前端 UI 实现

              - 项目背景 + swagger-bootstrap-ui 1.8.4 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/08/29 + 2018/09/25 - Blog + 开源资讯

              @@ -177,14 +177,14 @@

            64. - swagger-bootstrap-ui 1.8.2 发布,前端 UI 实现 + swagger-bootstrap-ui 1.8.3 发布,前端 UI 实现

              - swagger-bootstrap-ui 1.8.2 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.8.3 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/08/26 + 2018/09/17 @@ -197,19 +197,19 @@

            65. - swagger-bootstrap-ui 1.8.1 发布,前端 UI 实现 + swagger-bootstrap-ui详解

              - swagger-bootstrap-ui 1.8.1 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + 项目背景

              - 2018/08/14 + 2018/08/29 - 开源资讯 + Blog

              @@ -217,14 +217,14 @@

            66. - swagger-bootstrap-ui 1.8.0 发布,前端 UI 实现 + swagger-bootstrap-ui 1.8.2 发布,前端 UI 实现

              - swagger-bootstrap-ui 1.8.0 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.8.2 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/08/10 + 2018/08/26 @@ -237,14 +237,14 @@

            67. - swagger-bootstrap-ui 1.7.9 发布,前端 UI 实现 + swagger-bootstrap-ui 1.8.1 发布,前端 UI 实现

              - swagger-bootstrap-ui 1.7.9 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.8.1 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/08/06 + 2018/08/14 @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page16/index.html b/_site/page16/index.html index 2facddd..1ebb90b 100644 --- a/_site/page16/index.html +++ b/_site/page16/index.html @@ -97,14 +97,14 @@

              士不可以不弘毅,任重
            68. - swagger-bootstrap-ui 1.7.8 发布,前端 UI 实现 + swagger-bootstrap-ui 1.8.0 发布,前端 UI 实现

              - swagger-bootstrap-ui 1.7.8 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.8.0 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/08/03 + 2018/08/10 @@ -117,14 +117,14 @@

            69. - swagger-bootstrap-ui 1.7.7 发布,前端 UI 实现 + swagger-bootstrap-ui 1.7.9 发布,前端 UI 实现

              - swagger-bootstrap-ui 1.7.7 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.7.9 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/07/25 + 2018/08/06 @@ -137,14 +137,14 @@

            70. - swagger-bootstrap-ui 1.7.6 发布,前端 UI 实现 + swagger-bootstrap-ui 1.7.8 发布,前端 UI 实现

              - swagger-bootstrap-ui 1.7.6 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.7.8 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/07/18 + 2018/08/03 @@ -157,14 +157,14 @@

            71. - swagger-bootstrap-ui 1.7.5 发布,前端 UI 实现 + swagger-bootstrap-ui 1.7.7 发布,前端 UI 实现

              - swagger-bootstrap-ui 1.7.5 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.7.7 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/07/16 + 2018/07/25 @@ -177,19 +177,19 @@

            72. - 记录解决微信amr文件转mp3格式的过程 + swagger-bootstrap-ui 1.7.6 发布,前端 UI 实现

              - 我们在做微信语音上传功能开发时,因为微信的原因,音频文件在微信服务端只能存储3天,所以,我们需要根据微信的serverId,使用微信公众平台的接口将音频文件下载下来,存储到我们本地的服务器 + swagger-bootstrap-ui 1.7.6 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/06/26 + 2018/07/18 - Blog + 开源资讯

              @@ -197,14 +197,14 @@

            73. - oss-server 1.1 版本发布 小型对象存储系统 + swagger-bootstrap-ui 1.7.5 发布,前端 UI 实现

              - oss-server 1.1正式发布了,oss-server是针对项目开发时提供的小型对象存储系统,开发者在针对文件上传时业务剥离,同时方便文件迁移,为满足单个项目,多个系统的情况下,提供统一的oss服务 + swagger-bootstrap-ui 1.7.5 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/06/25 + 2018/07/16 @@ -217,19 +217,19 @@

            74. - oss-server 1.0 版本发布 小型对象存储系统 + 记录解决微信amr文件转mp3格式的过程

              - oss-server 1.0正式发布了,oss-server是针对项目开发时提供的小型对象存储系统,开发者在针对文件上传时业务剥离,同时方便文件迁移,为满足单个项目,多个系统的情况下,提供统一的oss服务 + 我们在做微信语音上传功能开发时,因为微信的原因,音频文件在微信服务端只能存储3天,所以,我们需要根据微信的serverId,使用微信公众平台的接口将音频文件下载下来,存储到我们本地的服务器

              - 2018/06/19 + 2018/06/26 - 开源资讯 + Blog

              @@ -237,19 +237,19 @@

            75. - 个人开源:oss-server 简单对象存储系统 + oss-server 1.1 版本发布 小型对象存储系统

              - oss-server + oss-server 1.1正式发布了,oss-server是针对项目开发时提供的小型对象存储系统,开发者在针对文件上传时业务剥离,同时方便文件迁移,为满足单个项目,多个系统的情况下,提供统一的oss服务

              - 2018/06/13 + 2018/06/25 - 开源 + 开源资讯

              @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page17/index.html b/_site/page17/index.html index 519271c..46c2ac9 100644 --- a/_site/page17/index.html +++ b/_site/page17/index.html @@ -97,19 +97,19 @@

              士不可以不弘毅,任重
            76. - 地球坐标系,了解一下? + oss-server 1.0 版本发布 小型对象存储系统

              - 大地坐标系(WGS-84) + oss-server 1.0正式发布了,oss-server是针对项目开发时提供的小型对象存储系统,开发者在针对文件上传时业务剥离,同时方便文件迁移,为满足单个项目,多个系统的情况下,提供统一的oss服务

              - 2018/06/06 + 2018/06/19 - Blog + 开源资讯

              @@ -117,19 +117,19 @@

            77. - postgresql 安装|重置密码|备份数据|导入数据 + 个人开源:oss-server 简单对象存储系统

              - 安装 + oss-server

              - 2018/05/31 + 2018/06/13 - 数据库 + 开源

              @@ -137,19 +137,19 @@

            78. - Lucene(7.3.1)学习笔记-Document类源码解析 + 地球坐标系,了解一下?

              - 本笔记针对Lucene版本为7.3.1 + 大地坐标系(WGS-84)

              - 2018/05/24 + 2018/06/06 - Java + Blog

              @@ -157,14 +157,14 @@

            79. - Mariadb创建索引 + postgresql 安装|重置密码|备份数据|导入数据

              - 英文原文地址:创建索引 + 安装

              - 2018/05/18 + 2018/05/31 @@ -177,19 +177,19 @@

            80. - 个人开源作品:依赖hugo+markdown搭建github博客 + Lucene(7.3.1)学习笔记-Document类源码解析

              - hugo-blog是作者整理最近两年的技术积累,以博客的方式整理、归类发布出来,希望能帮助到一些开发者 + 本笔记针对Lucene版本为7.3.1

              - 2018/04/29 + 2018/05/24 - 开源 + Java

              @@ -197,19 +197,19 @@

            81. - swagger-bootstrap-ui 1.7.3 发布,前端 UI 实现 + Mariadb创建索引

              - swagger-bootstrap-ui 1.7.3 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + 英文原文地址:创建索引

              - 2018/04/28 + 2018/05/18 - 开源资讯 + 数据库

              @@ -217,19 +217,19 @@

            82. - 前端技术大发展的背景下,谈谈前后端分离的发展与实践,以及后端研发思想的转变 + 个人开源作品:依赖hugo+markdown搭建github博客

              - 说在前面的话 + hugo-blog是作者整理最近两年的技术积累,以博客的方式整理、归类发布出来,希望能帮助到一些开发者

              - 2018/04/22 + 2018/04/29 - Blog + 开源

              @@ -237,19 +237,19 @@

            83. - 在Spring Boot中使用swagger-bootstrap-ui + swagger-bootstrap-ui 1.7.3 发布,前端 UI 实现

              - swagger-bootstrap-ui是基于swagger接口api实现的一套UI,因swagger原生ui是上下结构的,在浏览接口时不是很清晰,所以,swagger-bootstrap-ui是基于左右菜单风格的方式,适用与我们在开发后台系统左右结构这种风格类似,方便与接口浏览 + swagger-bootstrap-ui 1.7.3 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2018/01/31 + 2018/04/28 - Spring + 开源资讯

              @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page18/index.html b/_site/page18/index.html index a55412d..fe57d2f 100644 --- a/_site/page18/index.html +++ b/_site/page18/index.html @@ -97,19 +97,19 @@

              士不可以不弘毅,任重
            84. - mysql数据库只读用户创建 + 前端技术大发展的背景下,谈谈前后端分离的发展与实践,以及后端研发思想的转变

              - 登录mysql + 说在前面的话

              - 2018/01/30 + 2018/04/22 - 数据库 + Blog

              @@ -117,19 +117,19 @@

            85. - 在Linux操作系统上部署VUE开发的node应用 + 在Spring Boot中使用swagger-bootstrap-ui

              - Linux 服务器 + swagger-bootstrap-ui是基于swagger接口api实现的一套UI,因swagger原生ui是上下结构的,在浏览接口时不是很清晰,所以,swagger-bootstrap-ui是基于左右菜单风格的方式,适用与我们在开发后台系统左右结构这种风格类似,方便与接口浏览

              - 2018/01/26 + 2018/01/31 - Linux + Spring

              @@ -137,19 +137,19 @@

            86. - Spring Boot 任务task源码分析 + mysql数据库只读用户创建

              - EnableScheduling注解 + 登录mysql

              - 2018/01/26 + 2018/01/30 - Spring + 数据库

              @@ -157,19 +157,19 @@

            87. - swagger-bootstrap-ui 1.7.2 发布,前端 UI 实现 + 在Linux操作系统上部署VUE开发的node应用

              - 主要包含文档说明、在线调试两大核心功能 + Linux 服务器

              - 2018/01/20 + 2018/01/26 - 开源资讯 + Linux

              @@ -177,19 +177,19 @@

            88. - 工作流引擎技术选型 + Spring Boot 任务task源码分析

              - Snaker + EnableScheduling注解

              - 2018/01/11 + 2018/01/26 - 工作流 + Spring

              @@ -197,14 +197,14 @@

            89. - swagger-bootstrap-ui 1.7 发布,前端 UI 实现 + swagger-bootstrap-ui 1.7.2 发布,前端 UI 实现

              - swagger-bootstrap-ui 1.7 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + 主要包含文档说明、在线调试两大核心功能

              - 2017/12/18 + 2018/01/20 @@ -217,19 +217,19 @@

            90. - 云数据中心sdk快速入门 + 工作流引擎技术选型

              - 公司目前开发基础技术架构是:Spring、Spring Boot、lishicloud-sdk + Snaker

              - 2017/12/17 + 2018/01/11 - Blog + 工作流

              @@ -237,19 +237,19 @@

            91. - 九一八国耻日:莫忘那些血不曾凉的英雄 + swagger-bootstrap-ui 1.7 发布,前端 UI 实现

              - + swagger-bootstrap-ui 1.7 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2017/09/18 + 2017/12/18 - Blog + 开源资讯

              @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page19/index.html b/_site/page19/index.html index 2a3a824..cde4db9 100644 --- a/_site/page19/index.html +++ b/_site/page19/index.html @@ -97,19 +97,19 @@

              士不可以不弘毅,任重
            92. - PostgreSQL安装指南 + 云数据中心sdk快速入门

              - 下载 + 公司目前开发基础技术架构是:Spring、Spring Boot、lishicloud-sdk

              - 2017/09/07 + 2017/12/17 - 数据库 + Blog

              @@ -117,19 +117,19 @@

            93. - swagger-bootstrap-ui 1.6 发布,前端 UI 实现 + 九一八国耻日:莫忘那些血不曾凉的英雄

              - swagger-bootstrap-ui 1.6 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 +

              - 2017/09/06 + 2017/09/18 - 开源资讯 + Blog

              @@ -137,19 +137,19 @@

            94. - swagger-bootstrap-ui 1.5 发布,前端 UI 实现 + PostgreSQL安装指南

              - swagger-bootstrap-ui 1.5 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + 下载

              - 2017/09/01 + 2017/09/07 - 开源资讯 + 数据库

              @@ -157,19 +157,19 @@

            95. - confluence 安装指南(Linux) + swagger-bootstrap-ui 1.6 发布,前端 UI 实现

              - 环境说明 + swagger-bootstrap-ui 1.6 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2017/09/01 + 2017/09/06 - Blog + 开源资讯

              @@ -177,19 +177,19 @@

            96. - MariaDB 安装指南(windows) + swagger-bootstrap-ui 1.5 发布,前端 UI 实现

              - 下载 + swagger-bootstrap-ui 1.5 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2017/07/31 + 2017/09/01 - 数据库 + 开源资讯

              @@ -197,19 +197,19 @@

            97. - swagger-bootstrap-ui 1.4 发布,前端 UI 实现 + confluence 安装指南(Linux)

              - swagger-bootstrap-ui 1.4 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + 环境说明

              - 2017/07/11 + 2017/09/01 - 开源资讯 + Blog

              @@ -217,19 +217,19 @@

            98. - swagger-bootstrap-ui 1.3 发布,前端 UI 实现 + MariaDB 安装指南(windows)

              - swagger-bootstrap-ui 1.3 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + 下载

              - 2017/07/05 + 2017/07/31 - 开源资讯 + 数据库

              @@ -237,14 +237,14 @@

            99. - swagger-bootstrap-ui 1.2 发布,前端 UI 实现 + swagger-bootstrap-ui 1.4 发布,前端 UI 实现

              - swagger-bootstrap-ui 1.2 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + swagger-bootstrap-ui 1.4 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2017/05/14 + 2017/07/11 @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page2/index.html b/_site/page2/index.html index e80346e..f85744f 100644 --- a/_site/page2/index.html +++ b/_site/page2/index.html @@ -97,24 +97,19 @@

              士不可以不弘毅,任重
            100. - 实战0-1,Java开发者也能看懂的大模型应用RAG开发实践 + 超赞的博客主题分享,值得一看

              - 前言 + 最近在学习RAG、大模型等领域方面的技术,想在学习的过程中做总结性的输出,因此就想把自己之前弄的博客重新整理一番,主要有几个原因:

              - 2023/10/12 - - - - - 大模型 + 2023/10/16 - Java + Blog

              @@ -122,14 +117,14 @@

            101. - 全面进击AI大模型、RAG领域 + 用好大模型?这5种实用的Prompt框架你一定要看看!

              - 写在前面 + 前言

              - 2023/10/10 + 2023/10/15 @@ -142,19 +137,24 @@

            102. - Knife4jInsight平台版-MVP版本v1.0.0发布 + 实战0-1,Java开发者也能看懂的大模型应用RAG开发实践

              - 在之前发布的《Knife4j新产品的想法》一文中,我提到想给Knife4j的生态做一些扩展,区别于目前市面上不一样的功能或者工具产品。 + 前言

              - 2023/09/18 + 2023/10/12 - Knife4jInsight + 大模型 + + + + + Java

              @@ -162,19 +162,19 @@

            103. - Knife4jInsight的产品开发历程 + 全面进击AI大模型、RAG领域

              - 前言 + 写在前面

              - 2023/09/17 + 2023/10/10 - Knife4jInsight + 大模型

              @@ -182,14 +182,14 @@

            104. - Knife4j新产品的想法 + Knife4jInsight平台版-MVP版本v1.0.0发布

              - 写在开头 + 在之前发布的《Knife4j新产品的想法》一文中,我提到想给Knife4j的生态做一些扩展,区别于目前市面上不一样的功能或者工具产品。

              - 2023/09/15 + 2023/09/18 @@ -202,19 +202,19 @@

            105. - Spring Cloud Gateway网关下的文档聚合?就用它了 + Knife4jInsight的产品开发历程

              - 大家好,这篇文章主要是介绍分享Knife4j-gateway网关聚合文档组件,自4.0版本发布该组件后,得到了大家的积极响应,我们也是积极响应用户的需求,持续迭代优化 + 前言

              - 2023/08/13 + 2023/09/17 - Knife4j + Knife4jInsight

              @@ -222,19 +222,19 @@

            106. - 枚举烦恼终结!在Knife4j文档中如何优雅的处理枚举类型的展示及调试问题 + Knife4j新产品的想法

              - 本文主要介绍在Knife4j中如何处理枚举,主要包含两个方面: + 写在开头

              - 2023/08/07 + 2023/09/15 - Knife4j + Knife4jInsight

              @@ -242,14 +242,14 @@

            107. - 生产环境如何屏蔽Knife4j、Swagger等Ui资源和接口 + Spring Cloud Gateway网关下的文档聚合?就用它了

              - 本文主要介绍在 Spring Boot 应用中,如何在生产环境屏蔽Knife4j及相关Swagger资源 + 大家好,这篇文章主要是介绍分享Knife4j-gateway网关聚合文档组件,自4.0版本发布该组件后,得到了大家的积极响应,我们也是积极响应用户的需求,持续迭代优化

              - 2023/07/19 + 2023/08/13 @@ -355,7 +355,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -371,7 +371,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -383,7 +383,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page20/index.html b/_site/page20/index.html index 0ec2375..540f3d4 100644 --- a/_site/page20/index.html +++ b/_site/page20/index.html @@ -97,19 +97,19 @@

              士不可以不弘毅,任重
            108. - 技术架构整理 + swagger-bootstrap-ui 1.3 发布,前端 UI 实现

              - 简介 + swagger-bootstrap-ui 1.3 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2017/05/08 + 2017/07/05 - Java + 开源资讯

              @@ -117,19 +117,19 @@

            109. - Jformparser 开发指南 + swagger-bootstrap-ui 1.2 发布,前端 UI 实现

              - 简介 + swagger-bootstrap-ui 1.2 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2017/04/29 + 2017/05/14 - 开源 + 开源资讯

              @@ -137,19 +137,19 @@

            110. - swagger-bootstrap-ui的使用说明 + 技术架构整理

              - 很多朋友在使用这个jar包的时候会出现接口出不来的情况,或者只出现ui默认的几个接口,项目的api接口没有出来, + 简介

              - 2017/04/27 + 2017/05/08 - 开源资讯 + Java

              @@ -157,19 +157,19 @@

            111. - swagger-bootstrap-ui 1.1 发布,前端 UI 实现 + Jformparser 开发指南

              - swagger-bootstrap-ui 1.1 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿 + 简介

              - 2017/04/27 + 2017/04/29 - 开源资讯 + 开源

              @@ -177,10 +177,10 @@

            112. - node.js应用Linux安装部署 + swagger-bootstrap-ui的使用说明

              - 目的 + 很多朋友在使用这个jar包的时候会出现接口出不来的情况,或者只出现ui默认的几个接口,项目的api接口没有出来,

              @@ -189,7 +189,7 @@

              - NodeJs + 开源资讯

              @@ -197,19 +197,19 @@

            113. - swagger-bootstrap-ui发布到Maven中央仓库 + swagger-bootstrap-ui 1.1 发布,前端 UI 实现

              - 准备工作 + swagger-bootstrap-ui 1.1 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Swagger 默认的 UI 实现 Swagger-UI,使文档更友好一点儿

              - 2017/04/25 + 2017/04/27 - Blog + 开源资讯

              @@ -217,19 +217,19 @@

            114. - 开源个人作品:swagger-bootstrap-ui + node.js应用Linux安装部署

              - + 目的

              - 2017/04/22 + 2017/04/27 - 开源 + NodeJs

              @@ -237,19 +237,19 @@

            115. - 个人开源作品:swagger-bootstrap-ui-demo + swagger-bootstrap-ui发布到Maven中央仓库

              - + 准备工作

              - 2017/04/22 + 2017/04/25 - 开源 + Blog

              @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page21/index.html b/_site/page21/index.html index da43f5a..ae5d7f1 100644 --- a/_site/page21/index.html +++ b/_site/page21/index.html @@ -97,19 +97,19 @@

              士不可以不弘毅,任重
            116. - Java架构师之路 + 开源个人作品:swagger-bootstrap-ui

              - Java架构师之路 +

              - 2017/03/30 + 2017/04/22 - Java + 开源

              @@ -117,19 +117,19 @@

            117. - Linux部署常用命令 + 个人开源作品:swagger-bootstrap-ui-demo

              - 目的 +

              - 2017/03/30 + 2017/04/22 - Linux + 开源

              @@ -137,10 +137,10 @@

            118. - 前后端分离方案探索 + Java架构师之路

              - 背景 + Java架构师之路

              @@ -149,7 +149,7 @@

              - Blog + Java

              @@ -157,19 +157,19 @@

            119. - 开源个人作品:JFormParser + Linux部署常用命令

              - JFormParser插件:根据json结构,生成页面,达到解放后端开发人员的目的,降低后端对前端开发要求,后端专心开发后台接口等服务程序,前期以表单元素为主,后期会增加更多页面元素的支持 + 目的

              - 2017/01/20 + 2017/03/30 - 开源 + Linux

              @@ -177,14 +177,14 @@

            120. - 跨域请求,关于后端session会话丢失的解决办法 + 前后端分离方案探索

              - 目前使用前后端分离的模式开发,后端提供跨域接口、前端jsonp调用,绑定数据,但是在该站点下有个人中心模块存在的情况下,服务端的session会话会被跨域请求覆盖改掉 + 背景

              - 2016/11/26 + 2017/03/30 @@ -197,19 +197,19 @@

            121. - 前端本地nginx反向代理说明 + 开源个人作品:JFormParser

              - 背景 + JFormParser插件:根据json结构,生成页面,达到解放后端开发人员的目的,降低后端对前端开发要求,后端专心开发后台接口等服务程序,前期以表单元素为主,后期会增加更多页面元素的支持

              - 2016/11/15 + 2017/01/20 - Blog + 开源

              @@ -217,19 +217,19 @@

            122. - Linux部署规范 + 跨域请求,关于后端session会话丢失的解决办法

              - 前言 + 目前使用前后端分离的模式开发,后端提供跨域接口、前端jsonp调用,绑定数据,但是在该站点下有个人中心模块存在的情况下,服务端的session会话会被跨域请求覆盖改掉

              - 2016/11/08 + 2016/11/26 - Linux + Blog

              @@ -237,19 +237,19 @@

            123. - MariaDB Galera集群启动 + 前端本地nginx反向代理说明

              - 系统:CentOS7_x86_64 + 背景

              - 2016/10/12 + 2016/11/15 - 数据库 + Blog

              @@ -350,7 +350,7 @@

              标签

              - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

              标签

              - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

              标签

              - 大模型(9) + 大模型(11) diff --git a/_site/page22/index.html b/_site/page22/index.html index 5327d2c..e4da401 100644 --- a/_site/page22/index.html +++ b/_site/page22/index.html @@ -95,6 +95,46 @@

              士不可以不弘毅,任重
                +
              1. +

                + Linux部署规范 +

                +

                + 前言 +

                +

                + + 2016/11/08 + + + + + Linux + + +

                +
              2. + +
              3. +

                + MariaDB Galera集群启动 +

                +

                + 系统:CentOS7_x86_64 +

                +

                + + 2016/10/12 + + + + + 数据库 + + +

                +
              4. +
              5. 个人开源作品:Spring MVC 关于jsonp跨域处理 @@ -230,7 +270,7 @@

                标签

                - RAG实践(3) + RAG实践(5) @@ -246,7 +286,7 @@

                标签

                - TorchV(3) + TorchV(5) @@ -258,7 +298,7 @@

                标签

                - 大模型(9) + 大模型(11) diff --git a/_site/page3/index.html b/_site/page3/index.html index 93ff28b..c79282a 100644 --- a/_site/page3/index.html +++ b/_site/page3/index.html @@ -97,14 +97,14 @@

                士不可以不弘毅,任重
              6. - 使用Claude修改Knife4j中的issues + 枚举烦恼终结!在Knife4j文档中如何优雅的处理枚举类型的展示及调试问题

                - 本文和Knife4j使用无关,主要分享作者在解决Knife4j的issues过程中如何通过Claude.Ai快速解决问题 + 本文主要介绍在Knife4j中如何处理枚举,主要包含两个方面:

                - 2023/07/15 + 2023/08/07 @@ -117,14 +117,14 @@

              7. - 自定义API接口在Knife4j的Ui界面中显示 + 生产环境如何屏蔽Knife4j、Swagger等Ui资源和接口

                - 本文主要介绍在 Spring Boot 应用中,如何使用 springfox 和 springdoc 框架自定义添加外部 API 接口,并在 Knife4j 的 UI 界面中展示。 + 本文主要介绍在 Spring Boot 应用中,如何在生产环境屏蔽Knife4j及相关Swagger资源

                - 2023/07/13 + 2023/07/19 @@ -137,15 +137,14 @@

              8. - Knife4j框架相关的blog + 使用Claude修改Knife4j中的issues

                - 温馨提醒 -Knife4jInsight(简单、方便的OpenAPI接口文档私有化聚合平台),地址:http://knife4j.net + 本文和Knife4j使用无关,主要分享作者在解决Knife4j的issues过程中如何通过Claude.Ai快速解决问题

                - 2023/07/10 + 2023/07/15 @@ -158,19 +157,19 @@

              9. - 2023年6月最新注册ChatGPT账号流程 + 自定义API接口在Knife4j的Ui界面中显示

                - ChatGPT是什么? + 本文主要介绍在 Spring Boot 应用中,如何使用 springfox 和 springdoc 框架自定义添加外部 API 接口,并在 Knife4j 的 UI 界面中展示。

                - 2023/06/10 + 2023/07/13 - 大模型 + Knife4j

                @@ -178,14 +177,15 @@

              10. - Final.激活Knife4j官网的文档搜索功能 + Knife4j框架相关的blog

                - 1.前言 + 温馨提醒 +Knife4jInsight(简单、方便的OpenAPI接口文档私有化聚合平台),地址:http://knife4j.net

                - 2023/05/31 + 2023/07/10 @@ -198,19 +198,19 @@

              11. - Spring Security框架中踢人下线技术探索 + 2023年6月最新注册ChatGPT账号流程

                - 1.背景 + ChatGPT是什么?

                - 2021/04/20 + 2023/06/10 - SpringBoot + 大模型

                @@ -218,19 +218,19 @@

              12. - Spring Boot框架中使用Jackson的处理总结 + Final.激活Knife4j官网的文档搜索功能

                1.前言

                - 2021/03/26 + 2023/05/31 - SpringBoot + Knife4j

                @@ -238,14 +238,14 @@

              13. - Spring Boot框架中针对数据文件模板的下载总结 + Spring Security框架中踢人下线技术探索

                - 1.前言 + 1.背景

                - 2021/03/03 + 2021/04/20 @@ -351,7 +351,7 @@

                标签

                - RAG实践(3) + RAG实践(5) @@ -367,7 +367,7 @@

                标签

                - TorchV(3) + TorchV(5) @@ -379,7 +379,7 @@

                标签

                - 大模型(9) + 大模型(11) diff --git a/_site/page4/index.html b/_site/page4/index.html index 39a7528..cc664a6 100644 --- a/_site/page4/index.html +++ b/_site/page4/index.html @@ -97,14 +97,14 @@

                士不可以不弘毅,任重
              14. - 基于Servlet体系的HTTP请求代理转发Spring Boot组件 + Spring Boot框架中使用Jackson的处理总结

                - 背景概述 + 1.前言

                - 2021/02/03 + 2021/03/26 @@ -117,14 +117,14 @@

              15. - Spring Boot自定义starter必知必会条件 + Spring Boot框架中针对数据文件模板的下载总结

                - 前言 + 1.前言

                - 2020/12/10 + 2021/03/03 @@ -137,20 +137,19 @@

              16. - 有意思的两段java代码 + 基于Servlet体系的HTTP请求代理转发Spring Boot组件

                - 首先,创建一个实体类Order对象,代码如下: -```java + 背景概述

                - 2020/12/06 + 2021/02/03 - Java + SpringBoot

                @@ -158,19 +157,19 @@

              17. - 第一篇 Redis常用数据结构介绍及基本操作 + Spring Boot自定义starter必知必会条件

                - 目前Redis支持的主要数据结构包含5种,分别是: + 前言

                - 2020/11/29 + 2020/12/10 - Redis + SpringBoot

                @@ -178,19 +177,20 @@

              18. - 跨语言跨平台聚合 OpenAPI 文档从来没有这么简单过 + 有意思的两段java代码

                - Knife4j一直致力于将目前的Ui提供给更多的平台或者别的语言使用而努力,经过这么长时间的发展,Knife4j提供的轻量级聚合中间件终于诞生了,自2.0.8版本开始,Knife4j提供了knife4j-aggregation-spring-boot-starter组件,该组件是一个基于Spring Boot系统的starter,他提供了以下几种能力: + 首先,创建一个实体类Order对象,代码如下: +```java

                - 2020/11/26 + 2020/12/06 - Blog + Java

                @@ -198,19 +198,19 @@

              19. - Knife4j 2.0.8发布,轻量级微服务聚合文档中间件诞生 + 第一篇 Redis常用数据结构介绍及基本操作

                - Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具 + 目前Redis支持的主要数据结构包含5种,分别是:

                - 2020/11/22 + 2020/11/29 - 开源资讯 + Redis

                @@ -218,19 +218,19 @@

              20. - Knife4j 2.0.7发布,细节处理 + 跨语言跨平台聚合 OpenAPI 文档从来没有这么简单过

                - Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具 + Knife4j一直致力于将目前的Ui提供给更多的平台或者别的语言使用而努力,经过这么长时间的发展,Knife4j提供的轻量级聚合中间件终于诞生了,自2.0.8版本开始,Knife4j提供了knife4j-aggregation-spring-boot-starter组件,该组件是一个基于Spring Boot系统的starter,他提供了以下几种能力:

                - 2020/11/02 + 2020/11/26 - 开源资讯 + Blog

                @@ -238,14 +238,14 @@

              21. - Knife4j 2.0.6发布,支持OpenAPI3及Auth2认证 + Knife4j 2.0.8发布,轻量级微服务聚合文档中间件诞生

                - [v2.0.6-2020/10/26 Knife4j 2.0.6发布,支持OpenAPI3及Auth2认证] + Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具

                - 2020/10/26 + 2020/11/22 @@ -351,7 +351,7 @@

                标签

                - RAG实践(3) + RAG实践(5) @@ -367,7 +367,7 @@

                标签

                - TorchV(3) + TorchV(5) @@ -379,7 +379,7 @@

                标签

                - 大模型(9) + 大模型(11) diff --git a/_site/page5/index.html b/_site/page5/index.html index d65ee5c..7cbbb8c 100644 --- a/_site/page5/index.html +++ b/_site/page5/index.html @@ -97,19 +97,19 @@

                士不可以不弘毅,任重
              22. - Spring Boot框架中如何优雅的注入实体Bean + Knife4j 2.0.7发布,细节处理

                - 在Spring Boot框架中,注入实体Bean是几乎每一个Java程序员都能遇到的事情,因为Spring Boot采用约定优于配置的策略,去除了原来在Spring MVC中通过Xml进行注入的方式,全部通过Java Configuration的编码方式进行实体Bean的注入, + Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具

                - 2020/09/23 + 2020/11/02 - SpringBoot + 开源资讯

                @@ -117,14 +117,14 @@

              23. - Knife4j 2.0.5发布,性能优化 + Knife4j 2.0.6发布,支持OpenAPI3及Auth2认证

                - Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具 + [v2.0.6-2020/10/26 Knife4j 2.0.6发布,支持OpenAPI3及Auth2认证]

                - 2020/09/14 + 2020/10/26 @@ -137,19 +137,19 @@

              24. - Knife4j 2.0.4发布,支持自定义 Host + Spring Boot框架中如何优雅的注入实体Bean

                - Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具 + 在Spring Boot框架中,注入实体Bean是几乎每一个Java程序员都能遇到的事情,因为Spring Boot采用约定优于配置的策略,去除了原来在Spring MVC中通过Xml进行注入的方式,全部通过Java Configuration的编码方式进行实体Bean的注入,

                - 2020/06/28 + 2020/09/23 - 开源资讯 + SpringBoot

                @@ -157,14 +157,14 @@

              25. - Knife4j 2.0.3发布,支持springdoc和i18n + Knife4j 2.0.5发布,性能优化

                Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具

                - 2020/05/24 + 2020/09/14 @@ -177,14 +177,14 @@

              26. - Knife4j 2.0.2发布,Swagger接口文档赋能工具 + Knife4j 2.0.4发布,支持自定义 Host

                Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具

                - 2020/03/08 + 2020/06/28 @@ -197,14 +197,14 @@

              27. - Knife4j 2.0.1发布,细节处理! + Knife4j 2.0.3发布,支持springdoc和i18n

                - Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档服务的工具 + Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具

                - 2019/12/23 + 2020/05/24 @@ -217,14 +217,14 @@

              28. - Knife4j 2.0发布,涅槃重生~! + Knife4j 2.0.2发布,Swagger接口文档赋能工具

                - Knife4j前身是swagger-bootstrap-ui,取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍,更名也是希望把她做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于前端Ui前端.虽然目前还只是在前端,但以后功能肯定不止于此. + Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档赋能的工具

                - 2019/12/16 + 2020/03/08 @@ -237,14 +237,14 @@

              29. - swagger-bootstrap-ui 1.9.6 发布,解决长整型精度丢失的问题 + Knife4j 2.0.1发布,细节处理!

                - swagger-bootstrap-ui 1.9.6 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿 + Knife4j前身是swagger-bootstrap-ui,是一个为Swagger接口文档服务的工具

                - 2019/08/28 + 2019/12/23 @@ -350,7 +350,7 @@

                标签

                - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

                标签

                - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

                标签

                - 大模型(9) + 大模型(11) diff --git a/_site/page6/index.html b/_site/page6/index.html index 02cc602..11a4c6a 100644 --- a/_site/page6/index.html +++ b/_site/page6/index.html @@ -97,19 +97,19 @@

                士不可以不弘毅,任重
              30. - Kettle实战100篇 第28篇 Carte作业服务详解 + Knife4j 2.0发布,涅槃重生~!

                - 待续… + Knife4j前身是swagger-bootstrap-ui,取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍,更名也是希望把她做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于前端Ui前端.虽然目前还只是在前端,但以后功能肯定不止于此.

                - 2019/08/23 + 2019/12/16 - Kettle实战 + 开源资讯

                @@ -117,19 +117,19 @@

              31. - Kettle实战100篇 第27篇 系统级别任务调度调用转换&作业 + swagger-bootstrap-ui 1.9.6 发布,解决长整型精度丢失的问题

                - 待续… + swagger-bootstrap-ui 1.9.6 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿

                - 2019/08/22 + 2019/08/28 - Kettle实战 + 开源资讯

                @@ -137,14 +137,14 @@

              32. - Kettle实战100篇 第26篇 生产环境部署Pentaho + Kettle实战100篇 第28篇 Carte作业服务详解

                待续…

                - 2019/08/21 + 2019/08/23 @@ -157,14 +157,14 @@

              33. - Kettle实战100篇 第25篇 作业核心对象设置变量组件 + Kettle实战100篇 第27篇 系统级别任务调度调用转换&作业

                - 我们在很多场景下都需要用到设置变量组件,比如在分页查询数据时,然后分批次写入数据时,都需要事先定义好变量,一般作为作业中起始组件,设置变量的作业举足轻重,这考验你在一个完成的ETL过程中的逻辑能力,你的ETL是否能正常完美的执行,和开始设置的变量有很重要的关系. + 待续…

                - 2019/08/20 + 2019/08/22 @@ -177,14 +177,14 @@

              34. - Kettle实战100篇 第24篇 日志报表输出 + Kettle实战100篇 第26篇 生产环境部署Pentaho

                待续…

                - 2019/08/19 + 2019/08/21 @@ -197,14 +197,14 @@

              35. - Kettle实战100篇 第23篇 命令行介绍使用 + Kettle实战100篇 第25篇 作业核心对象设置变量组件

                - 我们在前面介绍的实战篇章中,基本都是在Spoon的图形化界面中点击运行按钮时来运行我们的作业或者转换的,但是Kettle也为我们提供了基于命令行的调用方式,基于命令行的方式可以方便我们通过Shell脚本或者Windows的Bat脚本来对作业&转换进行调用,这方便我们配置作业&转换的任务调度 + 我们在很多场景下都需要用到设置变量组件,比如在分页查询数据时,然后分批次写入数据时,都需要事先定义好变量,一般作为作业中起始组件,设置变量的作业举足轻重,这考验你在一个完成的ETL过程中的逻辑能力,你的ETL是否能正常完美的执行,和开始设置的变量有很重要的关系.

                - 2019/08/18 + 2019/08/20 @@ -217,14 +217,14 @@

              36. - Kettle实战100篇 第22篇 资源库的使用 + Kettle实战100篇 第24篇 日志报表输出

                - 我们在前面的实战博客中,都是将我们的作业和转换文件保存在磁盘中,这在小规模的使用中是没有问题的,可是当我们的ETL工程越来越庞大时,一个团队需要更多的ETL工程师来开发ETL的过程时,单人作战就很不合适了,这就和我们开发人员写代码一样,多人协作时需要一个代码的协作平台(GIT、SVN等)来帮助我们管理代码版本,合并代码等操作 + 待续…

                - 2019/08/17 + 2019/08/19 @@ -237,14 +237,14 @@

              37. - Kettle实战100篇 第21篇 JavaScript内置函数说明 + Kettle实战100篇 第23篇 命令行介绍使用

                - 我们在使用JavaScript组件的时候,在左侧核心树对象栏中可以看到Kettle为我们提供了很多简洁强大的内置函数,帮助我们在写脚本的时候对数据、参数变量等能很轻松的做处理,体验编码的感觉.本篇将详细介绍JavaScript组件中的函数功能 + 我们在前面介绍的实战篇章中,基本都是在Spoon的图形化界面中点击运行按钮时来运行我们的作业或者转换的,但是Kettle也为我们提供了基于命令行的调用方式,基于命令行的方式可以方便我们通过Shell脚本或者Windows的Bat脚本来对作业&转换进行调用,这方便我们配置作业&转换的任务调度

                - 2019/08/16 + 2019/08/18 @@ -350,7 +350,7 @@

                标签

                - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

                标签

                - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

                标签

                - 大模型(9) + 大模型(11) diff --git a/_site/page7/index.html b/_site/page7/index.html index 6fa77e8..45e7709 100644 --- a/_site/page7/index.html +++ b/_site/page7/index.html @@ -97,14 +97,14 @@

                士不可以不弘毅,任重
              38. - Kettle实战100篇 第20篇 MySQL数据库导出到ElasticSearch + Kettle实战100篇 第22篇 资源库的使用

                - 业务需求:在系统上线后,原系统的日志信息是存储到MySQL数据库中,但是随着日志数据越来越大,导致数据查询缓慢,加上日志数据并非业务系统关键数据,因此,系统考虑改版升级,使用ElasticSearch来存储日志数据,因此需要将源存在MySQL数据库上的数据迁移到ES中 + 我们在前面的实战博客中,都是将我们的作业和转换文件保存在磁盘中,这在小规模的使用中是没有问题的,可是当我们的ETL工程越来越庞大时,一个团队需要更多的ETL工程师来开发ETL的过程时,单人作战就很不合适了,这就和我们开发人员写代码一样,多人协作时需要一个代码的协作平台(GIT、SVN等)来帮助我们管理代码版本,合并代码等操作

                - 2019/08/15 + 2019/08/17 @@ -117,14 +117,14 @@

              39. - Kettle实战100篇 第19篇 转换核心对象Microsoft Excel输出组件 + Kettle实战100篇 第21篇 JavaScript内置函数说明

                - 我们在上面的实战系列中,多次用到了Excel作为输入或输出组件,该篇主要是针对官方英文文档做一个翻译说明,主要包括输入、输出、写入组件 + 我们在使用JavaScript组件的时候,在左侧核心树对象栏中可以看到Kettle为我们提供了很多简洁强大的内置函数,帮助我们在写脚本的时候对数据、参数变量等能很轻松的做处理,体验编码的感觉.本篇将详细介绍JavaScript组件中的函数功能

                - 2019/08/15 + 2019/08/16 @@ -137,10 +137,10 @@

              40. - Kettle实战100篇 第18篇 JavaScript脚本组件使用示例 + Kettle实战100篇 第20篇 MySQL数据库导出到ElasticSearch

                - JavaScript内置对象 + 业务需求:在系统上线后,原系统的日志信息是存储到MySQL数据库中,但是随着日志数据越来越大,导致数据查询缓慢,加上日志数据并非业务系统关键数据,因此,系统考虑改版升级,使用ElasticSearch来存储日志数据,因此需要将源存在MySQL数据库上的数据迁移到ES中

                @@ -157,14 +157,14 @@

              41. - Kettle实战100篇 第17篇 JSONPath组件介绍说明 + Kettle实战100篇 第19篇 转换核心对象Microsoft Excel输出组件

                - 在我们使用JSON input组件的时候,设置字段映射时,由于Kettle使用的是JSONPath组件来进行解析的,因此我们就需要了解他的相关语法 + 我们在上面的实战系列中,多次用到了Excel作为输入或输出组件,该篇主要是针对官方英文文档做一个翻译说明,主要包括输入、输出、写入组件

                - 2019/08/14 + 2019/08/15 @@ -177,14 +177,14 @@

              42. - Kettle实战100篇 第16篇 JSON文件导入Mysql + Kettle实战100篇 第18篇 JavaScript脚本组件使用示例

                - 待续… + JavaScript内置对象

                - 2019/08/14 + 2019/08/15 @@ -197,10 +197,10 @@

              43. - Kettle实战100篇 第15篇 Mysql数据库表迁移 + Kettle实战100篇 第17篇 JSONPath组件介绍说明

                - 待续… + 在我们使用JSON input组件的时候,设置字段映射时,由于Kettle使用的是JSONPath组件来进行解析的,因此我们就需要了解他的相关语法

                @@ -217,10 +217,10 @@

              44. - Kettle实战100篇 第14篇 参数与变量 + Kettle实战100篇 第16篇 JSON文件导入Mysql

                - 设置变量组件是我们在作业中非常常用的一个组件,通过设置变量,我们的子转换中可以非常方便的解决动态数据处理的问题,比如分页查询数据、导出Excel变量等等 + 待续…

                @@ -237,14 +237,14 @@

              45. - Kettle实战100篇 第13篇 MySQL数据导出Excel数据乱码 + Kettle实战100篇 第15篇 Mysql数据库表迁移

                - 该问题我在使用分页查询导出的时候碰到了乱码的情况,我的情况比较特殊,我通过浏览已经建立好的数据库连接的中的数据时并非乱码,而当我使用表输入组件中的预览数据时缺产生了乱码,因此我不得不设置我们的数据库连接参数 + 待续…

                - 2019/08/13 + 2019/08/14 @@ -350,7 +350,7 @@

                标签

                - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

                标签

                - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

                标签

                - 大模型(9) + 大模型(11) diff --git a/_site/page8/index.html b/_site/page8/index.html index 4381635..4afd690 100644 --- a/_site/page8/index.html +++ b/_site/page8/index.html @@ -97,14 +97,14 @@

                士不可以不弘毅,任重
              46. - Kettle实战100篇 第12篇 自定义开发Java工具类并在JavaScript脚本中运用 + Kettle实战100篇 第14篇 参数与变量

                - 我们在Kettle实战100篇 第1篇 介绍与安装中已经介绍过Kettle的相关目录结构,因为Kettle是使用纯Java语言开发,并且我们在JavaScript脚本中可以调用我们的Java类中的方法进行相关脚本的编写 + 设置变量组件是我们在作业中非常常用的一个组件,通过设置变量,我们的子转换中可以非常方便的解决动态数据处理的问题,比如分页查询数据、导出Excel变量等等

                - 2019/08/13 + 2019/08/14 @@ -117,10 +117,10 @@

              47. - Kettle实战100篇 第11篇 JavaScript表达式变量说明 + Kettle实战100篇 第13篇 MySQL数据导出Excel数据乱码

                - 待续… + 该问题我在使用分页查询导出的时候碰到了乱码的情况,我的情况比较特殊,我通过浏览已经建立好的数据库连接的中的数据时并非乱码,而当我使用表输入组件中的预览数据时缺产生了乱码,因此我不得不设置我们的数据库连接参数

                @@ -137,14 +137,14 @@

              48. - Kettle实战100篇 第9篇 Mysql数据库数据导出到Excel + Kettle实战100篇 第12篇 自定义开发Java工具类并在JavaScript脚本中运用

                - 我们在第8篇的时候已经介绍了将Excel的数据导入到Mysql数据库中,那么,本章我们将介绍将数据从数据库导出到Excel中. + 我们在Kettle实战100篇 第1篇 介绍与安装中已经介绍过Kettle的相关目录结构,因为Kettle是使用纯Java语言开发,并且我们在JavaScript脚本中可以调用我们的Java类中的方法进行相关脚本的编写

                - 2019/08/12 + 2019/08/13 @@ -157,14 +157,14 @@

              49. - Kettle实战100篇 第10篇 JavaScript脚本中日志输出 + Kettle实战100篇 第11篇 JavaScript表达式变量说明

                - 我们在编写作业或者转换的时候,运行时,尽管将Kettle的日志级别调整到最大,但是依然无法帮助我们定位到问题所在,此时我们就需要通过日志来输出我们的相关变量,以编程的思维来帮助我们快速定位到问题,以解决问题 + 待续…

                - 2019/08/12 + 2019/08/13 @@ -177,14 +177,14 @@

              50. - Kettle实战100篇 第8篇 Excel导入到Mysql数据库 + Kettle实战100篇 第9篇 Mysql数据库数据导出到Excel

                - 操作步骤是:选择表格类型(引擎) -> 浏览Excel文件 -> 增加 + 我们在第8篇的时候已经介绍了将Excel的数据导入到Mysql数据库中,那么,本章我们将介绍将数据从数据库导出到Excel中.

                - 2019/08/11 + 2019/08/12 @@ -197,14 +197,14 @@

              51. - Kettle实战100篇 第7篇 转换核心对象插入更新组件 + Kettle实战100篇 第10篇 JavaScript脚本中日志输出

                - 待续 + 我们在编写作业或者转换的时候,运行时,尽管将Kettle的日志级别调整到最大,但是依然无法帮助我们定位到问题所在,此时我们就需要通过日志来输出我们的相关变量,以编程的思维来帮助我们快速定位到问题,以解决问题

                - 2019/08/10 + 2019/08/12 @@ -217,14 +217,14 @@

              52. - Kettle实战100篇 第6篇 转换核心对象字段选择组件 + Kettle实战100篇 第8篇 Excel导入到Mysql数据库

                - 待续… + 操作步骤是:选择表格类型(引擎) -> 浏览Excel文件 -> 增加

                - 2019/08/09 + 2019/08/11 @@ -237,14 +237,14 @@

              53. - Kettle实战100篇 第5篇 转换核心对象生成记录组件 + Kettle实战100篇 第7篇 转换核心对象插入更新组件

                - 待续… + 待续

                - 2019/08/09 + 2019/08/10 @@ -350,7 +350,7 @@

                标签

                - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

                标签

                - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

                标签

                - 大模型(9) + 大模型(11) diff --git a/_site/page9/index.html b/_site/page9/index.html index 4f07307..d32ff71 100644 --- a/_site/page9/index.html +++ b/_site/page9/index.html @@ -97,14 +97,14 @@

                士不可以不弘毅,任重
              54. - Kettle 实战100篇 目录 + Kettle实战100篇 第6篇 转换核心对象字段选择组件

                - 在数据仓库技术中,ETL是必不可少,Kettle作为ETL的经典工具,已经得到广大ETL工程师的喜爱,甚至连开发工程师在使用ETL过程中,优先考虑的也是Kettle + 待续…

                - 2019/08/08 + 2019/08/09 @@ -117,14 +117,14 @@

              55. - Kettle实战100篇 第4篇 转换核心对象REST client组件 + Kettle实战100篇 第5篇 转换核心对象生成记录组件

                待续…

                - 2019/08/08 + 2019/08/09 @@ -137,10 +137,10 @@

              56. - Kettle实战100篇 第3篇 转换核心对象JSON input组件 + Kettle 实战100篇 目录

                - 待续… + 在数据仓库技术中,ETL是必不可少,Kettle作为ETL的经典工具,已经得到广大ETL工程师的喜爱,甚至连开发工程师在使用ETL过程中,优先考虑的也是Kettle

                @@ -157,10 +157,10 @@

              57. - Kettle实战100篇 第2篇 调用RESTful接口导入JSON结果入库 + Kettle实战100篇 第4篇 转换核心对象REST client组件

                - 不管是通过Java或者是Python编码的方式调用RESTful接口将结果入库,都是有一定复杂度的,首先你要加载第三方REST组件,然后连接数据库,写SQL语句,最后插入的目标数据库中 + 待续…

                @@ -177,10 +177,10 @@

              58. - Kettle实战100篇 第1篇 介绍与安装 + Kettle实战100篇 第3篇 转换核心对象JSON input组件

                - 简介 + 待续…

                @@ -197,19 +197,19 @@

              59. - swagger-bootstrap-ui 1.9.5 发布,支持过滤请求参数 + Kettle实战100篇 第2篇 调用RESTful接口导入JSON结果入库

                - swagger-bootstrap-ui 1.9.5 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿 + 不管是通过Java或者是Python编码的方式调用RESTful接口将结果入库,都是有一定复杂度的,首先你要加载第三方REST组件,然后连接数据库,写SQL语句,最后插入的目标数据库中

                - 2019/07/31 + 2019/08/08 - 开源资讯 + Kettle实战

                @@ -217,19 +217,19 @@

              60. - swagger-bootstrap-ui 1.9.4 发布,扩展支持动态字段注释 + Kettle实战100篇 第1篇 介绍与安装

                - swagger-bootstrap-ui 1.9.4 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿 + 简介

                - 2019/06/10 + 2019/08/08 - 开源资讯 + Kettle实战

                @@ -237,19 +237,19 @@

              61. - springfox 源码分析(二十二) 总结 + swagger-bootstrap-ui 1.9.5 发布,支持过滤请求参数

                - 待续… + swagger-bootstrap-ui 1.9.5 发布了。swagger-bootstrap-ui是 Swagger 的增强UI 实现,使文档更友好一点儿

                - 2019/06/03 + 2019/07/31 - springfox + 开源资讯

                @@ -350,7 +350,7 @@

                标签

                - RAG实践(3) + RAG实践(5) @@ -366,7 +366,7 @@

                标签

                - TorchV(3) + TorchV(5) @@ -378,7 +378,7 @@

                标签

                - 大模型(9) + 大模型(11) diff --git a/_site/sitemap.xml b/_site/sitemap.xml index c068571..de01dc8 100644 --- a/_site/sitemap.xml +++ b/_site/sitemap.xml @@ -681,116 +681,124 @@ 2024-04-01T00:00:00+08:00 +http://localhost:4000/2024/07/03/torchv-think/ +2024-07-03T00:00:00+08:00 + + +http://localhost:4000/2024/07/08/torchv-pdf-01/ +2024-07-08T00:00:00+08:00 + + http://localhost:4000/wiki/android-studio/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/axure/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/badminton/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/chinese-copywriting-guidelines/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/eclipse/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/emacs/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/git/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/good-soft/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/ida-pro/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/intellij-idea/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/linux/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/mac/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/markdown/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/mpv/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/ollydbg/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/onenote/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/php/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/powershell/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/python/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/qt-creator/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/source-insight/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/swagger-bootstrap-ui/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/swimming/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/template/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/vim/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/visio/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/visual-studio-code/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/wiki/visual-studio/ -2024-04-01T20:37:58+08:00 +2024-07-08T09:52:22+08:00 http://localhost:4000/about/ diff --git a/_site/wiki/android-studio/index.html b/_site/wiki/android-studio/index.html index 2d165d8..3aea37d 100644 --- a/_site/wiki/android-studio/index.html +++ b/_site/wiki/android-studio/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/axure/index.html b/_site/wiki/axure/index.html index c9ae652..b45692f 100644 --- a/_site/wiki/axure/index.html +++ b/_site/wiki/axure/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/badminton/index.html b/_site/wiki/badminton/index.html index f5ca9ca..e2fa37c 100644 --- a/_site/wiki/badminton/index.html +++ b/_site/wiki/badminton/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/chinese-copywriting-guidelines/index.html b/_site/wiki/chinese-copywriting-guidelines/index.html index 5670351..cafd9c4 100644 --- a/_site/wiki/chinese-copywriting-guidelines/index.html +++ b/_site/wiki/chinese-copywriting-guidelines/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/eclipse/index.html b/_site/wiki/eclipse/index.html index 6746a35..452e1cc 100644 --- a/_site/wiki/eclipse/index.html +++ b/_site/wiki/eclipse/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/emacs/index.html b/_site/wiki/emacs/index.html index b3d7be7..ea27d78 100644 --- a/_site/wiki/emacs/index.html +++ b/_site/wiki/emacs/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/git/index.html b/_site/wiki/git/index.html index dbfddfc..dfd0cbc 100644 --- a/_site/wiki/git/index.html +++ b/_site/wiki/git/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/good-soft/index.html b/_site/wiki/good-soft/index.html index e547f1b..fce28c3 100644 --- a/_site/wiki/good-soft/index.html +++ b/_site/wiki/good-soft/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/ida-pro/index.html b/_site/wiki/ida-pro/index.html index 8663844..67be00f 100644 --- a/_site/wiki/ida-pro/index.html +++ b/_site/wiki/ida-pro/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/index.html b/_site/wiki/index.html index b52fd99..0a55d41 100644 --- a/_site/wiki/index.html +++ b/_site/wiki/index.html @@ -303,7 +303,7 @@

                标签

                - RAG实践(3) + RAG实践(5) @@ -319,7 +319,7 @@

                标签

                - TorchV(3) + TorchV(5) @@ -331,7 +331,7 @@

                标签

                - 大模型(9) + 大模型(11) diff --git a/_site/wiki/intellij-idea/index.html b/_site/wiki/intellij-idea/index.html index 4413ba5..5c62bbe 100644 --- a/_site/wiki/intellij-idea/index.html +++ b/_site/wiki/intellij-idea/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/linux/index.html b/_site/wiki/linux/index.html index ce8a70f..4156799 100644 --- a/_site/wiki/linux/index.html +++ b/_site/wiki/linux/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/mac/index.html b/_site/wiki/mac/index.html index e6a9f21..a8bda56 100644 --- a/_site/wiki/mac/index.html +++ b/_site/wiki/mac/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/markdown/index.html b/_site/wiki/markdown/index.html index 49e1163..92883a2 100644 --- a/_site/wiki/markdown/index.html +++ b/_site/wiki/markdown/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/mpv/index.html b/_site/wiki/mpv/index.html index 158bf5b..ed2b88a 100644 --- a/_site/wiki/mpv/index.html +++ b/_site/wiki/mpv/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/ollydbg/index.html b/_site/wiki/ollydbg/index.html index 6d5dfd3..846e226 100644 --- a/_site/wiki/ollydbg/index.html +++ b/_site/wiki/ollydbg/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/onenote/index.html b/_site/wiki/onenote/index.html index 3fdbfd6..e32354e 100644 --- a/_site/wiki/onenote/index.html +++ b/_site/wiki/onenote/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/php/index.html b/_site/wiki/php/index.html index 0478f0a..14f69b9 100644 --- a/_site/wiki/php/index.html +++ b/_site/wiki/php/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/powershell/index.html b/_site/wiki/powershell/index.html index 082a735..46c7d96 100644 --- a/_site/wiki/powershell/index.html +++ b/_site/wiki/powershell/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/python/index.html b/_site/wiki/python/index.html index b39c06d..a8be924 100644 --- a/_site/wiki/python/index.html +++ b/_site/wiki/python/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/qt-creator/index.html b/_site/wiki/qt-creator/index.html index fd580c1..de81b22 100644 --- a/_site/wiki/qt-creator/index.html +++ b/_site/wiki/qt-creator/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/source-insight/index.html b/_site/wiki/source-insight/index.html index ef58840..ac5c7e7 100644 --- a/_site/wiki/source-insight/index.html +++ b/_site/wiki/source-insight/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/swagger-bootstrap-ui/index.html b/_site/wiki/swagger-bootstrap-ui/index.html index ec30248..a8b769c 100644 --- a/_site/wiki/swagger-bootstrap-ui/index.html +++ b/_site/wiki/swagger-bootstrap-ui/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/swimming/index.html b/_site/wiki/swimming/index.html index 4310a57..78697f8 100644 --- a/_site/wiki/swimming/index.html +++ b/_site/wiki/swimming/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/template/index.html b/_site/wiki/template/index.html index b8e2aa9..339bce8 100644 --- a/_site/wiki/template/index.html +++ b/_site/wiki/template/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/vim/index.html b/_site/wiki/vim/index.html index a63b75e..51759f0 100644 --- a/_site/wiki/vim/index.html +++ b/_site/wiki/vim/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/visio/index.html b/_site/wiki/visio/index.html index e29f408..78d1098 100644 --- a/_site/wiki/visio/index.html +++ b/_site/wiki/visio/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/visual-studio-code/index.html b/_site/wiki/visual-studio-code/index.html index 553f058..2d863ff 100644 --- a/_site/wiki/visual-studio-code/index.html +++ b/_site/wiki/visual-studio-code/index.html @@ -42,7 +42,7 @@ - + diff --git a/_site/wiki/visual-studio/index.html b/_site/wiki/visual-studio/index.html index 9fea543..80df817 100644 --- a/_site/wiki/visual-studio/index.html +++ b/_site/wiki/visual-studio/index.html @@ -42,7 +42,7 @@ - + diff --git a/assets/images/rag/.DS_Store b/assets/images/rag/.DS_Store index 0caf2db..465e8c8 100644 Binary files a/assets/images/rag/.DS_Store and b/assets/images/rag/.DS_Store differ diff --git a/assets/images/rag/torchv/.DS_Store b/assets/images/rag/torchv/.DS_Store index f7af3cd..7879568 100644 Binary files a/assets/images/rag/torchv/.DS_Store and b/assets/images/rag/torchv/.DS_Store differ diff --git a/assets/images/rag/torchv/pdf-01/image-20240706170720200.png b/assets/images/rag/torchv/pdf-01/image-20240706170720200.png new file mode 100644 index 0000000..7fc9e86 Binary files /dev/null and b/assets/images/rag/torchv/pdf-01/image-20240706170720200.png differ diff --git a/assets/images/rag/torchv/rag-4/image-20240701143924758.png b/assets/images/rag/torchv/rag-4/image-20240701143924758.png new file mode 100644 index 0000000..c182b58 Binary files /dev/null and b/assets/images/rag/torchv/rag-4/image-20240701143924758.png differ diff --git a/assets/images/rag/torchv/rag-4/image-20240701143941791.png b/assets/images/rag/torchv/rag-4/image-20240701143941791.png new file mode 100644 index 0000000..bc41fe5 Binary files /dev/null and b/assets/images/rag/torchv/rag-4/image-20240701143941791.png differ diff --git a/assets/images/rag/torchv/rag-4/image-20240703085452132.png b/assets/images/rag/torchv/rag-4/image-20240703085452132.png new file mode 100644 index 0000000..7197ffb Binary files /dev/null and b/assets/images/rag/torchv/rag-4/image-20240703085452132.png differ