MCP项目开发-一个简单的RAG示例
MCP项目开发-一个简单的RAG示例
前言
前言
- 客户端是基于官网的例子改的,模型改成了openai库连接
- 仅仅使用基础的RAG流程作为一个演示,包含了以下步骤
- query改写
- 搜索:使用google serper
- 重排序:使用硅基流动的api
- 大模型api也使用的硅基流动
- 调用速度还可以
官方文档
-
mcp官方文档
https://modelcontextprotocol.io/introduction
使用到的api注册
-
检索:google serper
https://serper.dev
有2500 Credits,具体也没搞明白,好像是每次检索返回的文本数量超过10则花费2Credits,不过这个不重要,反正自己用肯定够,api在这
连接示例
curl --location 'https://google.serper.dev/search' \ --header 'X-API-KEY: 你的api-key' \ --header 'Content-Type: application/json' \ --data '{"q": "你的问题","num": 2 }'
其中q表示要检索的问题,然后num为返回的文本数,返回示例如下
{"searchParameters": {"q": "中国首都是哪","type": "search","num": 2,"engine": "google"},"organic": [{"title": "中华人民共和国首都 - 维基百科","link": "https://zh.wikipedia.org/zh-hans/%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E9%A6%96%E9%83%BD","snippet": "中华人民共和国首都位于北京市,新中国成立前夕的旧称为北平,是中共中央及中央人民政府所在地,中央四个直辖市之一,全国政治、文化、国际交往和科技创新中心,中国古都、 ...","position": 1},{"title": "中华人民共和国首都_中华人民共和国中央人民政府门户网站","link": "https://www.gov.cn/guoqing/2005-05/24/content_2615214.htm","snippet": "1949年9月27日,中国人民政治协商会议第一届全体会议一致通过中华人民共和国的国都定于北平,即日起北平改名北京。 北京,简称京,是中国共产党中央委员会、中华人民共和国 ...","position": 2}],"relatedSearches": [{"query": "中国首都是北京还是上海"},{"query": "中国首都为什么是北京"},{"query": "中国首都上海"},{"query": "中国以前的首都"},{"query": "新中国首都选址"},{"query": "中国历代首都"},{"query": "中国首都候选"},{"query": "中国首都英文"}],"credits": 1 }
主要的就是在
organic
中,如果我们的num为2,则organic中返回两个dict,我们取的是没个dict中的snippet字段 -
聊天大模型与重排序模型:硅基流动
https://cloud.siliconflow.cn/
注册可以看我的另一篇
https://blog.csdn.net/hbkybkzw/article/details/145558234
api-key如图
服务器
环境搭建
-
官方推荐使用uv来管理环境,先下载uv
pip install uv#或者macos linux curl -LsSf https://astral.sh/uv/install.sh | sh#或者windows powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
之后重启终端
-
初始化项目。名称为rag_sample
uv init rag_sample
-
创建虚拟环境并激活
cd rag_sample uv venv# windows .venv\Scripts\activate# linux source .venv/bin/activate
-
安装依赖
openai库是客户端用的,为了方便,客户端就不初始化了,直接和服务器用同一个环境
# windows uv add mcp[cli] aiohttp dotenv openai rich# linux uv add "mcp[cli]" aiohttp dotenv openai rich
构建服务器
-
在rag_sample目录下,创建 .env 文件保存为环境变量
GOOGLE_SERPER_URL=https://google.serper.dev/search GOOGLE_SERPER_API= SILICONFLOW_RERANKING_BASE_URL=https://api.siliconflow.cn/v1/rerank SILICONFLOW_CHAT_BASE_URL=https://api.siliconflow.cn/v1/chat/completions SILICONFLOW_RERANKING_API_KEY= RERANKING_MODEL=BAAI/bge-reranker-v2-m3 OPENAI_CHAT_MODEL=Qwen/QwQ-32B OPENAI_BASE_URL=https://api.siliconflow.cn/v1
将
GOOGLE_SERPER_API
和SILICONFLOW_RERANKING_API_KEY
填为自己的 -
rag_client.py
import mcp import aiohttp import asyncio from mcp.server.fastmcp import FastMCP from utils import query_rewrite,search_with_serper,reranking_by_bgemcp = FastMCP("rag")@mcp.tool() async def rag_sample(query:str,doc_num:int=10,top_n:int=4) -> list:"""rag_sample: 输入query,输出检索重排序后的文档Parameters:-------------------------------------------------------------------------------------------------------------------query: type: str desc: 用户问题 doc_num: type: int desc: 检索文档数 top_n: type: top_n desc: 重排序后返回top_n Returns:-------------------------------------------------------------------------------------------------------------------reranked_doc: type: list desc: top_n检索文档"""rewrite_query = await query_rewrite(query=query)documents = await search_with_serper(query=rewrite_query,document_num=doc_num)reranked_doc = await reranking_by_bge(query=query,documents=documents,top_n=top_n)return reranked_docasync def test():query = "MCP协议介绍"reranked_doc = await rag_sample(query=query)importrich.print(reranked_doc)if __name__ == "__main__":# asyncio.run(test())mcp.run(transport="stdio")
test函数是用来测试的
我们将主要的代码放在
rag_client.py
,辅助函数都放在utils.py
中主要的流程就是
query_rewrite
: 传入用户问题,返回改写后的问题search_with_serper
: 传入改写后的问题和检索数量,返回检索到的文档信息reranking_by_bge
:传入用户问题和检索到的信息,返回相似度高的top_n文档信息
代码见下面的utils.py
-
utils.py
import asyncio import aiohttp from dotenv import load_dotenv import os#从.env文件加载环境变量 load_dotenv()# google serper google_serper_url = os.getenv("GOOGLE_SERPER_URL") google_serper_api = os.getenv("GOOGLE_SERPER_API")# siliconflow api chat_base_url = os.getenv("SILICONFLOW_CHAT_BASE_URL") reranking_base_url = os.getenv("SILICONFLOW_RERANKING_BASE_URL") reranking_api_key = os.getenv("SILICONFLOW_RERANKING_API_KEY") reranking_model = os.getenv("RERANKING_MODEL")# query rewrite prompt query_rewrite_prompt = """ 请根据以下规则优化用户的问题: 1. 首先判断用户query是否为问候或打招呼(例如:'你好'、'在吗'、'您好'等)。如果是问候,直接返回原文query。 2. 如果不是,对query进行优化改写,请保持原意并使改写后的query更精准更简洁,限制在15个字以内 示例:- 输入:'你好,能帮个忙吗?'输出:'你好,能帮个忙吗?'- 输入:'怎么重写句子结构?'输出:'句子结构优化步骤示例'输出时无需解释,仅返回最终结果。 """async def fetch_search_results(url, headers, payload):"""发动请求并获取响应"""async with aiohttp.ClientSession() as session:async with session.post(url, headers=headers, json=payload) as response:assert response.status == 200response_json = await response.json()return response_json # 返回响应jsonasync def query_rewrite(query:str):"""一个简单的query改写,直接用aiohttp了,没有使用openai"""url = chat_base_urlheaders = {'Authorization': f'Bearer {reranking_api_key}','Content-Type': 'application/json'}payload={"model": "Qwen/Qwen2.5-72B-Instruct","messages": [{"role": "system","content": query_rewrite_prompt},{"role": "user","content": query}],"max_tokens": 512,"stream":False}response_data = await fetch_search_results( url=url,headers=headers,payload=payload)rewrite_query = response_data['choices'][0]['message']['content']return rewrite_queryasync def search_with_serper(query:str,document_num:int=10):"""google serper 搜索并返回documents,形式如下[{"title1":"","link1":"","snippet1":"","position1":""},{"title2":"","link2":"","snippet2":"","position2":""},...]"""url = google_serper_urlheaders = {'X-API-KEY': google_serper_api,'Content-Type': 'application/json'}payload = {"q": query, # 要搜索的问题"num": document_num # 要所搜的文档数量}response_data = await fetch_search_results( url=url,headers=headers,payload=payload)documents = response_data['organic']return documents async def reranking_by_bge(query:str,documents:list[dict],top_n:int=4):"""调用排序模型,返回排序后的文档"""doc_to_rerank = [doc["snippet"] for doc in documents]url = reranking_base_urlheaders = {'Authorization': f'Bearer {reranking_api_key}','Content-Type': 'application/json'}payload = {"model": reranking_model,"query": query,"documents": doc_to_rerank,"top_n": top_n,"return_documents": True, # 如果是false则只返回索引,麻烦"max_chunks_per_doc": 1024,"overlap_tokens": 80}reranked_info = await fetch_search_results( url=url,headers=headers,payload=payload)reranked_doc =[item['document']['text'] for item in reranked_info['results']]return reranked_docasync def test():import richquery = "流水不争先"rewrite_query = await query_rewrite(query=query)rich.print('rewrite_query',rewrite_query)documents = await search_with_serper(query=rewrite_query,document_num=4)rich.print('documents',documents)reranked_doc = await reranking_by_bge(query=query,documents=documents,top_n=2)rich.print("reranked_doc",reranked_doc)if __name__ == "__main__":asyncio.run(test())
test函数是用来测试的
-
运行 python rag_client.py以确认一切正常
app端使用(cherrystudio为例)
-
安装cherrystudio,并配置好模型
https://cherry-ai.com/
-
在app端添加单个weather服务器,下面的json文件需要复制到cherrystudio中
{"mcpServers": {"rag": {"command": "uv","args": ["--directory","C:\\Users\\孟智超\\Desktop\\mac_backups\\MCP\\rag_sample","run","rag_client.py"]}} }
意思是:
- 有一个名为“天气”的 MCP 服务器
- 通过运行
uv --directory C:\\Users\\孟智超\\Desktop\\mac_backups\\MCP\\rag_sample run rag_client.py
来启动它(项目的地址)
-
将上面的json文本复制到cherrystudio
-
选择模型,因为mcp也借用了functioncalling,所以需要选用的模型必须支持functioncalling(tools)
在cherrystudio中的表现就是,有绿色的小扳手
-
开始聊天之前开启mcp
-
看看使用前后的对比
问题:什么是MCP?
未开启前,列举了很多,但是都不是我们想要的
开启后,虽然在思考过程中也提到了其他无关的,但是最后还是决定调用工具rag_sample,最后得到的是我们想要的正确答案。
客户端
代码
-
和服务器共用一个环境(不推荐,一般重新开一个环境)
-
代码
rag_client.py
import os import sys import json import asyncio from typing import Optional from contextlib import AsyncExitStackfrom mcp import ClientSession,StdioServerParameters from mcp.client.stdio import stdio_clientimport openai from openai import OpenAI from dotenv import load_dotenv import traceback# 从.env文件加载环境变量 load_dotenv() # siliconflow api openai.base_url = os.getenv("OPENAI_BASE_URL") openai.api_key = os.getenv("SILICONFLOW_RERANKING_API_KEY") openai_chat_model = os.getenv("OPENAI_CHAT_MODEL")class MCPClient:def __init__(self):# 初始化会话和客户端对象self.session: Optional[ClientSession] = None # 保存mcp客户端会话self.exit_stack = AsyncExitStack()self.model = openai_chat_modelself.openai = OpenAI(base_url=openai.base_url,api_key=openai.api_key)async def connect_to_server(self, server_script_path:str):"""connect_to_server: 连接到mcp服务器 Parameters:-------------------------------------------------------------------------------------------------------------------server_script_path: type:str desc: server脚本地址(.py or .js) """is_python = server_script_path.endswith('.py') # python脚本?is_js = server_script_path.endswith('.js') # node 脚本?if not (is_python or is_js):raise ValueError("Server script must be a .py or .js file")command = "python" if is_python else "node"server_params = StdioServerParameters(command=command,args=[server_script_path],env=None) # 告诉mcp客户端如何启动服务器,比如当前的 python rag_server.pystdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params) # 启动服务器进程,建立标准I/O通信管道)self.stdio,self.write = stdio_transport # 拿到读写流self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio,self.write) # 创建MCP客户端会话,与服务器交互)await self.session.initialize() # 发送初始化消息给服务器,等待服务器就绪。# 列出 mcp 服务器上可用的工具response = await self.session.list_tools() # 向 mcp 服务器请求所有已注册的工具(即@mcp.tool)tools = response.toolsprint("\nConnected to server with tools:", [tool.name for tool in tools])async def process_query(self,query:str) -> str:"""process_query: 使用大模型处理查询,调用已经注册的MCP工具 Parameters:-------------------------------------------------------------------------------------------------------------------query: type:str desc:用户问题 """messages = [{"role":"user","content": query}]response = await self.session.list_tools() # 向 mcp 服务器请求所有已注册的工具(即@mcp.tool)# 转换为functional calling 的available_tools格式available_tools = [{"type": "function","function": {"name": tool.name,"description": tool.description,"input_schema": tool.inputSchema}} for tool in response.tools]# print(f"available_tools:\n{available_tools}")# 初始化 大模型连接(OpenAI)response = self.openai.chat.completions.create(model=self.model,max_tokens=1000,messages=messages,tools=available_tools)content = response.choices[0]print(f"content.finish_reason : {content.finish_reason}")if content.finish_reason == "tool_calls": print(f"进入functional calling")# content.finish_reason == "tool_calls"表示要调用工具# 会在content.message.tool_calls 列表中声明要用哪个函数、参数是什么tool_call = content.message.tool_calls[0]tool_name = tool_call.function.nametool_args = json.loads(tool_call.function.arguments)# 取出工具名 tool_name 和参数 tool_args,执行mcp工具result = await self.session.call_tool(tool_name, tool_args)print(f"\n[Calling tool {tool_name} with args {tool_args}]\n\n")# print(f"\n\ncall_tool_result: {result}")# print(f"\n\ncall_tool_result.content[0].text:{result.content[0].text}")# print(f"i.text for i in result.content:{[i.text for i in result.content]}")# 将模型返回的调用哪个工具数据和工具执行完成后的数据都存入messages中messages.append(content.message.model_dump())messages.append({"role": "tool","content": f"{[i.text for i in result.content]}","tool_call_id": tool_call.id,})# 将上面的结果再次返回给大模型并产生最终结果response = self.openai.chat.completions.create(model=self.model,max_tokens=1000,messages=messages,)return response.choices[0].message.content# 如果没有调用工具则直接返回当前结果return content.message.contentasync def chat_loop(self):"""运行一个交互式聊天循环"""print("MCP 服务器已经启动!")print("输入你的问题(输入'quit'退出).")while True:try:query = input("\n你的问题:\n").strip()if query.lower() == "quit":breakresponse = await self.process_query(query)print(f"模型回答:\n{response}")except Exception as e:tb = traceback.extract_tb(e.__traceback__)for frame in tb:print("File:", frame.filename)print("Line:", frame.lineno)print("Function:", frame.name)print("Code:", frame.line)async def cleanup(self):"""清理资源"""# 异步地关闭所有在 exit_stack 中注册的资源(包括 MCP 会话)。await self.exit_stack.aclose()async def main():"""main: 主执行逻辑,以现在的rag为例子标准IO启动需要服务器的代码作为客户端的子进程启动服务器代码:rag_server.py客户端代码:rag_client.py因为都在同一个项目下,所以启动直接为python rag_client.py rag_server.py"""if len(sys.argv) < 2: # print("Usage: python client.py <path_to_server_script>")sys.exit(1)client = MCPClient()try:print(sys.argv[1])# python rag_client.py rag_server.py ,则argv[1] = rag_client.py 为客户端代码await client.connect_to_server(sys.argv[1]) await client.chat_loop()finally:await client.cleanup()if __name__ == "__main__":asyncio.run(main())
-
connect_to_server
:连接到MCP服务器 -
process_query
: 使用大模型处理查询,将MCP工具转换为OpenAI兼容的格式,允许模型决定是否调用工具,如果是,则调用已经注册的MCP工具 -
chat_loop
: 交互式聊天(只有单轮) -
main
:主函数因为在客户端脚本中,启动方式是"stdio"
if __name__ == "__main__":mcp.run(transport="stdio")
这种适合在客户端和服务器在同一个环境中的情况下,是将服务器作为客户端的子进程
所以其中这个客户端的命令如下
python rag_client.py rag_server.py
-
测试运行
-
启动
python rag_client.py rag_server.py
-
测试下
(模型不太好触发这个tool,所以我直接加了“请调用rag_sample”)
问题:
请调用rag_sample,解释下最近很火的mcp
相关文章:
MCP项目开发-一个简单的RAG示例
MCP项目开发-一个简单的RAG示例 前言 前言 客户端是基于官网的例子改的,模型改成了openai库连接仅仅使用基础的RAG流程作为一个演示,包含了以下步骤 query改写搜索:使用google serper重排序:使用硅基流动的api 大模型api也使用…...
Windows安装ssh服务
使用管理员权限打开Windows PowerShell Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0启动服务 Start-Service sshd 设置开机自启 Set-Service sshd -StartupType Automatic允许22端口 New-NetFirewallRule -Name “SSH” -DisplayName “SSH” -Enabled Tr…...
从零实现本地大模型RAG部署
1. RAG概念 RAG(Retrieval-Augmented Generation)即检索增强生成,是一种结合信息检索与大型语言模型(大模型)的技术。从外部知识库(如文档、数据库或网页)中实时检索相关信息,并将其…...
什么是ThreadLocal
ThreadLocal 是 Java 提供的一个工具类,它为每一个使用该变量的线程都提供了一个独立的变量副本。换句话说:每个线程都有自己的本地变量副本、互不干扰。它不是用来共享数据的,而是用来隔离数据的。 一、为什么需要 ThreadLocal?…...
MySQL-SQL-DQL语句、DQL基本查询、DQL条件查询、DQL分组查询、聚合函数、DQL排序查询、DQL分页查询
一. DQL DQL:Data Query Language(数据查询语言),用来查询数据库表中的记录。 关键字:SELETE -- DQL 完整语法select字段列表 from表名列表 where条件列表 group by分组字段列表 having分组后条件列表 order by排序字段列表 limit分页参数 …...
vue2 vue3 响应式差异
vue2 响应式原理看这 链接: link 总结: object.defineproperty()是对属性的劫持,对属性劫持有两大缺陷 1. 需要遍历对象的所有属性,深层属性需递归,存在效率问题 2. 后添加的属性,无法获得响应式,因为劫持…...
常见NLP模型发展脉络:从传统方法到大语言模型
自然语言处理作为人工智能领域的重要分支,经历了从传统统计方法到深度学习的巨大飞跃。本文将带你梳理NLP模型的发展脉络,回顾那些推动技术进步的重要里程碑。 一、统计学习阶段(1990s-2010s初) 早期的NLP模型主要基于统计方法&…...
Bert论文解析
文章目录 BERT:用于语言理解的深度双向转换器的预训练一、摘要三、BERT介绍BERT及其详细实现答疑:为什么没有标注的数据可以用来预训练模型?1. 掩码语言模型(Masked Language Model, MLM)2. 下一句预测(Nex…...
【数学】勒让德定理(legendres-formula)详解
勒让德定理(Legendre’s Formula)详解 这段代码使用的数学原理是勒让德定理,它是计算质数p在n!的质因数分解中指数的核心方法。 一、定理内容 对于任意质数p和正整数n,p在n!的质因数分解中的指数(即n!能被p整除的最…...
时空联合规划算法
本文主要讲解时空时空联合规划算法。 文章目录 前言一、时空联合规划基本概念1.1 EM Planner算法求解过程1.2 时空联合规划算法求解过程二、基于搜索的规划方法2.1 构建三维时空联合规划地图2.2 基于Hybrid A*的时空联合规划二、基于迭代搜索的规划方法2.1 这段时间更新中2.2 这…...
如何在idea中新建一个项目
Java通常展现的方式就是项目,但是在不熟悉idea的情况下,我们应该如何创建一个项目呢? 第一步:点击File-->New-->Project 第二步:选择 Empty Project 第三步:点击File-->找到Project Structure--&…...
设计模式简述(十三)适配器模式
适配器模式 描述基本使用使用关于适配器关联不兼容类的方式如果原有抽象层是抽象类若原有抽象是接口使用 描述 适配器模式常用于系统已经上限稳定运行,但现有需求需要将两个不匹配的类放到一起工作时使用。 也就是说这是一个迭代阶段使用的模式。 这种模式&#x…...
功耗日志抓取需求
最近罗列了一些功耗分析需要的常见日志: 测试功耗前: adb shell dumpsys batterystats --reset adb shell dumpsys batterystats --enable full-wake-history 测试功耗后,使用脚本导出如下功耗日志: 脚本 chmod x collect_logs.s…...
设计模式简述(十一)装饰器模式
装饰器模式 描述基本使用使用 描述 装饰器模式是一种功能型模式 用于动态增强对象的功能 这么一说感觉上和代理模式有些类似 抽象装饰器 要实现原有业务接口,并注入原有业务对象 至于对原有业务对象的调用,可以采用private业务对象 实现业务接口方法的…...
MongoDB基础知识
MongoDB基础知识 目录 基础篇 一、MongoDB入门指南(零基础必读)二、MongoDB简介三、MongoDB安装与配置四、MongoDB基本操作五、MongoDB查询操作 进阶篇 六、MongoDB索引七、MongoDB聚合操作八、MongoDB数据模型九、MongoDB安全十、MongoDB备份恢复十一…...
Kubernetes详细教程(一):入门、架构及基本概念
Kubernetes(常简称为K8s)是一个开源的平台,用于自动化部署、扩展和管理容器化应用程序。 官方文档:https://kubernetes.io/zh-cn/docs/concepts/overview/components/ 一、入门 (一)Kubernetes是什么&am…...
架构思维:限流技术深度解析
文章目录 Pre业务场景熔断 VS 限流4大限流算法固定时间窗口计数滑动时间窗口计数漏桶令牌桶 方案实现使用令牌桶还是漏桶模式?在 Nginx 中实现限流还是在网关层中实现限流?使用分布式限流还是单机限流?使用哪个开源技术? 限流方案…...
批量改CAD图层颜色——CAD c#二次开发
一个文件夹下大量图纸(几百甚至几千个文件)需要改图层颜色时,可采用插件实现,效果如下: 转换前: 转换后: 使用方式如下:netload加载此dll插件,输入xx运行。 附部分代码如…...
vue猜词游戏
说明:我希望用vue实现猜词游戏 Vue Wordle 游戏规则总结 核心规则 单词选择 目标单词从预设词库(DEFAULT_WORDS)中随机选取,均为5字母单词(如apple、zebra等)。 输入要求 长度限制:必须…...
SQL ②-库操作 | 数据类型
这里是Themberfue SQL语法 数据库术语 DATABASE:数据库,保存有组织的数据的容器(通常是一个文件或一组文件)。TABLE:表,某种特定类型数据的结构化清单。SCHEMA:模式,关于数据库和表…...
云轴科技ZStack CTO王为@中国GenAI大会:AI原生实践重构AI Infra新范式
4月1-2日,2025中国生成式AI大会(GenAICon 2025)在北京举办,该会议已成为国内AI领域最具影响力的产业峰会之一。来自学术界与产业界的50位嘉宾围绕GenAI应用、大模型、AI智能体、具身智能、DeepSeek R1与推理模型等话题,…...
处理甘特图启动依赖报错。
处理甘特图启动报错 一、修改甘特图下载地址1.1 配置修改1.2 修改地址(https://registry.npmmirror.com) 二、安装依赖1.1 安装sass-loader1.2 适配安装dhtmlx-gantt 一、修改甘特图下载地址 1.1 配置修改 npm config get registry1.2 修改地址(https://registry.npmmirror.c…...
JSX、支持HTML标签、Ref的使用、虚拟DOM的使用
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 🍚 蓝桥云课签约作者、…...
leetcode376-摆动序列
leetcode 376 思路 变量定义: prediff:记录上一次相邻元素的差值。用于判断当前差值与上一个差值的关系curdiff:记录当前相邻元素的差值result:记录当前的摆动序列的长度,初始化为 1,因为至少一个元素就…...
内网渗透(杂项集合) --- 中的多协议与漏洞利用技术(杂项知识点 重点) 持续更新
目录 1. NetBIOS 名称的网络协议在局域网中内网渗透中起到什么作用 2. 使用 UDP 端口耗尽技术强制所有 DNS 查找失败,这个技术如何应用在局域网内网渗透测试中 3. 在本地创建一个 HTTP 服务来伪造 WPAD 服务器 什么是 WPAD 服务器?这个服务器是干嘛的…...
14-产品经理-维护计划
产品经理的另一个职责是制定计划。古人云,凡事预则立,不预则废。 产品需要做规划,才能有轻重缓急,才能正确的做事。因此对于产品经理而言,计划是必需的。 对于产品经理自己而言,发布计划可以帮助他规划产…...
12-产品经理-维护模块
需求模块是帮助产品经理进行需求的分类和维护。 1. 维护模块 在具体产品的“研发需求”页面左侧,点击“维护模块”。也可以在具体产品的“设置”-“模块”下进行维护。 点击保存后,返回模块页面。还可以点击“子模块”对已有模块进行子模块的维护。 点击…...
解析HiveQL的ALTER TABLE ADD/REPLACE COLUMNS语句
阅读以下ALTER TABLE的ADD/REPLACE COLUMNS语句的语法,用C#编写解析函数,一个一个字符解析,所有关键字不区分大小写,一个或多个空格、Tab和换行的组合都可以是关键词之间的分隔,表名和字段名可能包含空格和Tab…...
MySQL-SQL-DML语句、INSER添加数据、UPDATE更新数据、DELETE删除数据
一. DML 1. DML的英文全称是Data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增、删、改操作。 2. 添加数据(INSERT);修改数据(UPDATE);删除数据(DELETE) 二. DML-INSER添加数据 -- DML insert -- 指定字段添加数…...
学透Spring Boot — 017. 处理静态文件
这是我的《学透Spring Boot》专栏的第17篇文章,了解更多内容请移步我的专栏: Postnull CSDN 学透 Spring Boot 目录 静态文件 静态文件的默认位置 通过配置文件配置路径 通过代码配置路径 静态文件的自动配置 总结 静态文件 以前的传统MVC的项目…...
Linux进程间通信——共享内存
1.概念 共享内存(Shared Memory)就是允许多个进程访问同一个内存空间,是在多个进程之间共享和传递数据最高效的方式。操作系统将不同进程之间共享内存安排为同一段物理内存,进程可以将共享内存连接到它们自己的地址空间中&#x…...
如何在大型项目中组织和管理 Vue 3 Hooks?
众所周知,Vue Hooks(通常指 Composition API 中的功能)是 Vue 3 引入的一种代码组织方式,用于更灵活地组合和复用逻辑。但是在项目中大量使用这种写法该如何更好的搭建结构呢?以下是可供参考实践的案例。 一、Hooks 组织原则 单一职责每个 Hook 应专注于完成单一功能,避…...
前后端开发的未来趋势
随着技术的不断进步,前后端开发模式也在不断演变。未来,微服务架构、Serverless、前后端融合(GraphQL、BFF)等趋势将深刻影响开发方式,使应用更高效、灵活、可扩展。 1. 微服务架构与 Serverless 1.1 微服务架构(Microservices Architecture) 微服务是一种软件架构模式…...
产品经理课程
原型工具 一、土耳其机器人 这个说法来源于 1770 年出现的一个骗局,一个叫沃尔夫冈冯肯佩伦(Wolfgang von Kempelen)的人为了取悦奥地利女皇玛丽娅特蕾莎(Maria Theresia),“制造”了一个会下国际象棋的机…...
【开源宝藏】30天学会CSS - DAY12 第十二课 从左向右填充的文字标题动画
用伪元素搞定文字填充动效:一行 JS 不写,效果炸裂 你是否曾经在设计页面标题时,觉得纯文字太寡淡?或者想做一个有动感的文字特效,但又不想引入 JS 甚至 SVG? 在这篇文章中,我们将通过 一段不到…...
Nginx 负载均衡案例配置
负载均衡案例 基于 docker 进行 案例测试 1、创建三个 Nginx 实例 创建目录结构 为每个 Nginx 实例创建单独的目录,用于存储 HTML 文件和配置文件 mkdir -p data/nginx1/html mkdir -p data/nginx2/html mkdir -p data/nginx3/html添加自定义 HTML 文件 在每个…...
Golang系列 - 内存对齐
Golang系列-内存对齐 常见类型header的size大小内存对齐空结构体类型参考 摘要: 本文将围绕内存对齐展开, 包括字符串、数组、切片等类型header的size大小、内存对齐、空结构体类型的对齐等等内容. 关键词: Golang, 内存对齐, 字符串, 数组, 切片 常见类型header的size大小 首…...
nginx中的limit_req 和 limit_conn
在 Nginx 中,limit_req 和 limit_conn 是两个用于限制客户端请求的指令,它们分别用于限制请求速率和并发连接数。 limit_req limit_req 用于限制请求速率,防止客户端发送过多请求影响服务器性能。它通过 limit_req_zone 指令定义一个共享内存…...
Python Cookbook-5.4 根据对应值将键或索引排序
任务 需要统计不同元素出现的次数,并且根据它们的出现次数安排它们的顺序——比如,你想制作一个柱状图。 解决方案 柱状图,如果不考虑它在图形图像上的含义,实际上是基于各种不同元素(用Python的列表或字典很容易处理)出现的次…...
U535982 J-A 小梦的AB交换
U535982 J-A 小梦的AB交换 - 洛谷 题目描述 小梦有一个长度为 2⋅n 的 AB 串 s,即 s 中只包含 "A" 和 "B" 两种字符,且其中恰好有 n 个 "A" 和 n 个 "B"。 他可以对 s 执行以下操作: 选择 i,j (…...
2025高频面试算法总结篇【排序】
文章目录 直接刷题链接直达把数组排成最小的数删除有序数组中的重复项求两个排序数组的中位数求一个循环递增数组的最小值数组中的逆序对如何找到一个无序数组的中位数链表排序从一大段文本中找出TOP K 的高频词汇 直接刷题链接直达 把一个数组排成最大的数 剑指 Offer 45. 把…...
计算机视觉基础4——特征点及其描述子
一、特征点检测 (一)特征点定义 图像中具有独特局部性质的点。 (二)特征点性质 具有局部性(对遮挡和混乱场景鲁棒)、数量足够多(一幅图像可产生成百上千个)、独特性(…...
React 初学者进阶指南:从环境搭建到部署上线
概览 环境搭建 核心概念 TodoList 实战 部署上线 一、快速搭建 React 开发环境 1. 选型:Vite 或 Create React App Vite:轻量、热更新速度快、可定制度高,适合追求更高效率的开发者。Create React App (CRA):社区支持全面,文档丰富,适合初学者上手。我使用的是Vite 提示…...
docker加docker compose实现软件快速安装启动
docker 下载镜像官网页面:https://hub.docker.com/ docker是什么? 加速应用构建、分享、运行 docker命令 镜像操作 容器操作 docker ps:查看运行中的容器 docker ps -a: 查看所有容器,包括停止的 除了docker run和docker exec两个命令其余执…...
使用人工智能大模型腾讯元宝,如何免费快速做工作总结?
今天我们学习使用人工智能大模型腾讯元宝,如何免费快速做工作总结? 手把手学习视频地址:https://edu.csdn.net/learn/40402/666429 第一步在腾讯元宝对话框中输入如何协助老师做工作总结,通过提问,我们了解了老师做工…...
【小兔鲜】day03 Home模块与一级分类
【小兔鲜】day03 Home模块与一级分类 1. Home-整体结构搭建和分类实现1.1 页面结构 2. Home-banner轮播图功能实现 1. Home-整体结构搭建和分类实现 1.1 页面结构 分类实现 2. Home-banner轮播图功能实现 轮播图实现 在HomeBanner.vue中写出轮播图的结构 在apis目录下新建h…...
c++使用gstreamer录屏+声音
说明: c使用gstreamer完成录制电脑桌面的功能 我希望用gstreamer录屏,默认10秒,自动保存录屏文件到本地 这里是不带声音的版本,仅录屏, step1:C:\Users\wangrusheng\source\repos\CMakeProject1\CMakeProject1\CMakeL…...
PowerToys:Windows高效工具集
Microsoft PowerToys 是微软官方推出的 免费开源效率工具集,专为 Windows 系统设计,通过模块化功能解决高频操作痛点,提升用户生产力。支持 Windows 10/11 系统,覆盖开发者、设计师及普通办公场景。 一、核心功能亮点 高…...
pulsar中的延迟队列使用详解
Apache Pulsar的延迟队列支持任意时间精度的延迟消息投递,适用于金融交易、定时提醒等高时效性场景。其核心设计通过堆外内存索引队列与持久化分片存储实现,兼顾灵活性与可扩展性。以下从实现原理、使用方式、优化策略及挑战展开解析: 一、核…...
import torch 失败
1. 使用 PyTorch 官方 Conda 频道安装 运行以下命令(根据你的 CUDA 版本选择): # CPU 版本 conda install pytorch torchvision torchaudio cpuonly -c pytorch# CUDA 11.8 版本 conda install pytorch torchvision torchaudio pytorch-cud…...