agent-memory 召回路装配内收:CompositeStorage 工厂化装配 Recaller 的架构设计与循环依赖破解
人工智能AI AgentAgent 记忆RAGMCP 服务【免费下载链接】agent-memoryMemory 是一款面向 AI 智能体的长期记忆模块为运行在 openJiuwen 框架上的智能体提供记忆提取、存储、检索与迁移能力。项目地址https://gitcode.com/openJiuwen/agent-memory点击查看免费下载本文以 agent-memory 项目特性文档 F06-composite-recaller-assembly.md 为骨架结合jiuwen_memory/storage与jiuwen_memory/retrieval的当前源码实现、默认装配配置与测试基线完整讲解「多路 Recaller 召回路装配从 Retriever 工厂内收到 Storage/StoreManager 工厂」这一设计决策。读完你将掌握七个*_recaller选择键与三个能力开关的配置语义、具名/匿名构建下循环依赖的双预注册破解方案、PipelineRetriever不再持有召回路后的委托模型以及手工接线与构建期 fail-fast 的测试验证方式。背景统一 Storage 落地后的装配错位在 F05-unified-storage-design 统一 Storage 落地之后PipelineRetriever的生产装配仍按旧世界做事retriever 工厂自己组装 keyword/vector/graph/L0/L1 各路 Recaller再通过isinstance(storage, CompositeStorage)判断后调用bind_recallers把召回路塞回 storage。这种装配方式带来三个结构性问题责任错位recall/get/rank 三条首选路径的执行都在 Storage 内唯独召回路的组装留在 Retriever 工厂——CompositeStorage的能力开关如vector_enabled要由别人替它解释能力声明与实际装配脱节。非 Composite 实现被拖进无关概念一体化 Storage 自带检索路径根本不需要 Recaller旧装配却仍先组装一整组 recaller再发现无处可绑白白浪费构建成本并造成概念污染。构造签名被迫膨胀PipelineRetriever构造签名被迫携带recallers参数并在构造期做「无 storage 就用 unit_reader.kv 临时拼一个 CompositeStorage 再绑 recaller」的兼容逻辑把一个装配期问题泄漏进运行期对象。核心决策五条设计主线针对上述问题F06 确立了五条相互咬合的决策其最终形态在当前仓库代码中完整落地。决策 1召回路装配内收到 Storage 工厂StorageProducer.register(composite)的_build按配置组装 recaller。在 F07 拆分后该装配入口位于 composite_store_manager.py 的from_config召回路组装逻辑收敛在 composite_domain_store.py 的_assemble_recallers与for_manager能力开关vector_enabled/graph_enabled/layers_index_enabled经config.get回退 globals属于跨切面意图开关recaller 选择键keyword_recaller/vector_recaller/graph_recaller/keyword_l0_recaller/keyword_l1_recaller/vector_l0_recaller/vector_l1_recaller共七个落在storage.default.paramsF07 后进一步下移到domain_stores.default。这组键相应从defaults.py的retriever.default.params移到了 storage 侧retriever段只保留本算子私有调参over_fetch_factor、recall_max、rerank_max等。默认装配下会同步组装出 7 路 recaller。决策 2构建期同步组装 双预注册打破循环recaller builder 内部会StorageProducer.resolve(config)回取本 Storage 实例而build_named没有「构建中」检测——如果装配期直接同步组装会形成「装配 CompositeStorage → 组装 recaller → recaller 回取 Storage → 再建一个 CompositeStorage」的无限递归。破解方案是_build先把构建中的实例预注册进具名缓存再组装且区分具名/匿名两条路径。决策 3PipelineRetriever 不再持有召回路构造签名删除recallers参数与recallers属性retrieve只按storage.preferred_retrieval_pipeline()委托recall/recall_and_get/retrieve。非 Composite 实现不再被拖进 recaller 概念。storageNone回退保留为CompositeStorage(kvunit_reader.kv)无召回路仅供只走点读/短路路径的调用。决策 4bind_recallers 保留为手工/测试接线口recaller 构造需要 storage 实例如KeywordRecaller(storage)手工接线仍是「先建 storage、再建 recaller、再 bind」绑定后惰性 loader 作废。重绑守卫不变同一实例不允许绑定两套不同 recaller。决策 5模块依赖方向不破composite_storage.py只在_assemble_recallers函数体内惰性from jiuwen_memory.retrieval.recaller import RecallerProducer模块层面 storage 仍不导入 retrieval。F07 E 组把 Recaller 整体移入 storage 数据面后这条延迟导入连同它绕开的循环一起消失——这正是当前代码中Recaller契约与实现已经位于 recaller.py 的原因。配置详解七个选择键与三个能力开关召回路装配的完整默认配置位于 defaults.py。F07 参数归位后数据面的全部装配参数住在store_manager.inst.params.domain_stores.name默认形状如下globals: schema_enabled: false vector_enabled: true graph_enabled: true rerank_enabled: true embedder_dim: 64 chunk_size: 120 store_manager: default # 全局唯一 StoreManager 指名 store_manager: default: target: composite params: domain_stores: default: # 数据面 default 必建命名实例 overlay 在它之上 kv_store: default preferred_retrieval_pipeline: recall_get_rank keyword_recaller: keyword vector_recaller: vector graph_recaller: graph keyword_l0_recaller: keyword_l0 keyword_l1_recaller: keyword_l1 vector_l0_recaller: vector_l0 vector_l1_recaller: vector_l1下表给出全部装配参数的语义参数取值/默认语义kv_store端口名字符串默认default数据面真源 KV 端口名与其余消费方同一套选择键机制运行期不硬编码defaultpreferred_retrieval_pipelinerecall_get_rank/recall_and_get_rank/retrieve数据面实例级稳定的首选检索路径见 retrieval.py 的RetrievalPipeline枚举keyword_recallerkeyword关键词/全文通道L2 content包一个FulltextStorevector_recallervector向量语义通道L2 content chunk包一个VectorStoregraph_recallergraph图遍历通道关键词种子 → 1 跳邻居候选keyword_l0_recallerkeyword_l0预生成概要分表的全文倒排召回keyword_l1_recallerkeyword_l1预生成片段分表的全文倒排召回vector_l0_recallervector_l0概要整段向量分表召回vector_l1_recallervector_l1片段整段向量分表召回recaller 具名实例声明在recaller:顶层命名空间target 与注册名在 F07 迁移后逐字不变YAML 配置零迁移recaller: keyword: { target: keyword } keyword_l0: { target: keyword_l0 } keyword_l1: { target: keyword_l1 } vector: { target: vector, params: { min_similarity: 0.0 } } vector_l0: { target: vector_l0 } vector_l1: { target: vector_l1 } graph: { target: graph }三个能力开关的生效逻辑见_assemble_recallersvector_enabledfalse时不装vector_recaller/vector_l0_recaller/vector_l1_recallergraph_enabledfalse时不装graph_recallerlayers_index_enabledfalse时不装 L0/L1 四路keyword_l0/l1、vector_l0/l1。注意一个易踩的静默退化陷阱RecallerProducer.dep读的是config.params直读不回退 globals因此domain_stores的命名 entry 必须先 overlay 在defaultentry 之上再传入。若命名 entry 漏掉*_recaller键dep会落到cls.build(default, {}, ctx)匿名新建一套不共享、params 为空的 recaller——装配不报错读写悄悄用上两套实例测试 test_named_domain_stores.py 中test_named_entry_shares_recaller_instance_with_default用对象身份is断言而非通道名来锁死该退化。源码级原理循环依赖的具名/匿名双预注册Factory.build_named见 factory.py没有「构建中」检测命中缓存即返回共享实例未命中则新建并入缓存。这意味着装配期直接同步组装 recaller 时recaller builder 内部的StorageProducer.resolve(config)会触发再建一个 CompositeStorage形成递归。_assemble_recallers按构建形态拆成两条分支具名构建config.name非空CompositeStoreManager.from_config先StoreManagerProducer.put(config.name, manager)把构建中的实例预注册进具名缓存recaller 命名空间下声明的具名实例recaller.keyword等带store_manager: name字符串引用RecallerProducer.dep走build_named命中缓存StoreManagerProducer.resolve在 builder 内回取成功打破循环。匿名构建无config.name如IndexBuilderProducer调StorageProducer.resolve落到第三分支构建无缓存键dep缺省会回落cls.build(default, {}, ctx)再次触发 recaller builder 用空 params 走StorageProducer.resolve落第三分支再建一个匿名 CompositeStorage → 递归。破解方案是用合成名__anon_store_manager_{id(storage)}__id保证唯一预注册本实例改走RecallerProducer.build(target, {store_manager: synthetic_name}, ctx)直接注入 storage 引用让 builder 内resolve走第一分支cls.dep命中合成名缓存。当前实现见 composite_domain_store.py_assemble_recallers的synthetic_name分支。装配错误选择键指向未注册实现、必填插件缺失等在构建期 fail-fast 暴露不拖到首次召回。这正是测试 test_storage_factory_wiring.py 中test_recaller_assembly_error_surfaces_at_build_time锁住的行为把vector_recaller指向nonexistent_impl后StoreManagerProducer.build_named(default, context)在构建期直接抛ValidationError。PipelineRetriever 的委托模型当前 pipeline_retriever.py 的构造签名已不含recallers只收parser/fuser/discloser/unit_reader/reranker与检索调参以及 keyword-only 的domain_storeF07 后 Retriever 运行期只持数据面。_build工厂只做两件事经StoreManagerProducer.resolve取全局 manager再用manager.domain_store(resolve_name(config, domain_store))取数据面注入。retrieve的召回段按self._domain.preferred_retrieval_pipeline()三选一首选路径行为RECALL_GET_RANK先recall多路并行召回 ScoredUnit→ 再get物化真源 复核 → fuser 融合RECALL_AND_GET_RANK数据面内一次完成recall_and_getRetriever 侧复核后直接融合RETRIEVE数据面内完成 recall get rank传入 fuserRetriever 只收已融合候选多路并行与结果合并由 composite_domain_store.py 的recall负责按channels过滤已装配 recallerThreadPoolExecutor并行提交逐路捕获异常记入ChannelError全路失败才抛StorageRetrievalError部分成功语义。每个 Recaller 对应一条召回通道互不感知其他通道。手工接线bind_recallers 的测试与定制路径bind_recallers仍是公开的手工/测试接线口F06 决策 4 不变装配路径改由for_manager内部调用。测试夹具 conftest.py 的make_world就是典型手工接线形态storage CompositeStoreManager(kvkv, vectorvector, fulltextfulltext) domain_store CompositeDomainStore( managerstorage, preferred_pipelineRetrievalPipeline.RECALL_GET_RANK ) keyword KeywordRecaller(storage) vector_recaller VectorRecaller(storage) domain_store.bind_recallers([keyword, vector_recaller]) # 先建 storage → 再建 recaller → 再 bind storage.bind_domain_store(domain_store)自定义召回路集成测试如 test_pipeline_retriever.py 的test_default_config_attaches_l0_l1_recallers、test_index_contract.py也走这条路径手工构造CompositeStoreManagerCompositeDomainStorebind_recallers注入故障注入型/固定候选型 recaller 验证通道级降级、并行性与 L0/L1 装配。验证体系F06 的验证覆盖在仓库中完整对应test_storage_factory_wiring.py默认装配下retriever.storage is storage且storage.recallers同步组装出 7 路globals 关闭三个能力开关后只剩 keyword 一路选择键指向未注册实现时构建期抛ValidationError。test_index_builder.pytest_fulltext_factory_*/test_vector_factory_*/test_unified_factory_*覆盖匿名 CompositeStorage 构建经StorageProducer.resolve第三分支合成名预注册打破循环、不触发递归。test_storage_pipelines.py、test_recallers.py、test_pipeline_retriever.py含keyword_recaller覆盖键移到 storage 段的用例、test_index_contract.py 全部适配并通过conftest.py的make_world改为 bind 手工接线。test_named_domain_stores.pydomain_stores段此前全仓零覆盖F07 补上 11 例其中test_named_entry_shares_recaller_instance_with_default锁死「命名 entry 继承 default 的 recaller 实例」这一静默退化。F06 文档记录的测试基线为.venv-wsl/bin/python -m pytest tests/unit tests/integration1318 passed / 82 skipped4 failed 均为 HEAD 既有问题2 个 bge_m3 缺 torch2 个 entity_linker 测试间干扰。F07 演进后基线为pytest tests/unit/1978 passed / 8 skipped、pytest tests/integration/48 passed / 61 skipped。拒绝的方案与取舍理由F06 明确记录了被否定的备选方案理解它们有助于把握内收设计的分寸装配期同步构建仅put预注册具名路径可行但匿名构建仍会经 recaller builder 回取storage.default递归构建默认实例。最终采纳时补上合成名预注册 直接RecallerProducer.build注入 storage 引用覆盖匿名路径。首次召回时惰性物化能彻底回避循环但装配错误推迟到首次召回才暴露违背「配置错误尽早暴露」原则且增加首次召回延迟与状态管理复杂度。保留 retriever 侧装配、仅按isinstance跳过非 Composite责任依然错位开关仍由 retriever 工厂替 storage 解释治标不治本。让 recaller 不再依赖 Storage改注入裸端口可彻底消除循环但要改全部 recaller 的构造契约与测试且违背「上层握共享 Storage 入口、勿构造期握死裸端口」的本地约束RoutingStorage 惰性代理依赖这一点。召回路用命名空间扫描替代显式选择键失去按配置裁剪/替换单路的能力且会把未接线入库的具名实例也拉进来。已知遗留与后续演进F07F06 的已知遗留当前依旧成立recaller 装配的运行时错误如距离型度量向量库被VectorRecaller在首次召回时拒绝、向量库连接不通等仍推迟到首次召回才暴露装配期 fail-fast 只覆盖选择键指向未注册实现、必填插件缺失等配置类错误运行时错误依赖冒烟/健康检查覆盖。注距离型度量的拒绝实际发生在构造期——vector_recaller.py 在__init__中检查score_higher_is_better()并抛ValidationError。匿名构建用id(storage)派生合成名预注册进_instances缓存装配后该缓存条目无人再引用recaller 已持直接引用属无害死条目Factory.reset_all在每次装配前清空。用户配置迁移写在retriever.*.params的*_recaller覆盖键不再生效需迁移到storage.*.paramsF07 后进一步迁至domain_stores.nameglobals 里的能力开关不受影响。后续演进见 F07-storage-manager-domain-store-split.md本文的召回装配链路整体保留仍由 manager 工厂末尾调_assemble_recallers仅符号随拆分更名CompositeStorage→CompositeStoreManager/CompositeDomainStore、StorageProducer.resolve→StoreManagerProducer.resolve、合成名__anon_storage_{id}__→__anon_store_manager_{id}__。F07 E 组进一步把Recaller契约与实现移入storage/domain_store_impl/_assemble_recallers的调用点下沉进CompositeDomainStore.for_manager本文决策 5 的惰性导入随之删除。值得强调的是F06 拒绝方案里「让 recaller 不再依赖 Storage改注入裸端口」始终未被采纳——E 组走的是相反方向不是把 recaller 从 storage 摘出去而是把它收进来。赞分享人工智能AI AgentAgent 记忆RAGMCP 服务【免费下载链接】agent-memoryMemory 是一款面向 AI 智能体的长期记忆模块为运行在 openJiuwen 框架上的智能体提供记忆提取、存储、检索与迁移能力。项目地址https://gitcode.com/openJiuwen/agent-memory点击查看免费下载相关推荐OpenStock 使用指南免费实时行情 价格提醒如何 10 分钟搭好盯盘流程OpenStock 使用指南免费实时行情 价格提醒如何 10 分钟搭好盯盘流程 OpenStock 是一款开源股票工具免费实时行情、板块热力图与自定义金融科技前端后端AI 应用Anki-Android 模块化架构中的 :anki-common打破循环依赖的共享层设计详解Anki Android 模块化架构中的 :anki common 打破循环依赖的共享层设计详解 导读 本文以 Anki AndroidAnkiDroid移动开发教育agent-memory 检索层实现规约深度解析QueryParser / Recaller / Fuser / Discloser / Retriever 的装配、语义与取舍agent memory 检索层实现规约深度解析QueryParser / Recaller / Fuser / Discloser / Retriever人工智能AI AgentAgent 记忆RAGMCP 服务上一篇Aptos Core 二进制发布与 cargo-binstall 集成指南让用户免编译安装预编译二进制下一篇Epic Stack 导入路径方案演进用 package.json 的 imports 字段配置 前缀路径别名创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

