【清华代码熊】GVPO:Coding Agent RL 解决奖励错位问题
1. 从 GRPO 到 GVPOCoding Agent 强化学习里的奖励错位到底长什么样如果你正在用 GRPO 训练 Coding Agent大概率遇到过一种很别扭的情况模型明明把测试用例跑通了奖励却给得很低或者模型前面几步就写错了关键逻辑最后靠硬编码把样例骗过去反而拿到了高奖励。这个现象就是奖励错位Reward Misalignment。它不是说奖励函数写错了而是奖励信号和代码真实执行结果在时间维度上对不齐。Coding Agent 和普通对话模型不一样。它的输出是一条 trajectory读题、分析、写代码、跑测试、根据报错改代码、再跑测试。GRPO 的做法是把整条 trajectory 当成一个整体最后给一个 outcome reward。问题就出在这个「最后」上。一条 trajectory 里可能有十几步真正决定成败的往往只有中间两三步但 GRPO 把功劳和锅平均分给了所有 token。我实测下来奖励错位最典型的两种表现是第一种早错晚对。Agent 在第三步选错了数据结构但后面靠大量补丁和特判把测试糊过去了。GRPO 看到最终测试通过给整条 trajectory 高奖励。模型学到的是「先写错没关系后面能补」而不是「一开始就要选对」。第二种早对晚错。Agent 前几步思路完全正确但在最后格式化输出时多打了一个换行测试挂了。GRPO 给 0 奖励前面正确的推理过程被一起丢掉。模型学到的是「这条路径不能走」可实际上路径是对的只是收尾有问题。GVPOGroup Verification-based Policy Optimization要解决的就是这个。它的核心思路是不只在 trajectory 末尾给奖励而是在 trajectory 的中间过程也插入验证信号把奖励重新分配到真正该负责的步骤上。你可以把它理解成从「期末考试定终身」改成「平时作业加期末考试」。这篇会从可复制的训练配置讲起给出奖励对齐的验证动作帮你在自己的 Agent 任务上观察奖励错位有没有缓解。适合已经在跑 GRPO、想进一步优化 Coding Agent 训练效果的读者。如果你还没搭好训练环境后面也会给出接入和验证的完整步骤。2. TaoToken 前置给 Coding Agent 训练管线接上可验证的模型调用在讲 GVPO 配置之前得先解决一个前置问题你的 Coding Agent 在训练和验证阶段需要一个稳定的模型调用入口来生成 trajectory、跑验证脚本、做 reward 打分。很多人的做法是直接调某个模型 API但训练管线里往往要同时用到多个模型——一个负责生成代码一个负责验证一个负责打分。如果每个都单独配 key、单独处理限流管线会变得很脆。我试过用 TaoToken 作为统一入口把生成模型和验证模型都挂在同一个 Base URL 下训练脚本里只维护一份配置。它的 API 地址是 https://taotoken.net/api兼容 OpenAI 风格的调用格式所以现有的 GRPO 训练代码基本不用大改把 base_url 和 api_key 换掉就行。具体来说Coding Agent 的 RL 训练管线通常有三个需要模型的地方生成阶段Agent 根据题目生成代码 trajectory这一步需要模型有较强的代码能力建议用 Claude 系列或同级别模型。验证阶段跑单元测试、静态检查、或者用另一个模型做代码审查这一步需要的是稳定和低延迟因为每条 trajectory 都要验证。打分阶段GVPO 的过程奖励需要模型对中间步骤做判断比如「这一步选的算法复杂度是否合理」这一步对模型的理解能力要求高。把这三个阶段都指向同一个 API 入口好处是配置统一、计费统一、限流策略统一。你不需要在训练脚本里维护三套 key也不需要在某个模型限流时手忙脚乱地切换。接入方式很简单在训练脚本的环境变量或配置文件里设置export TAOTOKEN_API_KEY你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api然后在代码里这样初始化客户端from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ[TAOTOKEN_BASE_URL], ) response client.chat.completions.create( modelclaude-sonnet-4-20250514, messages[{role: user, content: prompt}], temperature0.7, )这里要注意模型 ID 要和你实际使用的模型对齐。如果你在验证阶段想用更便宜的模型做初筛可以在这里换成对应的 model 名称。GVPO 的过程奖励验证对模型能力有要求建议验证模型不要选太弱的否则过程奖励本身就不准反而引入新的噪声。如果你还没拿到 key可以去 https://taotoken.net/api-keys 创建。创建时建议按用途分 key比如训练生成用一个、验证打分用一个这样后面排查问题时能快速定位是哪个环节的调用出了状况。对于长期跑 Coding Agent 训练的任务可以考虑 Coding Plan它在高频调用场景下更划算。模型对话入口可以用来快速测试 prompt 和验证脚本不用每次都跑完整训练管线。3. 可复制配置GVPO 训练片段与奖励重分配参数这一节给出可以直接抄的配置。GVPO 的关键改动在奖励分配上所以配置分两部分训练框架的 GRPO 基础配置以及 GVPO 的过程奖励插入点。先看训练配置。假设你用的是类似 TRL 或 OpenRLHF 的框架核心参数如下# gvpo_config.yaml training: algorithm: gvpo base_algorithm: grpo group_size: 8 kl_coef: 0.04 clip_range: 0.2 learning_rate: 1.0e-6 batch_size: 4 mini_batch_size: 1 gradient_accumulation_steps: 8 reward: outcome_weight: 0.6 process_weight: 0.4 process_verify_steps: [3, 6, 9] verify_model: claude-sonnet-4-20250514 verify_temperature: 0.0 early_error_penalty: 0.3 late_error_discount: 0.5 trajectory: max_steps: 12 step_reward_decay: 0.95 verification_window: 2这里几个参数需要解释。process_verify_steps是过程验证的插入点意思是第 3、6、9 步之后各做一次验证。这个不是随便定的要根据你任务的 trajectory 平均长度来。如果你的 Agent 平均 8 步完成那验证点放在 2、4、6 比较合适。early_error_penalty是早错晚对的惩罚系数当验证发现前面步骤有错但最终通过了从 outcome reward 里扣掉这个比例。late_error_discount是早对晚错的折扣前面步骤验证通过但最终失败时不直接给 0而是按这个系数保留部分奖励。然后是过程奖励的验证 prompt 模板这个直接决定 GVPO 能不能正确重分配奖励PROCESS_VERIFY_PROMPT 你是一个代码审查专家。下面是一个 Coding Agent 在第 {step} 步的输出。 题目要求 {problem} Agent 到目前为止的代码 {code_so_far} 请判断这一步的代码逻辑是否正确是否引入了后续难以修复的错误 只输出 JSON {{step_correct: true/false, error_type: logic|syntax|none, confidence: 0.0-1.0, reason: 简短说明}} 这个模板的关键是让验证模型只判断「这一步」不要让它看最终结果。很多人的过程奖励做不好就是因为验证 prompt 里带了最终测试结果验证模型会偷懒直接看结果反推过程奖励就失去意义了。再看 reward 计算的核心逻辑def compute_gvpo_reward(trajectory, outcome_reward, process_verifications, config): total_reward outcome_reward * config[outcome_weight] process_reward 0.0 step_count len(process_verifications) for i, verify in enumerate(process_verifications): step_weight config[step_reward_decay] ** (step_count - i - 1) if verify[step_correct]: process_reward verify[confidence] * step_weight else: process_reward - config[early_error_penalty] * step_weight if outcome_reward 0 and any(not v[step_correct] for v in process_verifications): total_reward - config[early_error_penalty] * outcome_reward if outcome_reward 0 and all(v[step_correct] for v in process_verifications): total_reward config[late_error_discount] * config[process_weight] total_reward process_reward * config[process_weight] return total_reward这段逻辑对应了前面说的两种错位。早错晚对时outcome 给的高奖励会被 early_error_penalty 扣掉一部分早对晚错时不会直接归零而是保留 late_error_discount 比例的奖励。step_reward_decay让越靠后的步骤权重越低因为 Coding Agent 里前面的决策通常更关键。如果你用的是 Claude Code 做 Agent 的代码生成可以在 settings 里配置验证模型的调用{ model: claude-sonnet-4-20250514, base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, verification: { enabled: true, verify_steps: [3, 6, 9], verify_model: claude-sonnet-4-20250514, temperature: 0.0 } }这个 settings 片段可以直接放进你的 Agent 配置目录。注意 base_url 和 api_key 要和前面训练脚本里的一致否则验证调用会走另一个入口排查问题时容易混淆。4. 验证请求跑一条 trajectory 看奖励是否对齐配置写完之后不要直接开全量训练。先跑一条 trajectory手动看奖励分配对不对。这一步很多人跳过结果训练跑了几小时才发现奖励还是错的。验证脚本的核心是生成一条 trajectory记录每一步的代码和验证结果然后打印奖励分解。import json from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ[TAOTOKEN_BASE_URL], ) def run_single_trajectory(problem, config): trajectory [] code_so_far process_verifications [] for step in range(config[trajectory][max_steps]): prompt build_step_prompt(problem, code_so_far, step) response client.chat.completions.create( modelclaude-sonnet-4-20250514, messages[{role: user, content: prompt}], temperature0.7, ) step_output response.choices[0].message.content code_so_far \n step_output trajectory.append({step: step, output: step_output}) if step in config[reward][process_verify_steps]: verify_result verify_step(problem, code_so_far, step) process_verifications.append(verify_result) print(fStep {step} verify: {verify_result}) outcome run_tests(code_so_far, problem) outcome_reward 1.0 if outcome[passed] else 0.0 final_reward compute_gvpo_reward( trajectory, outcome_reward, process_verifications, config[reward] ) print(fOutcome reward: {outcome_reward}) print(fProcess verifications: {json.dumps(process_verifications, indent2)}) print(fFinal GVPO reward: {final_reward}) return final_reward def verify_step(problem, code_so_far, step): prompt PROCESS_VERIFY_PROMPT.format( stepstep, problemproblem, code_so_farcode_so_far ) response client.chat.completions.create( modelclaude-sonnet-4-20250514, messages[{role: user, content: prompt}], temperature0.0, ) return json.loads(response.choices[0].message.content)跑这个脚本时重点看两个地方。第一process_verifications里每一步的step_correct是否和你的直觉一致。如果验证模型把明显错误的步骤判成正确说明验证 prompt 需要调整或者验证模型能力不够。第二final_reward和outcome_reward的差距。如果 outcome 是 1.0 但 final 只有 0.5 左右说明过程验证发现了早错晚对惩罚生效了。如果 outcome 是 0 但 final 还有 0.2 左右说明早对晚错的折扣生效了。成功的结果长这样Step 3 verify: {step_correct: true, error_type: none, confidence: 0.9, reason: 数据结构选择合理} Step 6 verify: {step_correct: false, error_type: logic, confidence: 0.8, reason: 边界条件处理遗漏} Step 9 verify: {step_correct: true, error_type: none, confidence: 0.85, reason: 补丁逻辑正确} Outcome reward: 1.0 Process verifications: [...] Final GVPO reward: 0.62这里 outcome 是 1.0但因为第 6 步验证发现逻辑错误最终奖励被压到 0.62。这就是 GVPO 在起作用测试虽然过了但过程有问题奖励不会给满。反过来如果 outcome 是 0 但前面步骤都对Step 3 verify: {step_correct: true, error_type: none, confidence: 0.9, reason: 算法选择正确} Step 6 verify: {step_correct: true, error_type: none, confidence: 0.88, reason: 实现逻辑正确} Step 9 verify: {step_correct: true, error_type: none, confidence: 0.9, reason: 仅输出格式有误} Outcome reward: 0.0 Final GVPO reward: 0.24最终奖励不是 0而是保留了 0.24。模型不会因为最后格式化错误就丢掉整条正确路径。验证通过后再开全量训练。训练过程中建议每 50 步打印一次奖励分解的统计观察 outcome 和 process 的分布有没有异常偏移。5. 常见报错排查401、local proxy failed、reading choices、OAuth训练管线跑起来之后报错基本集中在模型调用和验证环节。这一节按真实报错来排查。401 Unauthorized这个最常见。先检查TAOTOKEN_API_KEY环境变量有没有正确导出。在训练脚本里加一行print(os.environ.get(TAOTOKEN_API_KEY)[:8])确认 key 的前几位对得上。如果用的是配置文件而不是环境变量检查配置文件路径有没有被正确加载。还有一种情况是 key 创建后没有复制完整建议重新去 https://taotoken.net/api-keys 复制一次。local proxy failed / connection refused这个报错通常出现在训练机器有网络策略限制的场景。先确认TAOTOKEN_BASE_URL设置的是https://taotoken.net/api不要带多余的路径或斜杠。然后在训练机器上单独跑一个 curl 测试curl -X POST https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-20250514,messages:[{role:user,content:test}]}如果 curl 能通但训练脚本不通说明是脚本里的客户端配置问题检查 base_url 有没有被其他环境变量覆盖。如果 curl 也不通检查训练机器的出网策略确认能访问 taotoken.net。reading choices 报错 / choices 字段为空这个报错说明 API 返回了非预期格式。常见原因是模型 ID 写错了比如把claude-sonnet-4-20250514写成了别的名称API 返回了错误信息而不是正常的 choices 结构。排查方法是把原始 response 打印出来response client.chat.completions.create(...) print(response.model_dump_json(indent2))看返回体里是 error 字段还是 choices 字段。如果是 error按 error message 处理。另外验证阶段如果 temperature 设得太高偶尔会返回空 content建议验证调用统一用 temperature0.0。OAuth 相关报错如果你用的是 Claude Code 或类似的 Agent 工具可能会遇到 OAuth token 过期或未授权。这类工具通常有自己的认证流程和 API key 是两套。排查时先确认你用的是 API key 模式还是 OAuth 模式。如果是 API key 模式在 settings 里明确配置{ auth_mode: api_key, api_key_env: TAOTOKEN_API_KEY, base_url: https://taotoken.net/api }如果是 OAuth 模式需要重新走授权流程。训练管线里建议统一用 API key 模式避免 OAuth token 过期导致训练中断。验证模型返回非法 JSON过程验证的 prompt 要求返回 JSON但模型有时会加 markdown 代码块标记。在解析前先做清洗import re def parse_verify_json(text): text re.sub(rjson\s*|\s*, , text).strip() try: return json.loads(text) except json.JSONDecodeError: return {step_correct: False, error_type: parse_error, confidence: 0.0, reason: text[:100]}解析失败时不要直接抛异常中断训练给一个保守的默认值让训练继续跑同时记录失败次数。如果失败率超过 5%说明验证 prompt 需要加更强的格式约束。奖励值异常全 0 或全 1如果训练日志里 final_reward 全是 0 或全是 1先检查 outcome_reward 的分布。如果 outcome 本身全是 0说明生成阶段就有问题不是 GVPO 的锅。如果 outcome 有区分度但 final 没有检查 process_weight 和 outcome_weight 是不是设反了或者 process_verify_steps 设成了空列表。6. 把 GVPO 接进你的 Coding Agent 训练管线GVPO 的价值不在于替换 GRPO而在于给 GRPO 补上过程奖励这一环。你不需要推翻现有的训练框架只需要在 reward 计算那里插入过程验证把 outcome reward 和 process reward 按权重合并。实际落地时建议先在一条 trajectory 上验证奖励分配符合预期再开小批量训练观察 100 到 200 步的奖励曲线。如果 process reward 的方差远大于 outcome reward说明验证模型太不稳定需要降低 process_weight 或者换更稳的验证模型。训练管线里的模型调用统一走 https://taotoken.net/api生成、验证、打分三个环节用同一个入口配置和排查都会简单很多。验证脚本和 prompt 模板可以直接用第 3、4 节的代码改一下模型 ID 和验证步数就能跑。如果你在跑长期训练任务Coding Plan 在高频调用下更合适。快速测试 prompt 和验证逻辑时模型对话入口可以省去搭脚本的时间。接入文档里有完整的参数说明和示例遇到配置问题可以先查那里。

