创新实训2024.05.28日志:记忆化机制、基于MTPE与CoT技术的混合LLM对话机制

1. 带有记忆的会话

1.1. 查询会话历史记录

在利用大模型自身能力进行对话与解答时,最好对用户当前会话的历史记录进行还原,大模型能够更好地联系上下文进行解答。

在langchain chat chat的chat函数中,通过实现langchain框架提供的ChatMemory。就可以建立一个对话记录的缓冲区,随后读取历史会话记录到缓冲区,在对话时作为memory参数传入。

memory = ConversationBufferDBMemory(conversation_id=conversation_id,
                                                llm=model,
                                                message_limit=history_len)
                                                
chain = LLMChain(prompt=chat_prompt, llm=model, memory=memory)

而这个history_len,就会在Buffer初始化时,负责查找id为conversation_id最近的history_len的历史会话记录:

例如,如果history_len = 4,那么就查询前四条记录。

1.2. 与大模型进行对话

我将与大模型对话的过程封装起来,作为一个能够使用http协议进行访问的接口。

async def request_llm_chat(ca: LLMChat) -> dict:
    """
    生成llm对话请求
    包含参数有:
    1. query
    2. conv_id
    3. history_len
    4. model_name
    5. temperature
    6. prompt_name
    """
    request_body = {
        "query": ca.query,
        "conversation_id": ca.conv_id,
        "history_len": CHAT_ARGS["history_len"],
        "model_name": CHAT_ARGS["llm_models"][0],
        "temperature": CHAT_ARGS["temperature"],
        "prompt_name": ca.prompt_name
    }

    return await request(url=CHAT_ARGS["url"], request_body=request_body, prefix="data: ")

这里的参数解释一下:

  1. query:用户询问大模型的内容

  2. conv_id:会话的id

  3. history_len:前向检索的历史会话记录

  4. model_name:请求大模型的名字(因为可以同时部署多个大模型进行对话)

  5. temperature:LLM采样温度,用于控制文本生成的随机性。这个随机性不宜过高,过高大模型会随性发挥导致回答不准确;也不宜过低,过低大模型不敢做出回答。

  6. prompt_name:使用的prompt的模板,例如,with_history的模板如下:

    "with_history":
        'The following is a friendly conversation between a human and an AI. '
        'The AI is talkative and provides lots of specific details from its context. '
        'If the AI does not know the answer to a question, it truthfully says it does not know.\\n\\n'
        'Current conversation:\\n'
        '{history}\\n'
        'Human: {input}\\n'
        'AI:',
    

    提示AI,以下是AI之前与人类的对话记录,现在人类又给了一个输入,AI需要根据历史记录,对这个输入进行回答。

1.3. 记忆功能测试

现在我们来看一下这个大模型的记忆如何,这里我简单做了一个“你能记住我的名字吗”的小测试:

正例测试

先告诉大模型:“我的名字是xxx”

再紧接着在同一个conv_id的会话下问他:“我叫什么名字?”

他记住了我的名字。

反例测试

在看完一个正例后,我们再看一个反例:

现在我换了一个新的conv_id(相当于新创建一个会话),再问他我的名字,他就不知道了,说:“请告诉我你的名字。”

2. 与知识库对话

除了利用大模型本身的能力,我们还可以利用向量知识库检索相关的知识,再生成对应的回答。这和大模型依靠自身能力比对起来,优点是回答更加有依据、更加权威,缺点是如果检索不到相关的知识,那么几乎无法回答问题。

2.1. RAG技术的具体应用场景

检索知识库

首先我们开启一个异步操作,对相关知识库进行检索,返回匹配度最高的top k条相关资料。

        docs = await run_in_threadpool(search_docs,
                                       query=query,
                                       knowledge_base_name=knowledge_base_name,
                                       top_k=top_k,
                                       score_threshold=score_threshold)

词向量嵌入

其中search_docs依托于不同向量数据库的检索方式,例如在faiss知识库中:

    def do_search(self,
                  query: str,
                  top_k: int,
                  score_threshold: float = SCORE_THRESHOLD,
                  ) -> List[Tuple[Document, float]]:
        embed_func = EmbeddingsFunAdapter(self.embed_model)
        embeddings = embed_func.embed_query(query)
        with self.load_vector_store().acquire() as vs:
            docs = vs.similarity_search_with_score_by_vector(embeddings, k=top_k, score_threshold=score_threshold)
        return docs

