大模型调用成本越来越高怎么办?从Token统计到缓存复用,搭建LLM成本管理系统
一、引言Token 账单正在成为新的云成本黑洞过去两年大部分团队把 LLM 当作一个调用即付费的外部 API模型能力在涨、单价在跌似乎不需要精打细算。但真实账单往往给出相反的结论——单 token 价格下降了 90%总支出却涨了 10 倍。这不是幻觉而是典型的 Jevons 悖论成本下降激发了更多场景而每个场景的 token 消耗量远超预期。我们经历过一个非常典型的案例某团队 2023 年用 GPT-3.5 做客服问答月账单 3000 美元2024 年迁移到更强也更便宜的新模型还上线了 RAG 与 Agent 编排结果月账单直接冲到 40000 美元。模型单价降了业务量和单次请求的 token 量却涨了二十多倍。成本问题的本质从来不是单价而是消费者是谁、花了多少、值不值这三个问题无人回答。成本失控通常来自四个结构性原因输入 token 通胀。RAG 拼接知识库、Agent 携带工具 Schema、多轮对话携带完整历史一次请求的输入轻松从 500 token 涨到 20 万 token。更隐蔽的是很多团队每轮对话都把整段知识库原文塞进去而不是检索后的 Top-K 片段。Agent 循环放大。一次任务可能触发 10~30 次模型调用且每次都要重放全部上下文成本近似于 O(n²) 增长。一个帮我订机票的 Agent如果中间失败重试三次成本就是单一对话请求的几十倍。无法归因。财务只看到一张总账单研发不知道哪个业务线、哪个用户、哪个 Prompt 版本烧掉了钱。出了异常只能靠猜优化也无从下手。缺乏控制。没有预算熔断一次死循环重试或一个爬虫式的恶意请求就能在几小时内刷掉一个月的预算。真正的问题不在于模型太贵而在于缺少一套可观测、可归因、可优化的成本管理系统。本文从 Token 计量这一最小闭环出发逐层做到缓存复用与预算熔断给出一套可以在 1~2 周内落地的工程方案。二、核心原理成本模型、计量口径与缓存层次2.1 定价模型不止是 input/output 两个价格主流厂商的计费维度已经细化到四类忽略任何一项都会导致估算失真维度典型倍率说明输入 token1x常规 prompt输出 token3~5x生成成本最高是优化重点缓存写入1.25x前缀缓存首次写入缓存读取0.1x命中前缀缓存折扣最大Batch API0.5x异步批处理延迟换成本这里要强调一个经常被忽略的事实输出 token 的单价是输入的 3~5 倍。这意味着压缩 1000 个输入 token和让模型少写 250 个输出 token是等价的收益。很多团队把所有精力花在压缩 prompt输入却对输出 token 毫无约束比如要求模型输出冗长的 JSON、每轮都复述一遍完整推理过程。真正有效的做法是双向优化输入侧做检索裁剪输出侧限制max_tokens、约束 JSON Schema、禁止无意义的客套话。因此单个请求的成本应为cost fresh_input × p_in cached_input × p_cache_read cache_write × p_cache_write output × p_out举个具体数字假设gpt-4o输入 2.50 美元/1M、输出 10.00 美元/1M、缓存读取 1.25 美元/1M。一个 10000 token 输入的请求如果全部命中缓存输入成本从 0.025 美元降到 0.0125 美元如果一个对话有 20 轮、每轮重放历史未命中缓存的输入成本会累积到 0.5 美元——仅仅是输入就已经超过很多团队的单次预算预期。还有一个容易被漏算的成本失败的请求也是要计费的。超时、被限流、返回格式错误导致业务层重试只要模型产生了 token就要付钱。我们见过一个团队因为解析 JSON 失败就重试实际 token 消耗是成功请求的 3 倍。所以计量管道必须把status成功/失败/重试次数也记录进去。2.2 Token 统计的三种口径以及它们为什么对不上工程上能拿到 token 数的位置有三处本地估算用tiktokenOpenAI 系或官方count_tokens接口Anthropic 系在发送前预计算。响应回传response.usage字段是唯一的权威口径但只能在请求结束后拿到。网关计量在代理层解析请求体与响应体用于跨厂商统一。三者对不上是常态因为工具调用tool call的参数与结果会被重复计入、图片按 patch 折算 token、推理模型的思考 token 通常计入输出、system prompt 与函数定义有额外的封装开销。结论以usage为账本以本地估算为预算闸门两者偏差超过 15% 时告警。这里有个实战细节值得展开。我们上线计量系统后发现本地tiktoken估算和厂商usage的偏差在纯文本场景下通常只有 2%~5%但在下面几种场景会飙到 20% 以上带 tool/function calling 的请求。厂商会在 system 层注入函数定义模板指令里还有角色包装本地估算只算了messages漏掉了这层。多模态请求。一张高分辨率图片折算的 token 数取决于厂商的 patch 算法本地几乎不可能算准。推理模型reasoning model。思考 token 单独计费且不计入标准completion_tokens需要单独读取对应字段。流式响应。部分 SDK 在流式模式下最后一个 chunk 才带usage需要开启stream_options{include_usage: True}否则永远拿不到准确数字。所以正确做法是预算闸门用本地估算宁可高估防止超支账本用厂商usage两者定期做偏差回归一旦某模型的偏差持续超过阈值就说明该模型的计费规则变了需要更新估算器。2.3 缓存复用的四个层次缓存是降本杠杆最大的一环但需要分层设计L1 精确缓存对(model, messages, temperature, top_p)做哈希命中即返回。零误判适合事实性问答、SQL 生成等确定性场景。L2 语义缓存用 embedding 做近邻检索相似度超过阈值即复用。能吃掉换个说法问同一件事的流量但存在误判风险。L3 前缀缓存Provider 侧 Prompt Caching由厂商维护 KV Cache。要求前缀完全逐字节一致且通常有 1024 token 的最小长度门槛与 5 分钟~1 小时的 TTL。L4 上下文工程历史摘要、滑动窗口、结构化裁剪。它不叫缓存但收益往往比前三层加起来还大。四层的关系可以这样理解L1/L2 是业务级缓存直接替代一次模型调用收益是 100%L3 是引擎级缓存只降低输入单价到 10%但胜在无副作用、可普遍适用L4 是根治手段从源头减少要处理的 token。L2 语义缓存的阈值选择是最大的坑。阈值设 0.95 太严命中率低设 0.85 太松会把如何退款和如何取消订单混为一谈造成答非所问。工程上建议先设 0.92把每次命中都记录到日志人工抽样检查 200 条再逐步放宽。对于金融、医疗等高风险场景直接放弃 L2只用 L1L3。L3 前缀缓存有一个反直觉的约束前缀必须从第一个 token 开始连续一致。也就是说如果你把动态内容比如时间戳、“当前用户是张三”放在 prompt 最前面那么整段前缀就永远无法命中。正确做法是静态在前、动态在后system prompt、工具定义、知识库说明放最前用户的具体问题放最后。这一个排序的改动在我们一个项目里把前缀缓存命中率从 8% 拉到了 73%。三、实战搭建最小可用的 LLM 成本管理系统整体架构分四层统一调用入口 → 计量管道 → 存储与看板 → 预算熔断。下面给出关键模块的实现。3.1 统一入口与 Token 计量所有模型调用必须经过同一个 Client禁止业务代码直接import openai。# cost_tracker.pyimporttime,json,hashlibfromtypingimportCallable# 单价美元 / 1M tokens务必用配置文件维护并定期与官方价目表对账PRICING{gpt-4o:{in:2.50,out:10.00,cache_read:1.25},gpt-4o-mini:{in:0.15,out:0.60,cache_read:0.075},claude-sonnet:{in:3.00,out:15.00,cache_write:3.75,cache_read:0.30},}defestimate_cost(model:str,usage:dict)-float:根据一次响应的 usage 计算成本美元。 关键点 1. fresh_input 必须减去 cached否则命中缓存的部分会被重复计费 2. cache_write / cache_read 只在支持的厂商存在用 get 兜底 3. 单价都是每 1M token最后统一除以 1e6。 pPRICING[model]in_tokusage.get(prompt_tokens,0)out_tokusage.get(completion_tokens,0)cached(usage.get(prompt_tokens_details)or{}).get(cached_tokens,0)freshmax(in_tok-cached,0)writeusage.get(cache_creation_input_tokens,0)return(fresh*p[in]cached*p.get(cache_read,p[in])write*p.get(cache_write,p[in]*1.25)out_tok*p[out])/1_000_000上面这个函数只解决算一次成本但真正要落地的成本系统还需要把每次调用记录下来、可查询、可按维度聚合。为此我们再加一个薄薄的 Trackerimportsqlite3classCostTracker:def__init__(self,db_pathcost.db):self.connsqlite3.connect(db_path)self.conn.execute( CREATE TABLE IF NOT EXISTS calls ( id INTEGER PRIMARY KEY AUTOINCREMENT, ts REAL, model TEXT, tenant TEXT, feature TEXT, prompt_version TEXT, fresh_in INTEGER, cached_in INTEGER, cache_write INTEGER, out INTEGER, cost REAL, latency_ms INTEGER, status TEXT, cache_layer TEXT ))defrecord(self,*,model,usage,tenant,feature,prompt_version,latency_ms,statusok,cache_layerNone):costestimate_cost(model,usage)self.conn.execute(INSERT INTO calls (ts,model,tenant,feature,prompt_version,fresh_in,cached_in,cache_write,out,cost,latency_ms,status,cache_layer) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?),(time.time(),model,tenant,feature,prompt_version,usage.get(prompt_tokens,0)-(usage.get(prompt_tokens_details)or{}).get(cached_tokens,0),(usage.get(prompt_tokens_details)or{}).get(cached_tokens,0),usage.get(cache_creation_input_tokens,0),usage.get(completion_tokens,0),cost,latency_ms,status,cache_layer),)self.conn.commit()returncost这里四个业务标签tenant、feature、prompt_version、cache_layer是归因的核心。没有它们你只能看到总账有了它们你才能回答哪个客户、哪个功能、哪个 prompt 版本最烧钱这种真正能指导优化的问题。实战中踩过的坑早期我们只用feature一个维度后来发现某些大客户的功能成本高得不正常加了tenant之后才发现是两个大客户在疯狂调用同一个功能。如果不是按租户拆分这笔账会一直被平均掉。3.2 L1 精确缓存与 L2 语义缓存精确缓存实现简单用内存 Redis 两级即可。注意 key 必须包含所有影响输出的参数defcache_key(model,messages,temperature,top_p,toolsNone):payloadjson.dumps({model:model,messages:messages,temperature:temperature,top_p:top_p,tools:tools,},sort_keysTrue,ensure_asciiFalse)returnhashlib.sha256(payload.encode()).hexdigest()温度必须进 key。一个常见错误是缓存了temperature0.7的结果却给temperature0的确定性请求返回导致本该稳定的输出变得随机。同理tools、response_format、max_tokens都要进 key。语义缓存的实现依赖 embedding 向量检索核心是阈值与淘汰策略defsemantic_lookup(query_embedding,index,threshold0.92):# index 通常用 faiss / pgvector / redis-vectorhitsindex.search(query_embedding,k1)ifhitsandhits[0].scorethreshold:returnhits[0].cached_answerreturnNone语义缓存的三个坑1用错的 embedding 模型会让相似度不可比必须固定版本2缓存值要考虑时效性“今天天气这类问题必须按小时失效3必须加一个缓存旁路”当用户明确要求重新生成时跳过缓存。3.3 前缀缓存排序决定命中率前缀缓存的收益最大也最容易被浪费。核心原则只有一条把逐字节稳定的内容放在最前把动态内容放在最后。对比下面两种写法# 错误动态内容在最前导致所有请求前缀都不同 当前时间2024-06-01 10:23:01。用户问题如何退款 当前时间2024-06-01 10:23:02。用户问题如何退款 # 正确静态内容system、工具定义、知识库在前动态在后 [system: 你是一个客服助手...1500 token稳定] [tools: 退款/查询/取消的 schema800 token稳定] [user: 当前时间 2024-06-01 10:23:02问题如何退款]同时要注意前缀长度要超过厂商的最小门槛很多是 1024 token 或 2048 token否则不会触发缓存。如果你的 system prompt 只有 300 token可以通过补充更完整的角色说明、few-shot 示例来凑到门槛以上——这些内容本身也能提升输出质量一举两得。3.4 预算熔断防止一次事故烧掉一个月预算是最后一道防线必须在调用前检查、调用后扣减。粒度建议按租户 天和全局 小时双维度defcheck_budget(tenant,estimated_tokens,model):# 预估本次成本用本地估算宁可高估est_costestimate_cost(model,{prompt_tokens:estimated_tokens[in],completion_tokens:estimated_tokens[out],})ifspend_today(tenant)est_costDAILY_LIMIT[tenant]:raiseBudgetExceeded(f{tenant}日预算超限)ifspend_last_hour(__global__)est_costGLOBAL_HOURLY_LIMIT:raiseBudgetExceeded(全局小时预算超限)熔断之上还应有限速因为熔断是慢反馈要等预算接近耗尽而限速是快反馈。对单个用户的 QPS 做限制可以拦住爬虫式滥用。我们建议三层防护QPS 限速毫秒级→ 单次max_tokens上限请求级→ 日/小时预算熔断小时后级。3.5 看板只展示能指导决策的四个指标看板不要做成财务报表而要聚焦四个指标成本 / 请求按 feature 分组判断哪个功能在恶化。缓存命中率分 L1/L2/L3判断缓存是否真的在生效。平均输出 token 数输出失控是最常见的隐形浪费。失败重试率重试造成的重复计费往往被忽略。其中缓存命中率和平均输出 token是最灵敏的两个先行指标。当它们任一恶化时账单通常会在一两天后反映出来——这就是可观测性带来的提前量。四、常见问题 FAQQ1本地估算和厂商 usage 差得太多怎么办先确认是否漏算了 tool schema、图片、system 封装。如果某个模型偏差持续超过 15%就把该模型的偏差系数固化进估算器比如估算值 × 1.18并设置定期回归任务。Q2语义缓存会不会导致答非所问会。所以高风险场景禁用 L2一般场景也必须加人工抽检和重新生成旁路。永远不要把 L2 用在需要精确数字、法律条款、医疗建议的场景。Q3前缀缓存写入了为什么还是没命中90% 的情况是前缀里有动态内容时间戳、用户 ID、session ID。剩下 10% 是前缀长度不足门槛或两次请求之间超过了 TTL。用前缀 diff工具打印两次请求的前 N 个 token一眼就能看出来。Q4Batch API 便宜一半为什么不用因为它是异步的不满足实时交互场景。正确的策略是分流实时对话走同步 API离线批处理日报生成、批量打标、数据清洗走 Batch API能省一半。很多团队把所有流量都走同步白白多花了一倍钱。Q5要不要为每个业务线单独设置预算要而且强烈建议。全局预算只能防止整个公司破产无法防止某个功能烧光所有人的配额。按 feature 设预算才能在事故初期就精准拦截。Q6成本优化会不会牺牲质量会所以每一次优化都要配一个质量回归集。压缩 prompt、减少检索片段、降低max_tokens都可能让效果下降。没有质量护栏的成本优化是危险的最终往往会因为返工而花更多钱。五、踩坑与优化建议踩坑一只统计不归因。一张总账单没有任何优化价值。上线第一天就要打上 tenant/feature/version 标签。踩坑二缓存 key 漏参数。温度、工具、输出格式任一漏掉都会产生错误复用。建议用白名单方式显式列出进 key 的字段。踩坑三把动态内容放在 prompt 开头。这一条就让很多团队的前缀缓存命中率停在个位数。踩坑四没有输出上限。一个死循环的 Agent 可以无限生成max_tokens是最便宜的保险。踩坑五忽略重试成本。重试要计入成本且要限制重试次数与指数退避否则故障期间成本会指数级放大。优化优先级建议按 ROI 排序上下文工程L4→ 前缀缓存排序L3→ 精确缓存L1→ 输出约束 → Batch 分流L2 语义缓存放最后因为风险最高。大多数团队做完前两项成本就能降 40%~60%。六、总结大模型成本管理不是一个省钱技巧而是一套工程能力统一入口保证可计量业务标签保证可归因分层缓存保证可优化预算熔断保证可控。这四件事缺一不可。不要一开始就追求大而全。更多硬核网安与AI工具包请扫码获取完整源码最务实的路径是第一周接入统一 Client usage 计量 业务标签先把账算清楚第二周加 L1 缓存与前缀缓存排序通常就能看到明显下降之后再逐步补齐语义缓存、Batch 分流与预算熔断。先看见再优化最后才是控制——顺序错了任何一步都会变成盲人摸象。

