使用 LangChain 和 Elasticsearch 的隐私优先 AI 搜索

news2024/11/22 13:54:31

作者:Dave Erickson

在过去的几个周末里,我一直在 “即时工程” 的迷人世界中度过,并了解像 Elasticsearch® 这样的矢量数据库如何通过充当长期记忆和语义知识存储来增强像 ChatGPT 这样的大型语言模型 (LLM)。 然而,让我和许多其他经验丰富的数据架构师感到困扰的一件事是,那里的许多教程和演示完全依赖于向大型网络公司和基于云的人工智能公司发送您的私人数据。

私人数据有多种形式,并且出于多种原因受到保护。 对于初创公司和企业来说,他们都知道他们的私人数据有时是他们的竞争优势。 内部数据和客户数据通常包含个人身份信息,如果不加以保护,这些信息会在法律和现实世界中对人类造成后果。 在可观察性和安全领域,缺乏谨慎使用第三方服务可能是数据泄露的根源。 我们甚至听说过与使用 AI 聊天工具有关的网络安全漏洞指控。

没有任何设计是无风险或完全私密的,即使是与像 Elastic 这样对隐私和安全做出坚定承诺或在真正空气隔离(air gap)中进行部署的公司合作时也是如此。 但是,我处理过足够多的敏感数据用例,知道使用隐私优先的方法启用 AI 搜索具有非常实际的价值。 我喜欢我的同事 Jeff Vestal 关于将 OpenAI 工具与 Elasticsearch 结合使用的出色演练,但本文将采用不同的方法。

我对这个项目的方法有两个目标:

  • 私有  —— 当我说私有时,我是认真的。 虽然我将使用云托管的 Elasticsearch,但如果用例需要它,我希望它能够空气隔离(air-gapped)完全地工作。 让我们证明我们可以在不将我们的私人知识发送给第三方的情况下让人工智能搜索工作。
  • 乐趣 —— 另外,让我们在做的时候找点乐子。 我们将使用 Wookieepedia 的一部分,这是一个在数据科学练习中很受欢迎的社区星球大战维基百科,并制作一个私人 AI 琐事助手。 我写这篇文章时已接近 5 月 4 日,虽然在这篇文章发表时我们已经过了那个日期,但我的粉丝是全年无休的。

跟随并亲自尝试的最简单方法是在 Elastic Cloud 上启动一个 Elasticsearch 实例并运行提供的 Python notebook,这将在小规模上实施该项目。 如果你想运行包含 180K 段星球大战知识的完整 Wookieepedia 抓取并创建精通星球大战知识搜索,你可以在此处遵循 GitHub 存储库中的代码。

全部完成后,它应该如下所示:

本着开放的精神,让我们引入两项开源技术来帮助 Elasticsearch:Hugging Face transformers 库和新的有趣的 Python 库 LangChain,这将加快 Elasticsearch 作为矢量数据库的工作速度。 作为奖励,LangChain 将使我们的 LLM 在设置后以编程方式可互换,这样我们就可以自由地试验各种模型。

它将如何运作

LangChian 是什么? LangChain 是一个 Python 和 JavaScript 框架,用于开发由大型语言模型提供支持的应用程序。 LangChain 将与 OpenAI 的 API 一起工作,但它也擅长抽象出数据库和人工智能工具之间的差异。

就其本身而言,ChatGPT 在星球大战琐事方面并不差。 然而,它的训练数据集已经有好几年了,我们需要有关星球大战宇宙中最新电视节目和事件的答案。 还要记住,我们假装这些数据太私密,无法与云中的大型 LLM 共享。 我们可以用更新的数据自己调整一个大型语言模型,但有一种更简单的方法可以做到这一点,它还允许我们始终使用最新的可用数据。

今天让我们引入一个更小且易于自托管的 LLM。 我用谷歌的 flan-t5-large 模型得到了很好的结果,它弥补了它缺乏训练的能力,它具有很好的从注入的上下文中解析出答案的能力。 我们将使用语义搜索来检索我们的私人知识,然后将该上下文与问题一起注入我们的私人 LLM。

1)从 Wookieepedia 中抓取所有经典文章,将数据放入暂存的 Python Pickle 文件中。

2A)使用 LangChain 的内置 Vectorstore 库将这些文章的每一段加载到 Elasticsearch 中。

2B)或者,我们可以将 LangChain 与在 Elasticsearch 本身中托管 pytorch 转换器的新方法进行比较。 我们会将文本嵌入模型部署到 Elasticsearch 以利用分布式计算并加快该过程。

3)当有问题出现时,我们会使用 Elasticsearch 的向量搜索找到与问题语义最相似的段落。 然后,我们将把该段落添加到一个小型本地 LLM 的提示中作为问题的上下文,然后将其留给生成 AI 的魔力,以获得对我们的琐事问题的简短回答。

设置 Python 和 Elasticsearch 环境

确保你的机器上有 Python 3.9 或类似版本。 我使用 3.9 是为了更容易与 GPU 加速库兼容,但这对于这个项目来说不是必需的。 任何最新的 3.X 版本的 Python 都可以使用。

python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install beautifulsoup4 eland elasticsearch huggingface-hub langchain tqdm torch requests sentence_transformers

如果你已经下载了示例代码,你可以直接使用以下 pip install 命令提取我使用的代码的确切版本。

pip install -r requirements.txt

你可以按照此处的说明设置 Elasticsearch 集群。 免费云试用是最简单的入门方式。

在文件夹中创建一个 .env 文件并加载 Elasticsearch 的连接详细信息。

export ES_SERVER="YOURDESSERVERNAME.es.us-central1.gcp.cloud.es.io"
export ES_USERNAME="YOUR READ WRITE AND INDEX CREATING USER"
export ES_PASSWORD="YOUR PASSWORD"

步骤 1. 抓取数据

代码仓库在 Dataset/starwars_small_sample_data.pickle 中有一个小数据集。 如果你可以在小范围内工作,则可以跳过此步骤。

抓取代码改编自 Dennis Bakhuis 出色的数据科学博客和项目 - 看看吧! 他只拉取每篇文章的第一段,我改代码全部拉取。 他可能需要将数据保持在适合主内存的大小,但我们没有这个问题,因为我们有 Elasticsearch,这将使它能够很好地扩展到 PB 范围。

你也可以非常轻松地在此处插入你自己的私有数据源。 LangChain 有一些优秀的实用程序库,可以将你的文本数据拆分成更短的块。

抓取不是本文的重点,所以如果你想自己小规模运行,请查看 Python notebook,或者下载源代码并像这样运行:

source .env
python3 step-1A-scrape-urls.py
python3 step-1B-scrape-content.py

完成后,你应该能够像这样浏览保存的 Pickle 文件以确保它有效。

from pathlib import Path
import pickle


bookFilePath = "starwars_*_data*.pickle"
files = sorted(Path('./Dataset').glob(bookFilePath))
for fn in files:
   with open(fn,'rb') as f:
       part = pickle.load(f)
       for key, value in part.items():
           title = value['title'].strip()
           print(title)

如果你跳过网络抓取,只需将 bookFilePath 更改为 “starwars_small_sample_data.pickle” 即可使用我包含在 GitHub 存储库中的示例。

步骤 2A. 在 Elasticsearch 中加载嵌入

完整的代码展示了我是如何仅使用 LangChain 来做到这一点的。 代码的关键部分是像上面的例子一样循环遍历保存的 Pickle 文件并提取出作为段落的字符串列表,然后将它们交给 LangChain Vectorstorefrom_texts() 函数。

from langchain.vectorstores import ElasticVectorSearch
from langchain.embeddings import HuggingFaceEmbeddings
from pathlib import Path
import pickle
import os
from tqdm import tqdm


model_name = "sentence-transformers/all-mpnet-base-v2"
hf = HuggingFaceEmbeddings(model_name=model_name)


index_name = "book_wookieepedia_mpnet"
endpoint = os.getenv('ES_SERVER', 'ERROR')
username = os.getenv('ES_USERNAME', 'ERROR')
password = os.getenv('ES_PASSWORD', 'ERROR')
url = f"https://{username}:{password}@{endpoint}:443"
db = ElasticVectorSearch(embedding=hf, elasticsearch_url=url, index_name=index_name)


batchtext = []
bookFilePath = "starwars_*_data*.pickle"
files = sorted(Path('./Dataset').glob(bookFilePath))
for fn in files:
    with open(fn,'rb') as f:
       part = pickle.load(f)
       for ix, (key, value) in tqdm(enumerate(part.items()), total=len(part)):
           paragraphs = value['paragraph']
           for p in paragraphs:
               batchtext.append(p)
       db.from_texts(batchtext,
                     embedding=hf,
                     elasticsearch_url=url,
                     index_name=index_name)

步骤 2B. 使用托管训练模型节省时间和金钱

我发现在我的旧 Intel Macbook 上,创建嵌入需要很多小时的处理时间。 我很友善 —— 看起来好几天了。 我认为我可以使用 Elastic 托管服务的动态可扩展机器学习 (ML) 节点更快地完成这件事,而且花费更少。 免费试用集群不会让你扩展该层,因此此步骤对某些人来说可能比对其他人更有意义。

最终结果:这种方法在 Elastic Cloud 中运行成本为 5 美元/小时的节点上花费了 40 分钟,这比我在本地可以做的要快得多,并且与 OpenAI 当前的 token 收费处理嵌入的成本相当。 高效地执行此操作是一个更大的主题,但我对在 Elastic Cloud 中运行并行推理管道的速度如此之快印象深刻,而无需学习新技能或将我的数据交给非私有 API。

对于这一步,我们将把嵌入生成卸载到 Elasticsearch 集群本身,它可以托管嵌入模型并以分布式方式嵌入文本段落。 为此,我们必须加载数据并使用摄取管道来确保最终形式与 LangChain 使用的索引映射相匹配。 在 Kibana 的开发工具中运行以下 REST 命令:

PUT /book_wookieepedia_mpnet
{
 "settings": {
   "number_of_shards": 4
 },
 "mappings": {
   "properties": {
     "metadata": {
       "type": "object"
     },
     "text": {
       "type": "text"
     },
     "vector": {
       "type": "dense_vector",
       "dims": 768
     }
   }
 }
}

接下来,我们将使用 eland Python 库将嵌入模型上传到 Elasticsearch。

source .env
python3 step-3A-upload-model.py

接下来让我们转到 Elastic Cloud 控制台并将我们的 ML 层扩展到总共 64 个 vCPU(是我当前笔记本电脑的 8 倍)。

现在,在 Kibana 中,我们将部署经过训练的 ML 模型。 在规模上,性能测试表明,用户应该从每个模型分配 1 个线程开始,并增加分配数量以提高吞吐量。 可以在此处找到文档和指南。 我进行了实验,对于这个较小的集合,我得到了 32 个实例的最佳结果,每个实例有 2 个线程。 要进行设置,请转到 Stack Management > 机器学习。 使用 Synchronized saved objects 功能让 Kibana 看到我们使用 Python 代码推送到 Elasticsearch 的模型。 然后在单击它时出现的菜单中部署该模型。

现在让我们再次使用 Dev Tools 创建一个新的索引和摄取管道来处理文档中的文本段落,将结果放入一个称为 “vector” 的密集矢量字段中,并将该段落复制到预期的 “text” 字段中。

PUT /book_wookieepedia_mpnet
{
 "settings": {
   "number_of_shards": 4
 },
 "mappings": {
   "properties": {
     "metadata": {
       "type": "object"
     },
     "text": {
       "type": "text"
     },
     "vector": {
       "type": "dense_vector",
       "dims": 768
     }
   }
 }
}


PUT _ingest/pipeline/sw-embeddings
{
 "description": "Text embedding pipeline",
 "processors": [
   {
     "inference": {
       "model_id": "sentence-transformers__all-mpnet-base-v2",
       "target_field": "text_embedding",
       "field_map": {
         "text": "text_field"
       }
     }
   },
   {
     "set":{
       "field": "vector",
       "copy_from": "text_embedding.predicted_value"
     }
   },
   {
     "remove": {
       "field": "text_embedding"
     }
   }
 ],
 "on_failure": [
   {
     "set": {
       "description": "Index document to 'failed-<index>'",
       "field": "_index",
       "value": "failed-{{{_index}}}"
     }
   },
   {
     "set": {
       "description": "Set error message",
       "field": "ingest.failure",
       "value": "{{_ingest.on_failure_message}}"
     }
   }
 ]
}

测试管道以确保其正常工作。

POST _ingest/pipeline/sw-embeddings/_simulate
{
 "docs": [
   {
     "_source": {
       "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
       "metadata": {
         "a": "b"
       }
     }
   }
 ]
}

现在我们已准备好使用用于 Elasticsearch 的普通 Python 库批量加载数据,目标是我们的摄取管道以正确创建向量嵌入并转换我们的数据以符合 LangChain 的期望。

