基于MCP协议构建天气查询工具:从原理到Node.js实战
1. 项目概述为什么从MCP天气查询工具入手最近和几个做AI应用开发的朋友聊天发现大家不约而同地都在研究一个叫“模型上下文协议”的东西也就是MCP。这玩意儿听起来挺高大上但说白了它就像给大语言模型比如ChatGPT、Claude装上了一套标准化的“手”和“眼睛”。模型本身是个聪明的“大脑”但它没法直接操作电脑、读取文件、查询网络数据。MCP就是定义了一套标准方法让“大脑”可以安全、可控地指挥“手”去执行具体任务。那为什么选择从“天气查询”这个工具开始呢原因很简单它是一个绝佳的MCP入门练手项目。首先它的业务逻辑清晰——输入地点返回天气信息。其次它涉及了MCP最核心的几个概念工具Tools的定义、服务器Server的实现、以及客户端Client的调用。最后它需要与外部API天气服务交互这正好体现了MCP“连接模型与现实世界”的核心价值。通过亲手实现一个天气查询MCP工具你能把MCP的抽象概念迅速具象化理解数据是如何在模型、MCP服务器和外部服务之间流转的。这比你读十篇文档都管用。2. 核心概念与工具选型构建MCP的基石在动手写代码之前我们必须把几个关键概念和工具理清楚。这就像盖房子前得先认识砖瓦和图纸。2.1 MCP的三层架构Server, Client ToolsMCP的架构非常清晰主要包含三层MCP Server服务器这是你将要编写的核心部分。它对外暴露一组定义好的“工具”Tools。你可以把它想象成一个“技能提供者”。在我们的天气项目中这个服务器就提供了一个叫get_weather的工具。MCP Client客户端这是与大语言模型如Claude Desktop、Cursor等集成的部分。客户端负责与MCP Server建立连接获取可用的工具列表并在模型需要时代表模型去调用服务器上的工具。客户端通常由AI应用平台提供我们不需要从头写。Tools工具这是MCP协议中定义的“能力单元”。每个工具都有明确的名称、描述、输入参数input_schema和输出。模型的“大脑”通过阅读工具的描述来决定在什么时候、使用什么参数来调用它。对于我们开发者而言核心工作就是实现一个MCP Server并在其中定义好我们想让模型使用的工具。2.2 为什么选择Node.js和官方SDK实现MCP Server有多种语言选择比如Python、TypeScript等。这里我强烈推荐使用TypeScript (Node.js)并结合modelcontextprotocol/sdk这个官方SDK。理由如下官方背书与活跃度这是由AnthropicClaude的创造者官方维护的SDK更新及时与协议标准同步性最好遇到问题也容易找到答案。开发体验优秀TypeScript提供了完善的类型提示SDK的封装让建立连接、定义工具、处理请求变得非常直观能避免很多低级错误。生态成熟Node.js的异步和非阻塞I/O特性非常适合处理MCP这种多请求、需要调用外部网络API的场景。NPM上有海量的包可以辅助开发比如我们马上会用到的axios。注意虽然Python也有社区实现的库但就目前的稳定性和文档完整性来看官方的Node.js SDK是新手入门阻力最小的选择。2.3 天气数据源的选择与考量工具的核心是数据。为天气查询工具选择一个可靠、免费或低成本、易于使用的数据源至关重要。这里有几个常见选项OpenWeatherMap老牌服务提供免费层每分钟60次调用数据全面文档清晰。免费层需要注册获取API Key。WeatherAPI另一个流行的选择免费层额度也不错提供多种数据。和风天气国内如果你主要查询国内地点这是个非常优秀的选择中文支持好免费额度足够个人开发使用。我个人的选择是 OpenWeatherMap。原因在于其国际覆盖广API设计规范社区资源多遇到问题容易搜索到解决方案。我们接下来的实现也将以它为例。关键一步请立即去 OpenWeatherMap官网 注册一个免费账户获取你的API Key。这个Key将用于在代码中认证你的请求。3. 手把手实现MCP天气查询服务器理论铺垫完毕现在进入实战环节。请确保你的开发环境已经安装了Node.js (版本18或以上)和npm。3.1 项目初始化与依赖安装首先创建一个新的项目目录并初始化mkdir mcp-weather-server cd mcp-weather-server npm init -y接着安装我们需要的核心依赖npm install modelcontextprotocol/sdk axios npm install --save-dev typescript ts-node types/nodemodelcontextprotocol/sdk MCP官方SDK。axios 一个优秀的HTTP客户端用于调用OpenWeatherMap的API。typescript,ts-node,types/node 用于TypeScript开发和执行。然后初始化TypeScript配置npx tsc --init你可以根据需要修改生成的tsconfig.json一个简单的可用于快速启动的配置如下{ compilerOptions: { target: ES2022, module: commonjs, outDir: ./dist, rootDir: ./src, strict: true, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true }, include: [src/**/*], exclude: [node_modules] }创建源代码目录和入口文件mkdir src touch src/index.ts3.2 构建MCP服务器骨架现在打开src/index.ts开始编写服务器的核心代码。我们先从导入依赖和搭建基础结构开始import { Server } from modelcontextprotocol/sdk/server/index.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import axios from axios; // 1. 定义工具Tool的输入参数结构 // 这告诉MCP客户端和模型调用get_weather工具时需要提供一个location字符串参数。 const WEATHER_TOOL { name: get_weather, description: 获取指定城市或地区的当前天气信息。, inputSchema: { type: object, properties: { location: { type: string, description: 城市或地区名称例如: Beijing, London, Tokyo, }, }, required: [location], }, }; // 2. 创建MCP服务器实例 // WeatherServer 是我们给这个服务器起的名字。 const server new Server( { name: WeatherServer, version: 1.0.0, }, { capabilities: { tools: {}, // 这里先留空我们会在后面动态添加工具处理逻辑 }, } );3.3 实现工具处理逻辑这是服务器的“大脑”。我们需要告诉服务器当get_weather工具被调用时具体要执行什么操作。// 3. 设置工具处理函数 server.setRequestHandler(tools/call, async (request) { // 检查被调用的工具名称是否是我们定义的get_weather if (request.params.name WEATHER_TOOL.name) { const location (request.params.arguments as any).location; if (!location) { throw new Error(Location parameter is required.); } // 你的OpenWeatherMap API Key务必替换成你自己的 const API_KEY YOUR_OPENWEATHERMAP_API_KEY_HERE; // 使用标准单位摄氏度、米/秒等 const url https://api.openweathermap.org/data/2.5/weather?q${encodeURIComponent(location)}appid${API_KEY}unitsmetric; try { // 调用外部天气API const response await axios.get(url); const data response.data; // 从API响应中提取我们需要的信息 const weatherInfo { location: data.name, country: data.sys.country, temperature: ${data.main.temp}°C, feels_like: ${data.main.feels_like}°C, humidity: ${data.main.humidity}%, pressure: ${data.main.pressure} hPa, weather: data.weather[0].description, wind_speed: ${data.wind.speed} m/s, }; // 将结果格式化成易读的文本返回给MCP客户端最终给到大模型 const contentText 当前 ${weatherInfo.location} (${weatherInfo.country}) 的天气状况 - 天气${weatherInfo.weather} - 温度${weatherInfo.temperature} (体感 ${weatherInfo.feels_like}) - 湿度${weatherInfo.humidity} - 气压${weatherInfo.pressure} - 风速${weatherInfo.wind_speed} .trim(); return { content: [ { type: text, text: contentText, }, ], }; } catch (error: any) { // 错误处理网络问题、城市未找到、API Key无效等 let errorMessage 无法获取天气信息。; if (axios.isAxiosError(error) error.response) { if (error.response.status 404) { errorMessage 未找到地点 ${location}请检查名称是否正确。; } else if (error.response.status 401) { errorMessage 天气服务认证失败请检查API Key。; } else { errorMessage 天气服务返回错误: ${error.response.status}; } } // 将错误信息返回模型可以据此回复用户 return { content: [ { type: text, text: 错误: ${errorMessage}, }, ], isError: true, }; } } // 如果收到其他未知工具的调用请求抛出错误 throw new Error(Unknown tool: ${request.params.name}); });3.4 启动服务器与连接传输MCP服务器需要通过一种“传输”方式与客户端通信。对于本地开发调试最常用、最简单的方式是标准输入输出stdio。这意味着我们的服务器将通过命令行启动并通过控制台的输入输出来与客户端如Claude Desktop交换数据。// 4. 启动服务器 async function runServer() { // 使用Stdio传输这是与桌面客户端集成的最常见方式 const transport new StdioServerTransport(); await server.connect(transport); console.error(MCP Weather Server is running on stdio...); } // 5. 在服务器连接前告知客户端本服务器提供哪些工具 // 这是关键一步客户端在连接时会请求工具列表。 server.setRequestHandler(tools/list, async () { return { tools: [WEATHER_TOOL], }; }); runServer().catch((error) { console.error(Server fatal error:, error); process.exit(1); });至此一个完整的MCP天气查询服务器就编写完成了。你的src/index.ts文件现在应该包含了以上所有代码块。实操心得在开发过程中务必用你自己的真实API Key替换YOUR_OPENWEATHERMAP_API_KEY_HERE。一个常见的错误是忘记替换或误将Key提交到公开的代码仓库这会导致API调用失败或Key泄露。建议使用环境变量来管理敏感信息例如process.env.OPENWEATHER_API_KEY。4. 编译、运行与测试代码写好了我们得让它跑起来并验证是否工作。4.1 编译TypeScript并运行首先编译TypeScript代码到JavaScriptnpx tsc这会在dist目录下生成index.js文件。更便捷的方式是使用ts-node直接运行省去编译步骤特别适合开发阶段npx ts-node src/index.ts如果一切正常你会看到MCP Weather Server is running on stdio...这条信息输出到标准错误流stderr然后程序看起来就“挂起”了。这是正常的因为它正在等待来自标准输入stdin的MCP协议消息。此时你需要一个MCP客户端来连接它。4.2 使用MCP Inspector进行本地测试在集成到Claude Desktop等大型应用之前强烈建议先用一个轻量级的调试工具进行测试。这就是MCP Inspector。全局安装MCP Inspectornpm install -g modelcontextprotocol/inspector启动Inspector并连接我们的服务器 我们需要告诉Inspector如何启动我们的服务器。创建一个简单的配置文件比如server-config.json{ mcpServers: { weather: { command: node, args: [/ABSOLUTE/PATH/TO/YOUR/mcp-weather-server/dist/index.js], env: { NODE_ENV: development } } } }注意args中的路径必须替换为你项目dist/index.js的绝对路径。如果使用ts-nodecommand可以是npxargs可以是[ts-node, /ABSOLUTE/PATH/TO/src/index.ts]。运行Inspectormcp-inspector --config ./server-config.json这会打开一个本地网页通常是http://localhost:5173这就是MCP Inspector的界面。在Inspector中测试工具在Inspector网页中你应该能在左侧看到连接的weather服务器。点击它你会看到它提供的get_weather工具。在工具面板的输入框里输入{location: Beijing}。点击 “Call Tool”。如果一切配置正确右侧会显示来自OpenWeatherMap API的、格式化的北京天气信息。成功这证明你的MCP服务器逻辑正确能够处理请求、调用外部API并返回结果。4.3 集成到Claude Desktop可选但推荐真正的魅力在于让AI模型使用你的工具。以Claude Desktop为例找到Claude Desktop的配置文件位置。macOS:~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:%APPDATA%\Claude\claude_desktop_config.json编辑这个JSON文件如果不存在则创建{ mcpServers: { weather: { command: node, args: [/ABSOLUTE/PATH/TO/YOUR/mcp-weather-server/dist/index.js] } } }同样请替换为你的绝对路径。如果使用ts-node配置方式同Inspector。重启Claude Desktop。现在当你和Claude对话时你可以直接说“帮我查一下东京的天气。” Claude会自动识别出它有一个get_weather工具可用并在后台调用你的服务器然后将结果融入它的回复中。整个过程无缝衔接用户感知到的就是Claude“知道”了天气。5. 进阶优化与问题排查实录一个基础工具跑起来后我们可以让它更健壮、更实用。下面分享几个我在实际开发中总结的优化点和常见坑位。5.1 功能优化从基础查询到实用工具多单位支持让用户或模型可以选择温度单位摄氏/华氏。修改工具的inputSchema增加一个unit可选参数然后在调用API时根据这个参数决定units字段是metric还是imperial。位置模糊处理OpenWeatherMap对某些中文地名支持可能不完美。可以引入一个地理位置解析服务如OpenCage Geocoder先将地名转换为经纬度再用经纬度去查询天气提高准确率。缓存机制天气数据变化不频繁频繁调用API会浪费额度且慢。可以引入一个简单的内存缓存如node-cache将相同地点的结果缓存5-10分钟。更丰富的信息除了当前天气OpenWeatherMap的API还提供预报、空气质量等。你可以定义更多工具如get_forecast或者扩展当前工具的参数来返回更多数据。5.2 常见问题与解决方案速查表问题现象可能原因排查步骤与解决方案Inspector/Claude 无法连接服务器1. 配置文件路径错误。2. Node命令执行失败。3. 服务器代码有语法错误立即崩溃。1.检查绝对路径确保args中的路径完全正确特别是使用ts-node时。一个技巧是先在对应目录下用命令行手动执行该命令看是否成功。2.查看日志Claude Desktop会在其日志文件中记录MCP服务器的启动错误。去上述配置文件的同级目录找日志文件。3.独立运行测试在项目目录下直接运行node dist/index.js观察是否有错误输出。调用工具返回“未找到地点”1. 输入的地点名称API不认识。2. 地点名称含有特殊字符或格式问题。1.尝试英文名用“Beijing”而不是“北京”试试。2.URL编码确保代码中使用了encodeURIComponent(location)来处理输入。3.提供更具体信息在工具描述中提示用户输入“城市名,国家代码”格式如“London,GB”。返回“认证失败”1. API Key未设置或错误。2. API Key对应的免费额度已用尽。1.检查代码确认API_KEY变量已正确替换。2.访问OpenWeatherMap网站登录账号在控制面板检查API Key状态和调用次数。服务器运行后无响应或卡死1. 没有正确处理请求或响应格式不符合MCP协议。2.async/await使用不当Promise未捕获。1.使用Inspector调试Inspector能清晰显示通信的原始JSON消息对比MCP协议文档检查你的请求处理器返回的结构是否正确。2.强化错误处理确保所有可能的异常都被try...catch包裹并返回格式正确的错误信息给客户端而不是让进程崩溃或挂起。Claude不主动使用工具1. 工具描述不够清晰。2. 用户提问方式不够直接。1.优化工具描述description字段要写得非常清晰说明工具用途、输入是什么。例如“获取全球城市的当前天气情况需要提供城市名称。”2.明确指令直接对Claude说“请使用天气工具查询XX的天气”看它是否会调用。这是测试工具是否成功加载的好方法。5.3 安全与生产环境考量保护API Key永远不要将硬编码的API Key提交到Git仓库。使用环境变量.env文件配合dotenv包或运行时配置来管理。输入验证与清理虽然MCP客户端和模型会进行初步校验但服务器端仍应对location参数进行基本的清理和验证防止注入攻击。限流与配额如果你的工具公开使用需要考虑对调用频率进行限制防止滥用耗尽你的API免费额度。6. 总结与延伸思考通过这个简易的MCP天气查询工具项目我们完整走通了一个MCP Server从概念到实现、再到测试集成的全流程。你亲手搭建了一个桥梁让原本“困在”文本世界的大模型获得了感知现实世界天气的能力。这个项目的价值远不止于查询天气。它提供了一个可复用的范式。下一次当你想让AI模型帮你“读取某个GitHub仓库的最新Issue”、“查询数据库里的用户数据”、“控制家里的智能灯光”时你只需要做同样的事情定义一个工具实现一个MCP Server然后将它连接到你的AI助手。我个人在实践中的体会是MCP最大的魅力在于标准化和生态。一旦工具按照协议实现它就可以被任何支持MCP的客户端Claude, Cursor, 未来可能更多的AI应用所使用。这意味着你的一次开发可以赋能多个AI入口。随着协议的发展或许未来会出现一个丰富的“MCP工具商店”开发者可以共享工具用户则可以像安装插件一样为自己AI助手扩展各种超能力。从这个小工具出发你可以尝试更复杂的场景比如一个需要多步交互的工具先搜索再选择最后执行或者结合多个API的工具链。MCP的世界刚刚打开更多的可能性正等待被构建。

相关新闻

react - Hooks为什么不能写到判断里面

react - Hooks为什么不能写到判断里面

文章目录核心原因:React 依靠“调用顺序”来匹配 Hook底层机制:单向链表(Linked List)1. 首次挂载(Mount)2. 重新渲染(Update)如果把 Hook 写进 if 会发生什么?场景演示&…

2026/10/2 12:41:27 阅读更多 →
计算机毕业设计之基于Python网上购物商品评论的爬虫分析设计与实现

计算机毕业设计之基于Python网上购物商品评论的爬虫分析设计与实现

系统概述作为大数据分析系统,数据采集、数据处理、数据分析和数据可视化是基于Python网上购物商品评论的爬虫分析设计与实现具备的基本素质。除此之外,本系统在用户交互方面做到了傻瓜式一键交互,按下按键,功能完成。数据抓取、数…

2026/10/13 10:59:06 阅读更多 →
储水式电热水器选购指南:速热、一级能效与防电墙技术解析

储水式电热水器选购指南:速热、一级能效与防电墙技术解析

1. 先搞清楚“速热”、“一级能效”和“防电墙”到底意味着什么如果你正在看100L容量的储水式电热水器,特别是像美的F10033-X1(S)这类型号,最需要弄明白的不是品牌和型号,而是标题里这几个关键词在你实际使用中到底代表什么。很多人买热水器只…

2026/10/9 13:30:01 阅读更多 →

最新新闻

AI搜索时代,企业网络推广该换哪套判断标准

AI搜索时代,企业网络推广该换哪套判断标准

最近半年,一个明显的变化是:越来越多用户不再翻搜索结果页,而是直接问AI要答案。这个变化对企业网络推广的冲击,比很多人想象中更底层——它不是多了一个流量渠道,而是换了一套筛选逻辑。过去做推广,判断标…

2026/10/14 17:02:20 阅读更多 →
应届生简历怎么写?从HR筛选逻辑到STAR法则的完整指南

应届生简历怎么写?从HR筛选逻辑到STAR法则的完整指南

每年到秋招春招季,我都会被各种亲戚、学弟学妹、网友拖着看简历。说得不客气一点,大多数应届生的问题根本不是“经历太少”,而是“根本不知道简历是什么”。很多人把简历当成一篇自我介绍,恨不得把大学四年所有细节都写进去。结果…

2026/10/14 17:02:20 阅读更多 →
低功耗ASK射频发射芯片XL4456从原理到量产调试全攻略

低功耗ASK射频发射芯片XL4456从原理到量产调试全攻略

做低功耗无线硬件这么多年,我有一句话经常挂在嘴边:真正的物联网不只在云端和大屏上,更多藏在没人注意的遥控器、门铃、车位锁和传感器节点里。最近重新设计一款无线遥控门禁系统,发射端我选的就是标题里这颗低功耗 ASK 射频发射芯…

2026/10/14 17:02:20 阅读更多 →
XL4456低功耗ASK射频发射芯片:从原理到实战全解析

XL4456低功耗ASK射频发射芯片:从原理到实战全解析

很多做遥控器、传感器上报、电子标签这类项目的朋友,第一版方案里几乎都会遇到一颗低功耗 ASK 射频发射芯片 XL4456。它不像 MCU 那样需要写一堆初始化代码,也不像 2.4G 方案那样要跑协议栈,本质上它就是一个能用数字电平直接控制的射频功率开…

2026/10/14 17:02:20 阅读更多 →
宽温磁环电感可靠性验证:汽车电子EMC整改的关键防线

宽温磁环电感可靠性验证:汽车电子EMC整改的关键防线

一块板子在暗室里做EMC摸底,整改工程师换了三包磁环还是压不下那个700mV的尖刺,最后发现是电感在高温箱里呆过之后,磁导率掉了一半。这种问题,我在汽车电子项目里见过不止一次。项目组在开发阶段只测了磁环常温下的阻抗和电感量&a…

2026/10/14 17:02:20 阅读更多 →
学术AI工具怎么选更划算?六款科研工具按环节搭配的性价比盘点

学术AI工具怎么选更划算?六款科研工具按环节搭配的性价比盘点

一、工具越多,性价比这笔账越算越乱1、行业背景。 近几年大模型能力快速落地,学术场景成了试验田。检索、翻译、改写、润色、绘图,几乎每个环节都冒出专门工具,订阅方式从免费额度到按年付费各有不同。选择变多了,判断成本也跟着涨,同一笔预算怎么分配成了新问题。2、不同人群的…

2026/10/14 17:01:19 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →