Langchain-Chatchat实践详解
简介
本质上是在Langchain基础上封装的一层聊天服务,可以对接底层多种离线LLM和在线的LLM(也可以对接自定义的在线LLM)。提供基于知识库聊天功能相关的一系列API。
下载源码
源码地址:
https://github.com/chatchat-space/Langchain-Chatchat

实践版本:

注:
1. 因为requirements.txt里一些依赖没有标注版本号,所以,在安装使用中可能存在版本号不匹配问题,本文可用版本号参考
| openai 0.28.1 langchain 0.0.330 |
2. 显卡卡住问题https://leiblog.wang/%E8%B8%A9%E5%9D%91nvidia-driver/
执行:nvidia-smi -pm 1
下载模型

修改配置
修改configs/model_config.py中MODEL_PATH,你要使用的模型为本地模型路径


启动服务
python startup.py --all-webui
webui界面:

API 体验界面

Docker运行服务
安装docker:
| apt update apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" apt update apt install docker-ce docker-ce-cli containerd.io systemctl status docker |
Ubuntu 23.04 Support · Issue #72 · NVIDIA/nvidia-container-toolkit · GitHub
安装nvidia-container-toolkit
| distribution=ubuntu18.04 \ && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list apt-get update && apt-get install -y nvidia-container-toolkit service docker restart |
设置docker镜像源:
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"http://hub-mirror.c.163.com",
"https://z2ycya8q.mirror.aliyuncs.com"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
生成镜像:
cd /home
git clone https://code.dobest.com/research-nlp/Langchain-Chatchat.git
初始化数据库:
cp -r /home/Langchain-Chatchat/knowledge_base/* /home/data/Langchain-Chatchat/knowledge_base/
cd Langchain-Chatchat
docker build -f ./Dockerfile -t langchain-chatchat .
docker run -it -d -p 8501:8501 -p 7861:7861 -p 20000:20000 -p 20001:20001 -p 20002:20002 -p 21007:21007 --gpus all -e ZMENV="online" --restart=always -v "/home/models:/home/models" -v "/home/data/Langchain-Chatchat/knowledge_base:/usr/src/Langchain-Chatchat/knowledge_base" -v "/home/data/Langchain-Chatchat/logs:/usr/src/Langchain-Chatchat/logs" -v /etc/localtime:/etc/localtime:ro langchain-chatchat
远程调试代码
pycharm远程调试
PyCharm远程调试代码 - 知乎
【已解决】Pycharm:Can't get remote credentials for deployment server-CSDN博客

设置个ssh interpreter就可以远程调试了。
代码解析
start_main_server
-> run_controller
-> run_model_worker
-> run_openai_api
-> run_api_server
-> run_webui

主进程fork出7个子进程
每个模型起一个子进程

服务端运行FastChat
GitHub - lm-sys/FastChat: An open platform for training, serving, and evaluating large language models. Release repo for Vicuna and Chatbot Arena.
HTTP API Source | Segment Documentation

socket,长连接通信
run_api_server(startup.py)
run_api_server -> create_app
start_main_server -> run_model_worker
FastAPI拉起模型进程

document
app.get("/",
response_model=BaseResponse,
summary="swagger 文档")(document)
openai_chat
# Tag: Chat
app.post("/chat/fastchat",
tags=["Chat"],
summary="与llm模型对话(直接与fastchat api对话)")(openai_chat)
openai_chat -> ChatCompletion : acreate -> EngineAPIResource : acreate -> api_requestor : request
不带历史条件的单问题对话
| { "model": "chatglm2-6b", "messages": [ { "role": "user", "content": "hello" } ], "temperature": 0.7, "n": 1, "max_tokens": 1024, "stop": [], "stream": false, "presence_penalty": 0, "frequency_penalty": 0 } |
chat
app.post("/chat/chat",
tags=["Chat"],
summary="与llm模型对话(通过LLMChain)")(chat)
chat每个入参对应post里面的一个json字段
| def chat(query: str = Body(..., description="用户输入", examples=["恼羞成怒"]), |
chat ->chat_iterator

把所有历史记录作为prompt输入
| [[ChatMessage(content='我们来玩成语接龙,我先来,生龙活虎', additional_kwargs={}, role='user'), ChatMessage(content='虎头虎脑', additional_kwargs={}, role='assistant'), ChatMessage(content='恼羞成怒', additional_kwargs={}, role='user')]] |
chat ->chat_iterator ->acall ->llm : _acall -> agenerate -> agenerate_prompt ->agenerate ->_agenerate_with_cache ->openai:_agenerate ->openai: _astream -> openai: acompletion_with_retry -> chat_completion : acreate -> engine_api_resource : acreate -> api_requestor : arequest -> api_requestor : arequest_raw -> client : request




貌似大模型都按照openai_api的定义生成了一套标准http接口
langchain是封装了一层,对接所有大模型的openap_api
knowledge_base_chat
app.post("/chat/knowledge_base_chat",
tags=["Chat"],
summary="与知识库对话")(knowledge_base_chat)
长连接通信:
pages = {"对话": {"icon": "chat","func": dialogue_page,},"知识库管理": {"icon": "hdd-stack","func": knowledge_base_page,},} |
dialogue_page -> utils: knowledge_base_chat -> chat. knowledge_base_chat
http 接口:
create_app -> chat. knowledge_base_chat
所有接口都有两条路

knowledge_base_chat -> knowledge_base_chat_iterator -> kb_doc_api: search_docs -> base : search_docs -> faiss_kb_service : do_search -> langchain : similarity_search_with_score -> faiss : replacement_search
langchain 对接 faiss
docs返回相似度top5的答案
| [ChatMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], output_parser=None, partial_variables={}, template='{% raw %}我们来玩成语接龙,我先来,生龙活虎{% endraw %}', template_format='jinja2', validate_template=True), additional_kwargs={}, role='user'), ChatMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], output_parser=None, partial_variables={}, template='{% raw %}虎头虎脑{% endraw %}', template_format='jinja2', validate_template=True), additional_kwargs={}, role='assistant'), ChatMessagePromptTemplate(prompt=PromptTemplate(input_variables=['context', 'question'], output_parser=None, partial_variables={}, template='<指令>根据已知信息,简洁和专业的来回答问题。如果无法从中得到答案,请说 “根据已知信息无法回答该问题”,不允许在答案中添加编造成分,答案请使用中文。 </指令>\n\n<已知信息>{{ context }}</已知信息>\n\n<问题>{{ question }}</问题>', template_format='jinja2', validate_template=True), additional_kwargs={}, role='user')] |
chat_prompt = ChatPromptTemplate.from_messages(
[i.to_msg_template() for i in history] + [input_msg])
历史和prompt模版拼接成chat_prompt


knowledge_base_chat -> Chain : acall

会将文本作为已知信息,提出问题
所有的历史和搜索文本、问题拼装成提示语
Chain : agenerate -> Chain : aprep_prompts

将params一些数据转成bytes的data发给模型服务

knowledge_base_chat -> Chain : acall -> Chain : agenerate -> Chain : aprep_prompts -> BaseChatModel : agenerate -> BaseChatModel : _agenerate_with_cache -> ChatOpenAI : _agenerate -> ChatOpenAI : _astream -> chat_models : acompletion_with_retry -> _completion_with_retry -> ChatCompletion : acreate -> EngineAPIResource : acreate -> APIRequestor : arequest -> APIRequestor : arequest_raw
最后Chain : acall的response里获得模型答复
可以根据阈值返回TOPK作为先验知识
# 知识库匹配向量数量VECTOR_SEARCH_TOP_K = 5# 知识库匹配相关度阈值,取值范围在0-1之间,SCORE越小,相关度越高,取到1相当于不筛选,建议设置在0.5左右SCORE_THRESHOLD = 1 |
search_engine_chat
app.post("/chat/search_engine_chat",
tags=["Chat"],
summary="与搜索引擎对话")(search_engine_chat)
search_engine_chat -> lookup_search_engine -> duckduckgo_search
调用第三方搜索API,我们没有对应的库,就会抛异常报错。
agent_chat
app.post("/chat/agent_chat",
tags=["Chat"],
summary="与agent对话")(agent_chat)
LangChain Agent入门教程 - LangChain教程(Python版本) - 梯子教程网
是通过llm进行决策,然后,程序去调用对应的工具。目前不需要。对应工具可能没有。
都是调用langchain的agent接口。查天气不可用。翻译可用。

本质上还是语言模型输入输出,在大模型外层设计出对应字符串的action回调,回调中自定义功能。
天气这个是chatchat这边实现的,应该还没有调通,解决了一个参数问题,大模型返回格式还不太对。


大模型回复了,格式不对

修改了明确的提示语后,可以调通天气,只需要和风天气API的key就可以查询了。
明确的prompt很重要,问题后面就是接答案,不要乱搞。
_PROMPT_TEMPLATE = """用户将会向您咨询天气问题,您不需要自己回答天气问题,而是将用户提问的信息提取出来区,市和时间三个元素后使用我为你编写好的工具进行查询并返回结果,格式为 区+市+时间 每个元素用空格隔开。如果缺少信息,则用 None 代替。问题: ${{用户的问题}}答案:
```text${{拆分的区,市和时间}}```... weather(提取后的关键字,用空格隔开)...这是两个例子:问题: 上海浦东未来1小时天气情况?答案:
```text浦东 上海 1```...weather(浦东 上海 1)...问题: 北京市朝阳区未来24小时天气如何?答案:
```text朝阳 北京 24```...weather(朝阳 北京 24)...现在,这是我的问题:问题: {question}""" |
利用ChatGPT的函数调用功能实现:实时查询天气 - FooFish
agent_chat -> agent_chat_iterator -> Chain : acall -> BaseSingleActionAgent : _acall

| generations=[ChatGenerationChunk(text=' 我需要查询上海浦东的天气情况,可以使用天气查询工具帮助我。\nAction: 天气查询工具\nAction Input: 上海 浦东 未来1小时\nObservation', message=AIMessageChunk(content=' 我需要查询上海浦东的天气情况,可以使用天气查询工具帮助我。\nAction: 天气查询工具\nAction Input: 上海 浦东 未来1小时\nObservation'))] llm_output=None |


通过tool定义,能找到对应的func
然后再根据对应天气的特定的prompt调用大模型,从问题中提取出对应的参数,然后,提取校验返回值,并最为入参给到获取天气的函数,拿到天气信息。
list_kbs
# Tag: Knowledge Base Management
app.get("/knowledge_base/list_knowledge_bases",
tags=["Knowledge Base Management"],
response_model=ListResponse,
summary="获取知识库列表")(list_kbs)
SQlALchemy session详解 - 知乎
list_kbs -> list_kbs_from_db
使用SQLAlchemy来操作数据库
create_kb
app.post("/knowledge_base/create_knowledge_base",
tags=["Knowledge Base Management"],
response_model=BaseResponse,
summary="创建知识库"
)(create_kb)

封装了向量库服务 kb_service
再去调用langchain.vectorstores中封装好的方法
create_kb -> get_service_by_name ->load_kb_from_db
get_service_by_name -> KBServiceFactory : get_service
// 先创建向量库
create_kb -> KBService : create_kb -> do_create_kb -> load_vector_store -> load_faiss_vector_store
// 再创建对应数据库信息
-> KBService : create_kb -> add_kb_to_db
delete_kb
app.post("/knowledge_base/delete_knowledge_base",
tags=["Knowledge Base Management"],
response_model=BaseResponse,
summary="删除知识库"
)(delete_kb)
// 删除向量库内容
delete_kb ->clear_vs -> FaissKBService : do_clear_vs
// 删除对应数据库信息
delete_kb ->clear_vs -> delete_files_from_db
// 删除知识库
delete_kb -> drop_kb -> FaissKBService : do_drop_kb
delete_kb -> drop_kb -> delete_kb_from_db
list_files
app.get("/knowledge_base/list_files",
tags=["Knowledge Base Management"],
response_model=ListResponse,
summary="获取知识库内的文件列表"
)(list_files)
// 查数据库
list_files -> KBService : list_files -> list_files_from_db
search_docs
app.post("/knowledge_base/search_docs",
tags=["Knowledge Base Management"],
response_model=List[DocumentWithScore],
summary="搜索知识库"
)(search_docs)
search_docs -> KBService : search_docs -> FaissKBService : do_search -> FAISS : similarity_search_with_score
FaissKBService 属于Langchain基础上再封装
FAISS 是Langchain封装好的向量库接口
upload_doc
app.post("/knowledge_base/upload_doc",
tags=["Knowledge Base Management"],
response_model=BaseResponse,
summary="上传文件到知识库"
)(upload_doc)

保存知识文件到对应知识库路径
会将文件内容以行为单位截断,那么相邻两部分的首尾有一部分内容重合。


// 清理向量库和数据库
upload_doc -> KBService : add_doc -> KBService : delete_doc
// 将文档内容加入向量库
upload_doc -> KBService : add_doc -> FaissKBService : do_add_doc -> VectorStore : add_documents
VectorStore:langchain封装的向量库接口

// 将生成的向量id和对应文档信息,存入数据库
upload_doc -> KBService : add_doc -> add_file_to_db
delete_doc
app.post("/knowledge_base/delete_doc",
tags=["Knowledge Base Management"],
response_model=BaseResponse,
summary="删除知识库内指定文件"
)(delete_doc)

删除找对应id是遍历整个知识库比对文件路径
// 从向量库中删除数据
delete_doc -> KBService : delete_doc -> FaissKBService : do_delete_doc
// 从数据库中删除文件信息(可以选择是否删除内容)
delete_doc -> KBService : delete_doc -> delete_file_from_db
update_doc
app.post("/knowledge_base/update_doc",
tags=["Knowledge Base Management"],
response_model=BaseResponse,
summary="更新现有文件到知识库"
)(update_doc)
update_doc -> KBService : update_doc

所谓的更新就是先删除再重新添加
download_doc
app.get("/knowledge_base/download_doc",
tags=["Knowledge Base Management"],
summary="下载对应的知识文件")(download_doc)
http://10.225.20.233:7861/knowledge_base/download_doc?knowledge_base_name=samples&file_name=1.docx
postman选择 send and download可以下载文件
download_doc -> FileResponse
recreate_vector_store
app.post("/knowledge_base/recreate_vector_store",
tags=["Knowledge Base Management"],
summary="根据content中文档重建向量库,流式输出处理进度。"
)(recreate_vector_store)
// 最后刷新缓存
recreate_vector_store -> output -> KBService : add_doc -> FaissKBService : do_add_doc -> vector_store.save_local
list_models
# LLM模型相关接口@app.post("/llm_model/list_models",tags=["LLM Model Management"],summary="列出当前已加载的模型")
list_running_models
应该是LLM Model + FSCHAT_MODEL_WORKERS
本地模型和在线接口
list_running_models -> Controller : list_models
list_config_models
app.post("/llm_model/list_config_models",tags=["LLM Model Management"],summary="列出configs已配置的模型",)(list_config_models)
list_config_models -> list_llm_models
stop_llm_model
@app.post("/llm_model/stop",tags=["LLM Model Management"],summary="停止指定的LLM模型(Model Worker)",)
stop_llm_model -> release_worker -> release_model
网络中转了几次,最后,模型被释放了,显存释放了
change_llm_model
@app.post("/llm_model/change",tags=["LLM Model Management"],summary="切换指定的LLM模型(Model Worker)",)
change_llm_model -> release_worker -> release_model
模型停掉,就不能切换了,看来不能动态的更换大模型

webui.py
UI框架Streamlit
SQLAlchemy
SQLAlchemy入门和进阶 - 知乎

# 数据库默认存储路径。# 如果使用sqlite,可以直接修改DB_ROOT_PATH;如果使用其它数据库,请直接修改SQLALCHEMY_DATABASE_URI。DB_ROOT_PATH = os.path.join(KB_ROOT_PATH, "info.db")SQLALCHEMY_DATABASE_URI = f"sqlite:///{DB_ROOT_PATH}"
|
默认使用了sqlite
class KnowledgeFileModel(Base):"""知识文件模型
"""__tablename__ = 'knowledge_file'id = Column(Integer, primary_key=True, autoincrement=True, comment='知识文件ID')file_name = Column(String(255), comment='文件名')file_ext = Column(String(10), comment='文件扩展名')kb_name = Column(String(50), comment='所属知识库名称')document_loader_name = Column(String(50), comment='文档加载器名称')text_splitter_name = Column(String(50), comment='文本分割器名称')file_version = Column(Integer, default=1, comment='文件版本')file_mtime = Column(Float, default=0.0, comment="文件修改时间")file_size = Column(Integer, default=0, comment="文件大小")custom_docs = Column(Boolean, default=False, comment="是否自定义docs")docs_count = Column(Integer, default=0, comment="切分文档数量")create_time = Column(DateTime, default=func.now(), comment='创建时间')def __repr__(self):return f"<KnowledgeFile(id='{self.id}', file_name='{self.file_name}', file_ext='{self.file_ext}', kb_name='{self.kb_name}', document_loader_name='{self.document_loader_name}', text_splitter_name='{self.text_splitter_name}', file_version='{self.file_version}', create_time='{self.create_time}')>"class FileDocModel(Base):"""文件-向量库文档模型
"""__tablename__ = 'file_doc'id = Column(Integer, primary_key=True, autoincrement=True, comment='ID')kb_name = Column(String(50), comment='知识库名称')file_name = Column(String(255), comment='文件名称')doc_id = Column(String(50), comment="向量库文档ID")meta_data = Column(JSON, default={})def __repr__(self):return f"<FileDoc(id='{self.id}', kb_name='{self.kb_name}', file_name='{self.file_name}', doc_id='{self.doc_id}', metadata='{self.metadata}')>" |
两张表KnowledgeFileModel 和 FileDocModel
用的是SessionLocal,本地数据库
自定义线上API
server/model_workers下面添加线上API的具体定义,可以参考目录下其它线上API定义。

generate_stream_gate里面定义具体的接口对接代码。
server_config.py中 FSCHAT_MODEL_WORKERS下面新增api绑定端口。

model_config.py 中ONLINE_LLM_MODEL 新增 api配置

相关文章:
Langchain-Chatchat实践详解
简介 本质上是在Langchain基础上封装的一层聊天服务,可以对接底层多种离线LLM和在线的LLM(也可以对接自定义的在线LLM)。提供基于知识库聊天功能相关的一系列API。 下载源码 源码地址: https://github.com/chatchat-space/Lang…...
python求解优化问题的几个例子
目录 1、最优化问题 2、线性规划 3、无约束优化 3.1单变量 3.2多变量 1、最优化问题 使用scipy库中的minimize函数来求解最优化问题。在这个例子中,我们定义了一个目标函数 objective,其形式为x1^2 x2^2;以及一个约束条件 constraint&…...
HP惠普暗影精灵9P OMEN 17.3英寸游戏本17-cm2000(70W98AV)原装出厂Windows11-22H2系统镜像
链接:https://pan.baidu.com/s/1gJ4ZwWW2orlGYoPk37M-cg?pwd4mvv 提取码:4mvv 惠普暗影9Plus笔记本电脑原厂系统自带所有驱动、出厂主题壁纸、 Office办公软件、惠普电脑管家、OMEN Command Center游戏控制中心等预装程序 所需要工具:3…...
❤ Uniapp使用Ucharts(二)(组件类型)
❤ Uniapp使用Ucharts(二)(秋云组件类型) 一、折线图 1、结构 <template><view class"charts-box"><qiun-data-charts type"area":opts"opts":chartData"chartData"/&…...
Linux Vim批量注释和自定义注释
使用 Vim 编辑 Shell 脚本,在进行调试时,需要进行多行的注释,每次都要先切换到输入模式,在行首输入注释符"#"再退回命令模式,非常麻烦。连续行的注释其实可以用替换命令来完成。 换句话说,在指定…...
虚幻C++基础 day3
常见的游戏机制 Actor机关门 创建一个Actor类,添加两个静态网格与一个触发器 UBoxComponentUStaticMeshComponent 头文件: #include “Components/BoxComponent.h”#include “Components/StaticMeshComponent.h” TriggerDoor.h // Fill out your …...
第26期 | GPTSecurity周报
GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大型语言模型(LLM)等安全领域应用的知识。在这里,您可以…...
(动手学习深度学习)第7章 稠密连接网络---DenseNet
目录 DenseNetDenseNet的优点:DenseNet的改进思路总结 DenseNet代码实现 DenseNet DenseNet的优点: 省参数。在 ImageNet 分类数据集上达到同样的准确率,DenseNet 所需的参数量不到 ResNet 的一半。对于工业界而言,小模型可以显著…...
UART编程(寄存器)
1. 串口编程步骤 1.1 看原理图确定引脚 有很多串口,使用哪一个?看原理图确定 1.2 配置引脚为UART功能 至少用到发送、接收引脚:txd、rxd 需要把这些引脚配置为UART功能,并使能UART模块 1.3 设置串口参数 有哪些参数…...
事务码增删查改表数据
常用事务码 SE11 SE14 SE16 SE16N SM30 SE11:查看数据库表/修改表中字段数量_类型/查看表中数据/设置表为可维护或不可维护 SE14:查看数据库表的创建日期创建用户名/查看表中字段/删除表中全部数据(只能全部删) SE16:查看数据库表/对可维护数据库表进行数据维护/SE16通过调试…...
vue开发环境搭建部署(mac版)
前言 目前后端工作越来越少了,年底了,为了先过验收。项目负责人、产品、需求制定的方案就是先做假页面,所以前端的活多点。 其实现在不喜欢搞前端,原因很多,但是感觉现在似乎流行的码林绝学又是九九归一的瓶颈期…...
Java【算法 05】通过时间获取8位验证码(每两个小时生成一个)源码分享
通过时间获取验证码 1.需求2.代码实现2.1 依赖2.2 时间参数处理方法2.3 截取验证码方法2.4 验证方法 3.总结 1.需求 要求是很简单的,每个验证码的有效时间是2小时,这个并不是收到验证码开始计时的,而是每个两小时的时间段使用的是相同的验证…...
微服务 Spring Cloud 5,一图说透Spring Cloud微服务架构
目录 一、域名系统DNS二、LVS(Linux Virtual Server),Linux虚拟服务器三、CDN静态资源四、Nginx反向代理服务器1、Nginx的主要作用体现在以下几个方面:2、Nginx静态资源服务和CDN静态资源服务,如何选择? 五、Gateway网…...
conda清华源安装cuda12.1的pytorch
使用pytorch官方提供的conda command奇慢无比,根本装不下来(科学的情况下也这样) 配置一下清华源使用清华源装就好了 清华源:https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/ 配置方法:conda config --…...
安徽首届道医传承十八绝技发布会在合肥成功举办
近日,在安徽合肥举行了首届道医传承十八绝技发布会,本次会议由安徽渡罗门生物科技有限公司、北京道武易医文化传播有限公司、楼观台道医文化研究院联合举办。现场吸引了来自全国各地民族医学领域的专家学者参与讨论与交流。本次会议旨在促进道医的交流与…...
一款功能强大的web目录扫描器专业版
dirpro 简介 dirpro 是一款由 python 编写的目录扫描器,操作简单,功能强大,高度自动化。 自动根据返回状态码和返回长度,对扫描结果进行二次整理和判断,准确性非常高。 已实现功能 可自定义扫描线程 导入url文件进…...
【Linux网络】网卡配置与修改主机名,做好基础系统配置
目录 一、网络配置命令 1、查看网卡信息ifconfig Linux永久修改ip地址 2、主机名修改 ①hostname 临时修改主机名 ②永久修改主机名 第一种,使用命令修改 第二种:修改配置文件 3、路由信息 再来拓展一下,永久修改路由表信息 4、检查…...
三大基础排序 -选择排序、冒泡排序、插入排序
排序算法 文章目录 冒泡排序算法步骤动图代码优化总结 选择排序算法步骤动图代码总结 插入排序算法步骤动图代码总结 排序算法,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。一般默认排序是按照由小到大即…...
el-form添加自定义校验规则校验el-input只能输入数字
0 效果 1 代码 {1,5}是用来限制小数点后几位的 addFormRules: {investAmount: [{ validator: checkInvestAmount, trigger: blur }], }, const checkInvestAmount (rule, value, callback) > {if (value ! && value ! null && value ! undefined) {if (/…...
ios 开发问题小集 [持续更新]
文章目录 一、如何给列表上的UITableViewCell添加手势二、获取NSIndexPath的方式2.1 根据row, section 来创建2.2 根据point 的位置来找到 indexPath三、tableView在Grouped样式下,设置表头表尾空白一、如何给列表上的UITableViewCell添加手势 给cell添加手势,大家都会这么做…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
StarRocks 全面向量化执行引擎深度解析
StarRocks 全面向量化执行引擎深度解析 StarRocks 的向量化执行引擎是其高性能的核心设计,相比传统行式处理引擎(如MySQL),性能可提升 5-10倍。以下是分层拆解: 1. 向量化 vs 传统行式处理 维度行式处理向量化处理数…...
codeforces C. Cool Partition
目录 题目简述: 思路: 总代码: https://codeforces.com/contest/2117/problem/C 题目简述: 给定一个整数数组,现要求你对数组进行分割,但需满足条件:前一个子数组中的值必须在后一个子数组中…...