相关新闻

DeepSeek接入微信完整指南:从选型到搭建与避坑

DeepSeek接入微信完整指南:从选型到搭建与避坑

简介:deepseek接入微信聊天的项目实现包,面向有一定Python基础的开发者,旨在解决将DeepSeek大模型能力接入微信聊天场景的问题。项目采用模块化设计,包含模型调用、微信机器人交互、页面展示与文件处理等环节,适合用于…

2026/10/12 16:20:48 阅读更多 →
服务器故障排查实战:CPU、内存、磁盘、网络与服务启动全解析

服务器故障排查实战:CPU、内存、磁盘、网络与服务启动全解析

1. 从一次深夜告警说起:服务器故障排查的底层逻辑凌晨两点,手机突然震动,监控平台推送了一条告警:某台业务服务器的CPU使用率持续15分钟超过95%。我爬起来打开电脑,第一反应不是直接重启,而是先连上去看看到…

2026/10/12 16:19:47 阅读更多 →
多智能体框架MyCoWork:从架构设计到生产环境落地的全解析

多智能体框架MyCoWork:从架构设计到生产环境落地的全解析

我的真实体会开头 做企业应用落地做了快十年,我越来越确信一件事:业务方需要的不是"一个更聪明的对话框",而是一支能自己跑流程、互相配合、出了错还能自查的"AI 团队"。这也是我们团队把 MyCoWork 开源出来的直接原因—…

2026/10/12 16:19:47 阅读更多 →

最新新闻

Scala与Java混编Spark大数据平台源码解析与实战调优

Scala与Java混编Spark大数据平台源码解析与实战调优

简介:这份源码资源面向大数据开发初学者与进阶工程师,提供一套基于Scala与Java构建的Spark大数据处理平台完整实现,可用于学习分布式计算框架的工程结构、核心模块划分与多语言协作方式。压缩包共约2000个文件,大小103.62MB&#…

2026/10/12 19:51:10 阅读更多 →
Windows Server 2022主备域控部署:从AD DS到高可用同步验证

Windows Server 2022主备域控部署:从AD DS到高可用同步验证

简介:针对 Windows Server 2022 环境下 AD 域控的高可用部署,这份 PDF 文档详细拆解了主域控与备域控的搭建流程及同步机制。内容面向负责企业网络管理和维护的 IT 技术人员,尤其适合需要独立完成域控部署、熟悉域环境运行原理的运维工程师。…

2026/10/12 19:51:09 阅读更多 →
微博评论情感分析与LDA主题分析实战:完整项目代码拆解

微博评论情感分析与LDA主题分析实战:完整项目代码拆解

简介:这是一套面向NLP学习者、舆情分析人员及数据挖掘初学者的微博评论分析项目,完整覆盖从微博爬虫、数据清洗、分词预处理到LDA主题建模与情感分析的全流程代码与数据,可直接运行复现。压缩包整体约16.16MB,共39个文件&#xff…

2026/10/12 19:51:09 阅读更多 →
ZXing二维码扫描与生成实战:解码引擎原理及扫码率避坑指南

ZXing二维码扫描与生成实战:解码引擎原理及扫码率避坑指南

简介:这是一份面向Android开发者的Zxing二维码扫描学习资源,适合需要快速集成扫码功能或研究二维码识别原理的移动开发人员。压缩包共1172个文件,大小约4.88MB,包含491个flat编译资源、324个class字节码、134个xml布局与配置、118…

2026/10/12 19:51:09 阅读更多 →
知识工作插件:面向认知流的声明式操作系统内核

知识工作插件:面向认知流的声明式操作系统内核

1. 这不是插件市场,而是一套知识工作者的“操作系统内核”“knowledge-work-plugins”这个标题初看像一个技术名词堆砌——既没动词也没宾语,连个冒号或破折号都没有,更不像常见插件命名习惯(比如“notion-plugin-ai-summarize”&…

2026/10/12 19:51:08 阅读更多 →
如何为OpenMOSS创建自定义Agent:角色提示词编写与Skill配置完整教程

如何为OpenMOSS创建自定义Agent:角色提示词编写与Skill配置完整教程

【免费下载链接】OpenMOSS A self-organizing multi-agent collaboration platform for OpenClaw. Multiple AI agents work as an autonomous team — planning, executing, reviewing, and patrolling tasks with zero human intervention. 项目地址: https://git…

2026/10/12 19:50:05 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 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/11 10:45:37 阅读更多 →
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/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →