使用 LangServe 构建和部署 MinIO 支持的 LangChain Agent API

我们在LangChain的创新世界中的旅程揭示了其在转变数据管理和应用程序功能方面的强大能力。

通过之前的讨论,我们深入探讨了几个主题,同时探索了LangChain的复杂功能。在本文中,我们将以“使用 MinIO 赋能 Langchain 代理”中涵盖的概念为基础,扩展 MinIO 代理的功能,以封装其他功能并通过 LangServe 部署自定义代理。

  • **使用 LangChain 创新 S3 存储桶检索:**利用 LangChain 的 S3 加载程序和 OpenAI API 制作自定义对话式 AI 代理,建立简化的数据管理方法的演练。

  • **使用 MinIO 为 LangChain 代理赋能:**深入探讨如何利用 MinIO,展示 LangChain 如何与 OpenAI 的 GPT 相结合,开创 AI 和 ML 数据处理的新领域。

基于这些见解,我们现在将重点转向LangServe,这是将LangChain应用程序从开发过渡到部署的关键工具,简化了启动生产就绪API的过程。

LangServe:简化LangChain应用程序的部署

LangServe 是开发人员的基石,消除了传统上与 API 部署相关的复杂性。它使集成了 MinIO 的 LangChain 应用程序能够平稳过渡到可访问、用户友好的 API。以下是 LangServe 如何重新定义部署环境:

  • **自动创建 API 端点:**LangServe 的自动化功能可以轻松生成必要的 API 端点,从而简化开发工作并显着缩短部署时间。

  • **模式生成和验证:**凭借其智能模式推理,LangServe 确保 API 提供定义明确的接口,从而促进更轻松的集成和无缝的用户体验。

  • **可定制的端点配置:**LangServe 提供各种端点,以满足从同步操作到实时更新的各种应用程序需求,为开发人员提供无与伦比的灵活性。

  • **轻松集成:**LangServe与现有LangChain代码无缝集成的能力也许是其最引人注目的功能,这意味着开发人员可以利用他们当前的代码库和专业知识,而无需进行重大更改。

深入了解LangChain和Langserve

我们将在以下步骤中更深入地探讨将 MinIO 与 LangChain 集成的过程。

1 . 使用 langchain-cli 创建 LangChain 应用程序。

2 . 在 agent.py 文件中开发自定义 LangChain 代理。

3 . 实现我们的代理 server.py 以作为 LangServe API 运行。

使用LangChain的命令行界面创建应用程序

使用LangServe部署LangChain应用程序带来了无缝的集成之旅,弥合了复杂的AI功能和RESTful API暴露之间的差距,使开发人员能够有效地利用LangChain的全部功能,为在当今快节奏的数字环境中部署智能应用程序树立了新标准。

LangChain提供了一种方便而简单的方法,使用他们的 langchain-cli 库创建应用程序,该库可以与 pip .该软件包提供了一个界面,允许用户通过使用现有的LangChain应用程序模板或创建自己的应用程序来轻松创建新应用程序。

**注意:**所有必要的文件都位于 MinIO 的“blog-assets”存储库中名为“minio-langserve-deployment”的目录下。

要创建一个新的LangChain应用程序,我们可以从以下命令开始创建一个虚拟环境并安装 langchain-cli 软件包:

mkdir minio-langserve-testing
cd minio-Langserve-testing


python -m venv .myenv
source .myenv/bin/activate


pip install langchain-cli

为了创建一个 langchain-cli 新的应用程序,我们可以在终端中键入 langchain ,编写以下命令以创建一个名为 my-app 的新应用程序目录。

langchain app new my-app

使用上述命令创建的 langchain 应用程序通过创建一致的开发环境来完成所有繁重的工作。开箱即用的新LangChain应用程序的结构如下所示:


./my-app
├── Dockerfile
├── README.md
├── app
│   ├── __init__.py
│   └── server.py ⇐ (This is where we will import our agent into)
├── packages ⇐  (This directory is where we will write our agent)
│   └── README.md
└── pyproject.toml

在以下步骤中,我们将通过编写一个名为 packages/agent.py 的新文件并更改 app/server.py 来对新创建的 LangChain 应用程序 ( my-app ) 进行更改。

这些是我们将在本文中讨论的文件:

  • my-app/packages/agent.py

  • my-app/app/server.py

开发 LangChain MinIO 代理以使用 LangServe 进行部署

为了说明如何使用 LangServe 部署集成了 MinIO 的 LangChain 代理,我们将首先将代理链代码保存在 agent.py 中。

首先,让我们初始化minio_client连接到“play.min.io:443”公共服务器的服务器。这个文件最终将调用LangChain的, agent_executor 允许我们将其传递给LangServe的 add_route 包装器。

**注意:**阅读之前的出版物“MinIO Langchain Tool”将为使用 LangChain 和 MinIO 一起开发提供有价值的见解。我们将遵循类似的概念方法,但使用额外的 MinIO 工具逻辑。

首先,使用文本编辑器打开 agent.py 文件:

sudo nano packages/agent.py

在文件的开头,导入必要的包,例如 os io minioChatOpenAI

import os
import io
from minio import Minio
from minio.error import S3Error
from langchain_openai import ChatOpenAI


os.environ["OPENAI_API_KEY"] = "<<Your API Key Here>>"

# Initialize llm
llm = ChatOpenAI(api_key=os.environ["OPENAI_API_KEY"]) 

# Initialize MinIO client
minio_client = Minio('play.min.io:443',
                     access_key='minioadmin',
                     secret_key='minioadmin',
                     secure=True)
                     

在此代码片段中,我们导入所需的包,并使用 OPENAI_API_KEY 存储在环境变量中的 OpenAI API 密钥初始化 ChatOpenAI 语言模型。我们还通过向“play.min.io”公共服务器提供必要的连接详细信息来初始化minio_client。

接下来,让我们定义 MinIO 存储桶,如果它不存在,则创建它:


# This variable will check if bucket exists
bucket_name = "test"


try:
    # Check if bucket exists
    if not minio_client.bucket_exists(bucket_name):
        # Create the bucket because it does not exist
        minio_client.make_bucket(bucket_name)
        print(f"Bucket '{bucket_name}' created successfully.")
    else:
        print(f"Bucket '{bucket_name}' already exists.")
except S3Error as err:
    print(f"Error encountered: {err}")
    

在这里,我们将 定义为 bucket_name “test”,并使用该 minio_client.bucket_exists() 方法检查它是否已经存在。如果存储桶不存在,则使用 minio_client.make_bucket() .如果存储桶已存在,我们会打印一条消息,指示该存储桶已存在。我们还使用try-exception块进行错误处理,以捕获和打印在此过程中可能发生的任何 S3Error 错误。

完成基本设置后,我们现在可以继续定义 MinIO 工具功能并创建代理执行器,我们将在后续步骤中介绍。

将LangChain的函数装饰器用于代理工具

Langchain和Langserve都提供了类似的方法来封装逻辑和功能,使其能够无缝集成到代理和链逻辑中。这是通过在定义的函数中使用带有详细文档字符串的@tool装饰器来实现的,该文档字符串将函数标记为可由 AI 代理使用和解释的可重用组件。

让我们仔细看看提供的代码示例:


from langchain.agents import tool

@tool
def upload_file_to_minio(bucket_name: str, object_name: str, data_bytes: bytes):
    """
    Uploads a file to MinIO.
    
    Parameters:
        bucket_name (str): The name of the bucket.
        object_name (str): The name of the object to create in the bucket.
        data_bytes (bytes): The raw bytes of the file to upload.
    """
    data_stream = io.BytesIO(data_bytes)
    minio_client.put_object(bucket_name, object_name, data_stream, length=len(data_bytes))
    return f"File {object_name} uploaded successfully to bucket {bucket_name}."

upload_file_to_minio 函数用 @tool 装饰,表示它是可重用的组件。它采用将文件上传到 MinIO 存储桶所需的参数,例如存储桶名称、对象名称和文件的原始字节。该函数利用 minio_client 执行文件上传操作,并在完成后返回成功消息。


@tool
def download_file_from_minio(file_info):
    """
    Custom function to download a file from MinIO.
    
    Expects file_info dict with 'bucket_name', 'object_name', and 'save_path' keys.
    'save_path' should be the local path where the file will be saved.
    """
    bucket_name = file_info['bucket_name']
    object_name = file_info['object_name']
    save_path = file_info['save_path']
    minio_client.get_object(bucket_name, object_name, save_path)
    

同样,该 download_file_from_minio 函数也标有 @tool 。它需要一个 file_info 字典,其中包含从 MinIO 存储桶下载文件所需的信息,例如存储桶名称、对象名称和应保存文件的本地路径。该函数使用 从minio_client指定存储桶中检索对象并将其保存到指定的本地路径。


@tool
def list_objects_in_minio_bucket(file_info):
    """
    Custom function to list objects in a MinIO bucket.
    
    Expects file_info dict with 'bucket_name' key.
    Returns a list of dictionaries containing 'ObjectKey' and 'Size' keys.
    """
    bucket_name = file_info['bucket_name']
    response = minio_client.list_objects(bucket_name)
    return [{'ObjectKey': obj.object_name, 'Size': obj.size} for obj in response.items]

list_objects_in_minio_bucket 函数也装饰用于 @tool 列出 MinIO 存储桶中存在的对象。它需要一个 file_info 带有键的 bucket_name 字典。该函数使用 检索 minio_client 指定存储桶中的对象列表,并返回包含每个对象的对象键和大小的字典列表。

通过将这些功能封装为工具,Langchain和Langserve使AI代理能够将它们无缝地整合到其逻辑和决策过程中。代理可以根据手头的任务智能地选择和执行适当的工具,从而增强其功能,并允许与 MinIO 存储系统进行更复杂和动态的交互。

了解LangChain的Runnable方法

LangChain提供了无数种使用自定义逻辑进行构建的方法,其中一种方法是“可运行”的方法。至于上面的演示逻辑, RunnableLambda 它是LangChain提供的一种结构,它允许将函数视为AI代理逻辑中的可执行单元。


from langchain_core.runnables import RunnableLambda


upload_file_runnable = RunnableLambda(upload_file_to_minio)
download_file_runnable = RunnableLambda(download_file_from_minio)
list_objects_runnable = RunnableLambda(list_objects_in_minio_bucket)

通过使用 RunnableLambda 包装工具函数,我们可以创建可运行的实例 ( upload_file_runnabledownload_file_runnable , 和 list_objects_runnable ),代理可以在其执行期间调用这些实例。这些可运行项封装了相应的工具功能,并为代理提供了与它们交互的统一接口。


tools = [upload_file_to_minio, download_file_from_minio, list_objects_in_minio_bucket]


llm_with_tools = llm.bind_tools(tools)

工具列表包含原始工具函数 ( upload_file_to_minio download_file_from_minio , 和 list_objects_in_minio_bucket ),这些函数用作代理功能的构建块。该 llm.bind_tools(tools) 行将工具绑定到语言模型 (llm),在模型的推理功能和工具提供的特定功能之间建立连接。结果 llm_with_tools 表示通过使用绑定工具的知识和能力增强的语言模型。

工具的使用 RunnableLambda 和工具与语言模型的绑定展示了LangChain和LangServe在创建强大且可定制的AI代理方面的灵活性和可扩展性。通过将语言模型的强大功能与工具中封装的特定功能相结合,AI 代理能够执行复杂的任务,例如将文件上传到 MinIO、从 MinIO 下载文件以及列出 MinIO 存储桶中的对象。

编写提示模板来指导我们的代理

接下来,我们将重点转移到提示模板上,该模板指导 AI 代理理解和响应用户输入。它是使用该 ChatPromptTemplate.from_messages() 方法定义的,该方法采用表示为包含角色和消息内容的元组的消息列表。

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages
from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser
from langchain_core.messages import AIMessage, HumanMessage


prompt_template = ChatPromptTemplate.from_messages([
    ("system", "You are a powerful assistant equipped with file management capabilities."),
    ("user", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad"),
])

提示由三条消息组成:

1 . 一条“系统”消息,将 AI 代理的上下文设置为具有文件管理功能的强大助手。

2 . 使用 {input} 占位符表示用户输入的“用户”消息。

3 . MessagesPlaceholder 一个名为“agent_scratchpad”,用于存储代理的中间步骤和思维过程。

format_to_openai_tool_messages 函数将代理的暂存器格式化为 OpenAI 工具的兼容格式,而 OpenAIToolsAgentOutputParser 类将模型的响应解析为可由代理解释的结构化格式。

AIMessage and HumanMessage 类表示代理和用户之间交换的消息,提供了一种标准化的方式来处理代理逻辑中的通信。

通过定义提示模板,我们为 AI 代理提供了一个清晰的结构和上下文,用于理解和响应用户输入,利用“agent_scratchpad”占位符在解决任务时跟踪其中间步骤和思维过程。

使用代理工具定义代理

最后,为了完成我们的 agent.py 代理,我们定义了我们的代理并创建了一个 AgentExecutor,可以使用 LangServe 库中的 add_route 函数从 server.py 脚本导入和调用它。

我们实例化必要的组件并将它们链接在一起以创建单个代理变量。


agent = (
    {
        "input": lambda x: x["input"],
        "agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),
    }
    | prompt_template
    | llm_with_tools
    | OpenAIToolsAgentOutputParser()
)

代理是使用字典和链式操作的组合来定义的。输入键从传入数据中提取用户输入,而 agent_scratchpad 键则使用该 format_to_openai_tool_messages 函数格式化代理思维过程的中间步骤。代理还合并了提示模板 ( prompt_template )、带有工具的语言模型 ( llm_with_tools ) 和输出解析器 ( OpenAIToolsAgentOutputParser() )。

定义 AgentExecutor 以执行代理

为了创建一个 AgentExecutor ,我们为其提供了定义的代理、可用的工具,并设置 verbose=True 了详细的输出。


from langchain.agents import tool, AgentExecutor


agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

AgentExecutor 使用提供的代理和工具来了解任务,并根据用户的输入选择适当的工具。代理不会为每个工具提供单独的提示,而是使用单个提示模板来指导它如何根据给定的输入使用这些工具。代理在执行过程中动态选择适当的工具。

使用我们的 AgentExecutor 定义 LangServe 路由

设置我们的应用程序并将其与LangServe集成,为将我们的LangChain应用程序部署和管理为API提供了简化的途径。选择 FastAPI 是因为它的性能和易用性,支持异步操作并自动生成 API 文档。

使用 FastAPI 构建的 LangServe 库通过简化 LangChain 对象作为 REST API 的部署来丰富这一点,为 CORS 设置提供内置中间件,以确保我们的 API 可以从不同的域安全地调用。

有关更深入/用例演示,可以通过访问 examples 目录下的 langchain-ai/langserve GitHub 存储库进行探索。


from fastapi import FastAPI


app = FastAPI(
    title="MinIO Agent API",
    version="1.0",
    description="A conversational agent facilitating data storage and retrieval with MinIO",
)

为了设置 CORS 标头,我们可以添加以下行来增强我们的安全性:


from fastapi.middleware.cors import CORSMiddleware


# Set all CORS enabled origins
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
    expose_headers=["*"],
)

使用 LangServe 实现代理

现在我们已经完成了 , packages/agent.py 我们可以导入它并在脚本 app/server.py 中使用 LangServe 库中的 add_route 函数。

from packages.agent import agent_executor
from langserve import add_routes


add_routes(
   app,
   agent_executor.with_types(input_type=Input, output_type=Output).with_config(
       {"run_name": "agent"}
   ), path=”/invoke”
)

通过调用 add_route(app, agent_executor(…), path="/invoke") ,我们向服务器应用程序 (app) 添加一个路由,将 /invoke 路径映射到 agent_executor() 函数。这允许在向 /invoke 终结点发出请求时调用代理执行程序。

通过此设置,服务器可以处理传入的请求,将它们传递给代理执行程序,并将代理的响应返回给客户端。代理执行程序利用定义的代理(包含提示模板、带工具的语言模型和输出解析器)来处理用户输入并根据可用工具生成适当的响应。

通过 Uvicorn 启动 LangServe 应用程序

为了启动LangServe应用程序,我们使用Uvicorn作为ASGI服务器,为我们的应用程序运行奠定了基础。这段代码至关重要,因为它激活了服务器,为应用程序的接入点指定了通用主机和指定端口。


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

通过将此块嵌入到应用程序的主条目中,我们确保 Uvicorn 在直接执行脚本时掌舵,从而在预定义的主机和端口上点亮我们的 FastAPI 应用程序。此方法不仅简化了部署过程,而且还为在开发或生产环境中运行应用程序提供了明确的入口。

启动服务器应用程序

上面的代码已经演示了一种模块化方法,其中包括使用“langchain-cli”库,创建一个新的langchain应用程序,并将链逻辑保存到 agent.py ,同时将FastAPI和LangServe实现保存到 server.py

这是我们的最后一步,我们将保存我们的应用程序代码, server.py 用于构建应用程序的演示目的。

运行我们服务的最简单方法是:


python server.py

此命令将运行应用程序,同时返回仍需要调试的任何日志或错误消息。

LangServe 游乐场 LangServe

在 python 输出中,LangServe 日志标识 /invoke/playground 为应用程序终结点。现在,我们可以访问 playground WebUI 以及 API 的自动化文档,这些文档可通过访问 API 的 /docs 路径获得;通过为我们的每个应用程序功能提供试用按钮,以及我们可以从 WebUI 执行的预定义 cURL 请求,为我们提供了一种简化的测试和配置方法。

因此,我们集成了 MinIO 的 LangChain 代理现在已经熟练地转变为可部署的 API,可以为用户开发和扩展,其功能范围从批处理到实时交互。

LangServe API 的进一步使用

随着LangServe应用程序的启动和运行,我们可以从外部 server.py 使用它,方法是以我们的端点为目标,并将其封装在Langserve的 RemoteRunnable 模块中:


from langserve import RemoteRunnable


remote_runnable = RemoteRunnable("http://localhost:8000/<path>/")

LangChain在其库中拥有大量的模块,展示了一个多样化的工具包,旨在使开发人员能够构建复杂的人工智能驱动的应用程序。从复杂的链式结构到与各种AI模型的无缝集成,LangChain的模块化架构促进了广泛的功能,能够在AI和机器学习领域创建高度可定制和先进的解决方案。

使用 LangServe 开发 AI 管道

LangServe 不仅揭开了 LangChain 应用程序的神秘面纱,而且大大简化了部署 LangChain 应用程序的过程。通过弥合开发和部署之间的差距,它确保利用MinIO和LangChain的创新应用程序能够迅速从概念变为现实,准备好集成到更广泛的生态系统中并增强用户体验。

通过我们探索中涵盖的开发,我们已经看到MinIO与LangChain的无缝集成是绝对可能的,以及LangServe如何在部署这些高级解决方案方面发挥关键作用。随着我们继续驾驭不断发展的人工智能和机器学习领域,像LangServe这样的工具将继续在将尖端技术带到应用程序开发的最前沿方面发挥重要作用。

在MinIO,在这个技术丰富的时代,开发者社区的创造力和潜力让我们充满活力。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

postgres数据库的流复制

1. 流复制和逻辑复制的差异 逻辑复制和流复制最直观的不同是&#xff0c;逻辑复制支持表级别复制区分点事原理不同 逻辑日志是在wal日志产生的数据库上&#xff0c;由逻辑解析模块对wal日志进行初步的解析&#xff0c;解析结果是ReorderBufferChange&#xff08;理解为HeapTup…

SpringBoot整合拦截器和日期转换器

一、SpringBoot整合拦截器 1.添加拦截器 package com.by.interceptor;import com.by.pojo.User; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest; import java…

BaseMapper 接口介绍

基于 mybatis-mapper/provider 核心部分实现的基础的增删改查操作&#xff0c;提供了一个核心的 io.mybatis.mapper.BaseMapper 接口和一个 预定义 的 io.mybatis.mapper.Mapper 接口&#xff0c;BaseMapper 接口定义如下&#xff1a; /*** 基础 Mapper 方法&#xff0c;可以在…

React useImperativeHandle Hook

useImperativeHandle Hook 是一个比较比较简单的 hook&#xff0c;为 ref 节点添加一些处理方法&#xff0c;下面是来自官网例子&#xff0c;为 ref 添加了两个方法。 import { forwardRef, useRef, useImperativeHandle } from react;const MyInput forwardRef(function MyI…

香港办公室顺利落地,量子之歌发布白皮书开启银发新篇章

6月25日&#xff0c;量子之歌香港办公室开业典礼暨《2023年中国中老年服务市场白皮书&#xff1a;银发经济&#xff0c;耀眼的黄金赛道》发布会于香港中环交易广场隆重开幕。 这一里程碑事件不仅彰显了量子之歌在银发经济领域的行业领军者风范&#xff0c;更凸显了其在专业服务…

一文了解自定义表单系统开源的多个优势

降本、提质、增效&#xff0c;是当前很多企业都想实现的目的。什么样的软件可以助力企业创造价值&#xff1f;低代码技术平台是近些年得到了很多客户喜爱的平台产品&#xff0c;因为它能帮助大家减少编程代码的撰写&#xff0c;能轻松助力各部门之间做好协调沟通工作&#xff0…

算法导论 总结索引 | 第四部分 第十六章:贪心算法

1、求解最优化问题的算法 通常需要经过一系列的步骤&#xff0c;在每个步骤都面临多种选择。对于许多最优化问题&#xff0c;使用动态规划算法求最优解有些杀鸡用牛刀了&#xff0c;可以使用更简单、更高效的算法 贪心算法&#xff08;greedy algorithm&#xff09;就是这样的算…

13.1 Go 反射(Reflection)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

文本生成图像综述

本调查回顾了扩散模型在生成任务中广泛流行的背景下文本到图像的扩散模型。作为一份自成一体的作品&#xff0c;本调查首先简要介绍了基本扩散模型如何用于图像合成&#xff0c;然后介绍了条件或指导如何改善学习。基于这一点&#xff0c;我们介绍了文本到图像生成方面的最新方…

条码二维码读取设备在医疗设备自助服务的重要性

医疗数字信息化建设的深入推进&#xff0c;医疗设备自助服务系统已成为医疗服务领域的一大趋势&#xff0c;条码二维码读取设备作为自助设备的重要组成部分&#xff0c;通过快速、准确地读取条形码二维码信息&#xff0c;不公提升了医疗服务效率&#xff0c;还为患者提供了更加…

Flutter页面状态保留策略

目的: 防止每次点击底部按钮都进行一次页面渲染和网络请求 1. 使用IndexedStack 简单,只需要把被渲染的组件外部套一层IndexedStack即可 缺点: 在应用启动的时候,所有需要保存状态的页面都会直接被渲染,保存起来. 对性能有影响 2. 使用PageController 实现较为复杂,但是不用…

Biome-BGC生态系统模型与Python融合技术

Biome-BGC是利用站点描述数据、气象数据和植被生理生态参数&#xff0c;模拟日尺度碳、水和氮通量的有效模型&#xff0c;其研究的空间尺度可以从点尺度扩展到陆地生态系统。 在Biome-BGC模型中&#xff0c;对于碳的生物量积累&#xff0c;采用光合酶促反应机理模型计算出每天…

C++设计模式——Facade外观模式

一&#xff0c;外观模式简介 外观模式是一种结构型设计模式&#xff0c; 又称为门面模式&#xff0c;也是一种基于创建对象来实现的模式&#xff0c;为子系统中的各组接口的使用提供了统一的访问入口。 外观模式对外提供了一个对象&#xff0c;让外部客户端(Client)对子系统的…

dataguard 主备切换方式switchover 和 failover 操作步骤

作者介绍&#xff1a;老苏&#xff0c;10余年DBA工作运维经验&#xff0c;擅长Oracle、MySQL、PG数据库运维&#xff08;如安装迁移&#xff0c;性能优化、故障应急处理等&#xff09; 公众号&#xff1a;老苏畅谈运维 欢迎关注本人公众号&#xff0c;更多精彩与您分享。datagu…

【ATU Book - i.MX8系列 - OS】NXP i.MX Linux Desktop (Ubuntu) BSP 开发环境架设

一、概述 谈论嵌入式系统的开发环境&#xff0c;不得不提起近年来相当实用的 Yocto 建构工具。此工具拥有极为灵活的平台扩展性&#xff0c;广泛的软体套件与社群支持、多平台支援整合性&#xff0c;能够满足开发者特定需求和多种热门的嵌入式系统架设&#xff0c;已成为当今顶…

【深海王国】小学生都能玩的单片机?零基础入门单片机Arduino带你打开嵌入式的大门!(10)

Hi٩(๑o๑)۶, 各位深海王国的同志们&#xff0c;早上下午晚上凌晨好呀~辛勤工作的你今天也辛苦啦 (o゜▽゜)o☆ 今天大都督继续为大家带来系列——小学生都能玩的单片机&#xff01;带你一周内快速走进嵌入式的大门&#xff0c;let’s go&#xff01; &#xff08;10&#…

Java学习笔记(多线程):CompetableFuture

本文是自己的学习笔记&#xff0c;主要参考资料如下 https://www.cnblogs.com/dolphin0520/p/3920407.html JavaSE文档 https://blog.csdn.net/ThinkWon/article/details/102508721 1、Overview2、重要参数3、主要方法3.1、创建实例&#xff0c;获取返回值3.2、线程执行顺序相关…

三十九篇:UML与SysML:掌握现代软件和系统架构的关键

UML与SysML&#xff1a;掌握现代软件和系统架构的关键 1. 引言 1.1 为什么系统设计如此关键 在当今快速发展的技术环境中&#xff0c;系统设计的重要性不言而喻。无论是软件开发还是复杂的系统工程&#xff0c;良好的设计是确保项目成功的基石。系统设计不仅关系到功能的实现…

day38动态规划part01| 理论基础 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯

**理论基础 ** 无论大家之前对动态规划学到什么程度&#xff0c;一定要先看 我讲的 动态规划理论基础。 如果没做过动态规划的题目&#xff0c;看我讲的理论基础&#xff0c;会有感觉 是不是简单题想复杂了&#xff1f; 其实并没有&#xff0c;我讲的理论基础内容&#xff0c;…

状态压缩动态规划(State Compression DP)算法详解

状态压缩动态规划&#xff08;State Compression DP&#xff09;是一种高效解决组合优化问题的技术&#xff0c;特别适用于那些状态空间较大且可以用二进制表示的情况。本文将详细讲解状态压缩DP的原理、常用的位运算技巧、以及具体的例题分析。 原理概述 状态压缩DP的核心思…