LangChain:模型 I/O 封装使用解析和感触

目录

模型 API:LLM vs. ChatModel

OpenAI 模型封装

多轮对话 Session 封装

换个国产模型

模型的输入与输出

Prompt 模板封装

PromptTemplate

ChatPromptTemplate

MessagesPlaceholder

从文件加载 Prompt 模板

TXT模板

Yaml模板

Json模板

输出封装 OutputParser

​编辑Pydantic (JSON) Parser

Auto-Fixing Parser

总结

关键点提取

使用感触


        本文将继续延续Langchain专栏文章,本文将讲解Langchain的模型 I/O 封装。Langchain将不同的模型,统一封装成一个接口,方便更换模型而不用重构代码。

        对Langchain能做什么暂时还不了解的话可以移步先看这篇文章

直通车:LangChain:大模型框架的深度解析与应用探索-CSDN博客

模型 API:LLM vs. ChatModel

pip install --upgrade langchain # 安装最新版本
pip install --upgrade langchain-openai # v0.1.0新增的底包

OpenAI 模型封装

        最基本的调度封装

from langchain_openai import ChatOpenAIllm = ChatOpenAI(model="gpt-3.5-turbo")  # 默认是gpt-3.5-turbo
response = llm.invoke("你是谁")
print(response.content)

多轮对话 Session 封装

# 加载 .env 到环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())from langchain_openai import ChatOpenAIllm = ChatOpenAI()  # 默认是gpt-3.5-turbofrom langchain.schema import (AIMessage, #等价于OpenAI接口中的assistant roleHumanMessage, #等价于OpenAI接口中的user roleSystemMessage #等价于OpenAI接口中的system role
)
messages = [SystemMessage(content="从现在开始你叫AI助手-小京。"),HumanMessage(content="我是CSDN的一名博主,我叫Muller"),AIMessage(content="欢迎!"),HumanMessage(content="我是谁")
]
response = llm.invoke(messages)
print(response.content)

通过模型封装,实现不同模型的统一接口调用

        SystemMessage 描述你的大模型角色、功能、作用等等;

        HumanMessage 用户输入的内容 

        AIMessage 大模型回答

        通过这个Message数组就能表示一个摘要,原生的Openai通过一个json数组,每一轮都一个任务一个content来去表示一个对话上下文,那么在langchain的框架下,可以通过它定义的结构来去表示一个对话。然后呢,我们还是把这个对话通过invoke接口来传给大模型,就实现了这一种多轮对话的交互。

        和Openai一样,对话历史还是需要我们自行进行管理的 ,具体langchain这个框架下需要如何管理对话历史后面再详细讲解。也就是说它不会自动帮我们填充里面的信息,例如你不附上content,它返回的实际上就是一个ai message ,如果你要维护这一个上下文的话,那你就需要将这个ai message填到数组里去发起下轮,就是这么一个逻辑。

换个国产模型

pip install qianfan
# 加载 .env 到环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())# 其它模型分装在 langchain_community 底包中
from langchain_community.chat_models import QianfanChatEndpoint
from langchain.schema import HumanMessage
import os
qianfan = QianfanChatEndpoint(qianfan_ak=os.getenv('ERNIE_CLIENT_ID'),qianfan_sk=os.getenv('ERNIE_CLIENT_SECRET')
)messages = [HumanMessage(content="你是谁")
]response = qianfan.invoke(messages)
print(response.content)

        通过这么一个简单的例子就能体会到模型的封装的一个好处就是不同的模型我都用统一的接口去调用,如果都是openai我就不用管你是3.5还是4,我都统一用这个接口,甚至我换一个模型,还是这样一个结构去调用,我接口是不用变的。

模型的输入与输出

Prompt 模板封装

PromptTemplate

        对一段文字生成了一个提示词模板。提供了一个函数将字符串转成一个模板。

from langchain.prompts import PromptTemplate
print("====模板====")
template = PromptTemplate.from_template("帮我解释一下这个成语:{idiom}")
print(template)
print("====提示词====")
print(template.format(idiom='繁花似锦'))

         模板包含两个元素,一个是模板内容,另一个是模板内代填的变量给提取出来。

====模板====
input_variables=['idiom'] template='帮我解释一下这个成语:{idiom}'
====提示词====
#帮我解释一下这个成语:繁花似锦

ChatPromptTemplate

        提供了把一个多轮对话上下文整个变成一个多轮模板的形式,用模板表示的对话上下文。

# 加载 .env 到环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())from langchain.prompts import ChatPromptTemplate
from langchain.prompts.chat import SystemMessagePromptTemplate, HumanMessagePromptTemplate
from langchain_openai.chat_models import ChatOpenAI# 定义聊天提示词
template = ChatPromptTemplate.from_messages([SystemMessagePromptTemplate.from_template("你是一名{subject}老师,你的名字叫{name}"),HumanMessagePromptTemplate.from_template("{query}"),]
)llm = ChatOpenAI()
# 生成大模型输入
prompt = template.format_messages(subject="语文",name="muller",query="告诉我你是谁,然后帮我解释一下这个成语:繁花似锦")response = llm.invoke(prompt)
print(response.content)
#你好,我是一名语文老师,名叫Muller。#繁花似锦是一个形容词成语,用来形容景色美丽、繁华盛开的样子。其中,“繁花”指的是许多花朵,而“似#锦”则表示美丽多彩、如锦绣般的样子。
#这个成语常用来形容春天或夏天花朵盛开的景象,也可以用来形容其他美丽的景色或事物。它表达了繁花##绚烂的美丽,给人以愉悦和喜悦的感觉。

MessagesPlaceholder

        通过MessagesPlaceholder把多轮对话整个变成模板,它的作用就是解决逐轮对话写入麻烦的问题,例如上述代码,需要不断在from_messages填充多个元素表示多轮对话,当历史对话发生变化需重新填充,因为对话历史本身就是一个Message List,那么就可以直接把message List填写到对话的中间,如下列代码MessagesPlaceholder(variable_name="历史对话") 留了一个多轮的占位符  ,给该占位符取了一个名字为:“历史对话”。

# 加载 .env 到环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())from langchain.prompts import (ChatPromptTemplate,MessagesPlaceholder,
)
from langchain.prompts.chat import  HumanMessagePromptTemplate
from langchain_openai.chat_models import ChatOpenAI
llm = ChatOpenAI()# 定义一个用户对话模板
human_message_template = HumanMessagePromptTemplate.from_template("帮我解释一下这个成语: {idiom}.")# 定义当前聊天提示词,传参 历史聊天记录和用户对话模板
chat_prompt = ChatPromptTemplate.from_messages(# variable_name 是 message placeholder 在模板中的变量名# 用于在赋值时使用[MessagesPlaceholder(variable_name="历史对话"), human_message_template]
)#定义大模型角色说明,AI、Human、System
from langchain_core.messages import AIMessage, HumanMessage,SystemMessage#大模型角色说明
system_message = SystemMessage(content="你是一名语文老师,你的名字叫muller")
#用户对话1
human_message = HumanMessage(content="告诉我你是谁?")
#大模型回答1
ai_message = AIMessage(content="我是一名语文老师,名叫Muller")# 生成大模型输入
messages = chat_prompt.format_prompt(# 对 "conversation" 和 "language" 赋值历史对话=[system_message,human_message, ai_message], idiom="繁花似锦"
)print(messages.to_messages())result = llm.invoke(messages)
print(result.content)# 繁花似锦是一个形容词成语,用来形容景色美丽、繁华盛开的样子。其中,“繁花”指的是许多花朵,而# “似锦”则表示美丽多彩、如锦绣般的样子。# 这个成语常用来形容春天或夏天花朵盛开的景象,也可以用来形容其他美丽的景色或事物。它表达了繁花# 绚烂的美丽,给人以愉悦和喜悦的感觉。

从文件加载 Prompt 模板

        我们在开发模式可以通过在代码中通过字符串定义模板,但实际生产中则需要将代码和prompt进行分离,这样便于整个项目的管理。Langchain也提供了像SK一样的能力,可以支持加载一个文件为Prompt模板,例如Txt加载方式是将字符串放到了txt文件中。 

TXT模板

帮我解释一下这个成语:{idiom}
from langchain.prompts import PromptTemplatetemplate = PromptTemplate.from_file("example_prompt_template.txt")
print("===Template===")
print(template)
print("===Prompt===")
print(template.format(topic='繁花似锦'))# ===Template===
# input_variables=['idiom'] template='帮我解释一下这个成语:{idiom}'
#===Prompt===
# 帮我解释一下这个成语:繁花似锦

Yaml模板

    _type: promptinput_variables:["subject", "idiom"]template: 你是一名{subject}老师,帮我解释一下这个成语:{idiom}
from langchain.prompts import load_prompt
prompt = load_prompt("simple_prompt.yaml")
print(prompt.format(subject="语文", idiom="繁花似锦"))

Json模板

{"_type": "prompt","input_variables": ["idiom"],"template": "帮我解释一下这个成语:{idiom}"
}
from langchain.prompts import load_prompt
prompt = load_prompt("simple_prompt.json")
print(prompt.format(subject="语文", idiom="繁花似锦"))

输出封装 OutputParser

        自动把 LLM 输出的字符串按指定格式加载,如果通过规定格式输出,对程序解析有好处。

        LangChain 内置的 OutputParser 包括但不仅限于:

  • ListParser
  • DatetimeParser
  • EnumParser
  • JsonOutputParser
  • PydanticParser
  • XMLParser

详细用例直通车:Output Parsers | 🦜️🔗 LangChain

Pydantic (JSON) Parser

        我们可以使用python的Pydantic类,去定义一个特定的结构,且这个结构是带含义描述的结构体,然后这个结构体我们可以从JSON结构中转换成它,也可以将它转换成JSON格式。而Langchain就是提供了解析Pydantic结构对象的能力。

        打个比方有个日期类,日期有“年”、“月”、“日” 和 “公元前/公元后” 这四个字段组成。假设我们需要一个这个类的对象,那么我们就可以通过依据Pydantic类格式将它描述出来,然后用Langchain提供的Pydantic解析器让大模型按这个格式输出结果,然后用Parser从大模型的结果里去解析出这个对象来,后面就可以让依据程序逻辑使用这个结构化的结果了。

        具体例子如下:一般描述类属性对象已具备基本能力,但如果你需要校验对象值的合法性,就需要用到Pydantic的能力,即@validator和@staticmethod的注解内容。 

# 定义Pydantic结构
from langchain_core.pydantic_v1 import BaseModel, Field, validator
from typing import List, Dict# 定义你的输出对象class Date(BaseModel):year: int = Field(description="Year")month: int = Field(description="Month")day: int = Field(description="Day")era: str = Field(description="BC or AD")# ----- 可选机制 --------# 你可以添加自定义的校验机制@validator('month')def valid_month(cls, field):if field <= 0 or field > 12:raise ValueError("月份必须在1-12之间")return field@validator('day')def valid_day(cls, field):if field <= 0 or field > 31:raise ValueError("日期必须在1-31日之间")return field@validator('day', pre=True, always=True)def valid_date(cls, day, values):year = values.get('year')month = values.get('month')# 确保年份和月份都已经提供if year is None or month is None:return day  # 无法验证日期,因为没有年份和月份# 检查日期是否有效if month == 2:if cls.is_leap_year(year) and day > 29:raise ValueError("闰年2月最多有29天")elif not cls.is_leap_year(year) and day > 28:raise ValueError("非闰年2月最多有28天")elif month in [4, 6, 9, 11] and day > 30:raise ValueError(f"{month}月最多有30天")return day@staticmethoddef is_leap_year(year):if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0):return Truereturn False
#使用Pydantic
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAIfrom langchain.output_parsers import PydanticOutputParsermodel_name = 'gpt-3.5-turbo'
temperature = 0
model = ChatOpenAI(model_name=model_name, temperature=temperature)# 根据Pydantic对象的定义,构造一个OutputParser
parser = PydanticOutputParser(pydantic_object=Date)template = """提取用户输入中的日期。
{format_instructions}
用户输入:
{query}"""prompt = PromptTemplate(template=template,input_variables=["query"],# 直接从OutputParser中获取输出描述,并对模板的变量预先赋值partial_variables={"format_instructions": parser.get_format_instructions()}
)print("====Format Instruction=====")
print(parser.get_format_instructions())query = "2024年五月1日即将实施的《非银行支付机构监督管理条例》,将非银行支付机构及其业务活动进一步纳入法治化轨道进行监管。"
model_input = prompt.format_prompt(query=query)print("====Prompt=====")
print(model_input.to_string())output = model(model_input.to_messages())
print("====模型原始输出=====")
print(output)
print("====Parse后的输出=====")
date = parser.parse(output.content)
print(date)
====Format Instruction=====
The output should be formatted as a JSON instance that conforms to the JSON schema below.As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.Here is the output schema:
```
{"properties": {"year": {"title": "Year", "description": "Year", "type": "integer"}, "month": {"title": "Month", "description": "Month", "type": "integer"}, "day": {"title": "Day", "description": "Day", "type": "integer"}, "era": {"title": "Era", "description": "BC or AD", "type": "string"}}, "required": ["year", "month", "day", "era"]}
```
====Prompt=====
提取用户输入中的日期。
The output should be formatted as a JSON instance that conforms to the JSON schema below.As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.Here is the output schema:
```
{"properties": {"year": {"title": "Year", "description": "Year", "type": "integer"}, "month": {"title": "Month", "description": "Month", "type": "integer"}, "day": {"title": "Day", "description": "Day", "type": "integer"}, "era": {"title": "Era", "description": "BC or AD", "type": "string"}}, "required": ["year", "month", "day", "era"]}
```
用户输入:
2024年五月1日即将实施的《非银行支付机构监督管理条例》,将非银行支付机构及其业务活动进一步纳入法治化轨道进行监管。====模型原始输出=====
content='{"year": 2024, "month": 5, "day": 1, "era": "AD"}'
====Parse后的输出=====
year=2024 month=5 day=1 era='AD'

Auto-Fixing Parser

        Openai不一定保证百分之百每一次结果输出的格式你要的能一模一样,例如返回的内容都是中文或json格式错误等问题,所以大模型输出的结果本身存在一定的不确定性,那就导致如果格式错了,那么OutputParser解析会失败,为了失败了能够再次尝试去自动修复这个格式上的错误,重新解析,Langchain还提供了Auto-Fixing Paser。

        核心它完成了大模型输出的结果是错的,导致解析失败时,它会尝试修改格式再做一次自动的解析。定义这块功能需要将原始的Parser给它,同时还需要给它大模型对象。

# 加载 .env 到环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())from langchain_core.pydantic_v1 import BaseModel, Field, validator# 定义你的输出对象
class Date(BaseModel):year: int = Field(description="Year")month: int = Field(description="Month")day: int = Field(description="Day")era: str = Field(description="BC or AD")# ----- 可选机制 --------# 你可以添加自定义的校验机制@validator('month')def valid_month(cls, field):if field <= 0 or field > 12:raise ValueError("月份必须在1-12之间")return field@validator('day')def valid_day(cls, field):if field <= 0 or field > 31:raise ValueError("日期必须在1-31日之间")return field@validator('day', pre=True, always=True)def valid_date(cls, day, values):year = values.get('year')month = values.get('month')# 确保年份和月份都已经提供if year is None or month is None:return day  # 无法验证日期,因为没有年份和月份# 检查日期是否有效if month == 2:if cls.is_leap_year(year) and day > 29:raise ValueError("闰年2月最多有29天")elif not cls.is_leap_year(year) and day > 28:raise ValueError("非闰年2月最多有28天")elif month in [4, 6, 9, 11] and day > 30:raise ValueError(f"{month}月最多有30天")return day@staticmethoddef is_leap_year(year):if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0):return Truereturn Falsefrom langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAIfrom langchain.output_parsers import PydanticOutputParsermodel_name = 'gpt-3.5-turbo'
temperature = 0
model = ChatOpenAI(model_name=model_name, temperature=temperature)# 根据Pydantic对象的定义,构造一个OutputParser
parser = PydanticOutputParser(pydantic_object=Date)template = """提取用户输入中的日期。
{format_instructions}
用户输入:
{query}"""prompt = PromptTemplate(template=template,input_variables=["query"],# 直接从OutputParser中获取输出描述,并对模板的变量预先赋值partial_variables={"format_instructions": parser.get_format_instructions()}
)query = "2024年五月1日即将实施的《非银行支付机构监督管理条例》,将非银行支付机构及其业务活动进一步纳入法治化轨道进行监管。"
model_input = prompt.format_prompt(query=query)output = model(model_input.to_messages())# 解决output输出尽量可控
from langchain.output_parsers import OutputFixingParsernew_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI(model="gpt-3.5-turbo"))# 因为这个例子比较简单,大模型比较难出错,这里手动替换成错误值
output = output.content.replace("5", "五月")
print("===格式错误的Output===")
print(output)
try:date = parser.parse(output)
except Exception as e:print("===出现异常===")print(e)# 用OutputFixingParser自动修复并解析
date = new_parser.parse(output)
print("===重新解析结果===")
print(date)
===格式错误的Output===
{"year": 2024, "month": 五月, "day": 1, "era": "AD"}
===出现异常===
Failed to parse Date from completion {"year": 2024, "month": 五月, "day": 1, "era": "AD"}. Got: Expecting value: line 1 column 25 (char 24)
===重新解析结果===
year=2024 month=5 day=1 era='AD'

总结

关键点提取

本文关键内容提取:

        1、LangChain 统一封装了各种模型的调用接口,包括补全型和对话型两种;
        2、LangChain 提供了 PromptTemplate 类,可以自定义带变量的模板;
        3、LangChain 提供了一些列输出解析器,用于将大模型的输出解析成结构化对象;额外带有自动修复功能;
        4、模型属于 LangChain 中较为优秀的部分;美中不足的是 OutputParser 自身的 Prompt 维护在代码中,耦合度较高。

使用感触

从这段时间接触Langchain,从使用角度上感触如下:

  • Langchain对大模型的封装是可用的。对此结论的评价标准是假设即使不用Langchian的情况下,自己去设计一套应用,同样对大模型调用接口上也进行一个类似抽象,自己是否能保证从chatgpt模型切到claude模型后不会造成代码大规模的调整,在这个尝试上我发现是Langchain可行的,并且所调整的代码极少。
  • Langchain对于PromptTemplate的封装在早期的确实很粗糙,但现在的版本基本达到可用状态。不难看出从字符串加载、从文件加载,甚至嵌套方式加载目前都已具备了,所以PromptTemplate这个功能从个人而言并没有发现特别大的弊端导致不推荐的情况,因此可以认为它也是一个可用的模块,而且即使你不用Langchain来管理,你也可以来参考它这种模式,就是将Prompt和代码分开来管理,以完成填槽的逻辑。
  • OutputParser情况却没有很理想,首先它是基本可用的,例如JsonParser这些基础解析是可用的,但Auto-Fixing Parser则需要注意的就是它自己内部是有Prompt模板的。它的Prompt模板写的如何,在你的这个业务中是否通用?是否未来对所有的模型都兼容?这些是需要酌情考虑使用的。在使用这些非代码的功能,即不确定的功能的时候,需要注意的是不能因为模型变化了结果却不是最优解的情况,例如当初是基于gpt4编写生产好用,而更换到gpt5了它的这个模板就不是最优解了,或导致该功能就失效了。这里我更推荐的一个做法就是使用这些内置Prompt模板功能或不确定的代码时候,强烈推荐能够单独将这部分Prompt抽出来管理,就是把Prompt抽出来去维护,哪怕真的要用它写的功能也要拷贝出来单独维护,这样的好处在于未来你的模型换了,出现非最优解时,你能知道改哪里,好导致你不用梳理整个逻辑改整块代码。

        

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

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

