构建LangChain应用程序的示例代码:55、如何实现多代理模拟,其中特权代理决定谁发言。这遵循与多代理分散发言者选择相反的选择方案
示例展示了如何实现一个多代理模拟,其中一个特权代理决定谁来发言。
这遵循与多代理分散式发言人选择相反的选择方案。
我们在一个虚构的新闻网络模拟环境中展示这种方法的一个例子。这个例子将展示我们如何实现能够:
- 在说话前思考
- 终止对话
的代理。
导入LangChain相关模块
import functools
import random
from collections import OrderedDict
from typing import Callable, Listimport tenacity
from langchain.output_parsers import RegexParser
from langchain.prompts import (PromptTemplate,
)
from langchain.schema import (HumanMessage,SystemMessage,
)
from langchain_openai import ChatOpenAI# 导入所需的Python模块和LangChain组件
# 包括功能性工具、随机数生成、有序字典、类型提示
# 以及LangChain的输出解析器、提示模板、消息模式和OpenAI聊天模型
DialogueAgent 和 DialogueSimulator 类
我们将使用在其他示例多人龙与地下城和分散式发言人选择中定义的相同 DialogueAgent 和 DialogueSimulator 类。
class DialogueAgent:def __init__(self,name: str,system_message: SystemMessage,model: ChatOpenAI,) -> None:self.name = nameself.system_message = system_messageself.model = modelself.prefix = f"{self.name}: "self.reset()def reset(self):self.message_history = ["Here is the conversation so far."]def send(self) -> str:"""应用聊天模型到消息历史并返回消息字符串"""message = self.model.invoke([self.system_message,HumanMessage(content="\n".join(self.message_history + [self.prefix])),])return message.contentdef receive(self, name: str, message: str) -> None:"""将{name}说的{message}连接到消息历史中"""self.message_history.append(f"{name}: {message}")class DialogueSimulator:def __init__(self,agents: List[DialogueAgent],selection_function: Callable[[int, List[DialogueAgent]], int],) -> None:self.agents = agentsself._step = 0self.select_next_speaker = selection_functiondef reset(self):for agent in self.agents:agent.reset()def inject(self, name: str, message: str):"""用{name}的{message}启动对话"""for agent in self.agents:agent.receive(name, message)# 增加时间步self._step += 1def step(self) -> tuple[str, str]:# 1. 选择下一个说话者speaker_idx = self.select_next_speaker(self._step, self.agents)speaker = self.agents[speaker_idx]# 2. 下一个说话者发送消息message = speaker.send()# 3. 每个人接收消息for receiver in self.agents:receiver.receive(speaker.name, message)# 4. 增加时间步self._step += 1return speaker.name, message# 定义对话代理类,包含初始化、重置、发送和接收消息的方法
# 定义对话模拟器类,包含初始化、重置、注入消息和执行一步模拟的方法
DirectorDialogueAgent 类
DirectorDialogueAgent 是一个特权代理,负责选择其他代理中的哪一个下一个发言。这个代理负责
- 通过选择何时让哪个代理发言来引导对话
- 终止对话。
为了实现这样一个代理,我们需要解决几个问题。
首先,为了引导对话,DirectorDialogueAgent 需要在一条消息中(1)反思已经说过的内容,(2)选择下一个代理,以及(3)提示下一个代理发言。虽然可能可以提示LLM在同一个调用中执行所有三个步骤,但这需要编写自定义代码来解析输出的消息以提取选择的下一个代理。这不太可靠,因为LLM可以用不同的方式表达它如何选择下一个代理。
相反,我们可以做的是将步骤(1-3)明确地分成三个单独的LLM调用。首先,我们会要求DirectorDialogueAgent反思到目前为止的对话并生成一个响应。然后我们提示DirectorDialogueAgent输出下一个代理的索引,这很容易解析。最后,我们将选定的下一个代理的名字传回DirectorDialogueAgent,要求它提示下一个代理发言。
其次,简单地提示DirectorDialogueAgent决定何时终止对话通常会导致DirectorDialogueAgent立即终止对话。为了解决这个问题,我们随机抽样一个伯努利变量来决定对话是否应该终止。根据这个变量的值,我们将注入一个自定义提示,告诉DirectorDialogueAgent继续对话或终止对话。
class IntegerOutputParser(RegexParser):def get_format_instructions(self) -> str:return "Your response should be an integer delimited by angled brackets, like this: <int>."# 定义整数输出解析器,用于解析输出中的整数class DirectorDialogueAgent(DialogueAgent):def __init__(self,name,system_message: SystemMessage,model: ChatOpenAI,speakers: List[DialogueAgent],stopping_probability: float,) -> None:super().__init__(name, system_message, model)self.speakers = speakersself.next_speaker = ""self.stop = Falseself.stopping_probability = stopping_probabilityself.termination_clause = "Finish the conversation by stating a concluding message and thanking everyone."self.continuation_clause = "Do not end the conversation. Keep the conversation going by adding your own ideas."# 1. 有一个用于生成对前一个说话者的响应的提示self.response_prompt_template = PromptTemplate(input_variables=["message_history", "termination_clause"],template=f"""{{message_history}}Follow up with an insightful comment.
{{termination_clause}}
{self.prefix}""",)# 2. 有一个用于决定下一个说话者的提示self.choice_parser = IntegerOutputParser(regex=r"<(\d+)>", output_keys=["choice"], default_output_key="choice")self.choose_next_speaker_prompt_template = PromptTemplate(input_variables=["message_history", "speaker_names"],template=f"""{{message_history}}Given the above conversation, select the next speaker by choosing index next to their name:
{{speaker_names}}{self.choice_parser.get_format_instructions()}Do nothing else.""",)# 3. 有一个用于提示下一个说话者发言的提示self.prompt_next_speaker_prompt_template = PromptTemplate(input_variables=["message_history", "next_speaker"],template=f"""{{message_history}}The next speaker is {{next_speaker}}.
Prompt the next speaker to speak with an insightful question.
{self.prefix}""",)def _generate_response(self):# 如果self.stop = True,那么我们将注入带有终止条款的提示sample = random.uniform(0, 1)self.stop = sample < self.stopping_probabilityprint(f"\tStop? {self.stop}\n")response_prompt = self.response_prompt_template.format(message_history="\n".join(self.message_history),termination_clause=self.termination_clause if self.stop else "",)self.response = self.model.invoke([self.system_message,HumanMessage(content=response_prompt),]).contentreturn self.response@tenacity.retry(stop=tenacity.stop_after_attempt(2),wait=tenacity.wait_none(), # 重试之间无等待时间retry=tenacity.retry_if_exception_type(ValueError),before_sleep=lambda retry_state: print(f"ValueError occurred: {retry_state.outcome.exception()}, retrying..."),retry_error_callback=lambda retry_state: 0,) # 当所有重试都用尽时的默认值def _choose_next_speaker(self) -> str:speaker_names = "\n".join([f"{idx}: {name}" for idx, name in enumerate(self.speakers)])choice_prompt = self.choose_next_speaker_prompt_template.format(message_history="\n".join(self.message_history + [self.prefix] + [self.response]),speaker_names=speaker_names,)choice_string = self.model.invoke([self.system_message,HumanMessage(content=choice_prompt),]).contentchoice = int(self.choice_parser.parse(choice_string)["choice"])return choicedef select_next_speaker(self):return self.chosen_speaker_iddef send(self) -> str:"""应用聊天模型到消息历史并返回消息字符串"""# 1. 生成并保存对前一个说话者的响应self.response = self._generate_response()if self.stop:message = self.responseelse:# 2. 决定下一个说话者self.chosen_speaker_id = self._choose_next_speaker()self.next_speaker = self.speakers[self.chosen_speaker_id]print(f"\tNext speaker: {self.next_speaker}\n")# 3. 提示下一个说话者发言next_prompt = self.prompt_next_speaker_prompt_template.format(message_history="\n".join(self.message_history + [self.prefix] + [self.response]),next_speaker=self.next_speaker,)message = self.model.invoke([self.system_message,HumanMessage(content=next_prompt),]).contentmessage = " ".join([self.response, message])return message# 定义导演对话代理类,继承自DialogueAgent
# 包含生成响应、选择下一个说话者和发送消息的方法
# 使用tenacity库进行重试处理
定义参与者和话题
topic = "The New Workout Trend: Competitive Sitting - How Laziness Became the Next Fitness Craze"
director_name = "Jon Stewart"
agent_summaries = OrderedDict({"Jon Stewart": ("Host of the Daily Show", "New York"),"Samantha Bee": ("Hollywood Correspondent", "Los Angeles"),"Aasif Mandvi": ("CIA Correspondent", "Washington D.C."),"Ronny Chieng": ("Average American Correspondent", "Cleveland, Ohio"),}
)
word_limit = 50# 定义讨论话题、主持人名称、参与者信息和字数限制
生成系统消息
agent_summary_string = "\n- ".join([""]+ [f"{name}: {role}, located in {location}"for name, (role, location) in agent_summaries.items()]
)conversation_description = f"""This is a Daily Show episode discussing the following topic: {topic}.The episode features {agent_summary_string}."""agent_descriptor_system_message = SystemMessage(content="You can add detail to the description of each person."
)def generate_agent_description(agent_name, agent_role, agent_location):agent_specifier_prompt = [agent_descriptor_system_message,HumanMessage(content=f"""{conversation_description}Please reply with a creative description of {agent_name}, who is a {agent_role} in {agent_location}, that emphasizes their particular role and location.Speak directly to {agent_name} in {word_limit} words or less.Do not add anything else."""),]agent_description = ChatOpenAI(temperature=1.0)(agent_specifier_prompt).contentreturn agent_descriptiondef generate_agent_header(agent_name, agent_role, agent_location, agent_description):return f"""{conversation_description}Your name is {agent_name}, your role is {agent_role}, and you are located in {agent_location}.Your description is as follows: {agent_description}You are discussing the topic: {topic}.Your goal is to provide the most informative, creative, and novel perspectives of the topic from the perspective of your role and your location.
"""def generate_agent_system_message(agent_name, agent_header):return SystemMessage(content=(f"""{agent_header}
You will speak in the style of {agent_name}, and exaggerate your personality.
Do not say the same things over and over again.
Speak in the first person from the perspective of {agent_name}
For describing your own body movements, wrap your description in '*'.
Do not change roles!
Do not speak from the perspective of anyone else.
Speak only from the perspective of {agent_name}.
Stop speaking the moment you finish speaking from your perspective.
Never forget to keep your response to {word_limit} words!
Do not add anything else."""))agent_descriptions = [generate_agent_description(name, role, location)for name, (role, location) in agent_summaries.items()
]
agent_headers = [generate_agent_header(name, role, location, description)for (name, (role, location)), description in zip(agent_summaries.items(), agent_descriptions)
]
agent_system_messages = [generate_agent_system_message(name, header)for name, header in zip(agent_summaries, agent_headers)
]# 生成代理描述、代理头部和系统消息
# 使用OpenAI聊天模型生成创意描述
# 组合生成每个代理的完整系统消息
for name, description, header, system_message in zip(agent_summaries, agent_descriptions, agent_headers, agent_system_messages
):print(f"\n\n{name} Description:")print(f"\n{description}")print(f"\nHeader:\n{header}")print(f"\nSystem Message:\n{system_message.content}")# 打印每个代理的描述、头部和系统消息
使用LLM详细阐述讨论话题
topic_specifier_prompt = [SystemMessage(content="You can make a task more specific."),HumanMessage(content=f"""{conversation_description}Please elaborate on the topic. Frame the topic as a single question to be answered.Be creative and imaginative.Please reply with the specified topic in {word_limit} words or less. Do not add anything else."""),
]
specified_topic = ChatOpenAI(temperature=1.0)(topic_specifier_prompt).contentprint(f"Original topic:\n{topic}\n")
print(f"Detailed topic:\n{specified_topic}\n")# 使用OpenAI聊天模型生成更详细的话题描述
# 将话题转化为一个需要回答的问题
定义说话者选择函数
最后我们将定义一个说话者选择函数 select_next_speaker,它接受每个代理的出价并选择出价最高的代理(随机打破平局)。
我们将定义一个 ask_for_bid 函数,它使用我们之前定义的 bid_parser 来解析代理的出价。我们将使用 tenacity 来装饰 ask_for_bid,以便在代理的出价无法正确解析时多次重试,并在最大尝试次数后产生默认出价0。
def select_next_speaker(step: int, agents: List[DialogueAgent], director: DirectorDialogueAgent
) -> int:"""如果步骤是偶数,则选择导演否则,由导演选择下一个说话者。"""# 导演在奇数步骤说话if step % 2 == 1:idx = 0else:# 这里导演选择下一个说话者idx = director.select_next_speaker() + 1 # +1 因为我们排除了导演return idx# 定义选择下一个说话者的函数
# 在奇数步骤选择导演,否则由导演选择
主循环
director = DirectorDialogueAgent(name=director_name,system_message=agent_system_messages[0],model=ChatOpenAI(temperature=0.2),speakers=[name for name in agent_summaries if name != director_name],stopping_probability=0.2,
)agents = [director]
for name, system_message in zip(list(agent_summaries.keys())[1:], agent_system_messages[1:]
):agents.append(DialogueAgent(name=name,system_message=system_message,model=ChatOpenAI(temperature=0.2),))# 创建导演代理和其他对话代理
simulator = DialogueSimulator(agents=agents,selection_function=functools.partial(select_next_speaker, director=director),
)
simulator.reset()
simulator.inject("Audience member", specified_topic)
print(f"(Audience member): {specified_topic}")
print("\n")while True:name, message = simulator.step()print(f"({name}): {message}")print("\n")if director.stop:break# 创建对话模拟器并运行模拟
# 注入指定话题并循环执行模拟步骤
# 直到导演决定停止对话
总结
本文介绍了如何实现一个多代理模拟系统,其中一个特权代理决定谁来发言。这与分散式发言人选择方案相反。文章以一个虚构的新闻网络模拟为例,展示了如何实现能够在说话前思考并终止对话的代理。
扩展知识
-
多代理系统:这是人工智能和自然语言处理领域的一个重要研究方向,涉及多个AI代理之间的交互和协作。这种系统可以模拟复杂的社会互动,用于各种应用,如虚拟助手、游戏AI和社会模拟。
-
对话管理:在这个示例中,导演代理负责管理对话流程。这反映了现实世界中的对话管理策略,如在会议或访谈中由主持人引导讨论。
-
自然语言生成(NLG):系统中的每个代理都使用NLG技术来生成响应。这涉及到根据上下文和角色生成连贯、相关和自然的语言输出。
-
角色扮演AI:每个代理都被赋予了特定的角色和个性。这种技术可以用于创建更真实和引人入胜的AI角色,用于娱乐、教育或训练目的。
-
概率决策:使用随机抽样来决定是否结束对话是一种简单但有效的方法,可以引入不可预测性和多样性。在更复杂的系统中,这可能涉及更高级的概率模型和决策理论。
相关文章:
构建LangChain应用程序的示例代码:55、如何实现多代理模拟,其中特权代理决定谁发言。这遵循与多代理分散发言者选择相反的选择方案
示例展示了如何实现一个多代理模拟,其中一个特权代理决定谁来发言。 这遵循与多代理分散式发言人选择相反的选择方案。 我们在一个虚构的新闻网络模拟环境中展示这种方法的一个例子。这个例子将展示我们如何实现能够: 在说话前思考终止对话 的代理。 导入LangChain相关模块…...
船舶雷达与导航系统选择7/8防水插座的原因分析
概述 船舶雷达与导航系统在现代航海中扮演着至关重要的角色,它们为船舶提供准确的导航信息,确保航行的安全和效率。在这些系统中,7/8防水插座的使用尤为重要,因为它们能够在恶劣的海上环境中提供稳定的电力和信号连接。接下来&am…...
墨烯的C语言技术栈-C语言基础-006
六.常量 C语言的常量为 字面常量 const修饰的常变量 #define定义的 枚举常量 int main() { // 四个都是字面常量 30; 3.14; "w"; // 字符常量 "abc"; // const修饰的常变量 const int a 10; // 在C语言中,const修饰的a,本质是变量,但不能直…...
常用SHELL命令
在 Unix/Linux 系统中,除了基本的文件和目录操作命令外,还有许多强大的工具命令,用于文本处理、系统监控、文件操作等。以下是一些常用的 Shell 命令,特别是类似 sed 和 awk 的文本处理工具: 文本处理命令 sed - 流编…...
Python脚本:将Word文档转换为Excel文件
引言 在文档处理中,我们经常需要将Word文档中的内容转换成其他格式,如Excel,以便更好地进行数据分析和报告。针对这一需求,我编写了一个Python脚本,能够批量处理指定目录下的Word文档,将其内容结构化并转换…...
【单链表】03 设L为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值。
🕺作者: 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux算法题上机准备 😘欢迎 ❤️关注 👍点赞 🙌收藏 ✍️留言 题目 设L为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值。 算法…...
鸿蒙开发设备管理:【@ohos.vibrator (振动)】
振动 说明: 开发前请熟悉鸿蒙开发指导文档:gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 本模块首批接口从API version 8开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。 导入模块 imp…...
【信息学奥赛】CSP-J/S初赛07 排序算法及其他算法在初赛中的考察
本专栏👉CSP-J/S初赛内容主要讲解信息学奥赛的初赛内容,包含计算机基础、初赛常考的C程序和算法以及数据结构,并收集了近年真题以作参考。 如果你想参加信息学奥赛,但之前没有太多C基础,请点击👉专栏&#…...
第N7周:seq2seq翻译实战-pytorch复现-小白版
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 理论基础 seq2seq(Sequence-to-Sequence)模型是一种用于机器翻译、文本摘要等序列转换任务的框架。它由两个主要的递归神经网络&#…...
java集合(1)
目录 一.集合概述 二. 集合体系概述 1. Collection接口 1.1 List接口 1.2 Set接口 2. Map接口 三. ArrayList 1.ArrayList常用方法 2.ArrayList遍历 2.1 for循环 2.2 增强for循环 2.3 迭代器遍历 一.集合概述 我们经常需要存储一些数据类型相同的元素,之前我们学过…...
分布式数据库HBase:从零开始了解列式存储
在接触过大量的传统关系型数据库后你可能会有一些新的问题: 无法整理成表格的海量数据该如何储存? 在数据非常稀疏的情况下也必须将数据存储成关系型数据库吗? 除了关系型数据库我们是否还有别的选择以应对Web2.0时代的海量数据? 如果你也曾经想到过这些问题, 那么HBase将是…...
接口测试流程及测试点!
一、什么时候开展接口测试 1.项目处于开发阶段,前后端联调接口是否请求的通?(对应数据库增删改查)--开发自测 2.有接口需求文档,开发已完成联调(可以转测),功能测试展开之前 3.专…...
已经安装deveco-studio-4.1.3.500的基础上安装deveco-studio-3.1.0.501
目录标题 1、执行exe文件后安装即可2、双击devecostudio64_3.1.0.501.exe2.1、安装Note (注意和4.1的Note放不同目录)2.2、安装ohpm (注意和4.1版本的ohpm放不同目录)2.3、安装SDK (注意和4.1版本的SDK放不同目录) 1、执行exe文件后安装即可 2、双击devecostudio64_3.1.0.501.e…...
【C++】 解决 C++ 语言报错:Use of Uninitialized Variable
文章目录 引言 使用未初始化的变量(Use of Uninitialized Variable)是 C 编程中常见且危险的错误之一。它通常在程序试图使用尚未赋值的变量时发生,导致程序行为不可预测,可能引发运行时错误、数据损坏,甚至安全漏洞。…...
2024年7月6日 十二生肖 今日运势
小运播报:2024年7月6日,星期六,农历六月初一 (甲辰年庚午月辛未日),法定节假日。 红榜生肖:猪、马、兔 需要注意:狗、鼠、牛 喜神方位:西南方 财神方位:正…...
ubuntu丢失网络/网卡的一种原因解决方案
现象 开机进入ubuntu后发现没有网络,无论是在桌面顶部状态栏的快捷键 还是 系统设置中,都没有”有线网“和”无线网“的选项,”代理“的选项是有的使用数据线连接电脑和手机,手机开启”通过usb共享网络“,还是没有任何…...
第6篇 共识机制深度解析:PoW、PoS、DPoS和PBFT
在区块链的世界里,有一个非常重要的概念叫做“共识机制”。它就像是区块链的心脏,保证大家在这条链上的信息是可靠的、不可篡改的。今天,我们就来通俗易懂地聊聊区块链里的四大共识机制:工作量证明(PoW)、权益证明(PoS)、委托权益证明(DPoS)和拜占庭容错(PBFT)。为…...
Windows环境使用SpringBoot整合Minio平替OSS
目录 配置Minio环境 一、下载minio.exe mc.exe 二、设置用户名和密码 用管理员模式打开cmd 三、启动Minio服务器 四、访问WebUI给的地址 SpringBoot整合Minio 一、配置依赖,application.yml 二、代码部分 FileVO MinioConfig MinioUploadService MinioController 三…...
LeetCode 196, 73, 105
目录 196. 删除重复的电子邮箱题目链接表要求知识点思路代码 73. 矩阵置零题目链接标签简单版思路代码 优化版思路代码 105. 从前序与中序遍历序列构造二叉树题目链接标签思路代码 196. 删除重复的电子邮箱 题目链接 196. 删除重复的电子邮箱 表 表Person的字段为id和email…...
在Apache HTTP服务器上配置 TLS加密
安装mod_ssl软件包 [rootlocalhost conf.d]# dnf install mod_ssl -y此时查看监听端口多了一个443端口 自己构造证书 [rootlocalhost conf.d]# cd /etc/pki/tls/certs/ [rootlocalhost certs]# openssl genrsa > jiami.key [rootlocalhost certs]# openssl req -utf8 -n…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
C++11 constexpr和字面类型:从入门到精通
文章目录 引言一、constexpr的基本概念与使用1.1 constexpr的定义与作用1.2 constexpr变量1.3 constexpr函数1.4 constexpr在类构造函数中的应用1.5 constexpr的优势 二、字面类型的基本概念与使用2.1 字面类型的定义与作用2.2 字面类型的应用场景2.2.1 常量定义2.2.2 模板参数…...