我们先通过词嵌入模型(我们实验和部署时使用的词嵌入模型是bge-large-zh这个模型,由BAAI提供:BAAI/bge-large-zh · Hugging Face)将用户的输入嵌入为词向量,随后直接调用langchain封装好的函数检索top_k个相似度大于等于阈值的词向量。

随后我们把文档的内容拼接到上下文中:

context = "\\n".join([doc.page_content for doc in docs])

最终通过Langchain提供的与大模型对话的接口进行对话:

chain = LLMChain(prompt=chat_prompt, llm=model)

# Begin a task that runs in the background.
task = asyncio.create_task(wrap_done(
    chain.acall({"context": context, "question": query}),
    callback.done),
)

知识库问答需不需要带历史会话信息

经过我的实验,最好是不要带。因为优先级上历史会话信息会高于知识库检索出来的知识。用户之前的对话记录可能会影响到知识的客观性(也就是说大模型因为用户的对话舍弃了在回答中包含从知识库中检索出来的信息)。

2.2. Prompt工程

由于知识的客观性,我们需要让大模型尽可能客观地总结提炼知识,而非随意发挥:

"default":
    '<指令>根据已知信息,简洁和专业的来回答问题。如果无法从中得到答案,请说 “根据已知信息无法回答该问题”,'
    '不允许在答案中添加编造成分,答案请使用中文。 </指令>\\n'
    '<已知信息>{{ context }}</已知信息>\\n'
    '<问题>{{ question }}</问题>\\n',

例如此处建立的prompt模板就是要求大模型不得随意编造发挥,只能根据检索出来的知识进行回答。

而这个Prompt的模板格式,严格遵守了**(<指令>,(<问题>,<回答>))**的QA方式,其中<回答>是需要大模型给出的。

2.3. 知识库问答测试

存在相关文档

我们先来看一个能够检索得到相关文档/知识的例子:

可以看到大模型结合了知识库检索出来的所有相关知识进行了回答。

不存在相关文档

当然,知识库中可能不具有和用户输入比较相近的知识。但我们总不能不让大模型做出回复,所以此时我们只能转为依靠大模型自身能力作出解答这一模式:

3. 与搜索引擎进行对话

大模型也可以借助网络上能够检索到的一些信息进行解答。不过这里我的服务器代理还没配置好,查询搜索引擎时会出现连接超时的情况:

因此这一部分先放在这,等我把服务器配好再说。

4. 混合机制的对话

4.1. 为什么要把机制混合起来

经过微调的大模型的能力和训练时使用的语料/数据集的规模和质量显著相关。而知识库的知识也不能穷尽这个世界上所有有关易学的知识。搜索引擎检索到的内容也是鱼龙混杂,质量也可能不够高。这三个对话机制单拎出来,可能生成的回答质量都难以得到保证。

但这三种机制,恰好又是可以互为补充的:大模型首先自身要具备对专业性知识的理解和认知基础才能更好地运用知识库中检索出来的知识;知识库可以作为外接的知识来源提升大模型认知的深度和广度;而搜索引擎则能够更好地检索相关专业社区(专业的研究中心、论坛),为前二者提供更多补充。

因此我就想,能不能把这三种机制混合起来,让通过专业数据集进行训练的大模型在基于已有的认知基础上,把知识库和搜索引擎检索出来的知识系统地、有逻辑地整理成一个更加专业的回答?以此来显著提升回答的质量?

4.2. MTPE与CoT:渐增式文本生成

MTPE is short for Multi-Turn Prompt Engineering,这是LLM诞生后催生的一种提示工程技术(中文名可以翻译为多步提示工程)。他是基于CoT这一idea的技术,而后者是LLM领域内的一篇经典论文提出的:

Chain-of-Thought Prompting Elicits Reasoning in Large Language Models

这篇有谷歌的AI团队发表的论文中首先提到了一个简单的示例:

  1. 在Standard Prompting技术中,大模型有时会给出错误的解答,例如23-20+6=27这种错误。
  2. 在CoT技术中,大模型会详细给出每个问题的推理以及计算过程,且正确率大大提升。

这是怎么做到的?

CoT:引导式文本生成

这篇论文解释了"思维链提示"(chain-of thought prompting)对LLM尤其是大型LLM的提升作用。

思维链(Chain of Thought)是一种提示工具,用于帮助语言模型进行复杂的推理和思考过程。它通过引导模型逐步解决问题,以一系列连贯的步骤展示推理的思路和逻辑关系。

