Pollinations MCP Server 开发指南:薄代理设计、无状态 HTTP 与工具扩展实战
AI 应用媒体生成后端前端【免费下载链接】pollinationsYour Friendly Open-Source Gen-AI Platform项目地址https://gitcode.com/gh_mirrors/po/pollinations点击查看免费下载Pollinations 是一个开源多模型生成式 AI 平台Your Friendly Open-Source Gen-AI Platform其官方 MCPModel Context Protocol服务器将 Pollinations 的文本、图像、视频、音频、3D 与账户能力封装为一组 Agent 工具供 Claude Desktop、Cursor 等宿主通过 Streamable HTTP 调用。本文以仓库内 Agent Guidelines for MCP Server Development 为核心骨架结合 packages/mcp 的源码实现、测试用例 与 部署 Worker系统讲解该服务器的五大设计原则、代码结构、无状态 HTTP 纪律、工具注册流程、模型校验模式与测试方法。读完本文你将掌握如何在既有架构约束下安全地为 Pollinations MCP Server 新增一个工具并理解其薄代理 实时注册表校验 请求级鉴权的实现原理。一、设计原则为什么 MCP Server 要做得薄AGENTS.md开篇给出了五条设计原则它们是整个代码库的灵魂也是审查任何新增代码时的第一检查项。1. 薄代理Thin ProxyAPI 调用全部经由gen.pollinations.ai网关转发生成的媒体复用 API 已返回的公开 URL作为 MCP resource link不做下载再上传。媒体 URL 有两个来源图像 API 的 JSON 响应data[0].url字段二进制响应视频、音频、3D的Link响应头relenclosure。对应的实现位于 coreUtils.js 的 fetchMediaLink请求发出后读取响应头Link中^([^]); relenclosure$捕获组得到公开文件 URL随即response.body?.cancel()释放连接绝不把二进制数据拉进内存const mediaUrl response.headers .get(Link) ?.match(/^([^]); relenclosure$/)?.[1]; await response.body?.cancel(); if (!mediaUrl) throw new Error(Media generation returned no public file URL);同时服务端禁止直接调用其他服务主机必须走网关的 rewrite 路由/account/*、/image/*、/text/*、/audio/*、/v1/*。这一约束在 coreUtils.js 的 buildUrl 中落地所有请求都基于单一API_BASE_URL默认https://gen.pollinations.ai可由环境变量POLLINATIONS_BASE_URL覆盖拼接路径天然杜绝了向任意第三方主机发请求的写法。2. 无硬编码模型/音色枚举MCP Server不内置任何模型名或音色名的枚举而是通过 utils/models.js 实时拉取注册表校验。工具参数 schema 一律写成z.string()并在描述中提示使用listModels获取实时列表。原因很直接Pollinations 是活的多模型网关模型随时可能上下架、新增别名硬编码会让工具在模型变更后立刻失准。3. 不转换响应数据API 响应原样透传仅在需要 MCP content block 时才做重塑例如把生成的媒体 URL 包装成 resource link。这条原则保证了 MCP 返回内容与网关真实数据一致避免二次加工引入偏差。4. 最小工具面Minimal Tool Surface每个工具都会成为 LLM 推理的额外上下文也是选错工具的一个机会。因此只在宿主Claude Desktop、Cursor 等内真正有用的工具才会被加入。当前 server 注册了 17 个工具见下文工具全览每个都对应一个明确的 API 能力域。5. 无状态 HTTPStateless HTTP OnlyBearer token 从请求上下文读取不引入进程内状态、认证工具、会话或 stdio 入口。这是整个服务可部署为 Cloudflare Worker、可水平扩展的前提。二、代码结构按服务域组织的模块化布局AGENTS.md给出了标准目录结构仓库实际布局与之一致packages/mcp/ src/ server.js # server factory、工具注册、SERVER_INSTRUCTIONS services/ imageService.js # generateImage, generateVideo textService.js # generateText audioService.js # generateAudio, transcribeAudio embeddingService.js # createEmbeddings model3dService.js # generate3D discoveryService.js # listModels, getModelStatus accountService.js # getBalance, getUsage, getEarnings, listQuests, listKeys, createKey, revokeKey走 /account/* utils/ authUtils.js # 请求级 bearer 鉴权 coreUtils.js # fetch 封装、URL 构建、错误映射 models.js # 注册表拉取 校验器 test/ accountService.test.js audioService.test.js coreUtils.test.js discoveryService.test.js textService.test.js AGENTS.md README.md package.json各文件职责要点server.js导出createMcpHandler与buildServer()。buildServer创建McpServer实例声明SERVER_VERSION当前为 2.5.1见 package.json把来自 7 个 service 的工具数组全部 spread 进tools再通过server.registerTool(name, { description, inputSchema: z.object(inputSchema) }, handler)逐个注册server.js L70-L77。SERVER_INSTRUCTIONS作为注入给 LLM 的系统级指令包含鉴权方式、模型发现与生成约定、账户权限要求、API Endpoint 四部分其中 Endpoint 由validateApiBaseUrl()动态生成。utils/authUtils.js负责从context.http.authInfo.token解析密钥并拼装Authorization: Bearer ...头coreUtils.js提供buildUrl、fetchWithAuth、fetchJsonWithAuth、fetchMediaLink、createMCPResponse、createTextContent、parseApiErrormodels.js提供按模态分组的注册表获取与校验函数。apps/mcp/worker.js托管在 Cloudflare 的 Streamable HTTP Worker导入packages/mcp/src/server.js的工厂负责 bearer token 解析、健康检查、批量请求拒绝等 HTTP 边界职责。三、无状态 HTTP 纪律凭据只属于一个请求AGENTS.md强调The public server uses Streamable HTTP without MCP sessions. Credentials belong to one request and must never be stored in module state.这在两层代码中体现为硬约束第一层工具层。authUtils.js 每次调用都从请求上下文取密钥function resolveApiKey(context) { return context?.http?.authInfo?.token || null; }requireApiKey(context)在无密钥时抛出提示信息getAuthHeaders(context)在存在密钥时才附加Authorization头。密钥从不写入模块级变量、不缓存、不进会话。第二层HTTP 边界层。apps/mcp/worker.js 在fetch入口解析Authorization: Bearer token未携带则直接返回 401带WWW-Authenticate头通过后将 token 作为authInfo.token传入 MCP handlerreturn mcpHandler.fetch(request, { authInfo: { token, clientId: pollinations-api-key, scopes: [], }, });同时 Worker 使用legacy: stateless模式worker.js L6-L9并拒绝 JSON 数组形式的批量请求返回 400invalid_request进一步强化一次请求一次鉴权的纪律。/health端点返回stateless: true便于探活确认。四、添加一个工具五步标准流程AGENTS.md给出新增工具的标准步骤结合源码可将每一步落到具体位置在相关 service 文件中添加 handler新域则新建 service 文件。handler 签名统一为async (params, context) { ... }内部先requireApiKey(context)再校验模型如需要最后通过fetchJsonWithAuth/fetchMediaLink调用网关并组装 MCP 响应。在工具数组中导出[name, description, zodShape, handler]四元组。例如 imageService.js 的 imageToolsname是工具名description是给 LLM 看的能力说明含先用 listModels的提示语zodShape是 zod schema 对象handler是执行函数。在 src/server.js 导入数组并 spread 进tools。工具顺序即注册顺序buildServer会将其逐一注册。在SERVER_INSTRUCTIONS中补一行说明server.js L26-L54确保注入给 LLM 的指引与工具面同步。更新 README.md 的工具表格记录工具名、用途与对应 API 路由保持文档与实现一致。服务端的工具四元组会被z.object(inputSchema)包装成 MCP 输入 schemadescription会被 MCP 协议暴露给宿主 LLM因此描述的质量直接影响 Agent 的工具选择准确率——这也是最小工具面原则的延伸宁缺毋滥。五、校验模式剖析注册表实时校验 模糊建议AGENTS.md给出了标准的校验写法import { validateImageModel } from ../utils/models.js; const result await validateImageModel(model); if (!result.valid) { throw new Error(${result.error} Use listModels for the live registry.); }底层实现在 models.js 的 validateAgainstRegistry流程如下若模型名为空直接返回{ valid: true }未指定模型时走网关默认值拉取对应模态的实时注册表/image/models、/text/models、/video/models、/audio/models、/embeddings/models、/3d/models全部经 MODEL_PATHS 映射按m.name modelName || m.aliases?.includes(modelName)匹配规范名或别名未命中时对名称做双向子串匹配最多给出 3 个建议名并附带availableCount供错误提示使用。各模态的校验入口validateImageModel、validateTextModel、validateVideoModel、validateEmbeddingModel、validateModel3d均由该函数参数化生成。实际错误信息比模板更友好例如 imageService.js L16-L22throw new Error( ${validation.error} Did you mean: ${validation.suggestions.join(, )}? Use listModels with typeimage to see all available models., );这套机制保证模型名拼写错误、模型下线、新增模型都能得到实时、可操作的反馈而不会出现模型不存在但工具仍按旧枚举放行的过期行为。六、工具全览17 个工具的能力域与 API 路由结合 README.md 工具表 与各 service 源码当前工具面如下工具用途API 路由generateText文本生成、搜索、多模态输入与工具调用/v1/chat/completionsgenerateImage生成或编辑图像/v1/images/generationsgenerateVideo生成视频/video/{prompt}generateAudio生成语音、音乐或音效/audio/{text}transcribeAudio转写公开 HTTPS 音频 URL/v1/audio/transcriptionsgenerate3D生成 GLB 3D 模型/3d/{prompt}createEmbeddings创建文本或多模态嵌入/v1/embeddingslistModels搜索并列出实时模型、能力、音色与定价模型注册表路由getModelStatus查看近期请求、错误与延迟/models/statusgetBalance查询剩余 Pollen 余额需account:usage/account/balancegetUsage请求历史或按日汇总需account:usage/account/usage、/account/usage/dailygetEarningsBYOP 应用与社区模型的开发者收益需account:usage/account/earningslistQuests任务奖励与领取状态需account:usage/account/questslistKeys列出 API 密钥需account:keys/account/keyscreateKey创建 secret 或 publishable 应用密钥需account:keysPOST /account/keysrevokeKey按 id 吊销密钥需account:keysDELETE /account/keys/{id}几个值得深入的点生成类工具的典型返回图像返回resource_linkuri为image.urlmimeType为image.media_type 结构化文本元数据视频/音频/3D 通过fetchMediaLink拿到content-type与公开 URL 后同样组装resource_link。媒体以链接形式返回不占用模型上下文窗口且任何持有链接者都可访问过期文件返回 404README 原话。generateText是能力最重的工具textService.js 的 schema 覆盖 messages6 种角色、温度/采样参数temperature0-2、top_p0-1、三类惩罚系数、response_formattext/json_object/json_schema 结构化输出、reasoning_effort、tools/tool_choice/parallel_tool_calls、modalities/audio语音输出、logprobs/logit_bias、legacy 的functions/function_call等响应侧按assistantMessage拆分 content、reasoning_content、tool_calls、function_call、audio含转录文本与citations最后附上model、finish_reason、usage元数据。账户类工具权限由 API 端强制读类需account:usage密钥类需account:keys错误信息原样透传accountService.js L10-L11createKey返回完整密钥仅此一次工具描述明确要求展示给用户且不得存储accountService.js L179。getUsage支持dailytrue切换汇总口径days上限 90、limit默认 20accountService.js L50-L60。listModels的过滤参数typeall/text/image/video/audio/embedding/3d、community仅社区/仅官方模型、agent仅 Agent、query名称/别名/标题/描述/发布者全词匹配、capabilities如tool_calling、reasoning、web_search、limit上限 500服务端在 Gen 侧过滤客户端只传筛选条件discoveryService.js L10-L16。七、错误映射与安全细节coreUtils.js 的 parseApiError 把网关的 HTTP 错误翻译成对 LLM 友好的中文/英文提示400命中 content moderation/safety/blocked 时提示内容被安全过滤器拦截命中 invalid model 时提示用listModels查看可用模型401提示发送有效 API 密钥bearer token及其获取入口403优先透传 API 返回的原始错误消息如密钥无权使用该模型无消息时才用兜底文案404 / 429 / 5xx / 502-504分别给出资源不存在、限流并提示 publishablepk_密钥可升级 secretsk_密钥以提升限额、服务器错误与临时不可用提示。coreUtils.test.js 对该映射有针对性覆盖403 场景分别验证了网关权限错误消息原样保留含编辑密钥链接、非权限消息透传、staging 白名单限制消息透传与空 body 兜底文案四种分支。在音频转写上还有一层 SSRF 防护audioService.js 的 publicAudioUrl 强制source为无凭据的公开 HTTPS URL拒绝localhost、.localhost域名与 IP 地址同时因 Workers 拒绝redirect: error采用redirect: manual并显式拒绝 3xx 重定向audioService.js L45-L62防止代理访问内网地址。八、测试体系AGENTS.md给出两级测试npm run test在 packages/mcp 内执行聚焦工具 handler 的单元测试。脚本定义于 package.jsonnode --test test/*.test.js覆盖coreUtils、textService、audioService、discoveryService、accountService。运行环境要求 Node.js 20package.json engines。npm run test在 apps/mcp 内执行Streamable HTTP Worker 层的测试worker.test.js覆盖鉴权、路由、批量请求拒绝等 HTTP 边界行为。新增工具时应同时在对应 service 的测试文件中补充 handler 级用例保证工具注册 schema、错误分支与响应组装都有可验证的依据。九、连接与使用方式Streamable HTTP 客户端可连接至网关暴露的端点路径见 README 与SERVER_INSTRUCTIONS每次请求携带 Pollinations API 密钥Authorization: Bearer YOUR_KEY密钥的 Pollen 钱包、权限与预算即被用于该请求的计费与鉴权。所有模型、音色、能力与定价均来自实时注册表因此在选定模型或音色前应先用listModels查询。生成的媒体以 MCP resource link 形式返回无需下载与回传。十、小结packages/mcp/AGENTS.md用极简的篇幅定义了 Pollinations MCP Server 的全部架构约束而这些约束在源码中均有一一对应的强制实现薄代理→buildUrl单网关拼接 fetchMediaLink复用公开 URL无硬编码枚举→models.js注册表拉取与validateAgainstRegistry模糊建议不转换响应→ 除 resource link 包装外原样透传最小工具面→ 17 个工具全部有明确 API 路由对应无状态 HTTP→authUtils.js请求级取 token worker.js的legacy: stateless与批量请求拒绝。这套设计让服务器既能在 Cloudflare Worker 上无状态水平扩展又能保持对多模态模型生态的实时感知。对于希望为 Pollinations 贡献新工具或在其上构建自定义 MCP 工具集的开发者按四、添加一个工具的五步流程操作再以第八节的测试体系验证即可安全合入。延伸阅读进一步了解工具能力说明与 API 路由对应关系可读 packages/mcp/README.md模型校验与注册表映射可读 packages/mcp/src/utils/models.jsHTTP 边界实现可读 apps/mcp/worker.js 与 apps/mcp/worker.test.js。赞分享AI 应用媒体生成后端前端【免费下载链接】pollinationsYour Friendly Open-Source Gen-AI Platform项目地址https://gitcode.com/gh_mirrors/po/pollinations点击查看免费下载相关推荐metro-bootstrap开发环境搭建Gulp编译流程与依赖管理全攻略metro bootstrap开发环境搭建Gulp编译流程与依赖管理全攻略 metro bootstrap是一款融合Twitter Bootstrap框架与M如何快速扩展 mcp-server-browserbase自定义工具开发完整指南如何快速扩展 mcp server browserbase自定义工具开发完整指南 mcp server browserbase 是一个允许大型语言模型LLMmcp-for-beginners 实战用 FastMCP 为 Calculator MCP Server 扩展平方根工具mcp for beginners 实战用 FastMCP 为 Calculator MCP Server 扩展平方根工具 在本教程中你将基于 mcp fo教程文档人工智能上一篇如何快速优化Windows系统3步完成智能清理与性能提升终极指南下一篇Windows Cleaner终极指南简单三步告别C盘爆红让电脑重获新生创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

