OA集成AI大模型简单实践-我把大模型集成到致远OA中系列

AI资讯 2个月前 charles
1.8K 0

这篇文章讲解通过致远OA上传附件到文档中心后,把文档解析成文字,再把数据用大模型转成向量入库。用AI大模型进行文档的召回和基于文档的上下文进行简单对话。

思路:OA切入点

利用OA在附件上传和下载时提供拦截机制.
杀毒:附件上传时结合杀毒软件厂商提供的接口,对文件进行查毒和杀毒。
加密:附件上传下载时使用特定的加密算法对附件进行加解密。
舆情监控:扫描上传附件的内容,禁止含特定关键字的附件进入系统。
审计日志:对附件的上传和下载行为进行记录。
什么是Ollma
Ollama是一个专为在本地机器上便捷部署和运行大型语言模型(LLM)而设计的工具。

什么是embedding?

embedding在机器学习和自然语言处理中,主要是将词汇、句子、段落甚至整个文档转换为实数向量的过程。这种转换过程允许模型在进行训练和推理过程中,能够理解和处理语言数据。这些向量能够捕捉单词语义上的相似性,例如词义相近的单词在嵌入空间中的向量会更接近。

大语言模型 LLM

LLM(Large Language Model,大语言模型)是指使用大量文本数据训练的深度学习模型,能够生成自然语言文本或理解语言文本的含义。‌ LLM的核心思想是通过大规模的无监督训练学习自然语言的模式和结构,模拟人类的语言认知和生成过程。这些模型通常采用Transformer架构,并通过自监督学习方法利用大量未标注文本进行训练。‌

 LLM的使用场景非常广泛。首先,LLM可以用于文本生成,可以生成连贯的段落、文章、对话等,可以应用于自动写作、机器翻译等任务中。其次,LLM可以用于问答系统,可以回答复杂的问题,甚至进行对话式问答。再者,LLM可以用于语义理解和推理,可以进行情感分析、命名实体识别、文本分类等任务。此外,LLM还可以用于智能助理、机器人交互、自动摘要、信息提取等应用领域。

ChromaDB‌ 向量数据库

‌ChromaDB‌ 是一个轻量级向量数据库,主要用于存储和查询大规模、高维数据。它支持多种数据类型,包括文本、图像等,并且能够处理复杂的查询和大规模数据集。ChromaDB特别适用于自然语言处理(NLP)和机器学习应用,能够提供高效的向量检索和语义搜索功能‌。

环境搭建
安装Ollma
Ollma官网地址:https://ollama.com/
下载安装Ollma:

OA集成AI大模型简单实践-我把大模型集成到致远OA中系列

下载完成后,打开Ollma,安装后启动,其默认端口为11334,浏览器访问:http://localhost:11434 ,页面显示:Ollama is running,电脑右下角展示图标;

OA集成AI大模型简单实践-我把大模型集成到致远OA中系列

安装大模型

1、搜索大模型,查找运行大模型的命令,

地址:https://ollama.com/search

2、运行大模型,通过命令行下载大模型,命令行格式:ollmapull modelName,如:ollma pull llama3;

3、大模型一般要几个G,需要等一会;一般运行, llama3、 qwen(通义千问),这两个都是开源免费的,英文场景 用 llama3,中文场景用 qwen;

电脑如果内存小,建议运行一个就行了,8g内存的电脑肯定,开发肯定不行,至少16g

本次运行:qwen2.5:3b 这个3b的模型小适合开发用

通过 ollma list 可以查看 已下载的大模型:

OA集成AI大模型简单实践-我把大模型集成到致远OA中系列

启动大模型‍‍
用命令行 :ollma run 模型名称,来启动大模型;启动后,可以立即输入内容与大模型进行对话,如下:
让他介绍一下LangChain

OA集成AI大模型简单实践-我把大模型集成到致远OA中系列

安装ChromaDB‌ 

1.安装:pip install chromadb ; 安装需要先安装Python,不要安装最新的,安装python=3.11.10 左右的版本最合适。

2.启动:chroma run :

OA集成AI大模型简单实践-我把大模型集成到致远OA中系列

把大模型接入致远OA
加入jar包
 <properties>    <maven.compiler.source>8</maven.compiler.source>  <maven.compiler.target>8</maven.compiler.target>  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    <langchain4j.version>0.34.0</langchain4j.version> </properties><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai</artifactId>            <version>${langchain4j.version}</version></dependency><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-chroma</artifactId><version>${langchain4j.version}</version></dependency><!-- ollama --><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-ollama</artifactId><version>${langchain4j.version}</version></dependency><!--chroma 向量数据库--><dependency><groupId>io.github.amikos-tech</groupId><artifactId>chromadb-java-client</artifactId><version>0.1.7</version></dependency>
