5 分钟,开发自己的 AI 文档助手!手把手教程

大家好,我是鱼皮。

几个月前,我自己开发过一个 AI 文档总结助手应用。给大家简单演示一下,首先我上传了一个文档,定义 1 + 1 等于 3:

然后把文档喂给 AI 文档总结助手,再向它提问,然后 AI 就回答出了我们文档中的内容,如下图:

是不是很有趣哈哈~ 所以 AI 并不是完全可信的哦,要看原始数据是否可信!

当时参考网上的教程,做这个花了挺长一段时间,成就感满满。

但没想到,这段时间,AI 以一日千里的速度发展,现在开发一个同样的 AI 文档总结助手,大家猜猜要多久?

答案是:只要 5 分钟!!!

没错,使用腾讯云新出的向量数据库产品能力,哪怕没有 AI 知识,也能够轻轻松松开发出 AI 应用。

下面就给大家分享一下 AI 总结助手开发教程。

AI 总结助手开发教程

实现原理

动手写代码前,我们要先了解整个 AI 总结助手的实现原理,为什么 AI 能够回答出我们指定的文档内容呢?

那肯定要把文档数据先 “喂” 给 AI 呀,可是怎么 “喂” 呢?

因为 AI 的 “脑容量” 很小,接受的输入有限,所以我们要对文档进行拆分,比如将一篇万字长文拆为 20 个 500 字的小段落。

然后,我们要将这些小段落存储到 数据库 中,当用户向 AI 提问时,AI 要先从数据库中查询出和用户问题相似度最高的小段落,然后对这些小段路进行总结,再给用户回答。

为什么要给 AI 提供一个数据库呢?我举个通俗易懂的比喻:我们考试时如果脑袋记不住所有考点,是不是带本书进考场,然后根据考题从书中查出答案,再整理一下写到考卷上就行了呢?

那么问题就来了,怎么根据用户的问题从数据库中查出最相似的段落呢?文本段落应该以什么格式存储到数据库中呢?

这就需要用到一种特殊的数据库技术 —— 向量数据库。

什么是向量数据库?

向量数据库就是一个专门存储和处理 向量数据 的数据库,它内置了相似内容检索功能,可以找到和某个向量最相似的数据。

相比于传统关系型数据库(比如 MySQL)的模糊查询(like)而言,向量检索会更灵活。如今,得益于 AI 的发展,向量数据库作为 AI 的 “小抄”,也变得越来越流行。

那什么是向量数据呢?

其实就是用一些算法将文本、图片、音视频等内容统一转换成数值向量。

比如:“中午吃饺子”,经过转换后得到的向量数据可能是:[0.8, 0.6, 0.9, 0.4, ...];而 “晚上写代码”,经过转换后得到的向量数据可能是:[0.1, 0.2, 0.3, 0.4, ...]

如果用户要从向量数据库搜索内容,那么也可以把搜索关键字转换为类似的向量数据,然后计算两个向量之间的距离来判断相似度即可。

比如用户问:“中午吃什么?”,经过转换后得到的向量数据可能是:[0.8, 0.6, 0.7, 0.3, ...]。

显然,这个向量数据会和 “中午吃饺子” 的向量数据更接近,所以会优先搜出 “中午吃饺子”。

采用不同的向量转换算法、或者不同的相似度计算方法,得到的向量值和计算结果可能也是不同的。

具体实现流程

了解向量数据库后,我们可以整理出 AI 应用的具体实现流程:

1)将自己已有的知识库文档进行段落拆分;

2)利用算法(Embedding)将文档数据转换为向量

3)将向量存储到向量数据库中

4)将用户发送的问题通过算法(Embedding)转换为向量

5)根据用户问题向量,在向量数据库进行相似性查询

6)将检索到的最相似结果作为背景知识(上下文),转换为 prompt 并发送给 AI 大模型,从而获得响应结果

流程图如下:

此前,鱼皮就是按照这个流程自己开发实现的 AI 总结助手。但是要自己对文档进行拆分、还要通过某种算法转换成向量数据,想想都麻烦!

有没有更简单的实现方式呢?

流程简化

还真有!很多大厂云服务商都提供了云向量数据库,比如腾讯云的向量数据库,不仅提供了数据写入和检索的自动向量化功能(embedding),还支持文本自动拆分和一键上传,可以直接将文章转为拆分好的向量写入到向量数据库,大大简化了开发流程。

如果用腾讯云的向量数据库,上面的实现流程就简化为 3 个核心步骤:

1)将文档上传到向量数据库(自动拆分并转为向量存储)

2)将用户发送的问题传入到向量数据库进行相似性查询

3)将检索到的最相似结果作为背景知识(上下文),转换为 prompt 并发送给 AI 大模型,从而获得响应结果

那么流程图就简化为下面这样了:

流程确定后,就可以开始写代码了。

AI 总结助手开发

从上述流程中我们会发现,想要实现 AI 总结助手,向量数据库和 AI 大模型是两大不可或缺的角色。

此处,我们选用上面介绍的腾讯云向量数据库,并且搭配开源的百川 AI 大模型,可以节约开发成本。

1、免费领取资源

首先要免费领取腾讯云向量数据库 + 百川 AI 大模型的使用权。

2)在弹框中填入自己的手机号即可领取成功,等待初始化就好了

3)等初始化成功后,进入腾讯云向量数据库的实例列表,当状态显示为运行中时,开启外网访问:

4)开启外网时,需要填写允许访问的白名单,那由于此处仅为测试,我就直接设置为全网可访问了:

5)访问百川 AI 大模型,领取百川的免费调用次数

6)进入 API Key 管理页面,新建一个属于自己的 API Key,后面就可以调用百川大模型的 AI 能力了。

资源领取好了,我们就可以愉快地使用资源啦。

正式开发前,我们要先阅读向量数据库官方的 API 开发文档,以最新的文档为准去写代码。

2、引入依赖

我们以 Java Maven 项目开发为例,先引入程序所需的依赖,比如向量数据库、HTTP 调用客户端等。

代码如下:

<dependencies><dependency><groupId>com.tencent.tcvectordb</groupId><artifactId>vectordatabase-sdk-java</artifactId><version>1.0.4-SNAPSHOT</version><scope>system</scope><systemPath>${project.basedir}/src/main/libs/vectordatabase-sdk-java-1.0.4.jar</systemPath></dependency>
&lt;dependency&gt;&lt;groupId&gt;org.apache.commons&lt;/groupId&gt;&lt;artifactId&gt;commons-lang3&lt;/artifactId&gt;&lt;version&gt;3.12.0&lt;/version&gt;
&lt;/dependency&gt;&lt;dependency&gt;&lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;&lt;artifactId&gt;jackson-core&lt;/artifactId&gt;&lt;version&gt;2.12.3&lt;/version&gt;
&lt;/dependency&gt;&lt;dependency&gt;&lt;groupId&gt;com.qcloud&lt;/groupId&gt;&lt;artifactId&gt;cos_api&lt;/artifactId&gt;&lt;version&gt;5.6.8&lt;/version&gt;
&lt;/dependency&gt;&lt;dependency&gt;&lt;groupId&gt;com.squareup.okhttp3&lt;/groupId&gt;&lt;artifactId&gt;okhttp&lt;/artifactId&gt;&lt;version&gt;4.9.1&lt;/version&gt;
&lt;/dependency&gt;

</dependencies>

3、连接向量数据库

参考官方提供的 Java SDK Demo 代码,首先和向量数据库建立连接:

import com.tencent.tcvectordb.client.VectorDBClient;
import com.tencent.tcvectordb.model.param.database.ConnectParam;
import com.tencent.tcvectordb.model.param.enums.ReadConsistencyEnum;

public class VDBClientFactory {

public static VectorDBClient createClient() {ConnectParam param = getConnectParam();return new VectorDBClient(param, ReadConsistencyEnum.EVENTUAL_CONSISTENCY);
}private static ConnectParam getConnectParam() {return ConnectParam.newBuilder().withUrl("url").withUsername("username").withKey("key").withTimeout(30).build();
}

}

上述代码中的 url 可以直接在云向量数据库的实例列表中看到,直接选中复制即可:

对于 username 和 key 参数,则需要点进实例,选择密钥管理来获取:

4、上传文档到向量数据库