source .env
python3 step-3B-batch-hosted-vectorize.py

成功! 数据在 OpenAI 方面约为 1300 万个 tokens,因此在非私有和云中处理此数据大约需要 5.40 美元。 使用 Elastic Cloud,花费 5 美元/小时的机器需要 40 分钟。

加载数据后,请记住使用云控制台将你的 Cloud ML 缩小到零或更合理的值。

第 3 步。在星球大战问答中获胜

接下来我们来玩一下 LLM 和 LangChain。 我创建了一个库文件 lib_llm.py 来保存这段代码。

from langchain import PromptTemplate, HuggingFaceHub, LLMChain
from langchain.llms import HuggingFacePipeline
from transformers import AutoTokenizer, pipeline, AutoModelForSeq2SeqLM
from langchain.vectorstores import ElasticVectorSearch
from langchain.embeddings import HuggingFaceEmbeddings
import os


cache_dir = "./cache"
def getFlanLarge():
  
   model_id = 'google/flan-t5-large'
   print(f">> Prep. Get {model_id} ready to go")
   tokenizer = AutoTokenizer.from_pretrained(model_id)
   model = AutoModelForSeq2SeqLM.from_pretrained(model_id, cache_dir=cache_dir)
  
   pipe = pipeline(
       "text2text-generation",
       model=model,
       tokenizer=tokenizer,
       max_length=100
   )
   llm = HuggingFacePipeline(pipeline=pipe)
   return llm


local_llm = getFlanLarge()


def make_the_llm():
   template_informed = """
   I am a helpful AI that answers questions.
   When I don't know the answer I say I don't know.
   I know context: {context}
   when asked: {question}
   my response using only information in the context is: """
   prompt_informed = PromptTemplate(
       template=template_informed,
       input_variables=["context", "question"])
   return LLMChain(prompt=prompt_informed, llm=local_llm)


## continued below

template_informed 是关键但也很容易理解的部分。 我们所做的只是格式化一个提示模板,它将采用我们的两个参数:上下文和用户的问题。

从上面继续这个最终的主要代码,它看起来像下面这样:

## continued from above


topic = "Star Wars"
index_name = "book_wookieepedia_mpnet"


# Create the HuggingFace Transformer like before
model_name = "sentence-transformers/all-mpnet-base-v2"
hf = HuggingFaceEmbeddings(model_name=model_name)


## Elasticsearch as a vector db, just like before
endpoint = os.getenv('ES_SERVER', 'ERROR')
username = os.getenv('ES_USERNAME', 'ERROR')
password = os.getenv('ES_PASSWORD', 'ERROR')
url = f"https://{username}:{password}@{endpoint}:443"
db = ElasticVectorSearch(embedding=hf, elasticsearch_url=url, index_name=index_name)


## set up the conversational LLM
llm_chain_informed= make_the_llm()


def ask_a_question(question):
   ## get the relevant chunk from Elasticsearch for a question
   similar_docs = db.similarity_search(question)
   print(f'The most relevant passage: \n\t{similar_docs[0].page_content}')
   informed_context= similar_docs[0].page_content
   informed_response = llm_chain_informed.run(
       context=informed_context,
       question=question)
   return informed_response




# The conversational loop
print(f'I am a trivia chat bot, ask me any question about {topic}')
while True:
   command = input("User Question >> ")
   response= ask_a_question(command)
   print(f"\tAnswer  : {response}")

结论

因此,通过一些数据争论,我们现在已经使用了 AI,而没有将我们的数据暴露给第三方托管的 LLM。 AI 世界瞬息万变,但保护私人数据的安全和控制是我们所有人都应该认真对待的事情,以应对数据泄露带来的监管、财务和人员后果。 这不太可能改变。 我们与使用搜索来调查欺诈、保卫国家并改善弱势患者群体结果的客户合作。 隐私很重要。 要了解有关如何在这些空间中使用 Elastic 的更多信息,请查看:

  • Elastic 公共部门
  • Elastic 金融服务

你有没有像我一样爱上 LangChain? 正如一位睿智的老绝地武士曾经说过的那样:“那很好。 你已经迈出了迈向更大世界的第一步。” 从这里有很多方向。 LangChain 消除了使用 AI 提示工程的复杂性。 我知道 Elasticsearch 在这里可以扮演许多其他角色,比如生成式 AI 的长期记忆,所以我很高兴看到这个快速变化的空间会产生什么。

在这篇博文中,我们可能使用了由其各自所有者拥有和运营的第三方生成人工智能工具。 Elastic 对第三方工具没有任何控制权,我们对其内容、操作或使用不承担任何责任,也不对您使用此类工具可能产生的任何损失或损害承担任何责任。 使用带有个人、敏感或机密信息的 AI 工具时请谨慎行事。 你提交的任何数据都可能用于人工智能训练或其他目的。 无法保证你提供的信息将得到安全保护或保密。 在使用之前,你应该熟悉任何生成人工智能工具的隐私惯例和使用条款。

Elastic、Elasticsearch 和相关标志是 Elasticsearch N.V. 在美国和其他国家/地区的商标、徽标或注册商标。 所有其他公司和产品名称均为其各自所有者的商标、徽标或注册商标。

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

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

相关文章

波奇学STL:String入门和迭代器

目录 ​编辑 Constructor/Destructor/Operator Constructor:构造函数 Iterator:迭代器 begin()/end():迭代器像指针一样访问问函数 个人对迭代器的理解 rbegin()/rend():迭代器反向移动 除了用迭代器访问元素外string类还可以[]下标 Capacity:容量&#xff1f; s.siz…

Hystrix入门使用 服务熔断 服务降级 服务雪崩

一、概念 hystrix停止更新&#xff0c;理念优秀。 分布式系统面临的问题: 对于复杂的分布式体系&#xff0c;有数十个依赖&#xff0c;依赖不可避免的错误。 服务会出现雪崩&#xff0c;高可用受到破坏。 Hystrix就是用于解决分布式系统延迟和容错的开源库。 保证在一个依赖出…

Python五彩气球

文章目录 前言Turtle基础1.1 Turtle画板1.2 Turtle画笔1.3 Turtle画图1.4 Turtle填色1.5 Turtle写字 五彩气球气球类漂浮函数气球函数六一祝福 尾声 前言 六一要来啦&#xff0c;快来领取博主精心准备的五彩气球吧&#xff01; Turtle基础 小海龟(Turtle)是Python中画图的一…

SpringBatch历史数据的清理方案及实现

SpringBatch历史数据的清理方案及实现 需求背景 SpringBatch的程序已经运行了将近一年&#xff0c;数据量已经达到了一定的数据量级别。 对SpringBatch历史数据的清理也被提上日程。 但是SpringBatch的代码中似乎没有找到清理历史数据的代码&#xff0c;在官方文档中也没有…

一、STM32程序下载软件_FlyMCU

1、软件简介 (1)FlyMCU是一款STM32下载程序的软件。 (2)FlyMCU采用ISP下载方式。 (3)ISP&#xff1a;在线系统编程。 (4)FlyMCU支持STM32F1、STM32F2、STM32F4系列&#xff0c;其他暂不支持&#xff0c;后续应该也不会更新了。 (5)STM32芯片的ISP下载&#xff0c;只能使用…

LINUX系统编程-----中

文章目录 进程间的通信管道popen 和 pclosepipeFIFO 共享内存system V 版本的共享内存创建/获取共享内存 共享内存涉及的函数共享内存的通信两个进程同时对共享内存进行读写 信号量使用信号量保护共享资源消息队列死锁 信号内核不可中断状态 进程间的通信 管道 在操作系统中&…

【备战秋招】每日一题:4月1日美团春招(二批)第三题:题面+题目思路 + C++/python/js/Go/java带注释

2023大厂笔试模拟练习网站&#xff08;含题解&#xff09; www.codefun2000.com 最近我们一直在将收集到的各种大厂笔试的解题思路还原成题目并制作数据&#xff0c;挂载到我们的OJ上&#xff0c;供大家学习交流&#xff0c;体会笔试难度。现已录入200道互联网大厂模拟练习题&…

Electron简单开发

文章目录 1.参考网站2.HelloWold编写2.1新建空文件夹2.2node初始化2.3安装electron依赖2.4添加.gitignore 文件2.5创建main.js文件和index.html2.6运行electron应用 3.打包 接到一个任务&#xff0c;将electron集成到solidworks中&#xff0c;所以记录一下electron的简单操作&a…

【操作系统】05.文件管理

文件管理 文件的属性 文件内部数据的组织 文件之间的组织 操作系统向上层提供功能 创建文件 删除文件 打开文件 关闭文件 读文件 写文件 文件的逻辑结构 无结构文件 有结构文件 顺序文件 文件的物理结构 磁盘块&#xff08;文件块&#xff09; 连续分配 优点 对于机…

操作系统 四、文件管理

文章目录 4.1 文件的逻辑结构4.2 文件目录4.2.1 目录结构4.2.1.1 单级目录结构4.2.1.2 两级目录结构4.2.1.3 多级目录结构4.2.1.4 无环图目录结构 4.2.2 索引结点(FCB的改进) 4.3 文件的物理结构4.3.1 连续分配4.3.2 链接分配4.3.2.1 隐式链接4.3.2.2 显式链接 4.3.3 索引分配 …

稠密点云获取方法(二)

作为高分辨率三维重建的方法之一,从单张图像生成稠密三维点云在计算机视觉领域中一直有着较高的关注度。 以下文献提出了一种针对二维和三维信息融合的方法以解决三维点云稀疏难以检测远处的目标的问题。 Multimodal Virtual Point 3D Detection 该文献提出一种将 RGB 传感器…

【Mysql】| 超详细常见bug及解决方案

目录 一. &#x1f31f; 引入话题二. &#x1f31f; 引出bug1.1 查看bug1.2 Problem Solving2.1 查看bug2.2 Problem Solving3.1 字段长度异常3.2 Problem Solving 三. &#x1f31f; 最后 一. &#x1f31f; 引入话题 MySQL是一款广泛使用的开源数据库管理系统&#xff0c;它…

小白了解Docker容器技术

一、什么是Docker&#x1f451; 有一个最常见的例子来很好的帮我们简单了解Docker容器技术&#xff1a; 当我们在一台计算机中配置好了环境&#xff0c;花费了极大的时间和精力成功开发部署好了一个应用。准备尝试在不同操作系统、不同环境下部署这个应用时&#xff0c;我们需要…

图及其与图相关的算法

⭐️前言⭐️ 本篇文章主要介绍图及其与图相关的算法 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持续更新学习记录收获&#xff0c;友友们有任何问题可以在评论区留言 &#x1f349;博客中涉及源码及博主…

如何在 Rocky Linux 上检查磁盘空间?

在 Rocky Linux 上检查磁盘空间是系统管理和维护的重要任务之一。磁盘空间的监控和管理可以帮助我们及时发现和解决存储空间不足的问题&#xff0c;以确保系统的正常运行。本文将详细介绍在 Rocky Linux 上检查磁盘空间的方法。 方法 1&#xff1a;使用 df 命令 df 命令是 Li…

SOLIDWORKS技巧大全培训教程

1 您可以使用 CTRLTAB 键循环进入在 SolidWorks 中打开的文件。 2 使用方向键可以旋转模型。按 CTRL 键加上方向键可以移动模型。按 ALT 键加上方向键可以将模型沿顺时针或逆时1 您可以使用 CTRLTAB 键循环进入在 SolidWorks 中打开的文件。 2 使用方向键可以旋转模型。按 CTRL…

【CloudCompare教程】012:基于点云数据的测量功能

本文讲解CloudCompare基于点云数据的测量功能,主要有:点云索引、坐标、距离、角度、面积、标签等。 文章目录 一、加载地形点云数据二、基于点云数据的测量功能1. 选择单点并显示信息2. 选择两点并显示分割信息3. 选择三点并显示相关三角形信息4. 定义矩形2D标签5. 保存当前标…

Milvus向量数据库

Milvus vector database 第一章 Milvus概述 Milvus创建于2019年&#xff0c;唯一的目标是&#xff1a;存储、索引和管理由深度神经网络和其他机器学习(ML)模型生成的大量嵌入向量embedding vectors。 存储对象&#xff1a;向量 NOTE&#xff1a;embedding vectors是对非结构…

c#快速入门(下)

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析2 目录 &#x1f449;&#x1f3fb;Inline和lambda委托和lambda &#x1f449;&#x1f…

上海斯歌荣获中国低代码/零代码行业“卓越影响力厂商奖”

3月19日&#xff0c;在「第三届中国 ISIG 产业智能大会」隆重的颁奖典礼上&#xff0c;上海斯歌被授予“卓越影响力厂商奖”&#xff0c;并入围国内权威咨询机构LowCode低码时代的《2022年中国低代码&零代码行业研究报告》卓越影响力榜单。 「第三届ISIG中国产业智能大会」…