【LLM大模型】开发基于云的RAG应用,使用开源 LLM

news2024/11/15 20:02:48

检索增强生成 (RAG)通常用于开发定制的 AI 应用程序,包括 聊天机器人、推荐系统和其他个性化工具。该系统利用向量数据库和 大型语言模型 (LLM)的优势来提供高质量的结果。

为任何 RAG 模型选择合适的 LLM 非常重要,需要考虑成本、隐私问题和可扩展性等因素。OpenAI 的 GPT-4和 Google 的Gemini等商业 LLM 非常有效,但可能很昂贵并引发数据隐私问题。一些用户更喜欢 开源 LLM,因为它们灵活且节省成本,但它们需要大量资源进行 微调 和部署,包括 GPU 和专用基础设施。此外,使用本地设置管理模型更新和可扩展性可能具有挑战性。

更好的解决方案是选择一个 开源 LLM 并将其部署在 云 上。这种方法提供了必要的计算能力和可扩展性,而无需本地托管的高成本和复杂性。它不仅节省了初始基础设施成本,而且还最大限度地减少了维护问题。

让我们探索一种类似的方法来开发使用云托管开源 LLM 和可扩展向量数据库的应用程序。

工具和技术

开发此基于 RAG 的 AI 应用程序需要使用多种工具。这些工具包括:

  • BentoML: BentoML 是一个开源平台,简化了机器学习模型的部署到生产就绪的 API,确保可扩展性和易于管理。
  • LangChain: LangChain 是一个用于使用 LLM 构建应用程序的框架。它提供模块化组件,便于集成和定制。
  • MyScaleDB: MyScaleDB 是一个高性能、可扩展的数据库,针对高效的数据检索和存储进行了优化,支持高级查询功能。

在本教程中,我们将使用 LangChain 的 WikipediaLoader 模块从维基百科中提取数据,并在该数据上构建 LLM。

准备

设置环境

通过打开终端并输入以下内容,开始设置您的环境以在系统中使用 BentoML、MyScaleDB 和 LangChain:

代码语言:javascript

pip install bentoml langchain clickhouse-connect

这将在您的系统中安装所有三个软件包。之后,您就可以编写代码并开发 RAG 应用程序了。

加载数据

首先从 langchain_community.document_loaders.wikipedia 模块导入 WikipediaLoader。您将使用此加载器来获取与 “阿尔伯特·爱因斯坦”相关的维基百科文档。

代码语言:javascript

from langchain_community.document_loaders.wikipedia import WikipediaLoader
loader = WikipediaLoader(query="Albert Einstein")

# Load the documents
docs = loader.load()

# Display the content of the first document
print(docs[0].page_content)

这使用 load 方法检索“阿尔伯特·爱因斯坦”文档,并使用 print 方法打印第一个文档的内容以验证加载的数据。

将文本拆分为块

导入来自 CharacterTextSplitter langchain_text_splitters,将所有页面的内容合并到一个字符串中,然后将文本拆分为可管理的块。

代码语言:javascript

from langchain_text_splitters import CharacterTextSplitter
# Split the text into chunks
text = ' '.join([page.page_content.replace('\t', ' ') for page in docs])
text_splitter = CharacterTextSplitter(
   separator="\n",
   chunk_size=400,
   chunk_overlap=100,
   length_function=len,
   is_separator_regex=False,
)
texts = text_splitter.create_documents([text])
splits = [item.page_content for item in texts]

CharacterTextSplitter 配置为将此文本拆分为 400 个字符的块,重叠 100 个字符,以确保块之间不会丢失任何信息。page_content 或文本存储在 splits 数组中,该数组仅包含文本内容。您将使用 splits 数组来获取 嵌入。

在 BentoML 上部署模型

… 您的数据已准备就绪,下一步是在 BentoML 上部署模型并在您的 RAG 应用程序中使用它们。首先部署 LLM。您需要一个免费的 BentoML 帐户,如果您需要,可以 在 BentoCloud 上注册一个。接下来,导航到 部署 部分,然后单击右上角的 创建部署 按钮。将打开一个新页面,如下所示:

