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

news2024/11/17 2:31:25

大家好,我是鱼皮。

几个月前,我自己开发过一个 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.coloradmin.cn/o/1242779.html

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

相关文章

将所有图片居中对齐

Ctrl h 调出替换框 ^g表示所有图片 格式里面选择段落 全部替换

SOLIDWORKS Explorer是什么?

前几天小编在微信上跟人聊天的时候被问到这样的问题&#xff1a; 这个是干什么用的&#xff1f;看着好像没有建模的功能。。。。。 当时我的内心是这样的 。。。。。。。抱歉&#xff0c;是没做好普及工作的小编的锅。。。。。。这个就不是用来建模用的&#xff0c;通常只有…

获取ip属地(ip2region本地离线包-超简单)

背景 最近有涉及要显示ip属地&#xff0c;但我想白嫖&#xff0c;结果就是白嫖的api接口太慢了&#xff0c;要延迟3到4秒左右&#xff0c;很影响体验&#xff0c;而且不一定稳定。 结果突然看到了这个【ip2region】开源项目&#xff0c;离线识别ip属地&#xff0c;精度自己测…

Excel计算索蒂诺比率

索蒂诺的计算方法如下&#xff1a; 索蒂诺 年化收益率 − 无风险收益率 年化下行标准差 索蒂诺 \frac{年化收益率-无风险收益率}{年化下行标准差} 索蒂诺年化下行标准差年化收益率−无风险收益率​ 其中下行标准差是指&#xff1a;小于均值的数据&#xff0c;构成的序列的标…

S71200通过PROFINET协议和岛电数字控制器通讯

项目要求 西门子S71200PLC需要通过PROFINET协议和岛电数字控制器&#xff08;型号&#xff1a;SRS13A&#xff09;通讯&#xff0c;读取温度的测量值PV和设定值SV。 项目实施 采用NET90-PN-MBT&#xff08;以下简称“网关”&#xff09;&#xff0c;它是一款将Modbus TCP/RT…

TP5制作图片压缩包

目标:将多张图片制成在一个压缩包内,供调取使用 public function test() {//引入压缩包类$zip new \ZipArchive();//新定义一个zip包$zipname ROOT_PATH./public/zip/.date("YmdHis").rand(111,999)..zip;if ($zip->open($zipname, \ZipArchive::CREATE) true…

基于Vue+SpringBoot的APK检测管理系统

项目编号&#xff1a; S 038 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S038&#xff0c;文末获取源码。} 项目编号&#xff1a;S038&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 开放平台模块2.3 软…

外设——CAN总线收发器TJA1043

目录 1. 引脚 2. 工作模式 3. 5种模式和7种状态标识的理解和使用 1. 引脚 2. 工作模式 该收发器相较于普通收发器&#xff0c;引脚多了几个&#xff0c;就是功能等多了。TJA1043支持五种操作模式&#xff0c;就是通过控制引脚STB_N和EN来原则。五种模式&#xff1a; 正常模式…

Raptor安装

Raptor官网:https://raptor.martincarlisle.com/ 进入官网后&#xff0c;下拉找到 Download RAPTOR&#xff0c;windows系统的选择Windows Users 下载完成后打开&#xff0c;选择“next” 修改一下路径&#xff0c;不要放到C: 继续next 完结撒花

2023亚太杯数学建模C题思路代码 - 我国新能源电动汽车的发展趋势

1 赛题 问题C 我国新能源电动汽车的发展趋势 新能源汽车是指以先进技术原理、新技术、新结构的非常规汽车燃料为动力来源( 非常规汽车燃料指汽油、柴油以外的燃料&#xff09;&#xff0c;将先进技术进行汽车动力控制和驱动相结 合的汽车。新能源汽车主要包括四种类型&#x…

Redis-Day1基础篇(初识Redis, Redis常见命令, Redis的Java客户端)

Redis-Day1基础篇 初识Redis认识NoSQL认识Redis安装Redis启动RedisRedis客户端 Redis命令数据结构介绍通用命令操作命令StringHashListSetSortedSet Redis的Java客户端客户端对比Jedis客户端Jedis快速入门Jedis连接池 SpringDataRedis客户端SpringDataRedis概述SpringDataRedis…

CS2的到来会对csgo产生什么影响?

从左手持枪到教练观战位&#xff0c;周四更新的CS新版本缺乏CSGO里很多关键功能。社区服务器和创意工坊地图&#xff0c;目前最重要的功能缺失是创意工坊地图和社区服务器。这些社区制作的地图长期以来一直是玩家磨练技能的首选场所&#xff0c;从死斗服务器到用来练习瞄准、跑…

使用Pytorch从零开始构建LSTM

长短期记忆&#xff08;LSTM&#xff09;网络已被广泛用于解决各种顺序任务。让我们了解这些网络如何工作以及如何实施它们。 就像我们一样&#xff0c;循环神经网络&#xff08;RNN&#xff09;也可能很健忘。这种与短期记忆的斗争导致 RNN 在大多数任务中失去有效性。不过&a…

Java Web 学习之路(1) —— 前端篇

文章目录 前言1. JS1.1 引入方式1.2 基础语法1.3 函数1.4 对象1.5 事件监听 2. Vue3. Ajax4. Element5. Nginx 前言 在学习后端前&#xff0c;还需要大致了解下前端的一些知识&#xff0c;所以本篇就先快速把前端的一些知识过一遍。本篇不含过多干货和技术知识&#xff0c;仅仅…

13年测试老鸟,APP性能测试-响应时间与指标总结整理...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、性能指标在性能…

zerotier + rclone 异地同步minio文件

zerotier rclone 异地同步minio文件 场景说明解决方案部署zerotier私有化服务docker部署zerotierzerotier客户端下载加入虚拟网络web控制台设置测试网络连通性 使用rclone同步minio数据解压后文件结构使用cmd配置rclone本地minio配置远程minio配置 查看配置 同步文件 场景说明…

java:CommandLineRunner命令行操作

背景 CommandLineRunner是一个SpringBoot提供的接口&#xff0c;这个接口可以让我们在SpringBoot启动之后&#xff0c;执行一些特定的命令行操作。 实现CommandLineRunner接口后&#xff0c;SpringBoot在启动的时候会自动执行run方法。通常&#xff0c;我们可以在run方法中进…

【计算思维题】少儿编程 蓝桥杯省赛考试计算思维真题 中小学生计算思维真题详细解析第12套

中小学生蓝桥杯计算思维题真题解析第12套 1、机器人可以向上、下、左、右移动,每步移动一个格我们把机器人移动到某一格子的最短步数,叫做格子与机器人的距离。在下图中,与机器人的距离不超过3的所有格子中,一共有多少个“X”标志? A、6 B、7 C、8 D、9 答案:C 考点…

设计高手的秘密武器:5款让平面作品更出彩的软件

平面设计是一种迷人而多样化的艺术形式&#xff0c;它结合了颜色、形状、排版和创造力&#xff0c;通过图像和文本传达信息。市场上有各种各样的平面设计软件&#xff0c;选择合适的设计软件是成为优秀设计师的重要一步。为了降低软件成本&#xff0c;大多数设计师会优先使用免…

Windows如何使用key登录Linux服务器

场景&#xff1a;因为需要回收root管理员权限&#xff0c;禁止root用户远程登录&#xff0c;办公环境只允许普通用户远程登录&#xff0c;且不允许使用密码登录。 一、生成与配置ssh-key 1.使用root管理员权限登录到目标系统。 2.创建一个新的普通用户&#xff0c;和设置密码用…