上传文档到数据库前,肯定要先初始化数据库表。

让我们新建一个 AISearchExample 类,在这个类中编写调用向量数据库的方法,创建数据库和数据表,代码如下:

public class AISearchExample {private static final String DB_NAME = "ai_test_db";private static final String COLLECTION_NAME = "ai_test_collection";
private static void initDatabase(VectorDBClient client) {System.out.println("init database..");try {client.dropAIDatabase(DB_NAME);} catch (VectorDBException e) {// ignore}client.createAIDatabase(DB_NAME);
}private static void initCollection(VectorDBClient client) {System.out.println("init collection..");Database database = client.database(DB_NAME);CreateAICollectionParam param = CreateAICollectionParam.newBuilder().withName(COLLECTION_NAME).build();database.createAICollection(param);
}

}

然后编写一个 writeKnowledgeByFile 方法,把本地的文档上传到向量数据库里:

可以直接上传文档,不需要再操心文档段落的拆分、如何转换为数值向量等复杂的问题,大幅节约时间

public class AISearchExample {...
private static void writeKnowledgeByFile(VectorDBClient client) throws Exception {AICollection collection = client.database(DB_NAME).describeAICollection(COLLECTION_NAME);for (String f : Objects.requireNonNull(new File("doc").list())) {String filePath = "doc/" + f;System.out.println("upload file " + filePath);collection.upload(filePath, Collections.emptyMap());}System.out.println("all file uploaded.");System.out.println("文件上传后,向量数据库会进行解析和Embedding,请耐心等待10-20秒后可以开始进行知识检索。");

}
}

这里我把自己写的学习路线文章都上传到向量数据库:

编写好上述的初始化方法后,依次调用即可:

public class AISearchExample {...private static void initKnowledge(VectorDBClient client) throws Exception {initDatabase(client);initCollection(client);writeKnowledgeByFile(client);}
}
5、搜索文档

将文档都上传到向量数据库后,就可以实现数据的检索了。

在 AISearchExample 类中,再添加一个搜索方法 searchKnowledge,代码如下:

public class AISearchExample {...
private static String searchKnowledge(String question, VectorDBClient client) {// 访问指定的表AICollection collection = client.database(DB_NAME).describeAICollection(COLLECTION_NAME);// 构造搜索条件SearchByContentsParam param = SearchByContentsParam.newBuilder().withContent(question).build();StringBuilder allKnowledge = new StringBuilder();List&lt;Document&gt; results = collection.search(param);int index = 1;// 获取搜索结果for (Document document : results) {ChunkInfo chunk = (ChunkInfo)document.getObject("chunk");allKnowledge.append(chunk.getText()).append(" ");}return allKnowledge.toString();
}

}

运行代码,测试下效果,成功检索出了指定回答:

效果不错,我再试试,问问 “中午吃什么”:

What?这什么啊,你不要睁着眼睛乱说好不好!

这里我们发现了一个关键问题:当我搜索一个完全不存在的问题时,向量数据库仍然会给出结果,然而这并不是我想要的。如果没有相关的内容,直接不返回结果好像更符合预期。

好在腾讯云向量数据库返回了检索相似度,可以根据这个值设定一个阈值,从而进行过滤。

修改一下代码,过滤相似度低于 0.8 的文档:

public class AISearchExample {...
/*** 文档相关性的阈值*/
private static final Double THRESHOLD = 0.8;

private static String searchKnowledge(String question, VectorDBClient client) {
AICollection collection = client.database(DB_NAME).describeAICollection(COLLECTION_NAME);
SearchByContentsParam param = SearchByContentsParam.newBuilder().withContent(question).build();

    StringBuilder allKnowledge = new StringBuilder();List&lt;Document&gt; results = collection.search(param);int index = 1;for (Document document : results) {Double score = document.getScore();if (ObjectUtils.isEmpty(score) || score &lt; THRESHOLD) {continue;}ChunkInfo chunk = (ChunkInfo)document.getObject("chunk");allKnowledge.append(chunk.getText()).append(" ");}return allKnowledge.toString();
}

}

再测试下效果,这次正常了:

至此,我们使用向量数据库实现了文档数据的存储和查询。“小抄” 已经准备好,接下来就把它给 AI 吧!

6、使用 AI 大模型

可以通过 OKHttp 库向 AI 大模型发送请求,实现 AI 的问答能力。

代码看起来比较长,但其实只需要按照百川要求的参数格式来设置请求头、封装 prompt,最后发起调用并获取返回结果就好了,代码如下:

public class BaiChuanLLM {
private static final String URL = "https://api.baichuan-ai.com/v1/chat";/*** 这里的ak和sk可以从百川官网获取,文章中已经演示过了,直接替换掉即可*/
private static final String API_KEY = "ak";
private static final String SECRET_KEY = "sk";private static final ObjectMapper MAPPER = new ObjectMapper();private static volatile OkHttpClient HTTP_CLIENT;public static String ask(String question, String knowledge) {try {String prompt = getPrompt(question, knowledge);return llmRequest(prompt);} catch (Exception e) {e.printStackTrace();return null;}
}private static String llmRequest(String prompt) throws IOException {String requestData = getBaiChuanRequest(prompt);String timestamp = String.valueOf(System.currentTimeMillis() / 1000);String signature = calculateMd5(SECRET_KEY + requestData + timestamp);Headers headers = getHeaders(timestamp, signature);RequestBody body = RequestBody.create(requestData, MediaType.parse("application/json; charset=utf-8"));Request request = (new Request.Builder()).url(URL).headers(headers).post(body).build();try (Response response = getHttpClient().newCall(request).execute()) {JsonNode node = null;if (response.body() != null) {node = MAPPER.readTree(response.body().string());}if (node != null) {return node.get("data").get("messages").get(0).get("content").asText();}return null;}
}private static Headers getHeaders(String timestamp, String signature) {return (new Headers.Builder()).add("Content-Type", "application/json").add("Authorization", "Bearer " + API_KEY).add("X-BC-Request-Id", "RequestId-1001").add("X-BC-Timestamp", timestamp).add("X-BC-Signature", signature).add("X-BC-Sign-Algo", "MD5").build();
}public static String calculateMd5(String inputString) {try {MessageDigest md = MessageDigest.getInstance("MD5");md.update(inputString.getBytes());byte[] digest = md.digest();StringBuilder buffer = new StringBuilder();for (byte b : digest) {buffer.append(String.format("%02x", b &amp; 0xff));}return buffer.toString();} catch (NoSuchAlgorithmException e) {e.printStackTrace();return null;}
}private static String getBaiChuanRequest(String prompt) throws JsonProcessingException {ObjectNode data = JsonNodeFactory.instance.objectNode();data.put("model", "Baichuan2-53B");ObjectNode node = JsonNodeFactory.instance.objectNode();node.put("role", "user");node.put("content", prompt);data.put("messages", JsonNodeFactory.instance.arrayNode().add(node));return new ObjectMapper().writeValueAsString(data);
}private static String getPrompt(String question, String knowledge) throws JsonProcessingException {JsonNodeFactory factory = JsonNodeFactory.instance;ObjectNode obj = factory.objectNode();obj.put("请回答问题", question);obj.put("背景知识如下", knowledge);return new ObjectMapper().writeValueAsString(obj);
}synchronized private static OkHttpClient getHttpClient() {if (HTTP_CLIENT == null) {HTTP_CLIENT = (new OkHttpClient.Builder()).connectTimeout(2L, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).connectionPool(new ConnectionPool(10, 5L, TimeUnit.MINUTES)).build();}return HTTP_CLIENT;
}

}

上面的代码大家也不用记,直接复制到自己的程序中就行。

最后,我们在刚刚创建的 AISearchExample 类中编写一个 main 方法,以实现调用。

示例代码如下:

public static void main(String[] args) throws Exception {VectorDBClient client = createClient();initKnowledge(client);
Scanner scanner = new Scanner(System.in);
System.out.print("请输入您的问题(exit退出):");
String inputString = scanner.nextLine();
while (!"exit".equalsIgnoreCase(inputString)) {if (!inputString.trim().isEmpty()) {String result = searchKnowledge(inputString, client);if (StringUtils.isBlank(result)) {System.out.println("未找到相关内容");}else {System.out.println(result);}String llmResult = BaiChuanLLM.ask(inputString, result);System.out.println("----&gt;LLM回答结果:");System.out.println(llmResult);}System.out.println("\n\n");System.out.print("请输入您的问题(exit退出):");inputString = scanner.nextLine();
}

}

注意:

1)由于版本持续更新迭代,请以官方最新的 SDK Demo 为准

2)相比于 Java,Python 调用会更加简单,只需要不到 100 行代码就能搞定

最终效果

查询向量数据库中已有的信息时,向量数据库成功查询到了文档段落:

AI 大模型基于上面的文档段落,给出了更清晰的回答:

很好,一个 AI 总结助手就开发完成啦!学会的同学点个赞吧 🌹~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/163656.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

登陆页面模板

简单好看的登陆页面 vue项目代码 可忽略js部分 先来个效果图 <template><div class"login"><div class"content"><p >账户密码登录</p><div class"unit"><label class"label">用户名</…

Hadoop学习总结(MapReduce的数据去重)

现在假设有两个数据文件 file1.txtfile2.txt2018-3-1 a 2018-3-2 b 2018-3-3 c 2018-3-4 d 2018-3-5 a 2018-3-6 b 2018-3-7 c 2018-3-3 c2018-3-1 b 2018-3-2 a 2018-3-3 b 2018-3-4 d 2018-3-5 a 2018-3-6 c 2018-3-7 d 2018-3-3 c 上述文件 file1.txt 本身包含重复数据&…

汇编-PROTO声明过程

64位汇编 64 模式中&#xff0c;PROTO 伪指令指定程序的外部过程&#xff0c;示例如下&#xff1a; ExitProcess PROTO ;指定外部过程&#xff0c;不需要参数.code main PROCmov ebx, 0FFFFFFFFh mov ecx,0 ;结束程序call ExitProcess ;调用外部过程main ENDP END 32位…