思维链提示的基本思想是将推理过程分解为多个步骤,并在每个步骤中指导模型逐步进行推理。每个步骤都通过自然语言描述,使模型能够理解和执行每个推理阶段所需的操作。

具体而言,思维链提示通常由多个中间步骤组成,每个中间步骤都解释了问题的一个方面或子问题。模型需要根据前一个步骤的结果和当前问题的要求来推断下一个步骤。通过这种逐步推理的方式,模型可以逐渐获得更多信息,并在整个推理过程中累积正确的推断。

这里Google团队给出了一张图,在GSM8K标准的benchmark中,CoT技术的Sr(Solve Rate)提升至57%,远超微调的GPT3以及标准提示工程技术,略胜之前历史最佳的表现。

在进行思维链提示时,需要将思维过程、推理过程告知大模型,随后大模型生成解答:

例如,在StrategyQA类下的问题:是还是否:梨会沉到水里吗?

引导过程如下:

  1. 为了解决这个问题,我们需要明确一个物理上的公式:

    $$ F_{buoyant} = \rho_{liquid} \cdot g \cdot V_{displaced} $$

  2. 当物体完全沉到水中时,有:

    $$ F_{buoyant} = \rho_{liquid} \cdot g \cdot V_{item} $$

  3. 因为物体完全沉到水中,所以浮力小于等于重力,也就是说:

    $$ F_{buoyant} ≤ G_{item} $$

  4. 我们知道物体的重力等于质量乘以重力加速度g,也就是:

    $$ G_{item} = m_{item} \cdot g $$

  5. 不等式两边展开得到:

    $$ \rho_{liquid} \cdot g \cdot V_{item} ≤ m_{item} \cdot g $$

  6. g≥0,两边约去,又因为:

    $$ m_{item} = \rho_{item} \cdot V_{item} $$

    因此我们得到:

    $$ \rho_{liquid} \cdot V_{item} ≤ \rho_{item} \cdot V_{item} $$

  7. 物体体积大于0,所以可以约去,最终我们得到:

    $$ \rho_{liquid} ≤ \rho_{item} $$

    则物体会沉于水中,反之不会。

  8. 现在请利用你的知识,获取梨和水的密度进行比较,根据第7.步的结论,给出回答

最终,大模型根据他的知识,得出梨会漂浮在水上的结论。并且他列出了获取梨的密度的过程以及与水的密度比较的过程

MTPE:CoT的具体应用

多步提示工程(Multi-turn Prompt Engineering)是指在人机交互或人工智能系统中,设计和使用一系列连贯的提示(prompts)来引导用户或AI通过多个步骤完成任务或获取信息的过程。这种方法在自然语言处理(NLP)和对话系统设计中尤其重要,因为它可以帮助系统更有效地理解和响应复杂的用户需求。

在设计多步提示时,需要考虑以下几个方面:

  • 上下文管理:系统需要能够理解和跟踪对话的上下文,以便提供相关的后续提示。
  • 用户意图识别:系统需要准确识别用户的意图,并根据意图提供相应的提示。
  • 灵活性和适应性:系统应该能够适应用户的不同回答,并灵活调整提示策略。
  • 用户体验:设计提示时要考虑用户体验,确保对话流畅自然,避免让用户感到困惑或沮丧。

假设我们现在已经获得了大模型分别利用自身能力、知识库、搜索引擎给出的解答,现在我们就可以构造出一个Prompt模板,来进行多步提示:

