纯 Java 打造企业级 Agent Harness:BizBuddy 架构设计与工程实践
1. 为什么我要用纯 Java 造一个 Agent Harness1.1 从一个真实的痛点说起去年下半年我所在的团队接了一个内部效率工具的需求把公司里散落在各个业务系统中的重复性操作用一个智能代理串起来。比如每天早上自动拉取前一天的订单异常数据、生成摘要、推送到值班群再根据异常类型自动创建跟进任务。听起来不复杂但真正动手的时候问题就来了。我们试过市面上几种主流的 Agent 框架Python 生态的居多功能确实强大但落地到我们这套以 Java 为主的技术栈里处处别扭。运维团队不愿意为一个内部工具单独维护一套 Python 运行时和依赖环境安全团队对引入外部框架的供应链风险有顾虑而业务侧的同事希望能像调用普通 Spring Service 一样调用这些 Agent 能力。折腾了两周我做了个决定干脆用纯 Java 自己搭一个 Agent Harness 平台把代理编排这件事做成团队内部的基础设施。这就是 BizBuddy 的起点。它不是又一个通用 Agent 框架而是一个面向企业内网的、纯 Java 实现的 Agent 运行与编排底座。所谓 Harness我理解就是马具——它不负责造马模型能力而是负责把马套好、缰绳理顺、让车能稳稳地跑起来。BizBuddy 要解决的核心问题就三个怎么把大模型的调用封装成企业可管控的服务、怎么把多个 Agent 的协作流程编排清楚、怎么让业务代码零成本接入。这篇文章我会把整个设计和取舍过程摊开讲包括为什么坚持纯 Java、Harness 层到底该管什么、编排引擎怎么设计、状态和上下文怎么处理以及我在实际踩坑中总结出来的一堆经验。适合正在做企业内部 AI 基础设施的工程师、架构师也适合想了解 Agent 工程化落地细节的读者。哪怕你暂时不打算自己造轮子这里面的取舍逻辑也能帮你在选型时少走弯路。1.2 先明确边界Harness 不是框架是运行时在动手之前我花了很长时间想清楚一件事BizBuddy 到底该做什么、不该做什么。市面上很多所谓的 Agent 框架恨不得把提示词管理、工具注册、记忆存储、流程编排、模型路由全包了结果就是又重又难改。我给自己划了条线——BizBuddy 只做运行时和编排不做能力本身。具体来说它负责四件事第一把模型调用抽象成统一的ModelClient接口屏蔽不同厂商 API 的差异第二提供 Agent 的生命周期管理包括注册、发现、执行、销毁第三实现一套基于状态机的编排引擎让多个 Agent 能按流程协作第四提供上下文管理和可观测性让每一次 Agent 执行都可追溯、可回放。它不负责的事也很明确不内置具体的提示词模板那是业务的事、不绑定特定的模型厂商通过 SPI 扩展、不提供可视化编排界面初期用代码配置就够。这条边界非常重要因为它决定了整个平台的复杂度上限。我见过太多内部工具因为想什么都能干最后变成谁都不敢动的巨石。提示做企业内部基础设施克制比功能丰富更重要。每多一个功能就多一份维护成本和被滥用的风险。2. 核心架构设计与技术选型取舍2.1 为什么坚持纯 Java而不是混用多语言这个决定在当时是有争议的。团队里有人建议核心编排用 Java模型调用和提示词处理用 Python通过进程间通信对接。听起来合理但我否决了理由有三。第一是部署和运维的一致性。我们整个后端是 Spring Boot 体系CI/CD、监控、日志、配置中心都是围绕 Java 建的。引入 Python 意味着要额外维护一套运行时、一套依赖管理、一套健康检查运维成本直接翻倍。对于一个内部工具来说这个代价不划算。第二是类型安全和可维护性。Agent 编排涉及大量的状态流转、参数传递、错误处理Java 的强类型和成熟的并发模型在这里是优势。Python 写起来快但流程一复杂动态类型带来的隐性 bug 会让人头疼。我们这套东西是要长期跑的稳定性优先。第三是团队技能栈。让一群写了多年 Java 的工程师去维护 Python 代码短期能应付长期一定出问题。技术选型要服务于团队的可持续维护能力而不是追求技术上的最优解。当然纯 Java 也有代价。比如一些前沿的模型 SDK 只有 Python 版本我们就得自己封装 HTTP 调用再比如 Java 在流式处理上的写法比 Python 啰嗦。但这些代价是可控的而多语言带来的运维复杂度是不可控的。2.2 分层架构把变化隔离在边界之外BizBuddy 的整体架构我分成了四层从下到上依次是模型接入层、Agent 运行时层、编排引擎层、业务接入层。这个分层的核心思想是把变化隔离在边界之外——模型厂商会变、业务需求会变但层与层之间的契约要尽量稳定。模型接入层通过ModelClient接口定义统一契约核心方法就两个complete(request)返回完整结果stream(request)返回流式结果。不同厂商的实现通过 SPI 注册业务代码只依赖接口。这样换模型厂商时只需要新增一个实现类业务代码一行不用改。Agent 运行时层负责 Agent 的注册、发现和执行。每个 Agent 是一个实现了Agent接口的 Bean通过注解AgentDefinition声明自己的名称、能力和所需工具。运行时负责在启动时扫描注册执行时根据名称路由。编排引擎层是重头戏我用了基于状态机的方式来实现多 Agent 协作。每个编排流程定义为一个Workflow由若干State和Transition组成。引擎负责驱动状态流转、处理分支和循环、管理超时和重试。业务接入层就是给业务方用的门面提供BizBuddyClient这样的统一入口业务代码通过它提交任务、查询状态、获取结果。层级核心职责关键接口变化频率模型接入层屏蔽模型厂商差异ModelClient中Agent 运行时层Agent 生命周期管理Agent低编排引擎层多 Agent 流程编排Workflow中业务接入层统一对外门面BizBuddyClient高2.3 编排引擎状态机 vs 工作流引擎编排引擎的设计我纠结了很久主要是在自己写状态机和集成现成工作流引擎之间摇摆。现成的方案比如一些 BPMN 引擎功能强大、可视化好但引入成本高而且它们的模型是为人工审批流程设计的套到 Agent 编排上有点削足适履。最后我选择自己实现一个轻量级状态机。核心类就三个WorkflowDefinition定义流程结构WorkflowInstance表示一次运行实例StateMachineEngine负责驱动流转。状态之间的转换用Transition描述支持条件表达式来决定走哪条分支。这个选择的好处是完全可控。Agent 编排和传统工作流有个本质区别Agent 的执行结果是不确定的可能成功、可能失败、可能返回需要人工介入的中间态。自己写状态机可以针对这些情况做精细处理比如某个状态失败后自动重试三次还失败就转人工审核状态。用现成引擎反而要绕很多弯。代价是要自己处理并发、持久化、恢复这些问题。我的做法是状态机的流转逻辑保持无状态所有状态存在数据库里每次流转都是一个事务。这样即使服务重启也能从数据库恢复未完成的流程。3. 核心模块的实操实现细节3.1 ModelClient统一模型调用的抽象模型接入层是整个平台的地基我把它设计得尽量薄。ModelClient接口定义如下public interface ModelClient { CompletionResult complete(CompletionRequest request); StreamCompletionChunk stream(CompletionRequest request); String provider(); }CompletionRequest里封装了模型名称、消息列表、温度、最大 token 等参数。这里有个关键取舍我没有把厂商特有的参数放进通用请求对象而是用一个MapString, Object extraParams来承载。这样通用逻辑保持干净厂商特有的能力通过扩展参数传递实现类自己解析。具体实现上我用了 Spring 的ConditionalOnProperty来控制不同厂商实现的加载。配置文件里指定bizbuddy.model.providerxxx对应的实现类才会被注册。这样部署时切换模型厂商改一行配置就行。流式处理是另一个重点。Java 里做流式我用的是FlowAPI 或者 Reactor 的Flux最终选了 Reactor因为它在背压处理和错误传播上更成熟。stream方法返回FluxCompletionChunk业务侧可以订阅处理。这里要注意的是流式响应的超时控制我设置了两级超时单个 chunk 之间的间隔超时默认 30 秒和整个流的总超时默认 5 分钟避免某个卡住的流把线程占死。注意模型调用一定要设置超时而且要有熔断。我早期没做熔断某次模型服务抖动导致大量请求堆积把整个应用拖垮了。后来引入了 Resilience4j配置了基于失败率的熔断策略才稳住。3.2 Agent 运行时注册、发现与执行Agent 的抽象我设计得很简单就是一个接口加一个注解public interface Agent { AgentResult execute(AgentContext context); } AgentDefinition(name order-anomaly-detector, description 检测订单异常, tools {orderQuery, dataAnalysis}) public class OrderAnomalyDetector implements Agent { ... }运行时在启动时扫描所有带AgentDefinition的 Bean把元信息注册到一个AgentRegistry里。执行时编排引擎通过名称从注册表拿到 Agent 实例构造AgentContext传进去。AgentContext里包含三样东西输入参数、共享上下文、工具访问器。输入参数是本次执行的入参共享上下文是整个工作流级别的多个 Agent 可以读写用来传递中间结果工具访问器让 Agent 能调用外部工具比如查数据库、调 API。这里有个设计细节值得说Agent 的执行是同步的但编排引擎的调度是异步的。也就是说单个 Agent 的execute方法阻塞执行完返回结果但引擎在调度时会把 Agent 执行提交到线程池避免阻塞主流程。这样既保证了 Agent 实现的简单性不用考虑异步又保证了整体吞吐。工具访问器的设计我用了能力声明 运行时注入的模式。Agent 在注解里声明自己需要哪些工具运行时只注入声明过的工具。这样既安全Agent 不能访问未授权的工具又清晰看注解就知道这个 Agent 依赖什么。3.3 编排引擎状态流转的实现编排引擎的核心是状态机。一个WorkflowDefinition由若干State组成每个State可以是 Agent 执行状态、条件判断状态、等待状态或结束状态。状态之间通过Transition连接Transition上可以挂条件表达式。WorkflowDefinition workflow WorkflowDefinition.builder() .name(daily-order-check) .state(State.agent(fetch, order-fetcher)) .state(State.agent(detect, order-anomaly-detector)) .state(State.condition(judge, ctx - ctx.get(anomalyCount, 0) 0)) .state(State.agent(notify, alert-notifier)) .state(State.end(done)) .transition(fetch, detect) .transition(detect, judge) .transition(judge, notify, ctx - ctx.get(hasAnomaly, false)) .transition(judge, done, ctx - !ctx.get(hasAnomaly, false)) .transition(notify, done) .build();引擎驱动流程时每次从当前状态出发评估所有出边的条件选择第一条满足条件的边流转到下一个状态。这个评估条件选边的逻辑是引擎的核心我把它抽成了一个TransitionSelector方便替换不同的策略比如优先级策略、随机策略。状态持久化我用的是数据库表每次流转前把当前状态和上下文序列化存进去流转后更新。这样服务重启后可以从数据库恢复所有未完成的流程实例。这里有个坑上下文序列化要控制大小。早期我把整个上下文都存进去结果有些流程上下文里塞了几百 KB 的数据数据库压力很大。后来改成只存必要的状态数据大对象走对象存储上下文里只存引用。3.4 上下文管理共享数据的读写与隔离上下文管理是容易被忽视但很关键的部分。多个 Agent 协作时数据怎么传递、怎么隔离、怎么避免污染都需要设计。我的方案是分层上下文每个 Agent 有自己的私有上下文AgentContext工作流有共享上下文WorkflowContext。Agent 执行时私有上下文从共享上下文初始化执行完把需要传递的结果写回共享上下文。这样 Agent 之间不直接耦合只通过共享上下文通信。共享上下文的读写我加了版本控制。每次写入会递增版本号读取时可以指定版本。这样在并发场景下能检测到冲突。虽然初期大部分流程是串行的用不上这个但为后续并行编排留了余地。还有一个细节是上下文的生命周期。工作流结束后共享上下文会被归档保留一段时间供排查问题然后清理。私有上下文在 Agent 执行完就销毁。这个清理策略要配好否则上下文数据会无限增长。4. 常见问题与排查技巧实录4.1 模型调用超时和重试的坑模型调用超时是最常见的问题。我踩过的坑是重试策略没区分错误类型。早期我对所有失败都重试三次结果遇到参数错误比如 token 超限也重试白白浪费三次调用。后来改成只对网络超时和 5xx 错误重试4xx 错误直接失败。重试还有个坑是幂等性。如果 Agent 执行有副作用比如创建了任务重试可能导致重复创建。我的做法是在 Agent 层面做幂等控制每次执行带一个唯一的executionId副作用操作先检查这个 ID 是否已处理过。错误类型是否重试重试次数退避策略网络超时是3指数退避5xx 服务错误是3指数退避4xx 参数错误否--限流 429是5固定间隔4.2 状态机死循环和状态丢失状态机最怕两件事死循环和状态丢失。死循环通常是因为条件表达式写错导致两个状态之间来回跳。我的防护措施是给每个流程实例设置最大流转次数默认 100 次超过就强制终止并告警。状态丢失一般发生在持久化环节。有次线上出现流程卡住不动排查发现是某次流转后数据库更新失败但内存里的状态已经变了导致内存和数据库不一致。后来我改成先持久化再更新内存并且每次流转都加乐观锁版本号冲突就重试。提示状态机的每一次流转都要当作一次事务来处理宁可慢一点也不能出现状态不一致。4.3 Agent 执行结果不确定的处理Agent 的执行结果天然不确定可能返回成功、失败、或者需要人工介入的中间态。我定义了三种结果类型SUCCESS、FAILURE、PENDING。PENDING表示需要外部介入比如等待人工审核。引擎遇到PENDING会把流程挂起等外部信号再恢复。这个设计解决了很多实际问题。比如某个 Agent 检测到异常但不确定是否要告警就返回PENDING流程挂起等待人工确认确认后再继续。这样既保留了自动化的效率又保留了人工的判断权。4.4 可观测性日志、指标和追踪Agent 编排的调试比普通服务难因为一次执行涉及多个 Agent、多次模型调用链路很长。我做了三件事来提升可观测性。第一是结构化日志。每次 Agent 执行都打一条结构化日志包含workflowId、executionId、agentName、duration、result。这样排查问题时可以按workflowId把所有相关日志串起来。第二是关键指标。我埋了几个核心指标Agent 执行成功率、平均耗时、模型调用 token 消耗、流程完成率。这些指标接入监控后能快速发现异常。第三是执行追踪。每次工作流执行生成一个 trace记录每个状态的进入时间、退出时间、流转原因。这个 trace 存在数据库里排查问题时可以完整回放整个执行过程。5. 一些设计上的取舍与反思5.1 为什么不做可视化编排很多人问我为什么不做可视化编排界面。我的回答是现阶段不值得。可视化编排的价值在于让非技术人员也能配置流程但我们的用户是工程师他们更习惯用代码定义流程。而且可视化编排的复杂度很高要处理布局、连线、校验、版本管理投入产出比不划算。我的替代方案是提供一套流畅的 DSL。上面展示的WorkflowDefinition.builder()就是 DSL 的一部分写起来接近自然语言工程师上手很快。等未来真的有非技术用户的需求再考虑可视化也不迟。5.2 关于性能和资源控制Agent 编排是 IO 密集型任务大部分时间在等模型响应。所以线程模型上我用了异步 线程池隔离。不同优先级的流程用不同的线程池避免低优先级任务把高优先级任务饿死。资源控制上我加了并发流程数限制和单流程 Agent 调用次数限制。前者防止系统被大量流程压垮后者防止某个流程因为 bug 无限调用 Agent。这两个限制都是可配置的根据实际负载调整。5.3 后续可以扩展的方向这套平台跑了大半年基本稳定。后续我考虑扩展几个方向一是支持并行编排让没有依赖关系的 Agent 并行执行提升效率二是引入更智能的路由根据历史执行数据自动选择最优的 Agent 组合三是完善工具生态把常用的企业内网工具数据库、消息队列、内部 API封装成标准工具让 Agent 开发更简单。不过这些都是后话。现阶段最重要的是把这套东西用稳、用好让业务方真正感受到 Agent 编排带来的效率提升。基础设施的价值不在于功能多而在于稳定可靠、让人愿意用。我在实际维护这套平台的过程中最大的体会是企业级 Agent 平台的难点从来不在模型调用而在工程化。怎么让流程可控、怎么让问题可查、怎么让业务方用得放心这些才是真正花时间的地方。纯 Java 的选择、状态机的设计、上下文的隔离每一个决定背后都是对可控性的追求。如果你也在做类似的事情希望这些经验能帮你少踩几个坑。