《县中的孩子》:看见县域教育生态的真实困境

《县中的孩子》:看见县域教育生态的真实困境

书读到一半的时候,我好几次停下来。不是看不懂,是有些场景太熟悉了。教室后墙的倒计时、县城中学门口等孩子的电动车、晚自习熄灯后还在走廊背书的影子——这些画面明明离大城市很遥远,却又让人觉得哪儿哪儿都是。《县中的孩子》不是那种告诉…

2026/10/14 21:02:40 阅读更多 →
GORM开发必备:Go结构体字段用值类型还是指针?

GORM开发必备:Go结构体字段用值类型还是指针?

做Go后端开发,天天跟GORM打交道的人迟早会纠结一个问题:表结构对应的struct字段,到底要不要用指针?这问题没有标准答案,但我可以从一个线上事故讲起。之前维护一个订单管理系统,前端提交"把商品数量改…

2026/10/14 21:01:39 阅读更多 →
执行上下文进阶:this绑定、TDZ与异步调度的运行机制

执行上下文进阶:this绑定、TDZ与异步调度的运行机制

这个系列写到第四篇了。前几篇我分别聊了执行上下文的基本模型、调用栈怎么管理函数调用,以及作用域链和闭包到底是怎么串起来的。这三块内容放在一起,其实已经能把“JavaScript 代码运行时的空间模型”讲出一个比较完整的框架。但很多同学继续往下读的时…

2026/10/14 21:01:39 阅读更多 →

最新新闻

电影院在线选座系统实战:Django+Flask架构下的并发抢座与状态一致性设计

电影院在线选座系统实战:Django+Flask架构下的并发抢座与状态一致性设计

提到电影院在线选座系统,很多人第一反应是“这不就是课设或者毕业设计的经典题目吗”。确实,这类系统的核心链路看着不复杂,但真从头到尾完整落地一遍,就会发现难度根本不在于增删改查,而在于几个信息量很大的隐性模块…

2026/10/14 21:52:59 阅读更多 →
PHP圈子系统源码实战:语音贴、语音房与直播后台开发

PHP圈子系统源码实战:语音贴、语音房与直播后台开发

简介:多客圈子系统是一套面向社交与直播创业者的综合性源码方案,适合具备PHP与uniapp基础的开发者二次开发,可快速搭建社区兴趣圈、语音交友、婚恋、本地门户等应用。压缩包共约2000个文件,整体56.7MB,以js、xml、php、…

2026/10/14 21:52:59 阅读更多 →
Java后端对象映射全解析:JSON、VO、Entity转换与MapStruct实战

Java后端对象映射全解析:JSON、VO、Entity转换与MapStruct实战

做 Java 后端时间长了你会发现,项目里最琐碎、最不起眼、但线上问题最多的往往不是复杂业务逻辑,而是对象之间的数据搬运。尤其是接口接收的 JSON、对内处理的 VO、最终落库的 Entity,这三者之间来回转换的代码,每天都在团队里被反…

2026/10/14 21:52:59 阅读更多 →
多客圈子系统:PHP实现语音贴、语音房与直播统一后台

多客圈子系统:PHP实现语音贴、语音房与直播统一后台

简介:多客圈子系统是一套面向社交与直播创业者的综合性源码方案,适合具备PHP与uniapp基础的开发者二次开发,可快速搭建社区兴趣圈、语音交友、婚恋、本地门户等应用。压缩包共约2000个文件,整体56.7MB,以js、xml、php、…

2026/10/14 21:52:59 阅读更多 →
Qoder智能IDE的Rule规则配置:让AI编程助手真正听懂约束

Qoder智能IDE的Rule规则配置:让AI编程助手真正听懂约束

用过AI编程助手的朋友应该都有过这种体验:第一次让它写个函数,挺惊艳;等写多了就会发现,它生成的东西总是差那么点意思——变量命名风格跟项目其他代码对不上,错误处理逻辑东一个西一个,提交信息更是七零八…

2026/10/14 21:52:59 阅读更多 →
局域网内WebUI接入OAuth2/OIDC企业SSO的完整实践指南

局域网内WebUI接入OAuth2/OIDC企业SSO的完整实践指南

刚开始做这件事的时候,我其实不太情愿。团队里那个本地 WebUI 是给内部大模型任务管理和参数调优用的,最初只是“谁要用谁自己问管理员要密码”,大家也这么用了大半年。直到公司网络合规审计点名了这个系统,要求所有内部 Web 服务…

2026/10/14 21:51:58 阅读更多 →

日新闻

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