相关新闻

Linux CFS调度器原理与实战调优指南

Linux CFS调度器原理与实战调优指南

1. 什么是CFS调度器:一个让CPU时间分配更公平的底层引擎CFS Scheduler,全称Completely Fair Scheduler(完全公平调度器),是Linux内核自2.6.23版本起默认启用的进程调度核心模块。它不是某个用户可见的图形工具&#xf…

2026/10/13 23:44:36 阅读更多 →
HDFS进阶核心:高可用、元数据、联邦与纠删码实践

HDFS进阶核心:高可用、元数据、联邦与纠删码实践

1. HDFS进阶内容概览这应该是HDFS系列的第四篇了。前三篇聊了集群搭建、Shell操作、客户端读写,基本把日常运维和开发常用的东西过了一遍,但很多人在这个阶段都会遇到同一个问题:单NameNode不够用的时候怎么办,或者集群规模上去了…

2026/10/13 23:44:36 阅读更多 →
GitHub热门项目趋势解析:从榜单看开源技术新风向

GitHub热门项目趋势解析:从榜单看开源技术新风向

如果你和我一样,每天早上的第一件事不是看天气,而是点开 GitHub Trending,那你应该能体会那种感觉——明明昨晚睡前刚刷过一遍,今天一早又变天了。GitHub 热门项目排行榜,或者说 Trending,已经不只是一个简…