手把手云开发小程序-(四)-uniclould增删改查业务开发

一&#xff0c;导入uView 在开发小程序的时候&#xff0c;我习惯使用uView这个ui库。主要是直接用当然比自己写省时间。 它的官网&#xff1a;uView - 多平台快速开发的UI框架 - uni-app UI框架 (gitee.io) 导入&#xff1a; npm install uview-ui2.0.31然后按照官网进行配…

UltraCompare 23 for Mac文件对比工具

UltraCompare是一款功能强大的文件比较和合并工具&#xff0c; 以下是它的特色介绍&#xff1a; 多种文件格式支持&#xff1a;UltraCompare支持比较和合并多种文件格式&#xff0c;包括文本文件、二进制文件、office文档、PDF文件等。 文件差异高亮显示&#xff1a;UltraComp…

内测分发平台的合作生态和生态效应如何

大家好&#xff0c;我是咕噜-凯撒&#xff0c;随着移动互联网和智能设备的快速发展&#xff0c;越来越多的开发者和企业开始关注产品的质量和体验。而内测分发平台则成为了一种重要的工具&#xff0c;能够帮助他们更好地测试、优化和推广产品。在此过程中&#xff0c;内测分发平…

特殊企业信息轻松查询:特殊企业基本信息查询API的实用性探讨

引言 在当今数字化时代&#xff0c;企业管理和决策往往取决于有效获取和分析关键信息。对于特殊企业&#xff0c;如香港公司、社会组织、律所、事业单位、基金会和新机构&#xff0c;获取准确、及时的基本信息至关重要。在这个背景下&#xff0c;特殊企业基本信息查询API正逐渐…

〔004〕虚幻 UE5 像素流部署

✨ 目录 ▷ 启用像素流插件▷ 打包项目▷ 下载环境包▷ 手动下载▷ 安装信令服务器环境▷ 启动信令服务器▷ 设置启动参数▷ 启动程序▷ 网页运行▷ 开启触控界面▷ 启用像素流插件 打开虚幻启动程序,选择 编辑 后点击 插件在插件列表中搜索 pixel streaming 关键字,勾选后重…

springcloud宿舍管理系统源码

开发技术&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;idea&#xff0c;vscode springcloud springboot mybatis vue elementui 功能介绍&#xff1a; 用户端&#xff1a; 登录注册 首页展示轮播&#xff0c;公告&#xff0c;报修&#xff0c;晚归登记&#xff0…

提升抖音小店服务分:优化策略与实操指南

抖音小店服务分是抖音平台为评估和提升小店服务质量而设立的一项指标。它通过对小店在订单管理、售后服务、物流管理等多个方面的表现进行评估和计算&#xff0c;为小店提供一个可衡量的服务质量指标。提高抖音小店服务分数对于增加用户信任度、提升销售额和增加曝光度都非常重…

第十七章 Java链接数据库

目录 1.登录MySQL 2.创建库和表 3.使用Java命令查询数据库操作 4.右击——点击“Build Path”——选择第四个——找到包的位置——导入成功 一、创建java项目 1.注册驱动 2.获取链接 3.获取statment对象 4.执行sql语句返回结果集 5.遍历结果集 6.关闭连接释放资源 封装…

Linux:设置Ubuntu的root用户密码

执行以下命令&#xff1a; 给root用户设置密码 sudo passwd 输入两次密码 切换root su root 退出root用户 exit

windows根据已有的安卓签名文件获取MD5签名

windows根据已有的安卓签名文件获取MD5签名 0 现状 uniapp 本机号码一键登录需要MD5的&#xff0c;现有的签名文件但是只有SHA1和SHA256 查看SHA1和SHA256 keytool -list -v -keystore [你的.keystore文件]1 前提 已有生成签名文件的环境 搭建Openssl环境&#xff0c;设置…

0基础能不能转行做网络安全?网络安全人才发展路线

最近有同学在后台留言&#xff0c;0基础怎么学网络安全&#xff1f;0基础可以转行做网络安全吗&#xff1f;以前也碰到过类似的问题&#xff0c;想了想&#xff0c;今天简单写一下。 我的回答是先了解&#xff0c;再入行。 具体怎么做呢&#xff1f; 首先&#xff0c;你要确…

idea 2023 安装配置 Gradle8.4

官网&#xff1a;https://gradle.org 下载 Gradle8.4 https://gradle.org/releases/ 解压到本地&#xff0c;到 gradle-8.4\init.d 目录下新建文件&#xff1a;init.gradle 这里有个坑&#xff0c;编译报http协议安全的问题&#xff0c;解决办法&#xff0c;加入&#xff1…

Android7.1 高通平台 修改系统默认语言

客户需求&#xff1a;修改系统默认语言为英文&#xff08;美国&#xff09; 源码位置&#xff1a;/build/tools/buildinfo.sh 只需修改 ro.product.locale的值即可&#xff0c;如下图&#xff1a;

【Java】定时器的简单应用

在写代码的过程中&#xff0c;如果我们遇到了隔一段时间就要进行一项任务时&#xff0c;采用定时器会提高我们的效率。下面对定时器的使用进行简单说明 1、应用说明 首先我们要创建一个Timer类 Timer timer new Timer(); 然后在timer中调用schedule()方法添加任务 timer.…

redis运维(十三) hash哈希

一 哈希 ① 定义 hash&#xff1a; 散列说明&#xff1a;key对应是值是键值对[python中的字典],其中键在redis中叫field.形如&#xff1a;value[{field1,value1},...{fieldN,valueN}],值本身又是一种键值对结构 ② 优点和缺点 wzj_height 180wzj_age 18等价 -->…

Confluence Server Webwork 预身份验证 OGNL 注入 (CVE-2021-26084)

漏洞描述 Confluence 是由澳大利亚软件公司 Atlassian 开发的基于 Web 的企业 wiki。 存在一个 OGNL 注入漏洞&#xff0c;允许未经身份验证的攻击者在 Confluence Server 或 Data Center 实例上执行任意代码。 漏洞环境及利用 搭建docker环境 Confluence搭建见前文 Atlas…

高效聚合 | AIRIOT智慧虚拟电厂管理解决方案

传统的电力供应模式主要依靠大型发电厂和电网进行能源传输和分配&#xff0c;但这种模式会导致能源浪费、环境污染等问题&#xff0c;往往存在如下的运维问题和管理痛点&#xff1a; 资源整合能力差&#xff1a;传统电力供应模式无法集成和整合分散的电力资源&#xff0c;包括…