LangChain开发(五)消息管理与聊天历史存储
文章目录
- 消息存储在内存
- 使用单参数session_id
- 配置会话唯一键
- 消息持久化到redis
- 安装redis依赖
- 安装redis
- 调用聊天接口,看Redis是否存储历史记录
- 裁剪消息
- 总结记忆
- 源码地址
- 参考资料
消息存储在内存
我们展示一个简单的示例,其中聊天历史保存在内存中,此处通过全局Python字典实现。
我们构建一个名为get_session_history
的可调用对象,引用此字典以返回ChatMessageHistory
实例。通过在运行时向RunnableWithMessageHistory
传递配置,可以指定可配置对象的参数。默认情况下,期望配置参数是一个字符串session_id
。可以通过history_factory_config
关键字参数进行调整。
使用单参数session_id
# 基于运行内存存储记忆,使用session_id字段
import os
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI
from langchain_core.chat_history import BaseChatMessageHistory# 创建一个聊天提示词模板
prompt = ChatPromptTemplate.from_messages([("system","You are a helpful assistant who's good at {ability}. Respond in 20 words or fewer"),# 历史消息占位符MessagesPlaceholder(variable_name="history"),("human", "{input}"),
])# 这里使用阿里百炼的api,用官网的或者其他第三方网站也可以
llm = ChatOpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",model="qwen-turbo",temperature=0,
)runnable = prompt | llmstore = {}# 定义获取会话历史的函数,入参是session_id, 返回是会话历史记录
def get_session_history(session_id: str) -> BaseChatMessageHistory:if session_id not in store:store[session_id] = ChatMessageHistory()return store[session_id]# 创建一个带历史记录的Runnable
with_message_history = RunnableWithMessageHistory(runnable,get_session_history,input_messages_key="input",history_messages_key="history"
)response = with_message_history.invoke({"ability": "math", "input": "余弦是什么意思?"},config={"configurable": {"session_id": "abc123"}},
)
print(response)response = with_message_history.invoke({"ability": "math", "input": "什么?"},config={"configurable": {"session_id": "abc123"}},
)
print(response)response = with_message_history.invoke({"ability": "math", "input": "什么?"},config={"configurable": {"session_id": "def234"}},
)
print(response)
输出示例:
content='余弦是一个数学函数,定义为在单位圆上角度的邻边与斜边之比,在三角形中表示角度相邻边与最长边的比例。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 34, 'prompt_tokens': 37, 'total_tokens': 71, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-turbo', 'system_fingerprint': None, 'id': 'chatcmpl-eb59cccb-0100-9dfd-a908-ffb02ef7bd80', 'finish_reason': 'stop', 'logprobs': None} id='run-d9dcb77a-846e-465e-af30-59d3db9dc420-0' usage_metadata={'input_tokens': 37, 'output_tokens': 34, 'total_tokens': 71, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
content='余弦是三角函数之一,表示角的邻边与斜边的比值,在直角三角形中定义。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 26, 'prompt_tokens': 83, 'total_tokens': 109, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-turbo', 'system_fingerprint': None, 'id': 'chatcmpl-2934ecd5-f194-9ebf-b28f-6c6fb416f30a', 'finish_reason': 'stop', 'logprobs': None} id='run-cc88f2eb-ecfd-4531-b40d-5a31622b42fe-0' usage_metadata={'input_tokens': 83, 'output_tokens': 26, 'total_tokens': 109, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
content='您好!请明确您的问题,我会尽力用20字以内解答。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 16, 'prompt_tokens': 34, 'total_tokens': 50, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-turbo', 'system_fingerprint': None, 'id': 'chatcmpl-c16193e8-a637-963f-b8b1-0699e88ce114', 'finish_reason': 'stop', 'logprobs': None} id='run-507d33d7-00b6-4b2d-b328-ffdcd324836f-0' usage_metadata={'input_tokens': 34, 'output_tokens': 16, 'total_tokens': 50, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
# 第二句话和第一句话用了同样的session_id,所以第二句话获取到了第一句话的记录传给了大模型,所以第二句话接上了第一句话 # 第三局话用了不同的session_id,所以第三句话没有获取到历史记录传给大模型,所以大模型不知道是啥意思。
配置会话唯一键
我们可以通过向history_factory_config
参数传递一个ConfigurableFieldSpec
对象列表来自定义跟踪消息历史的配置参数。下面我们使用了两个参数:user_id
和conversation_id
。
# 基于内存存储记忆,使用user_id、conversation_id字段import os
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI
from langchain_core.chat_history import BaseChatMessageHistory
# 引入langchain会话配置
from langchain_core.runnables import ConfigurableFieldSpecprompt = ChatPromptTemplate.from_messages([("system","You are a helpful assistant who's good at {ability}. Respond in 20 words or fewer"),MessagesPlaceholder(variable_name="history"),("human", "{input}"),
])model = ChatOpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",model="qwen-turbo",temperature=0,
)
runnable = prompt | modelstore = {}def get_session_history(user_id: str, conversation_id: str) -> BaseChatMessageHistory:if (user_id, conversation_id) not in store:store[(user_id, conversation_id)] = ChatMessageHistory()return store[(user_id, conversation_id)]with_message_history = RunnableWithMessageHistory(runnable,get_session_history,input_messages_key="input",history_messages_key="history",history_factory_config=[ConfigurableFieldSpec(id="user_id",annotation=str,name="User ID",description="用户唯一标识符",default="",is_shared=True), ConfigurableFieldSpec(id="conversation_id",annotation=str,name="Conversation ID",description="对话的唯一标识符",default="",is_shared=True)]
)response = with_message_history.invoke({"ability": "math", "input": "余弦是什么意思?"},config={"configurable": {"user_id": "abc123", "conversation_id": "1"}},
)
print(response)response = with_message_history.invoke({"ability": "math", "input": "什么?"},config={"configurable": {"user_id": "abc123", "conversation_id": "1"}},
)
print(response)response = with_message_history.invoke({"ability": "math", "input": "什么?"},config={"configurable": {"user_id": "abc123", "conversation_id": "2"}},
)
print(response)
消息持久化到redis
请查看memory integrations页面,了解使用Redis和其他提供程序实现聊天消息历史的方法。这里我们演示使用内存中的ChatMessageHistory
以及使用RedisChatMessageHistory
进行更持久存储。
安装redis依赖
pip install redis
安装redis
docker安装
docker run -p 6379:6379 --name redis -d redis
或参考以下链接安装
Windows系统启动Redis
调用聊天接口,看Redis是否存储历史记录
更新消息历史实现只需要我们定义一个新的可调用对象,这次返回一个RedisChatMessageHistory
示例:
# 消息持久化到redis
import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import RedisChatMessageHistoryprompt = ChatPromptTemplate.from_messages([("system","You are a helpful assistant who's good at {ability}. Respond in 20 words or fewer"),MessagesPlaceholder(variable_name="history"),("human", "{input}"),
])llm = ChatOpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",model="qwen-turbo",temperature=0,
)
runnable = prompt | llmstore = {}REDIS_URL = "redis://localhost:6379/0"def get_session_history(session_id: str) -> RedisChatMessageHistory:return RedisChatMessageHistory(session_id, url=REDIS_URL)with_message_history = RunnableWithMessageHistory(runnable,get_session_history,input_messages_key="input",history_messages_key="history"
)response = with_message_history.invoke({"ability": "math", "input": "余弦是什么意思?"},config={"configurable": {"session_id": "abc123"}},
)
print(response)response = with_message_history.invoke({"ability": "math", "input": "什么?"},config={"configurable": {"session_id": "abc123"}},
)
print(response)response = with_message_history.invoke({"ability": "math", "input": "什么?"},config={"configurable": {"session_id": "def234"}},
)
print(response)
执行完之后,查看Redis中就会发现多了两条记录,记录里面就是与ai对话的信息
我这里用的软件是Another Redis Desktop Manager
裁剪消息
LLM和聊天模型有限的上下文窗口,有时候为了降低token消耗,就会对消息进行裁剪,只加载和存储最新的n条消息。让我们使用一个带有预加载消息的示例历史记录:
# 保留两条记录测试不同的问题是否能回答
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnablePassthrough
import ostemp_chat_history = ChatMessageHistory()
temp_chat_history.add_user_message("我叫张三,你好")
temp_chat_history.add_ai_message("你好")
temp_chat_history.add_user_message("我今天心情挺开心")
temp_chat_history.add_ai_message("你今天心情怎么样")
temp_chat_history.add_user_message("我下午在打篮球")
temp_chat_history.add_user_message("你下午在做什么")
temp_chat_history.messagesprompt = ChatPromptTemplate.from_messages([("system", "你是一个乐于助人的助手。尽力回答所有问题。提供的聊天历史包括与您交谈的用户试试"),MessagesPlaceholder(variable_name="chat_history"),("human", "{input}"),]
)chat = ChatOpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",model="qwen-turbo",temperature=0,
)chain = prompt | chat# 只取最新的两条记录
def trim_messages(chain_input):stored_messages = temp_chat_history.messagesif len(stored_messages) <= 2:return Falsetemp_chat_history.clear()for message in stored_messages[-2:]:temp_chat_history.add_message(message)return Truechain_with_message_history = RunnableWithMessageHistory(chain,lambda session_id: temp_chat_history,input_messages_key="input",history_messages_key="chat_history",
)
chain_with_trimming = (RunnablePassthrough.assign(messages_trimmed=trim_messages)| chain_with_message_history
)# 对话
response = chain_with_trimming.invoke(# {"input": "我下午在干啥"}, # 能回答{"input": "我是谁"}, # 不能回答{"configurable": {"session_id": "unused"}},
)print(response.content)
print(temp_chat_history.messages)
输出示例:
input:我下午在干啥
你下午在打篮球呀!那应该很有趣!我下午在这里,想着帮助像你一样的大家,解答各种问题呢!你打得怎么样?
input:我是谁
根据你的描述,你是下午在打篮球的人。至于“我是谁”,从聊天内容来看,你是在和我分享你的活动,但并没有提供足够的信息让我确切知道你是谁。如果你愿意,可以告诉我更多关于你的信息!不过请记得保护个人隐私哦。
上面例子中,我们只保留2条的记忆,所以问大模型,我“下午在干啥”,他能回答在打篮球。问“我是谁”,他则回答不了。
如果将记忆片段扩大为6,他则能回答“我是谁”
input:我是谁
你是张三!😄 下午我在想象中陪你一起打了会儿篮球呢!运动很开心吧?我虽然不能真正参与,但能感受到你的活力!有什么趣事可以跟我分享哦~
总结记忆
我们也可以使用额外的LLM调用,来在调用链之前生成对话摘要。
实际场景中,可以让参数少、消耗资源的模型来生成摘要,然后再把摘要给参数大、消耗资源的模型用来对话
# 过往聊天记录总结
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnablePassthrough
import ostemp_chat_history = ChatMessageHistory()
temp_chat_history.add_user_message("我叫张三,你好")
temp_chat_history.add_ai_message("你好")
temp_chat_history.add_user_message("我今天心情挺开心")
temp_chat_history.add_ai_message("你今天心情怎么样")
temp_chat_history.add_user_message("我下午在打篮球")
temp_chat_history.add_user_message("你下午在做什么")
temp_chat_history.messagesprompt = ChatPromptTemplate.from_messages([("system", "你是一个乐于助人的助手。尽力回答所有问题。提供的聊天历史包括与您交谈的用户试试"),MessagesPlaceholder(variable_name="chat_history"),("user", "{input}"),]
)chat = ChatOpenAI(api_key=os.getenv("DASHSCOPE_API_KEY"),base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",model="qwen-turbo",temperature=0,
)chain = prompt | chat
chain_with_messgaes_history = RunnableWithMessageHistory (chain,lambda session_id: temp_chat_history,input_messages_key="input",history_messages_key="chat_history",
)def summarize_messages(chain_input):stored_messages = temp_chat_history.messagesif len(stored_messages) == 0:return Falsesummarization_prompt = ChatPromptTemplate.from_messages([MessagesPlaceholder(variable_name="chat_history"),("user","将上述聊天消息浓缩成一条摘要消息.尽可能包含多个具体细节",),])summarization_chain = summarization_prompt | chatsummary_messages = summarization_chain.invoke({"chat_history": stored_messages})temp_chat_history.clear()temp_chat_history.add_message(summary_messages)return Truechain_with_summarization = (RunnablePassthrough.assign(messages_summarized=summarize_messages)| chain_with_messgaes_history
)response = chain_with_summarization.invoke({"input": "名字,下午在干嘛,心情"},{"configurable": {"session_id": "unused"}},
)
print(response.content)
print(temp_chat_history.messages)
输出示例:
名字是张三,下午在打篮球,心情很好。
[AIMessage(content='张三下午打篮球,提问关于自己下午的活动。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 13, 'prompt_tokens': 70, 'total_tokens': 83, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-turbo', 'system_fingerprint': None, 'id': 'chatcmpl-9683a078-e696-954a-a692-073a25bff5c9', 'finish_reason': 'stop', 'logprobs': None}, id='run-588c8cca-33a0-4d71-b665-54d15c82b830-0', usage_metadata={'input_tokens': 70, 'output_tokens': 13, 'total_tokens': 83, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}), HumanMessage(content='名字,下午在干嘛,心情', additional_kwargs={}, response_metadata={}), AIMessage(content='名字是张三,下午在打篮球,心情很好。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 13, 'prompt_tokens': 66, 'total_tokens': 79, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-turbo', 'system_fingerprint': None, 'id': 'chatcmpl-0c5e55a9-4689-9a8f-8699-5473e59247b6', 'finish_reason': 'stop', 'logprobs': None}, id='run-b7505feb-d382-48e5-9d67-0f01e6d31a5b-0', usage_metadata={'input_tokens': 66, 'output_tokens': 13, 'total_tokens': 79, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}})]
请注意,下次调用链式模型会生成一个新的摘要,该摘要包括初始摘要以及新的消息。还可以设计一种混合方法,其中一定数量的消息保留在聊天记录中,而其他消息被摘要
源码地址
https://github.com/lys1313013/langchain-example/tree/main/06-memory
参考资料
B站:2025吃透LangChain大模型全套教程(LLM+RAG+OpenAI+Agent)第5集
相关文章:
LangChain开发(五)消息管理与聊天历史存储
文章目录 消息存储在内存使用单参数session_id配置会话唯一键 消息持久化到redis安装redis依赖安装redis调用聊天接口,看Redis是否存储历史记录 裁剪消息总结记忆源码地址参考资料 消息存储在内存 我们展示一个简单的示例,其中聊天历史保存在内存中&…...
HTML 表单处理进阶:验证与提交机制的学习心得与进度(一)
引言 在前端开发的广袤领域中,HTML 表单处理堪称基石般的存在,是构建交互性 Web 应用不可或缺的关键环节。从日常频繁使用的登录注册表单,到功能多样的搜索栏、反馈表单,HTML 表单如同桥梁,紧密连接着用户与 Web 应用…...
【文献25/03/26】Hyperspectral Image Transformer Classification Networks
高光谱图像Transformer分类网络 Hyperspectral Image Transformer Classification Networks | IEEE Journals & Magazine | IEEE Xplore 摘要 高光谱图像(HSI)分类是地球观测任务中的一项重要工作。 卷积神经网络(CNN)凭借…...
数字转换(c++)
【题目描述】 如果一个数 xx 的约数和 yy (不包括他本身)比他本身小,那么 xx 可以变成 yy ,yy 也可以变成 xx 。例如 44 可以变为 33 ,11 可以变为 77 。限定所有数字变换在不超过 nn 的正整数范围内进行,…...
WPF ContentPresenter详解2
ContentPresenter与ContentControl的区别 ContentControl 和 ContentPresenter 是 WPF 中两个相关的控件,但它们在用途和功能上有一些关键的区别。理解这两者的区别和联系有助于更好地设计和开发用户界面。 1. 类层次结构 ContentControl:位于 WPF 控件…...
【git】认识git的本地仓库
1.创建本地仓库 git init2. 配置本地仓库 git config user.name xxx git config user.email xxx3. 认识本地仓库 创建完本地仓库后,目录下会有一个.git文件,这个就是本地仓库 而创建本地仓库的目录叫做工作区,我们不能对.git文件进行任何手…...
正则表达式基本语法和Java中的简单使用
先来个例子 public static final Pattern CHINESE_PATTERN Pattern.compile("[\\u4e00-\\u9fa5]"); / 检测字符串是否包含汉字 String text "Hello 世界"; boolean hasChinese CHINESE_PATTERN.matcher(text).find(); // 返回 true// 提取所有汉字 Mat…...
【大模型】什么是循环神经网络(RNNs)
在人工智能(AI)的世界里,**循环神经网络(Recurrent Neural Networks, RNNs)**是一种非常强大的工具,特别适合处理序列数据。无论是语言、时间序列还是音乐,RNNs都能帮助我们理解和预测这些数据的…...
Leetcode 交错字符串
java solution class Solution {public boolean isInterleave(String s1, String s2, String s3) {//首先获取这三个字符串的长度int m s1.length();int n s2.length();int l s3.length();if(m n ! l) return false;//创建dp数组,dp[i][j]其含义是s3的前ij个字符是否可以由…...
Vue动态绑定:文本框、单选按钮、下拉列表、多选按钮
Vue 指令系列文章: 《Vue插值:双大括号标签、v-text、v-html、v-bind 指令》 《Vue指令:v-cloak、v-once、v-pre 指令》 《Vue条件判断:v-if、v-else、v-else-if、v-show 指令》 《Vue循环遍历:v-for 指令》 《Vue事件处理:v-on 指令》 《Vue表单元素绑定:v-model 指令》…...
MySQL - 数据库基础操作
SQL语句 结构化查询语言(Structured Query Language),在关系型数据库上执行数据操作、数据检索以及数据维护的标准语言。 分类 DDL 数据定义语言(Data Definition Language),定义对数据库对象(库、表、列、索引)的操作。 DML 数据操作语言(Data Manip…...
从入门到精通:SQL注入防御与攻防实战——红队如何突破,蓝队如何应对!
引言:为什么SQL注入攻击依然如此强大? SQL注入(SQL Injection)是最古老且最常见的Web应用漏洞之一。尽管很多公司和组织都已经采取了WAF、防火墙、数据库隔离等防护措施,但SQL注入依然在许多情况下能够突破防线&#…...
关于优麒麟ukylin如何更换清华源以及ubuntu24.04安装gcc-i686-linux-gnu找不到包的问题
打算把这个文章当成一个调试Linux bug的汇总,会持续更新 1、关于优麒麟ukylin如何更换清华源 (1)首先打开命令行,切换root权限 su root 输入密码 如果第一次使用ubuntu会提示密码不正确,输入 sudo passwd root …...
Spring Boot 自定义 Starter 组件的技术指南
1、简述 Spring Boot 通过 Starter 机制,让开发者可以快速集成第三方组件。在企业级开发中,我们常常需要封装自己的 Starter 组件,以提高代码复用性,简化配置,并实现可插拔的模块化开发。 Spring Boot Starter 机制 …...
基于Spring Boot的ONLY在线商城系统设计与实现的设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
HarmonyOS 之 @Require 装饰器自学指南
在 HarmonyOS 应用开发工作中,我频繁碰到组件初始化传参校验的难题。在复杂的组件嵌套里,要是无法确保必要参数在构造时准确传入,就极易引发运行时错误,而且排查起来费时费力。一次偶然的机会,我接触到了 Require 装饰…...
【Unity】 HTFramework框架(六十三)SerializableDictionary可序列化字典
更新日期:2025年3月26日。 Github 仓库:https://github.com/SaiTingHu/HTFramework Gitee 仓库:https://gitee.com/SaiTingHu/HTFramework 索引 一、SerializableDictionary可序列化字典1.使用SerializableDictionary2.实现思路 二、Serializ…...
JavaScript的性能优化指导
JavaScript 的性能优化可以从多个层面入手,涵盖代码执行效率、内存管理、DOM 操作、网络请求等。以下是一些关键优化策略: 一、代码执行优化 减少作用域链查找 避免在循环中频繁访问全局变量或深层嵌套的属性,将其缓存到局部变量中。 // 优化…...
如何在 Vue 项目中使用v - for指令进行列表渲染,如何优化其性能?
大白话如何在 Vue 项目中使用v - for指令进行列表渲染,如何优化其性能? 在Vue项目里,咱们常常会碰到要把一组数据渲染成列表的状况。这时候,v-for指令就派上大用场啦!它能让咱们轻松地把数据数组里的每个元素渲染成对…...
Notepad++ 替换 换行符 为 逗号
多行转一行,逗号分隔 SPO2025032575773 SPO2025032575772 SPO2025032575771 SPO2025032575771 SPO2025032575770为了方便快速替换,我们需要先知道这样类型的数据都存在哪些换行符。 点击【视图】-【显示符号】-【显示行尾符】 对于显示的行尾换行符【C…...
《基于机器学习发电数据电量预测》开题报告
个人主页:大数据蟒行探索者 目录 一、选题背景、研究意义及文献综述 (一)选题背景 (二)选题意义 (三)文献综述 1. 国内外研究现状 2. 未来方向展望 二、研究的基本内容,拟解…...
【Linux】MAC帧
目录 一、MAC帧 (一)IP地址和MAC地址 (二)MAC帧格式 (三)MTU对IP协议的影响、 (四)MTU对UDP协议的影响 (五)MTU对TCP协议的影响 二、以太网协议 &…...
企业入驻成都国际数字影像产业园,可享150多项专业服务
企业入驻成都国际数字影像产业园,可享150多项专业服务 全方位赋能,助力影像企业腾飞 入驻成都国际数字影像产业园,企业将获得一个涵盖超过150项专业服务的全周期、一站式支持体系,旨在精准解决企业发展各阶段的核心需求…...
飞速(FS)企业网布线解决方案:赋能能源行业客户高效网络部署与智能化管理
国家:中国 行业:能源与公用事业 网络类型:楼宇主干局域网 方案类型:企业网络布线 案例亮点 部署高密度、高性能飞速(FS)24口千兆企业级交换机,有效节省客户机房安装空间,提高并发…...
前端性能优化方案总结
首屏加载优化 把老版本的库替换成新版本,支持tree shaking的库,按需引入,只打包用到的部分,大大优化项目体积,加快项目的首屏渲染。 能不用第三方库,就不用第三方库,比如时间格式化,…...
基于ADMM无穷范数检测算法的MIMO通信系统信号检测MATLAB仿真,对比ML,MMSE,ZF以及LAMA
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 ADMM算法 4.2 最大似然ML检测算法 4.3 最小均方误差(MMSE)检测算法 4.4 迫零(ZF)检测算法 4.5 OCD_MMSE 检测算法 4.6 LAMA检测算法 …...
[plugin:vite:import-analysis] Cannot find module ‘vuex\dist\vuex.esm-bundler
我的是升级了uview-plus版本,导致一直报错,即时将版本降回去也报错,需要将package-lock.json和package-lock.yaml文件删掉重新安装软件包...
用Deepseek + Kimi 快速生成高质量的ppt
AI系列文章: AWS AI认证考试中经常提及几个重要的工具介绍 简单理解机器学习中top_k、top_p、temperature三个参数的作用 用Deepseek Kimi 快速生成高质量的ppt 在职场,不管干什么,都少不了和 PPT 打交道:客户交流,…...
【Go万字洗髓经】Golang中sync.Mutex的单机锁:实现原理与底层源码
本章目录 1. sync.Mutex锁的基本用法2. sync.Mutex的核心原理自旋到阻塞的升级过程自旋CAS 饥饿模式 3. sync.Mutex底层源码Mutex结构定义全局常量Mutex.Lock()方法第一次CAS加锁能够成功的前提是?竞态检测 Mutex.lockSlow()lockSlow的局部变量自旋空转state新值构造…...
Maven入门
1、简介 Apache Maven是一个项目管理及自动构建工具,由Apache软件基金会所提供。基于项目对象模型(缩写:POM)概念,Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。 2、作用 1)依赖导…...
SpringCloud Stream:消息驱动的微服务架构设计
文章目录 引言一、Spring Cloud Stream基础概念二、核心组件和架构三、消息生产者实现四、消息消费者实现五、消息分组与持久化六、消息分区与扩展七、函数式编程模型八、错误处理与重试机制九、测试与监控总结 引言 在当今复杂的分布式系统环境中,微服务架构已经成…...
进程通信(进程池的模拟实现) read write函数复习 Linux ─── 第23课
目录 进程池(process pool) 第一步: 创建并初始化processpool 第二步:主进程对子进程派发任务 补充: 第三步: 子进程执行完退出进程池 回收子进程 进程池的实现 Channel.hpp ProcessPool.hpp Task.hpp main.cc makefile 匿名管道的应用: 进程池 进程池(process po…...
Docker技术全景解析
一、Docker是什么 1.1 定义 Docker是一种容器化技术平台,它通过操作系统级别的虚拟化,将应用程序及其依赖打包成标准化的可移植单元(容器)。这种技术实现了: 环境一致性:消除“在我机器上能跑”的问题进…...
23种设计模式-状态(State)设计模式
状态设计模式 🚩什么是状态设计模式?🚩状态设计模式的特点🚩状态设计模式的结构🚩状态设计模式的优缺点🚩状态设计模式的Java实现🚩代码总结🚩总结 🚩什么是状态设计模式…...
【计算机网络运输层详解】
文章目录 一、前言二、运输层的功能1. 端到端通信2. 复用与分用3. 差错检测4. 流量控制5. 拥塞控制 三、运输层协议:TCP 和 UDP1. TCP:面向连接的可靠传输协议2. UDP:无连接的传输协议 四、端口号与进程通信1. 端口号分类2. 端口通信模型 五、…...
C# 多标签浏览器 谷歌内核Csharp
采用框架 :FBrowserCEF3lib 视频演示:点我直达 成品下载: https://wwms.lanzouo.com/iYOd42rl8vje...
分布式锁实战:Redis与Redisson的深度解析
一、分布式锁的必要性 在分布式系统中,当多个节点需要对共享资源进行读写操作时,传统的本地锁(如Java的synchronized或ReentrantLock)无法跨节点生效。此时,必须引入分布式锁来保证操作的原子性和一致性。分布式锁需满…...
【Centos7搭建Zabbix4.x监控HCL模拟网络设备:zabbix-server搭建及监控基础05
兰生幽谷,不为莫服而不芳; 君子行义,不为莫知而止休。 5.zabbix监控HCL模拟网络设备 在保证zabbix-server与HCL网络相通的情况下进行如下操作。 5.1创建主机群 配置-主机群-创建主机群 图 19 取名,添加。 图 20 5.2 创建监控…...
如何在 Windows 上安装并使用 Postman?
Postman 是一个功能强大的API测试工具,它可以帮助程序员更轻松地测试和调试 API。在本文中,我们将讨论如何在 Windows 上安装和使用 Postman。 Windows 如何安装和使用 Postman 教程?...
Zabbix监控K8s集群
虽然 Prometheus 被认为是 监控的Kubernetes最合适的工具 ,但其配置复杂、存储成本高以及告警管理繁琐等问题,使得一些传统运维团队更倾向于使用 Zabbix 这样的成熟监控方案。Zabbix 凭借其强大的数据采集、灵活的告警机制和直观的图形化界面,…...
基于硅基流动平台API构建定制化AI服务的实践指南
在人工智能技术快速迭代的今天,硅基流动平台(SiliconFlow)凭借其高效的计算资源调度能力和开放的API接口,成为开发者快速实现AI服务落地的利器。本文将深入探讨如何通过硅基流动平台的API构建一个轻量级AI服务接口,并提…...
自动驾驶系统的车辆动力学建模:自行车模型与汽车模型的对比分析
在自动驾驶系统的车辆动力学建模中,自行车模型(Bicycle Model)和更复杂的汽车模型(如双轨模型或多体动力学模型)各有其适用场景和优缺点。以下是两者的详细对比及选择原因解析: 1. 模型定义与核心差异 特性自行车模型复杂汽车模型(如双轨模型)简化假设将四轮车辆简化为…...
element-ui messageBox 组件源码分享
messageBox 弹框组件源码分享,主要从以下两个方面: 1、messageBox 组件页面结构。 2、messageBox 组件属性。 一、组件页面结构。 二、组件属性。 2.1 title 标题,类型为 string,无默认值。 2.2 message 消息正文内容…...
洛谷题单1-B2025 输出字符菱形-python-流程图重构
题目描述 用 * 构造一个对角线长 5 5 5 个字符,倾斜放置的菱形。 输入格式 没有输入要求。 输出格式 如样例所示。用 * 构成的菱形。 输入输出样例 #1 输入 #1 输出 #1 **** *********方式-前半区推导,后半区逆序 代码 class Solution:static…...
23中设计模式-迭代器(Iterator)设计模式
迭代器设计模式 🚩什么是迭代器设计模式?🚩迭代器设计模式的特点🚩迭代器设计模式的结构🚩迭代器设计模式的优缺点🚩迭代器设计模式的Java实现🚩代码总结🚩总结 🚩什么是…...
第十三章:优化内存管理_《C++性能优化指南》_notes
优化内存管理 一、内存管理基础概念二、自定义分配器三、智能指针优化重点知识代码示例:智能指针性能对比 四、性能优化关键点总结多选题设计题答案与详解多选题答案设计题示例答案(第1题) 一、内存管理基础概念 重点知识 动态内存分配开销…...
requestAnimationFrame和requestIdleCallback分别是什么,是用在什么场景下
深入解析 requestAnimationFrame 和 requestIdleCallback requestAnimationFrame (rAF) 和 requestIdleCallback (rIC) 都是浏览器提供的 异步调度 API,但它们的执行时机和用途完全不同。 API主要用途何时执行是否保证执行适合场景requestAnimationFrame高优先级 U…...
SAP-ABAP:SAP BW模块架构与实战应用详解
SAP BW模块架构与实战应用详解 目录导航 核心架构分层设计数据建模关键技术典型行业应用场景BW/4HANA革新特性实施路线图常见问题解决方案学习资源推荐一、核心架构分层设计 1. 数据仓库层(Data Warehousing Layer) 组件功能说明典型对象🔄 ETL引擎数据抽取、转换、加载Da…...
准确--配置服务器文件数
某些系统可能在 /etc/security/limits.d/ 目录下有额外配置覆盖全局设置。检查是否存在冲突文件: ls /etc/security/limits.d/如果有文件(如 90-nproc.conf 或 90-nofile.conf),需编辑或删除这些文件中的冲突配置。 确保系统启用…...
揭秘大数据 | 12、大数据的五大问题 之 大数据管理与大数据分析
书接上文,老夫讲到规划大数据战略、构建大数据的解决方案与体系架构、解决大数据问题及大数据发展历程中通常会依次涉及到大数据存储、大数据管理、大数据分析、数据科学、大数据应用这五大问题。上篇内容主要围绕的是大数据存储,今天主要聊一下大数据管…...