2026/10/13 23:43:35 阅读更多 →

最新新闻

tidyr数据整形核心指南:从宽表长表转换到字段拆解

tidyr数据整形核心指南:从宽表长表转换到字段拆解

1. 为什么“整理数据”比“分析数据”更耗时——从一个真实项目说起我带过不少刚接触R语言的某高校数据分析课程学员,也帮某公司做过几轮业务数据清洗支持。几乎所有人第一次拿到原始数据时,第一反应都不是建模或画图,而是盯着Excel里那些“看…

2026/10/14 0:33:52 阅读更多 →
特征值与特征向量:从几何重数到代数重数,拆解矩阵的灵魂

特征值与特征向量:从几何重数到代数重数,拆解矩阵的灵魂

先问一个问题:你拿到一个矩阵,是不是下意识就想去算行列式、算秩、解方程组?这些操作当然没错,但它们更像“体检报告”——告诉你矩阵健康不健康。而真正决定一个矩阵“性格”的,是特征值与特征向量。这俩东西才是矩阵…

2026/10/14 0:33:52 阅读更多 →
逻辑回归向量化:从循环到矩阵运算的性能飞跃

逻辑回归向量化:从循环到矩阵运算的性能飞跃

1. 从单样本循环到矩阵运算:为什么必须做向量化逻辑回归的模型训练,绕不开两个核心计算:假设函数输出和梯度更新。很多刚上手的朋友在实现逻辑回归时,第一反应就是写一个for循环,逐个样本计算预测值,再逐个…