BentoML 部署页面

BentoML 部署页面

BentoML 部署页面

从下拉菜单中选择 bentoml/bentovllm-llama3-8b-instruct-service 模型,然后单击右下角的“提交”。这将开始部署模型。将打开一个新的页面,如下所示:

LLM 配置页面

LLM 配置页面

LLM 配置页面

部署可能需要一些时间。部署完成后,复制端点。

注意:BentoML 的免费层级只允许部署单个模型。如果您有付费计划并且可以部署多个模型,请按照以下步骤操作。如果没有,不用担心 - 我们将在本地使用开源模型进行嵌入。

部署嵌入模型与您部署 LLM 所采取的步骤非常相似:

  1. 转到 部署 页面。
  2. 点击 创建部署 按钮。
  3. 选择 sentence-transformers 模型,然后单击 提交
  4. 部署完成后,复制端点。

接下来,转到 API 令牌页面 并生成一个新的 API 密钥。现在您已准备好将部署的模型用于您的 RAG 应用程序。

定义嵌入方法

您将定义一个名为 get_embeddings 的函数来为提供的文本生成嵌入。此函数接受三个参数。如果提供了 BentoML 端点和 API 令牌,则该函数使用 BentoML 的嵌入服务;否则,它使用本地 transformerstorch 库来加载 sentence-transformers/all-MiniLM-L6-v2 模型并生成嵌入。

代码语言:javascript

# Import the libraries
import subprocess
import sys
import numpy as np

# Install the packages if the API key isn't provided
def install(package):
   subprocess.check_call([sys.executable, "-m", "pip", "install", package])

# Define the embedding method
def get_embeddings(texts: list, BENTO_EMBEDDING_MODEL_END_POINT=None, BENTO_API_TOKEN=None) -> list:
   # If the BentoML KEY is provided, the method will use BENTOML model to get embeddings
   if BENTO_EMBEDDING_MODEL_END_POINT and BENTO_API_TOKEN:
       import bentoml
       embedding_client = bentoml.SyncHTTPClient(BENTO_EMBEDDING_MODEL_END_POINT, token=BENTO_API_TOKEN)
       return embedding_client.encode(sentences=texts).tolist()
  
   # Otherwise it'll use transformers library
   else:
       # Install transformers and torch if not already installed
       try:
           import transformers
       except ImportError:
           install("transformers")
       try:
           import torch
       except ImportError:
           install("torch")
      
       from transformers import AutoTokenizer, AutoModel
      
       # Initialize the tokenizer and model for embeddings
       tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
       model = AutoModel.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
      
       inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt", max_length=512)
       with torch.no_grad():
           outputs = model(**inputs)
       embeddings = outputs.last_hidden_state.mean(dim=1)
       return embeddings.numpy().tolist()

此设置允许免费层级 BentoML 用户灵活使用,他们一次只能部署一个模型。如果您有付费版本的 BentoML 并且可以部署两个模型,则可以传递 BentoML 端点和 Bento API 令牌以使用部署的嵌入模型。

获取嵌入

25 的批次迭代文本块 (splits) 以使用上面定义的 get_embeddings 函数生成嵌入。

代码语言:javascript

all_embeddings = []
# Pass the splits in a batch of 25
for i in range(0, len(splits), 25):
   batch = splits[i:i+25]
   # Pass the batch to the get_embeddings method
   embeddings_batch = get_embeddings(batch)
   # Append the embeddings to the all_embeddings list holdng the embeddings of the whole dataset
   all_embeddings.extend(embeddings_batch)

这可以防止一次将过多的数据加载到嵌入模型中,这对于管理内存和计算资源特别有用。

创建数据帧

现在,创建一个 pandas 数据帧来存储文本块及其相应的嵌入。

代码语言:javascript

import pandas as pd
df = pd.DataFrame({
   'page_content': splits,
   'embeddings': all_embeddings
})

这种结构化格式使在 MyScaleDB 中操作和存储数据变得更加容易。

连接到 MyScaleDB

知识库已完成,现在是将数据保存到向量数据库的时候了。此演示使用 MyScaleDB 进行向量存储。通过遵循 快速入门指南 在云环境中启动 MyScaleDB 集群。然后,您可以使用 clickhouse_connect 库建立与 MyScaleDB 数据库的连接。 此处创建的客户端对象将用于执行 SQL 命令并与数据库交互。

代码语言:javascript

import clickhouse_connect
client = clickhouse_connect.get_client(
   host='your-host-name',
   port=443,
   username='your-user-name',
   password='your-password'
)
创建表并插入数据

在 MyScaleDB 中创建一个表来存储文本块和嵌入。表模式包括一个 idpage_contentembeddings

代码语言:javascript

# Create the table named RAG
client.command("""
CREATE TABLE IF NOT EXISTS default.RAG (
   id Int64,
   page_content String,
   embeddings Array(Float32),
   CONSTRAINT check_data_length CHECK length(embeddings) = 384
) ENGINE = MergeTree()
   ORDER BY id
""")

# Insert data into the table
batch_size = 100
num_batches = (len(df) + batch_size - 1) // batch_size

for i in range(num_batches):
   batch_data = df[i * batch_size: (i + 1) * batch_size]
   client.insert('default.RAG', batch_data.values.tolist(), column_names=batch_data.columns.tolist())
   print(f"Batch {i+1}/{num_batches} inserted.")

这确保嵌入具有 384 的固定长度。然后将数据帧中的数据以批次插入表中,以有效地管理大量数据。

创建向量索引

下一步是在 RAG 表中的 embeddings 列中添加向量索引。

代码语言:javascript

client.command("""
ALTER TABLE default.RAG
   ADD VECTOR INDEX vector_index embeddings
   TYPE MSTG
""")

向量索引允许进行有效的相似性搜索,这对于检索增强生成任务至关重要。

检索相关向量

定义一个函数,根据用户查询检索相关文档。查询嵌入是使用 get_embeddings 函数生成的,并且执行高级 SQL 向量查询以在数据库中找到最接近的匹配项。

代码语言:javascript

def get_relevant_docs(user_query, top_k):
   query_embeddings = get_embeddings(user_query)[0]
   results = client.query(f"""
       SELECT page_content,
       distance(embeddings, {query_embeddings}) as dist FROM default.RAG ORDER BY dist LIMIT {top_k}
   """)
   relevant_docs = " "
  
   for row in results.named_results():
       relevant_docs=relevant_docs + row["page_content"]
  
   return relevant_docs

# Example query
message="Who is albert einstein?"
relevant_docs = get_relevant_docs(message, 8)
print(relevant_docs)

结果按距离排序,并返回前 k 个匹配项。此设置找到了给定查询的最相关文档。

注意:distance 方法接受一个嵌入列和用户查询的嵌入向量,通过应用余弦相似度来查找相似的文档。

连接到 BentoML LLM

建立与您在 BentoML 上托管的 LLM 的连接。llm_client 对象将用于与 LLM 交互,以根据检索到的文档生成响应。

代码语言:javascript

import bentoml
BENTO_LLM_END_POINT = "add-your-end-point-here"

llm_client = bentoml.SyncHTTPClient(BENTO_LLM_END_POINT, token="your-token-here")

替换 BENTO_LLM_END_POINT 以及 token 使用您之前在 LLM 部署期间复制的值。

执行 RAG

定义一个执行 RAG 的函数。该函数以用户问题和检索到的上下文作为输入。它为 LLM 构建一个提示,指示它根据提供的上下文回答问题。然后将 LLM 的响应作为答案返回。

代码语言:javascript

def dorag(question: str, context: str):
   # Define the prompt template
   prompt = (f"You are a helpful assistant. The user has a question. Answer the user question based only on the context: {context}. \n"
             f"The user question is {question}")
   # Call the LLM endpoint with the prompt defined above
   results = llm_client.generate(
       max_tokens=1024,
       prompt=prompt,
   )
   res = ""
   for result in results:
       res += result
   return res