相关新闻

Mac单机部署HBase+Phoenix完整实践指南

Mac单机部署HBase+Phoenix完整实践指南

1. 为什么在Mac上单机部署HBasePhoenix这件事值得花两小时认真做一遍HBasePhoenix组合,是很多数据工程师、后端开发者、甚至刚接触大数据生态的测试同学绕不开的一组“轻量级生产级”存储方案。它不像Spark或Flink那样动辄要搭集群、调YARN,也不像MySQL那…

2026/10/14 7:42:41 阅读更多 →
含冰蓄冷空调的CCHP微电网多时间尺度优化调度解析

含冰蓄冷空调的CCHP微电网多时间尺度优化调度解析

第一次看到“探索含冰蓄冷空调的 CCHP-MG 多时间尺度优化调度”这个项目名,我脑子里蹦出来的是三个非常务实的问题:这套系统到底靠什么省钱?冰蓄冷空调在里头扮演什么角色?为什么调度非要折腾出多个时间尺度?把这三个问…

2026/10/14 7:42:41 阅读更多 →
单片机毕设选题推荐:基于51单片机的MPU6050老人跌倒报警与定位系统设计 基于单片机的老人跌倒检测短信定位与SOS报警装置设计(032601)

单片机毕设选题推荐:基于51单片机的MPU6050老人跌倒报警与定位系统设计 基于单片机的老人跌倒检测短信定位与SOS报警装置设计(032601)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/10/14 7:42:41 阅读更多 →

最新新闻

插件加载失败排查:从生命周期到激活机制,一篇搞定

插件加载失败排查:从生命周期到激活机制,一篇搞定

先说一句,我带过好几个插件化改造的项目,也修过无数跟插件相关的启动报错,所以看到 "failed to load plugins web boot: 2 entries did not activate" 这种日志时,第一反应不是翻框架文档,而是看插件的激活方…

2026/10/14 18:19:43 阅读更多 →
Linux下源码编译安装PostgreSQL 12.0实战指南

Linux下源码编译安装PostgreSQL 12.0实战指南

我们聊聊怎么在Linux环境下把PostgreSQL 12.0老老实实装好、配好。写这篇是因为我最近刚好在一台CentOS 7.9的机器上从源码编译部署了一套PG 12.0,整个过程踩了几个不大不小的坑,网上很多教程都只讲“敲命令”,不讲“为什么”,导致…

2026/10/14 18:19:43 阅读更多 →
插件加载失败?从 MusicFree 到 web boot 激活链路全拆解

插件加载失败?从 MusicFree 到 web boot 激活链路全拆解

最近在很多技术社区和问答平台看到同一个热搜词:plugins。具体一点说,是“musicfree plugins”和“failed to load plugins web boot: 2 entries did not activate”这类带着具体上下文的长尾热词。如果你也和几千个点进这些关键词的人一样,刚…

2026/10/14 18:19:43 阅读更多 →
Linux下PostgreSQL 12.0编译安装与配置实战

Linux下PostgreSQL 12.0编译安装与配置实战

开头PostgreSQL 12.0这个版本虽然已经不算最新,但我一直认为它是近年里“最值得部署的版本”之一——性能优化覆盖面广、分区表体验大幅改善、日志和监控机制也更成熟。到现在,我身边还有不少生产环境跑在12.x上,稳定得让人懒得升级。这篇博文…

2026/10/14 18:19:43 阅读更多 →
Python Selenium复用已打开Chrome实例的完整指南

Python Selenium复用已打开Chrome实例的完整指南

1. 项目概述:为什么“复用已打开的Chrome”比从零启动更值得深挖你有没有遇到过这种场景:写好了一段 Selenium 脚本,运行起来一切正常,但每次执行都得重新打开一个全新的 Chrome 窗口——登录态没了、Cookie 清空了、插件没加载、…

2026/10/14 18:19:43 阅读更多 →
Kiln AI Server 实战指南:REST API 服务与 MCP 工具服务器的安装、配置与二次集成

Kiln AI Server 实战指南:REST API 服务与 MCP 工具服务器的安装、配置与二次集成

人工智能AI 应用AI 评测RAG微调提示工程开发工具桌面应用 【免费下载链接】Kiln Build, Evaluate, and Optimize AI Systems. Includes evals, RAG, agents, fine-tuning, synthetic data generation, dataset management, MCP, and more. 项目地址: https://gitcod…

2026/10/14 18:18:42 阅读更多 →

日新闻

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