2026/10/14 0:33:52 阅读更多 →
微信小程序原生课程表源码:本地存储与离线渲染实战

微信小程序原生课程表源码:本地存储与离线渲染实战

简介:这份资源是面向微信小程序初学者与前端练手者的原生课程表项目源码,基于微信小程序原生框架实现,可帮助读者快速理解并搭建一个查看、管理每周课程安排的应用,适合学生、教师及想通过完整小项目巩固基础的前端学习者。压缩包…

2026/10/14 0:33:52 阅读更多 →
匈牙利算法矩阵形式详解:从成本约减到最优分配的完整推导

匈牙利算法矩阵形式详解:从成本约减到最优分配的完整推导

前阵子有个做调度优化的朋友来问,说看网上的匈牙利算法教程,流程图一摆、代码一贴,看着都懂,可自己拿个成本矩阵一算就发懵,尤其是“矩阵形式”这一层,总觉得像魔术:为什么行减一减、列减一减&a…

2026/10/14 0:33:52 阅读更多 →
微信小程序原生课程表开发:周视图与本地存储实战

微信小程序原生课程表开发:周视图与本地存储实战

简介:这份资源是面向微信小程序初学者与前端练手者的原生课程表项目源码,基于微信小程序原生框架实现,可帮助读者快速理解并搭建一个查看、管理每周课程安排的小工具,适合学生、教师及想熟悉小程序开发流程的开发者参考。压缩包为…

2026/10/14 0:32:51 阅读更多 →

日新闻

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/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

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

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

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

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

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

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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/12 18:11:17 阅读更多 →