相关文章

目标检测标注工具Labelimg安装与使用

目录 一、安装Labelimg与打开 二、使用 1、基本功能介绍 2、快捷键 3、状态栏的工具 三、附录 1、YOLO模式创建标签的样式 2、create ML模式创建标签的样式 3、PascalVOC模式创建标签的样式 一、安装Labelimg与打开 labelimg是一款开源的数据标注工具&#xff0c;可以…

51基于单片机的温室大棚系统设计

设计摘要&#xff1a; 本设计旨在基于51单片机和蓝牙技术&#xff0c;实现一个功能完善的温室大棚系统。该系统具备以下主要功能&#xff1a;首先&#xff0c;通过连接的显示屏能够实时地显示当前的温度和湿度信息&#xff0c;方便用户了解温室内的环境变化。其次&#xff0c;…

ctfshow web271--web273

web271 laravel5.7反序列化漏洞 define(LARAVEL_START, microtime(true));/* |-------------------------------------------------------------------------- | Register The Auto Loader |-------------------------------------------------------------------------- | |…

凸优化理论学习二|凸函数及其相关概念

系列文章目录 凸优化理论学习一|最优化及凸集的基本概念 文章目录 系列文章目录一、凸函数&#xff08;一&#xff09;凸集&#xff08;二&#xff09;凸函数的定义及举例&#xff08;三&#xff09;凸函数的证明1、将凸函数限制在一条直线上2、判断函数是否为凸函数的一阶条件…

贝叶斯分类器详解

1 概率论知识 1.1 先验概率 先验概率是基于背景常识或者历史数据的统计得出的预判概率&#xff0c;一般只包含一个变量&#xff0c;例如P(A)&#xff0c;P(B)。 1.2 联合概率 联合概率指的是事件同时发生的概率&#xff0c;例如现在A,B两个事件同时发生的概率&#xff0c;记…

华为交换机配置导出备份python脚本

一、脚本编写思路 &#xff08;一&#xff09;针对设备型号 主要针对华为&#xff08;Huawei&#xff09;和华三&#xff08;H3C&#xff09;交换机设备的配置备份 &#xff08;二&#xff09;导出前预处理 1.在配置导出前&#xff0c;自动打开crt软件或者MobaXterm软件&am…

掌握MySQL执行计划分析【Explain】

前言 MySQL是一个强大的关系型数据库管理系统&#xff0c;其高效执行SQL查询的能力是其核心价值之一。然而&#xff0c;当查询变得复杂或者数据量急剧增长时&#xff0c;SQL查询的性能问题往往成为我们不得不面对的挑战。为了深入了解查询的执行过程并找到性能瓶颈&#xff0c…

Modbus通讯协议初学

目录 Modbus通讯协议初学什么是Modbus?Modbus用来做什么?4个种类的寄存器协议速记功能码Modbus 报文帧示例解读 Modbus通讯协议初学 什么是Modbus? 顾名思义,它是一个bus,即总线协议。比如串口协议、IIC协议、SPI都是通讯协议。你接触到这种协议,相信你所处的行业是工业方…

如何自定义Linux命令

说明&#xff1a;本文介绍如何将自己常用的命令设置为自定义的命令&#xff0c;以下操作在阿里云服务器CentOS上进行。 修改配置文件 修改配置文件前&#xff0c;先敲下面的命令查看当前系统配置的shell版本 echo $SHELL或者 echo $0区别在于&#xff0c;$SHELL查看的是系统…

落雪音乐 超好用的桌面端音乐播放器

之前一直都是充某Q音乐的会员&#xff0c;突然不想氪金了&#xff0c;终于找到一个开源的音乐播放器&#xff0c;在此先给落雪无痕大佬跪了 太爱了 简直白嫖怪的福音 话不多说&#xff0c;直接上操作&#xff1a;解压密码&#xff1a;www.1234f.com下载地址&#xff1a;极速云…

图片批量管理迈入智能新时代:一键输入关键词,自动生成并保存惊艳图片,轻松开启创意之旅!

在数字化时代&#xff0c;图片已成为我们表达创意、记录生活、传递信息的重要工具。然而&#xff0c;随着图片数量的不断增加&#xff0c;如何高效、便捷地管理这些图片&#xff0c;却成为了一个令人头疼的问题。 第一步&#xff0c;进入首助编辑高手主页面&#xff0c;在上方…

视频封面一键提取:从指定时长中轻松获取您想要的帧图片

在数字媒体时代&#xff0c;视频已成为人们获取信息、娱乐和沟通的主要形式之一。而一个好的视频封面&#xff0c;往往能够吸引观众的眼球&#xff0c;增加视频的点击率和观看量。然而&#xff0c;对于很多视频创作者和编辑者来说&#xff0c;如何从视频中快速、准确地提取出合…

Git知识点总结

目录 1、版本控制 1.1什么是版本控制 1.2常见的版本控制工具 1.3版本控制分类 2、集中版本控制 SVN 3、分布式版本控制 Git 2、Git与SVN的主要区别 3、软件下载 安装&#xff1a;无脑下一步即可&#xff01;安装完毕就可以使用了&#xff01; 4、启动Git 4.1常用的Li…

Shell编程之循环语句之for

一.for循环语句 读取不同的变量值&#xff0c;用来逐个执行同一组命令 for 变量名 in 取值列表 do命令序列 done 示例&#xff1a; 1.计算从1到100所有整数的和 2.提示用户输入一个小于100的整数&#xff0c;并计算从1到该数之间所有整数的和 3.求从1到100所有整数的偶数和…

【牛客】SQL206 获取每个部门中当前员工薪水最高的相关信息

1、描述 有一个员工表dept_emp简况如下&#xff1a; 有一个薪水表salaries简况如下&#xff1a; 获取每个部门中当前员工薪水最高的相关信息&#xff0c;给出dept_no, emp_no以及其对应的salary&#xff0c;按照部门编号dept_no升序排列&#xff0c;以上例子输出如下: 2、题目…

SBM模型、超效率SBM模型代码及案例数据(补充操作视频)

01、数据简介 SBM&#xff08;Slack-Based Measure&#xff09;模型是一种数据包络分析&#xff08;Data Envelopment Analysis, DEA&#xff09;的方法&#xff0c;用于评估决策单元&#xff08;Decision Making Units, DMUs&#xff09;的效率。而超效率SBM模型是对SBM模型的…

轮转数组 与 消失的数字

轮转数组 思路一 创建一个新内存空间&#xff0c;将需轮转的数依次放入&#xff0c;之后在把其它数放入 代码&#xff1a; void rotate(int* nums, int numsSize, int k) {k k % numsSize;// 确定有效的旋转次数if(k 0)return;int* newnums (int*)malloc(sizeof(int) * nu…

企业OA办公系统开发笔记:1、搭建后端环境

文章目录 企业办公系统&#xff1a;搭建环境一、项目介绍1、介绍2、技术栈3、项目模块4、数据库 二、搭建环境1、搭建后端1.1、搭建父工程clfwzx-oa-parent1.2、搭建工具类父模块common1.3、搭建工具类common的子模块1.4、搭建实体类模块model和项目模块service-oa 2、配置依赖…

2024最新最全【NMAP】零基础入门到精通

一、Nmap介绍 Nmap(Network Mapper&#xff0c;网络映射器)是一款开放源代码的网络探测和安全审核工具。它被设计用来快速扫描大型网络&#xff0c;包括主机探测与发现、开放的端口情况、操作系统与应用服务指纹识别、WAF识别及常见安全漏洞。它的图形化界面是Zenmap&#xff…

[AIGC] redis 持久化相关的几道面试题

文章目录 1. 什么是Redis持久化&#xff1f;2. Redis 的持久化机制是什么&#xff1f;各自的优缺点&#xff1f;2.1 RDB&#xff08;Redis DataBase&#xff09;&#xff0c;快照2.2 AOF&#xff08;Append Only File&#xff09;&#xff0c;日志 3. 优缺点是什么&#xff1f;…