"mix_chat": """
    你是一个知无不言言无不尽的易学(周易)专家。先前我问了你一个易学方面的问题,你通过自身的能力、知识库检索以及搜索引擎检索的方式,给出了三个答案。\\n
    现在请你将这三个答案系统地整理成一篇针对原始问题的中文回答。\\n
    请你直接了当地给出回答,请一定不要添加任何诸如:\\n
    '根据您的要求,我将这三个答案系统地整理成一篇针对原始问题的中文回答。'、'好的,以下是xxx的回答’、'非常抱歉,我刚刚没有理解您的问题。'、'根据您的对话和我所掌握的资料,我为您整理了以下回答'等\\n
    这样与实际答案无关紧要的话!\\n
    此外,给出回答时,你一定不要重复原始问题!请务必记住,任何与答案正文无关的文本,均不要出现在回答中。\\n
    原始问题:\\n
    {question}\\n
    先前与你的对话如下:\\n
    {history}\\n
    你通过自身能力给出的解答如下:\\n
    {answer1}\\n
    你通过知识库检索给出的解答如下:\\n
    {answer2}\\n
    你通过搜索引擎检索给出的解答如下:\\n
    {answer3}\\n
    
    现在请你给出针对原始问题的中文回答。\\n
    AI:
"""
  1. 首先,我们告知大模型他的认知基础:你是一个知无不言言无不尽的易学(周易)专家。
  2. 其次,我们告知大模型上下文的metaData:先前我问了你一个易学方面的问题,你通过自身的能力、知识库检索以及搜索引擎检索的方式,给出了三个答案。
  3. 随后,我们规定,大模型给出的回答中,不得出现令实际用户迷惑的语句:例如 '根据您的要求,我将这三个答案系统地整理成一篇针对原始问题的中文回答。',因为用户原始的问题并没有**“三个问题”**。
  4. 我们把之前大模型三种机制下给出的解答附在对话中: 原始问题:\\n {question}\\n 先前与你的对话如下:\\n {history}\\n 你通过自身能力给出的解答如下:\\n {answer1}\\n 你通过知识库检索给出的解答如下:\\n {answer2}\\n 你通过搜索引擎检索给出的解答如下:\\n {answer3}\\n
  5. 最终,要求大模型给出解答:现在请你给出针对原始问题的中文回答。\\n

这就是一个MTPE在混合机制对话中的实际应用。

4.3. 接口实现

async def request_mix_chat(mc: MixChat) -> BaseResponse:
    """
    混合对话
    1. 先请求大模型以自身能力给出解答
    2. 再请求大模型检索知识库给出解答
    3. 最后请求大模型通过询问搜索引擎给出解答
    4. 最终将解答融合在一起返回
    """
    # 先请求大模型以自身能力给出解答
    llm_response = await request_llm_chat(LLMChat(query=mc.query, conv_id=mc.conv_id))
    if not llm_response["success"]:
        return BaseResponse(code=200, message="大模型请求失败", data={"error": f'{llm_response["error"]}'})

    # 请求知识库
    kb_response = await request_knowledge_base_chat(KBChat(query=mc.query, conv_id=mc.conv_id))
    if not kb_response["success"]:
        return BaseResponse(code=200, message="知识库请求失败", data={"error": f'{kb_response["error"]}'})

    # 请求搜索引擎
    search_response = await request_search_engine_chat(SEChat(query=mc.query, conv_id=mc.conv_id))
    if not search_response["success"]:
        return BaseResponse(code=200, message="搜索引擎请求失败", data={"error": f'{search_response["error"]}'})

    # 生成prompt
    prompt = get_mix_chat_prompt(question=mc.query, history=await gen_history(mc.conv_id),
                                 answer1=llm_response["data"]["text"], answer2=kb_response["data"]["answer"],
                                 answer3="")

    # 请求大模型
    response = await request_llm_chat(LLMChat(query=prompt, conv_id=mc.conv_id, prompt_name=mc.prompt_name))

    # 确保问题和回答原子性地入库
    with record_lock:
        add_record_to_conversation(mc.conv_id, mc.query, False)
        add_record_to_conversation(mc.conv_id, response["data"]["text"], True)

    return BaseResponse(code=200, message="混合对话请求成功", data={"answer": response["data"]["text"]})
  1. 首先,请求大模型以自身能力给出解答
  2. 请求大模型根据知识库的知识给出解答
  3. 请求大模型根据搜索引擎的检索结果给出解答
  4. 根据prompt模板生成多步prompt
  5. 请求大模型根据该上下文信息综合性地给出解答
  6. 返回该最终解答

4.4. 混合机制对话测试

这里我问了大模型一个周易中“逆向格义”这个概念相关示例的问题:

他给出的解答如下:

历史上有哪些在日常生活中运用逆向格义的例子?

逆向格义是一种思维方式,它强调从相反的角度来理解事物,从而得出更深刻的理解和解决问题的方法。在周易中,逆向格义被认为是一种有效的思维方式,可以帮助人们更全面地理解事物。以下是几个关于逆向格义的例子:

1. 卦象分析:在周易中,每个卦象都代表了一种特定的元素、方向和能量。通过逆向格义,我们可以从相反的角度来分析卦象,从而得出更全面的含义。例如,乾卦代表天、刚强、积极等,如果我们将乾卦的内涵 reversed,它就变成了坤卦,象征地、柔弱、消极。这种分析方法可以帮助我们更全面地理解卦象所代表的意义。

2. 爻辞解读:在周易的卦辞中,每一卦的爻(即阳爻和阴爻)都有特定的含义。通过逆向格义,我们可以从相反的角度来解读爻辞,从而得出更深刻的理解。例如,在一卦中,阳爻表示事物的发展,阴爻表示事物的衰退。如果我们将这个观念 reversed,那么阳爻就代表了事物的衰退,阴爻就代表了事物的发展。这种解读方法可以帮助我们更全面地理解爻辞所要传达的信息。

3. 人事决策:在周易预测中,我们常常需要根据卦象来判断事物的发展趋势和解决方案。通过逆向格义,我们可以从相反的角度来分析卦象所代表的意义,从而得出更全面的解决方案。例如,如果卦象显示事物发展趋势不利,那么我们可以考虑采取相反的行动,如增加投资、增加风险等,从而避免不利的结果。

4. 互传:在周易中,互传是一种特殊的卦象组合,它反映了事物之间的相互影响和变化。通过逆向格义,我们可以从互传中找到事物发展中的矛盾和问题,从而找到更好的解决方案。例如,在互传中,两个卦象相互影响,一个卦象代表了正面的力量,另一个卦象代表了负面的力量。我们可以通过逆向格义来理解互传中的矛盾,并找到解决问题的方法。

这些例子说明,逆向格义在周易中的运用可以帮助我们更全面地理解事物的发展趋势和变化,从而更好地解决问题。这种思维方式不仅限于周易,还可以应用于其他领域,帮助我们更好地理解问题并找到更好的解决方案。

而中间过程给出的解答如下:

其中第一段是大模型自身能力的,第二段是知识库的(搜索引擎在我做实验的时候还不可用)

大模型发现知识库的知识偏向于商业应用而非周易,因此大部分的解答来自于第一段。当知识库的知识与对话的topic相关性更大之后,将会更多的融合知识库的知识到最终回答中。

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

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

相关文章

虚拟化技术 分布式资源调度

一、实验内容 实现分布式资源调度 二、实验主要仪器设备及材料 安装有64位Windows操作系统的台式电脑或笔记本电脑&#xff0c;建议4C8G或以上配置已安装VMware Workstation Pro已安装Windows Server 2008 R2 x64已安装vCenter Server 三、实验步骤 将主机esxi1和esxi2加入…

【找出缺失的观测数据】python

思路&#xff1a; 主要在于分配剩余的部分分配问题 代码&#xff1a; class Solution:def missingRolls(self, rolls: List[int], mean: int, n: int) -> List[int]:m len(rolls)total_sum (n m) * meantoset total_sum - sum(rolls)# 检查 toset 是否在可能的范围内i…

R可视化:可发表的prism点图

介绍 可发表的prism点图 加载R包 knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE) library(tidyverse) library(ggpubr) library(ggprism)rm(list = ls()) options(stringsAsFactors = F)导入数据 data("iris")head(iris)处理数据 plotd…

git stash 命令

线上版本出现了bug&#xff0c;我们应该放下手头上的开发工作先将线上的bug修复&#xff0c;这个时候dev分支下的改动怎么处理&#xff1f; 是向分支行上提交代码还是直接切换到master分支下&#xff1f; 首先我们的开发工作还未完成&#xff0c;就把代码提交到分支上&#xf…

安装ROS 2 Jazzy Jalisco

参考&#xff1a; https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debians.html 先要安装一个ubuntu&#xff0c;对老旧硬件最友好的版本Lubuntu&#xff1a; 安装Lubuntu24.04-CSDN博客 过程&#xff1a; 按文档一步步走下去&#xff1a; 遇到问题查找通用案…

(三)MobaXterm、VSCode、Pycharm ssh连接服务器并使用

背景&#xff1a;根据前两篇文章操作完成后&#xff0c; 手把手教学&#xff0c;一站式安装ubuntu及配置服务器-CSDN博客 手把手教学&#xff0c;一站式教你实现服务器&#xff08;Ubuntu&#xff09;Anaconda多用户共享-CSDN博客 课题组成员每人都有自己的帐号了&#xff0…

linux文件编程api: creat

1.基本信息 功能 创建新文件 头文件 #include<fcntl.h> 函数形式 int creat(const char *pathname, mode_t mode); 返回值 如果成功&#xff0c;则返回文件描述符号 如果失败&#xff0c;则返回-1 参数 pathname: 创建的文件名 mode: 新建文件时&#xff0c;文件权限…

企业微信hook接口协议,ipad协议http,已读消息

已读消息 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信send_userid是long要发送的人idisRoom是bool是否是群消息 请求示例 {"uuid":"1753cdff-0501-42fe-bb5a-2a4b9629f7fb","send_userid":788130255…

C++入门3——类与对象(2)

1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。可是空类中真的什么都没有吗&#xff1f; 其实并不是的&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&#xf…

《Java数据结构》--单链表详解

一.单链表的概念 1.概念 单链表是一种物理存储结构是非连续&#xff0c;非线性的但是在逻辑结构上是连续且线性的&#xff0c;链表是通过一个个结点来实现的&#xff0c;使每个相邻结点之间存在一定关系来将所有结点串起来&#xff0c;在物理存储上像是一条链子。 2.链表的原…

《Ai企业知识库》-rasa X安装使用

背景&#xff1a; Rasa X 是一个为构建、改进和管理对话式AI助手而设计的工具。它是Rasa开源机器学习框架的一个扩展&#xff0c;旨在实现“对话驱动开发”&#xff08;Conversation-Driven Development&#xff09;。Rasa X 主要特点包括&#xff1a; 交互式学习&#xff1a;…

二叉树的实现(递归实现)

前言&#xff1a;本文讲解通过递归的方式实现二叉树的一些基本接口。 目录 通过左右子树的方式实现二叉树&#xff1a; 二叉树的遍历&#xff1a; 求二叉树结点的个数&#xff1a; 二叉树所有节点的个数&#xff1a; 二叉树叶子节点的个数&#xff1a; 求第k层节点的节点…

传输层安全性 (TLS)

传输层安全 (TLS) 旨在提供传输层的安全性。TLS 源自称为安全套接字层 (SSL)的安全协议。 TLS 确保任何第三方都无法窃听或篡改任何消息。 TLS 有几个好处&#xff1a; ● 加密&#xff1a; TLS/SSL 可以帮助使用加密来保护传输的数据。 ● 互操作性&#xff1a; TLS/S…

PHP框架 Laravel

现在因为公司需求&#xff0c;需要新开一个Laravel框架的项目&#xff0c;毫无疑问&#xff0c;我又被借调过去了&#xff0c;最近老是被借调&#xff0c;有点阴郁&#xff0c;不过反观来看&#xff0c;这也是好事&#xff0c;又可以复习和巩固一下自己的知识点&#xff0c;接下…

第八大奇迹

目录 题目描述 输入描述 输出描述 输入输出样例 示例 输入 输出 运行限制 原题链接 代码思路 题目描述 在一条 R 河流域&#xff0c;繁衍着一个古老的名族 Z。他们世代沿河而居&#xff0c;也在河边发展出了璀璨的文明。 Z 族在 R 河沿岸修建了很多建筑&#xff0c…

[Algorithm][动态规划][简单多状态DP问题][买卖股票的最佳时机 III][买卖股票的最佳时机 Ⅳ]详细讲解

目录 1.买卖股票的最佳时机 III1.题目链接2.算法原理详解3.代码实现 2.买卖股票的最佳时机 IV1.题目链接2.算法原理详解3.代码实现 1.买卖股票的最佳时机 III 1.题目链接 买卖股票的最佳时机 III 2.算法原理详解 注意&#xff1a;本题为了便于初始化&#xff0c;有较多细节服…

Java之Writer类:探索Java中的输出流

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

在CentOS 8上卸载与安装MySQL 8的详细步骤

关键词&#xff1a;MySQL 8安装、CentOS 8、YUM源配置、卸载MySQL、MySQL残留文件删除、首次登录MySQL临时密码、服务状态检查、MySQL社区服务器 阅读建议&#xff1a;本文适合需要在CentOS 8操作系统上部署最新MySQL 8数据库的系统管理员或开发者阅读。文中步骤简洁清晰&#…

Spring+SpringBoot面试总结(近两万字)

SpringSpringBoot面试总结 一、Spring Bean1.1、bean的生命周期&#xff08;对象的创建使用销毁&#xff09;1.1.1、准备工作1.1.2、创建Bean对象1.1.3、注册销毁 1.2、 bean的作用域1.2.1、配置方式 1.3、 spring 自动装配 bean 有哪些方式&#xff08;存疑存疑&#xff09;1.…

452. 用最少数量的箭引爆气球(中等)

452. 用最少数量的箭引爆气球 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;452. 用最少数量的箭引爆气球 2.详细题解 引爆所有气球&#xff0c;弓箭数要最少&#xff0c;那么每支弓箭尽量多的引爆气球&#xff0c;采用贪心策略。对于…