报文交换 vs 分组交换:串行与并行如何决定传输效率

报文交换 vs 分组交换:串行与并行如何决定传输效率

前阵子帮朋友调一个内网传输的老问题:同样的百兆链路,同时传二十个小文件居然比传一个几百兆的大文件还要快。乍一听不合直觉,小文件多路并发,在网络里是典型的“分组并行”;大文件虽然被TCP拆成了段,但应用…

2026/10/14 20:47:12 阅读更多 →
atomcode 内核内部继续(Internal Continuation)自动压缩设计解析:让截断恢复与 Hook 驱动验证循环同样获得上下文压缩机会

atomcode 内核内部继续(Internal Continuation)自动压缩设计解析:让截断恢复与 Hook 驱动验证循环同样获得上下文压缩机会

人工智能AI Agent代码智能体自主智能体MCP ClientsCLI 【免费下载链接】atomcode Claude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source…

2026/10/14 20:47:12 阅读更多 →
蓝色任务悬赏系统源码:uni-app+PHP完整功能拆解与部署指南

蓝色任务悬赏系统源码:uni-app+PHP完整功能拆解与部署指南

简介:一份基于uni-app PHP MySQL构建的在线悬赏任务平台完整源码,适合熟悉Vue与PHP的开发者快速启动任务发布/接取类APP项目。前端以uni-app实现iOS、Android、H5多端覆盖,包含任务列表、任务详情、注册登录、发布接取等核心模块&#xff1…

2026/10/14 20:47:12 阅读更多 →

最新新闻

AI辅助开发实战:用Python重做一个mini版Photoshop

AI辅助开发实战:用Python重做一个mini版Photoshop

最近技术社区和设计圈都在讨论一件事:Adobe 更新应用内许可条款后,不少开发者担心“用 AI 辅助开发软件”会撞上版权红线;随后 Adobe 官方人员在社区公开回应,表示不会对使用 AI 辅助开发的非商业开源替代品采取法律行动&#xff…

2026/10/14 21:38:32 阅读更多 →
ASO优化实力品牌怎么选:从关键词到转化闭环的筛选指南

ASO优化实力品牌怎么选:从关键词到转化闭环的筛选指南

做应用推广这些年,我接触最多的词就是ASO优化。不管你的产品是新上架还是已经跑了一年,应用商店的搜索结果、榜单位置、详情页转化,都直接决定自然量的大小。很多人一听说某个品牌擅长ASO优化,第一反应是“那家能帮我冲榜吗”&…

2026/10/14 21:38:32 阅读更多 →
无人自助拼豆系统核心逻辑实现与全流程部署实战操作指南

无人自助拼豆系统核心逻辑实现与全流程部署实战操作指南

无人自助拼豆系统概述 无人自助拼豆系统是一种基于物联网与软件开发技术的智能设备管理系统,旨在为用户提供便捷的拼豆服务。该系统通常包括用户端、管理后台及硬件设备之间的交互逻辑,实现从用户操作到数据处理的全流程自动化。通过结合Spring Boot、My…

2026/10/14 21:38:32 阅读更多 →
深入解析 CMake 缓存机制:删掉 CMakeCache.txt 与 CMakeFiles/ 的正确时机

深入解析 CMake 缓存机制:删掉 CMakeCache.txt 与 CMakeFiles/ 的正确时机

先说一个近乎人人遇过的场景:白天还好好的 CMake 工程,下午一改CMakeLists.txt,再一编译就开始闹脾气——头文件找不到、链接器报一堆 undefined reference、甚至改动完全没有生效。这时候老手多半会不动声色抛出千古名句:“把 CM…

2026/10/14 21:38:32 阅读更多 →
教务系统后端实战:MySQL 8.0 + Spring Boot 3.2 工程化搭建指南

教务系统后端实战:MySQL 8.0 + Spring Boot 3.2 工程化搭建指南

简介:本资源是一份面向高校计算机专业学生的数据库课程设计实践材料,聚焦教务管理系统的完整开发流程,以MySQL为数据存储核心、Java为应用实现语言,帮助初学者掌握需求分析、ER建模、SQL脚本编写、JDBC连接、前后端基础交互等关键…

2026/10/14 21:38:32 阅读更多 →
48V输入LDO稳压芯片方案:PW8600 80V耐压/70V宽压/1.8μA低功耗电路详解

48V输入LDO稳压芯片方案:PW8600 80V耐压/70V宽压/1.8μA低功耗电路详解

LDO 稳压芯片 选型助手 面向硬件工程师与电子研发人员,通过输入电压 / 输出电压快速匹配合适的 LDO 型号, 并提供完整参数查阅、外围器件建议与型号清单,让选型一步到位。 传统 LDO 耐压不足 5V/6V LDO 无法直连 24V/36V/48V 总线&#xff0c…

2026/10/14 21:37:29 阅读更多 →

日新闻

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 阅读更多 →