进行查询

最后,您可以通过对 RAG 应用程序进行查询来测试它。询问“谁是阿尔伯特·爱因斯坦?”并使用 dorag 函数根据之前检索到的相关文档获取答案。

代码语言:javascript

query = "Who is albert einstein?"
dorag(question=query, context=relevant_docs)

输出提供了对问题的详细响应,证明了 RAG 设置的有效性。

LLM 响应提供了关于阿尔伯特·爱因斯坦的传记信息

LLM 响应提供了关于阿尔伯特·爱因斯坦的传记信息

LLM 响应

如果您询问 RAG 模型关于阿尔伯特·爱因斯坦的死亡,响应应该如下所示:

LLM 响应提供了关于阿尔伯特·爱因斯坦死亡的信息

LLM 响应提供了关于阿尔伯特·爱因斯坦死亡的信息

LLM 响应

结论

BentoML 作为部署机器学习模型(包括 LLM)的出色平台而脱颖而出,无需费心管理资源。使用 BentoML,您可以快速部署和扩展您的 AI 应用程序到云端,确保它们已准备好投入生产并高度可访问。它的简单性和灵活性使其成为开发人员的理想选择,使他们能够更多地专注于创新,而无需过多关注部署复杂性。

另一方面,MyScaleDB 是专门为 RAG 应用程序开发的,提供高性能 SQL 向量数据库。它熟悉的 SQL 语法使开发人员可以轻松地将其集成到他们的应用程序中并使用它,因为学习曲线很小。MyScaleDB 的 多尺度树图 (MSTG) 算法在速度和准确性方面明显优于其他向量数据库。此外,MyScaleDB 为每个新用户提供高达 500 万个向量的免费存储空间,使其成为希望实施高效且可扩展的 AI 解决方案的开发人员的理想选择。

如何系统的去学习大模型LLM ?

作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的 AI大模型资料 包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来

所有资料 ⚡️ ,朋友们如果有需要全套 《LLM大模型入门+进阶学习资源包》,扫码获取~

👉CSDN大礼包🎁:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)👈

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

在这里插入图片描述

四、AI大模型商业化落地方案

img

阶段1:AI大模型时代的基础理解

  • 目标:了解AI大模型的基本概念、发展历程和核心原理。
  • 内容
    • L1.1 人工智能简述与大模型起源
    • L1.2 大模型与通用人工智能
    • L1.3 GPT模型的发展历程
    • L1.4 模型工程
      - L1.4.1 知识大模型
      - L1.4.2 生产大模型
      - L1.4.3 模型工程方法论
      - L1.4.4 模型工程实践
    • L1.5 GPT应用案例

阶段2:AI大模型API应用开发工程

  • 目标:掌握AI大模型API的使用和开发,以及相关的编程技能。
  • 内容
    • L2.1 API接口
      - L2.1.1 OpenAI API接口
      - L2.1.2 Python接口接入
      - L2.1.3 BOT工具类框架
      - L2.1.4 代码示例
    • L2.2 Prompt框架
      - L2.2.1 什么是Prompt
      - L2.2.2 Prompt框架应用现状
      - L2.2.3 基于GPTAS的Prompt框架
      - L2.2.4 Prompt框架与Thought
      - L2.2.5 Prompt框架与提示词
    • L2.3 流水线工程
      - L2.3.1 流水线工程的概念
      - L2.3.2 流水线工程的优点
      - L2.3.3 流水线工程的应用
    • L2.4 总结与展望

阶段3:AI大模型应用架构实践

  • 目标:深入理解AI大模型的应用架构,并能够进行私有化部署。
  • 内容
    • L3.1 Agent模型框架
      - L3.1.1 Agent模型框架的设计理念
      - L3.1.2 Agent模型框架的核心组件
      - L3.1.3 Agent模型框架的实现细节
    • L3.2 MetaGPT
      - L3.2.1 MetaGPT的基本概念
      - L3.2.2 MetaGPT的工作原理
      - L3.2.3 MetaGPT的应用场景
    • L3.3 ChatGLM
      - L3.3.1 ChatGLM的特点
      - L3.3.2 ChatGLM的开发环境
      - L3.3.3 ChatGLM的使用示例
    • L3.4 LLAMA
      - L3.4.1 LLAMA的特点
      - L3.4.2 LLAMA的开发环境
      - L3.4.3 LLAMA的使用示例
    • L3.5 其他大模型介绍