通过监听FileUploadEvent事件可以拦截附件上传进行处理。
/** * 〈监听附件上传〉 * * @author OA同学 * @create 2024/11/11 * @since 1.0.0 */public class RAGFileEvent {
@ListenEvent(event = FileUploadEvent.class)public void onFileUpload(FileUploadEvent evt) throws Exception {// 取得上传的文件FileItem fileItem = evt.getFileItem();String originalFilename = fileItem.getOriginalFilename();if (originalFilename.contains(".txt")) {//保存文件到临时目录String systemTempFolder = SystemEnvironment.getSystemTempFolder();String pathname = systemTempFolder + File.separator + UUIDUtil.getUUIDString() + File.separator + originalFilename;CtpFile tempFile = new CtpFile(pathname);InputStream inputStream = fileItem.getInputStream();GlobalFileUtils.saveCtpFile(inputStream, tempFile);
//解析文件 DocumentDocument document = LangChainUtils.getDocument(pathname);            //拆分文件内容                        //文本向量化                        //向量库存储                        //向量库检索                        //与LLM交互            String chat=LangChainUtils.llmChat(message);}}}
解析文件

把文件解析成langchain4j的Document对象。

public static Document getDocument(String fileName) {URL docUrl = LangChainUtils.class.getClassLoader().getResource(fileName);if (docUrl == null) {log.error("未获取到文件");}Document document = null;try {Path path = Paths.get(docUrl.toURI());document = FileSystemDocumentLoader.loadDocument(path);} catch (URISyntaxException e) {log.error("加载文件发生异常", e);}return document;}

拆分文件

//======================= 拆分文件内容=======================// 参数:分段大小(一个分段中最大包含多少个token)、重叠度(段与段之前重叠的token数)、分词器(将一段文本进行分词,得到token)DocumentByLineSplitter lineSplitter = new DocumentByLineSplitter(200, 0, new OpenAiTokenizer());List<TextSegment> segments = lineSplitter.split(document);log.info("segment的数量是: {}", segments.size());
//查看分段后的信息segments.forEach(segment -> log.info("========================segment:" +segment.text()));

文本向量化并保存向量

 private static final String CHROMA_DB_NAME = "rag-oa"; private static final String CHROMA_URL = "http://localhost:8000" private static final String OLLAMA_URL = "http://localhost:11434"; private static final String OLLAMA_NAME = "qwen2.5:3b";  //======================= 文本向量化=======================OllamaEmbeddingModel embeddingModel = OllamaEmbeddingModel.builder().baseUrl(Optional.ofNullable(AppContext.getSystemProperty("rag.ollama_url")).orElse(OLLAMA_URL)).modelName(Optional.ofNullable(AppContext.getSystemProperty("rag.ollama_name")).orElse(OLLAMA_NAME)).build();//======================= 向量库存储=======================   //创建向量数据库EmbeddingStore<TextSegment> embeddingStore = ChromaEmbeddingStore.builder().baseUrl(Optional.ofNullable(AppContext.getSystemProperty("rag.chroma_url")).orElse(CHROMA_URL)).collectionName(Optional.ofNullable(AppContext.getSystemProperty("rag.chroma_db_name")).orElse(CHROMA_DB_NAME )).build();segments.forEach(segment -> {Embedding e = embeddingModel.embed(segment).content();embeddingStore.add(e, segment);});

向量库检索

//======================= 向量库检索=======================String qryText = "待办";Embedding queryEmbedding = embeddingModel.embed(qryText).content();
EmbeddingSearchRequest embeddingSearchRequest = EmbeddingSearchRequest.builder().queryEmbedding(queryEmbedding).maxResults(1).build();EmbeddingSearchResult<TextSegment> embeddedEmbeddingSearchResult = embeddingStore.search(embeddingSearchRequest);List<EmbeddingMatch<TextSegment>> embeddingMatcheList = embeddedEmbeddingSearchResult.matches();EmbeddingMatch<TextSegment> embeddingMatch = embeddingMatcheList.get(0);TextSegment textSegment = embeddingMatch.embedded();log.info("查询结果:" +textSegment.text());

与LLM交互

//======================= 与LLM交互=======================PromptTemplate promptTemplate = PromptTemplate.from("基于如下信息用中文回答:n" + "{{context}}n" + "提问:n" + "{{question}}");Map<String, Object> variables = new HashMap<>();//以向量库检索到的结果作为LLM的信息输入variables.put("context", textSegment.text());variables.put("question", "我总共几个待办事项");Prompt prompt = promptTemplate.apply(variables);
//连接大模型OllamaChatModel ollamaChatModel = OllamaChatModel.builder().baseUrl(Optional.ofNullable(AppContext.getSystemProperty("rag.ollama_url")).orElse(OLLAMA_URL)).modelName(Optional.ofNullable(AppContext.getSystemProperty("rag.ollama_name")).orElse(OLLAMA_NAME)).build();UserMessage userMessage = prompt.toUserMessage();Response<AiMessage> aiMessageResponse = ollamaChatModel.generate(userMessage);AiMessage response = aiMessageResponse.content();log.info("大模型回答: "+ response.text());

我们写个接口测试一下:

@Path("ai")@Produces({"application/json"})public class AIRestResource extends BaseResource {private static final Log log = LogFactory.getLog(AIRestResource.class);
@POST@Path("/message")public Response mesasge(@QueryParam("message") String message) { //与LLM交互        return ok(LangChainUtils.llmChat(message));}}

上传一个测试.txt,内容如下

在致远OA中有2个待办协同,有3个待办公文,有1个10点的会议
调用接口输入问题:“我总共几个待办事项”,程序打印如下结果:
根据你的描述,在致远OA中你有以下几个待办事项:- 两个待办协同任务- 三个待办公文任务- 一次在10点开始的会议将这些加起来,你可以得出总共的待办事项目数是:[ 2 + 3 + 1 = 6 ]所以,你总共有 **六个** 待办事项目。
总结:
1、上面是一个简单的入门级实践AI大模型。
2、回答系统可以使用Spring AI 和Spring AI ALibaba来搭建这个两个社区都很活跃。
3、集成在OA中一般都用langchain 另外它还有很多很强大的能力,prompt Fomat、output Fomat、工具调用、memory存储等,这个社区也非常活跃;
4、我一直在思考,客开这行是否还可以做,AI这么火,能否用AI来解决客户的需求,我觉得客开还是能一直做,大家对用AI来帮助客开有什么看法,欢迎在评论区讨论。

5、接下来我将用AI大模型把OA的大部分功能重做一遍。

版权声明:charles 发表于 2025年2月4日 pm6:54。
转载请注明:OA集成AI大模型简单实践-我把大模型集成到致远OA中系列 | AI工具大全&导航

相关文章