阶段4:AI大模型私有化部署

  • 目标:掌握多种AI大模型的私有化部署,包括多模态和特定领域模型。
  • 内容
    • L4.1 模型私有化部署概述
    • L4.2 模型私有化部署的关键技术
    • L4.3 模型私有化部署的实施步骤
    • L4.4 模型私有化部署的应用场景

学习计划:

  • 阶段1:1-2个月,建立AI大模型的基础知识体系。
  • 阶段2:2-3个月,专注于API应用开发能力的提升。
  • 阶段3:3-4个月,深入实践AI大模型的应用架构和私有化部署。
  • 阶段4:4-5个月,专注于高级模型的应用和部署。
这份完整版的所有 ⚡️ 大模型 LLM 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

全套 《LLM大模型入门+进阶学习资源包↓↓↓ 获取~

👉CSDN大礼包🎁:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)👈

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

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

相关文章

仿写SpringMVC

1.创建简单的注解 1.1 Controller package com.heaboy.annotation;import java.lang.annotation.*;Documented Retention(RetentionPolicy.RUNTIME) Target(ElementType.TYPE) public interface Controller { } 1.2 RequestMapping package com.heaboy.annotation;import …

喜讯|华院钢铁行业大模型入选“2024全国企业新质生产力赋能典型案例”

7月2日,由中国科学院主管、科学出版社主办的商业周刊《互联网周刊》(CIW)联合德本咨询(DBC)、中国社会科学院信息化研究中心(CIS)发布了“2024全国企业新质生产力赋能典型案例”。华院计算技术&…

基于FPGA的千兆以太网设计(1)----大白话解释什么是以太网

1、什么是以太网? 还记得初学以太网的时候,我就被一大堆专业名词给整懵了:什么以太网,互联网,MAC,IP,局域网,万维网,网络分层模型等等等等。慢着!我学的不是以太网吗?怎么出来这么一大堆东西? 啊!以太网究竟是什么?别急,我接下来就尽量用通俗的大白话来给你解释…

香港优才计划多少分获批成功率高?一文看懂各分数段获批情况!

有留意香港优才计划的朋友,应该都了解过,申请优才计划采用打分制,得分多少与最终获批有密不可分的关系。但有一点要提前清楚,申请优才不是得分越高就一定能获批,也不是得分低就一定没希望。 香港优才计划能否获批成功…

将直流电转换为交流电:逆变器的基本原理

什么是逆变器? 大多数电源设计都包括一个称为整流器的部分,该整流器将输入的交流波转换为不稳定的直流电压。但是,我们不能总是依赖来自建筑物主电源的交流输入到我们的系统中。 逆变器是一种将直流电 (DC) 转换为交…

前端javascript中的排序算法之冒泡排序

冒泡排序(Bubble Sort)基本思想: 经过多次迭代,通过相邻元素之间的比较与交换,使值较小的元素逐步从后面移到前面,值较大的元素从前面移到后面。 大数据往上冒泡,小数据往下沉,也就是…

Docker-安装MongoDB、RabbitMQ、ActiveMQ、Portainer(保姆篇图示详解)

文章目录 MongoDB 安装RabbitMQ 安装ActiveMQ 安装Portainer 安装 更多相关内容可查看 MongoDB 安装 1.拉取镜像(默认为最新版本,也可指定版本) docker pull mongo:版本号2.根据镜像 运行容器实例 (暴露端口 数据挂载 用户密码设…

【NLP】利用 RAG 模分块技术提升文档处理效能

将大型文档划分为较小的部分是一项至关重要但又复杂的任务,它对检索增强生成 (RAG) 系统的性能有重大影响。这些系统旨在通过结合基于检索和基于生成的方法,提高输出的质量和相关性。有效的分块,即将文档拆分为可管理的片段的过程&#xff0c…

百度Feed业务数仓建模实践

作者 | XY 导读 Feed,即个性化推荐信息流,是百度 App 上承载各种类型内容(如文章、视频、图集等)的重要 topic。本文概要讲述了随着业务发展,移动生态数据研发部在 Feed 数据宽表建模上的演进过程以及一些实践&#xf…

LeetCode67(二进制求和[位运算,大数运算])

二进制求和 题目要求: 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 这道题其实有几种解法.我们先来介绍简单的方法. 我们可以将两个字符串的二进制转成十进制,获取对应值相加之后,我们可以不断对2取余,获取尾数拼接即可.也就是像我们平常求一…

记一次线上流量突增问题排查

一.问题 接流量告警出现获取 xx 信息接口调用次数同比往年大促活动猛涨.扩大至 10 倍之多.心里顿时咯噔一下.最近各种严打,顶风作案.某不是摸到电门了.一下子要把自己带走.从此走向求职之路.一时间脑子哇哇的思绪万千. 202x.5.20 大促开门红的调用.这个是往年活动的时候的调用…

01-引论-操作系统的目标和作用

操作系统的目标 1.方便性 2.有效性 3.可扩充性 4.开放性 操作系统的目标与应用环境有关 在不同的应用环境下,操作系统的重点和功能可能会有所不同。例如,对于桌面操作系统,用户界面的友好性和多媒体功能可能是重点;对于服务…

Qt/C++项目积累: 2.主机监控器 - 2.1 项目介绍

修改记录 序号日期说明对应软件版本号120240709对预期功能和已完成功能进行新增无 一:项目主体编写背景 在观察程序的运行状态时,其对系统的CPU,内存,硬盘占用无疑是几项重要参考指标,而现有的监控软件,搜…

2024-07-08 base SAS programming学习笔记10(read data)

1.读入SAS 数据集 格式如下: data sas-data-set; set sas-data-set; run; sas-data-set 是数据集名称,可以是libname.filename的形式 举例如下: 2.在DATA步使用BY 语句 BY variable语句使用方法: a.必须在PROC SORT里面进行排序…

国产芯片四大流派,你最看好哪一条?

曾经,我们以为“地球村”是大势所趋,大家取长补短,合作共赢。 然而,2018年开始的那一场断供,让芯片自主从一个产业的隐忧变成了我国的一个“明伤”。近几年“卡脖子”事件屡屡上演,“缺芯”、“芯痛”成为…

Redis连接Resp图形化工具和springboot

Redis连接Resp图形化工具和springboot 1.redis配置1.1 备份、修改conf文件1.2 Redis的其它常见配置:1.3 启动Redis:1.4 停止服务:1.5 开机自启: 2. resp的安装、配置和连接:2.1 GitHub上下载2.2 开始连接redis ![在这里…

【Dison夏令营 Day 13】使用 Python 创建扫雷游戏

在本文中,我们将介绍如何使用 Python 语言创建自己的基于终端的扫雷程序。 关于游戏 1992年4月6日,扫雷和纸牌、空当接龙等小游戏搭载在Windows 3.1系统中与用户见面,主要目的是让用户训练使用鼠标。扫雷是一款单人游戏,这个游戏…

单例模式(大话设计模式)C/C++版本

单例模式 C 饿汉 /* HM hungry man 饿汉 */ #include <iostream> using namespace std; class Singleton { private:Singleton() { cout << "单例对象创建&#xff01;" << endl; };Singleton(const Singleton &);Singleton &operator(c…

app: 和 android:的区别

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

如何切换手机的ip地址

在数字时代的浪潮中&#xff0c;智能手机已成为我们日常生活中不可或缺的一部分。然而&#xff0c;随着网络安全问题的日益凸显&#xff0c;保护个人隐私和数据安全变得尤为重要。其中&#xff0c;IP地址作为网络身份的重要标识&#xff0c;其安全性与隐私性备受关注。本文将详…