B树原理与实现:从磁盘I/O优化到数据库索引的工程实践
刚接触B树的时候我第一反应是“又多了一个抽象的数据结构背就完事了”。直到在《Handbook of Data Structures and Applications》里啃完这一章又在项目里真正用B树处理过百万级数据的索引场景才意识到这东西不只是面试题而是数据库、文件系统这些基础设施的命根子。这篇文章我不打算照着书念定义而是结合书里那套严谨的数学模型和我实际调试B树代码踩过的坑把这个结构讲明白讲透顺便给你一套可以直接手写实现的思路。1. B树是什么从“多路平衡”到磁盘的现实毒打1.1 为什么数据量一大二叉树就顶不住了先聊一个非常实际的问题如果你有100万条有序记录要用内存中的二叉搜索树BST查找最坏情况要比较多少次如果这棵树退化成链表那就是100万次比较基本废了。就算平衡得很好AVL树或红黑树的查找也就是O(log n)大约20次比较。看起来挺不错的但这只是内存视角。一旦数据量到千万级、亿级事情就变了。数据不可能全放内存得放在磁盘上。机械磁盘的规矩是一次寻道加旋转延迟大约要花5到10毫秒。你读一个字节和读一个4KB块的速度差距没有你想的那么大。麻烦的地方在于你每访问一次磁盘就要付一次“5到10毫秒”的代价。二叉搜索树的高度决定了磁盘I/O次数。一亿条数据log2一亿大约是27意味着最坏情况要找27次磁盘。一次10毫秒270毫秒跑不掉。对在线查询来说这个延迟是致命的。所以核心矛盾很简单二叉树把树的高度压下来了但没压到磁盘能接受的程度。而B树的思路本质上就是让每个节点多存几个键把树从“二叉”变成“多叉”。如果一个节点能存100个键高度就能变成log100一亿大约是4。磁盘I/O从27次降到4次性能差着数量级。1.2 读书笔记B树的两个核心参数《Handbook》里定义B树是有几个关键参数的其中最重要的就是最小度数 tminimum degree。这本书的写法和其他教材不太一样它用最小度数来定义整棵树的性质每个非根节点至少含有 t-1 个关键字。每个非根节点至多含有 2t-1 个关键字。每个内部节点至少有 t 个子节点根节点除外。所有叶子节点都在同一层。习惯上我们说B树的“阶数m”有些书定义为每个节点最多有多少个子节点有些定义为最多有多少个关键字。两种定义都有人用但《Handbook》用最小度数的好处在于它能直接推导出复杂度的界。t2时每个节点最少1个关键字最多3个关键字实际上就是2-3-4树。t值越大单节点容量越大树的层高越矮但单节点的内存占用和分裂代价也会变大。这个选择背后是磁盘页大小和B树节点大小匹配的逻辑。数据库的页通常设为4KB或16KBB树节点的键数量就要尽量填满这个页。如果每个键占16字节加上指针开销一个节点能放200到300个键此时t大概在100左右。完全不用纠结具体数字只要明白B树的目标就是通过“大节点”来换取“矮树”以空间换时间。1.3 和红黑树的关系同一个思路两种表达我学B树的时候有个很大的疑问B树和红黑树长得完全不一样为什么很多书说它们在结构上是等价的红黑树本质上就是一棵2-3-4树。把红黑树里的红色节点向上合并到黑色父节点你就会得到一个每个节点最多3个键的4叉树也就是t2的B树。红黑树的“红黑约束”其实就是在模拟B树节点内部的键分布。这个等价关系很有用。如果你理解了B树的分裂、合并逻辑再看红黑树的旋转和变色会发现很多操作思路是相通的。旋转本质上就是B树的键移动变色就是节点内部分配键。所以不要觉得B树和红黑树是两个孤立的东西它们是同一套平衡思想在不同视角下的投影。2. 从演示到上手B树查找和高度演进的数学直觉2.1 先讲清楚B树的样子B树的节点长这样一个节点里有一段有序的关键字数组以及若干指向子节点的指针。假设某个节点有n个关键字那么它就有 n1 个指针。关键字把区间切成 n1 个开区间每个子节点的所有关键字都落在那一段区间里。比如一个节点有关键字 [10, 20, 30]那它就有四个指针分别指向小于10的子树、10到20之间的子树、20到30之间的子树、大于30的子树。这和二叉搜索树里“左小右大”的规则一模一样只是从“两路”变成了“多路”而已。你要留意的是B树里的所有数据是不重复的。不存在一个值既在父节点又出现在子节点里的情况父节点的每个关键字都是对应区间的分界值。这个设计和后面你常见的B树不一样B树把数据全部放在叶子内部节点只放索引键。B树是每个节点都可能带数据B树是只在叶子带数据。数据库里为什么偏爱B树我后面会单独讲。2.2 查找操作的细节别被“多叉”吓住B树的查找本质上就是把二分查找推广到多路。比如在某个节点里查关键字k先在这个节点的关键数组里做二分查找找到相等值直接返回这个节点。找到比k大的最小位置i那么下一层往 child[i] 走。如果所有关键字都比k小就往 child[n] 走。就这么简单。一层一层往下直到叶子节点。如果叶子节点的关键数组里还找不到那就是不存在。这里有个实际编码需要注意的点每个节点内部的关键字数组通常不会用线性遍历而是用二分查找。因为磁盘I/O次数已经由B树的高度决定了节点内部是内存操作用二分是合理的。如果节点容量特别大比如几百个键二分查找和线性查找的差距就明显了。不过现实中很多简化实现为了代码清晰直接用顺序扫描数据量小的时候性能也说得过去但你如果做的是对性能敏感的系统这里的二分绝对值得写。2.3 为什么一层能存那么多数据我尽量用最直白的数学给你算一算。假设B树的最小度数t100那么根节点最少有1个关键字最多199个关键字。第二层每个节点最少99个关键字最多199个关键字。树的高度为h那么整棵树最多能存的关键字数大约为 (2t-1) 乘以节点增长幂次。简化来说一棵高度为3的B树根层算1层下面还有2层在t100时能轻松存几百万条数据。高度为4时能存上亿条。这就是为什么数据库用B树做索引三到四次磁盘I/O就能从上亿条记录里找到一条。对比一下红黑树高度log2上亿大约27B树在磁盘场景下的优势是碾压级的。这个优势完全来自“把宽度拉大把高度压扁”这一条原则。3. 插入和删除的艺术分裂、合并、借位3.1 插入先找位置满了就分裂B树插入的逻辑和二叉搜索树有一个显著差异它不是到了叶子直接插入就完事而是通过“分裂”来维持平衡。算法是这样的从根出发沿着查找路径一直走到叶子。在路上只要碰到一个满节点关键字数达到 2t-1就先把它分裂掉再继续往下走。到达叶子后直接把关键字插进叶子节点的有序数组里。为什么要“先分裂再往下”因为在向下的过程中提前处理满节点就能保证下一步插入的目标节点一定有位置留给新关键字。如果只在叶子满了再分裂分裂时可能涉及到修改父节点处理起来更麻烦。最重要的是B树的“先分裂”保证了所有叶子在同一层不会出现树长歪的情况。具体分裂操作把中间那个关键字第t个提上去给父节点剩下的左右两部分变成两个新节点每个大约 t-1 个关键字。分裂时如果父节点也满了怎么办没关系你在往下走的路上已经把父节点分裂过了所以父节点一定有空位。根节点分裂是个特例当根节点满了就需要新建一个空根节点把旧根节点分裂成两个孩子。这是B树唯一长高的时机。整棵树的高度每次增加1都是因为根节点分裂。这一点在我们手写代码时必须特别注意。3.2 删除棘手的下半场删除操作比插入要复杂得多因为删除任何一个关键字后你都得保证非根节点至少有 t-1 个关键字。如果删完不够了怎么办书上有一套经典流程我在实现和测试中反复踩过坑之后把情况归纳成这么几类假设你要删除的关键字是k先从根一路向下找到它所在的节点x。如果k在x里且x是叶子直接删完事。如果k在x里且x是内部节点如果x左边那个子节点关键字数大于t-1就用左子树里的最大值替代k删除那个最大值。对称地如果右边那个子节点关键字数大于t-1就用右子树里的最小值替代k删除那个最小值。如果两个子节点都刚好是t-1个关键字那就把左右两个子节点和k合并成一个新节点然后在新节点里继续删。如果k不在x里那必然在某棵子树里。在进入那棵子树前如果发现目标子节点只有t-1个关键字已经不够了就要从它的兄弟节点“借”一个过来。如果兄弟节点也都只有t-1个了就合并它们。这类操作说起来绕但核心思路就两条借borrow和合并merge。借用兄弟的关键字绕过父节点往下转移保住节点数量的下限合并则把不满的兄弟和父节点的一个关键键拼成一个新节点。我自己的实现心得是删除写完后一定要准备一组专门的边界测试反复删除最小值、反复删除最大值、删除根节点、删除导致根节点变空的情况。很多时候你以为逻辑对了结果在某些组合操作下节点会降到 t-1 个以下B树直接失效。3.3 用“朋友圈”类比理解分裂合并如果觉得上面逻辑太绕就拿朋友圈的人数类比一下。假设一个微信群最多能容纳10个人类比 t2最大 2t-13 个关键字。当群满员了比如有10个人那第11个人加进来怎么办群主把第1个到第5个人分到一个新群第6个人踢到上级群去“代表”这个群的议题第7到第11个人分到另一个新群。这样每个群的规模保持在一个合理范围内。删除时如果一个群不足5个人先去隔壁群“挖”一个人过来。如果隔壁群也就5个人好干脆把两个群加上它们的上级代表合并成一个群再重新调整。B树的分裂和合并本质上就是这个群管理的规则只不过用严谨的“最少t-1个关键字”来保证无论怎么折腾每个节点都始终是“半满以上、满以下”的状态。4. 实操记录手写一个能跑的B树4.1 节点结构的两种选择写B树第一步是设计节点数据结构。我推荐在实践中用两个数组一个存关键字一个存子节点指针长度设为maxKeys 2t - 1。Java里的示例结构大概长这样class BTreeNode { int[] keys; // 简化起见用BTreeNode数组表示子节点叶子此数组为null或长度0 BTreeNode[] children; int n; // 当前关键字数量 boolean leaf; BTreeNode(int t, boolean isLeaf) { this.keys new int[2 * t - 1]; this.children new BTreeNode[2 * t]; this.n 0; this.leaf isLeaf; } }注意children的长度是2t而不是2t-1因为n个关键字的内部节点拥有n1个子指针。这是新手最容易写错的地方。如果你把children开成2t-1那么当节点是满的时候最后那个子指针就无处安放分裂那步必炸。4.2 实现插入分裂的要点插入的主流程分成两个方法对外入口insert() 和递归实现 insertNonFull()。对外入口处理根分裂这两行很多人会漏掉public void insert(int key) { BTreeNode r root; if (r.n 2 * t - 1) { // 根满分裂 BTreeNode s new BTreeNode(t, false); s.children[0] r; splitChild(s, 0, r); root s; insertNonFull(s, key); } else { insertNonFull(r, key); } }insertNonFull 的递归思路当前节点必须是“非满”状态找到key应该落入的子节点如果那个子节点满了先分裂它然后重新定位再进入。这个“先分裂再往下走”的思路我一开始没想通后来发现它的好处在于递归调用时你可以假定下一个节点肯定能容纳新元素层级逻辑清晰不容易把状态改乱。splitChild 是一个有点琐碎但非常机械化的方法。你把满子节点 y 分裂成两个节点 y 和 zz 取 y 的后半段关键字和指针y 的关键字数缩减为 t-1中间的关键字提到父节点 x 的keys数组里。注意操作顺序一定是“先把y的后半段复制到z再在父节点插入中间键和z的指针”因为父节点此时必须是非满状态由调用者保证。代码我就不全部贴了你按这个思路写跑通经典的“插入1到20再全部删除”测试基本就说明分裂和合并的骨架是对的。4.3 合法性检查验证B树没写歪的窍门手写B树最容易出问题的不是实现本身而是你没法判断它是否“合法”。我写的时候写了三个检查函数每个都很简单但非常关键检查每个非根节点的关键字数在 [t-1, 2t-1] 区间内。检查所有叶子在同一层递归时记录每条路径到达叶子的深度全部相等才算对。检查父节点关键字与子节点区间的一致性每个子节点的所有键必须严格落在父节点对应区间的开区间里。这三条过了树才算基本正确。特别是第三条我经常在删除操作后漏掉维护指针区间导致查询结果对不上。这套检查对调试帮助极大强烈建议你写B树时至少保留第一和第三条。5. 应用场景从数据库索引到文件系统5.1 数据库索引为什么用B树而不是B树很多人把B树和B树混为一谈数据库里说的“B树索引”其实几乎总是B树。B树和B树的差别主要在B树的内部节点只存键不存数据所有数据都在叶子节点。B树的叶子节点之间用双向链表串联起来。查询时最优情况是走到底部叶子再取数据因为数据只存在于叶子。为什么这样做第一个原因内部节点不存数据意味着同样大小的节点能放更多键树更矮磁盘I/O次数更少。第二个原因范围查询。B树要找到范围内的每个值都回到内部节点B树在叶子链表上直接顺序扫就行。MySQL InnoDB默认主键索引就是B树叶子节点上存放整行数据。二级索引的叶子节点存放主键值需要通过回表查主键索引。明白了B树的节点结构和磁盘页的关系你就能理解为什么InnoDB推荐用自增主键因为B树插入新主键永远是在最右叶子追加不需要频繁分裂和页分裂索引碎片少写入性能更稳定。5.2 文件系统里的B树变体数据库之外B树在文件系统里也随处可见。像某些文件系统用B树来管理目录条目和块分配利用它有序和矮层的特性快速定位文件路径。日志结构文件系统则用LSM树来优化写放大这算是B树思想的另一条岔路B树是原地更新LSM树是汇入式写入读放大换写性能。实际工程里B树还会衍生出B*树分裂时考虑兄弟节点先分配、前缀B树压缩键公共前缀、缓存体B树节点按热度调整等一堆变体。但万变不离其宗底层就是“多路平衡搜索树 节点分裂合并”的机制。5.3 B树与哈希索引的适用边界B树索引和哈希索引常常被人放在一起比较。哈希索引对单点精确查找有O(1)的优势但一遇到范围查询、排序、前缀匹配就歇菜因为哈希破坏了有序性。B树索引天然有序所以范围查询、ORDER BY、like abc% 这种前缀匹配都能命中索引。一个反直觉的细节就是当数据量特别大时哈希索引的内存占用会非常大要预分配很多桶而B树可以直接只加载根节点到内存按需向下读取。这就是为什么即使在内存数据库里B树仍有一席之地——它对内存的使用并不是“全量常驻”而是“按需加载”配合缓存策略非常优雅。6. 常见问题与排查技巧实录6.1 分裂时节点数组越界这是新手最常踩的坑。如果一个节点的children长度只开了2t-1或者分裂时忘了把父节点的count先加1就可能出现数组越界。我的排查建议是分裂前打印当前节点的n、children.length、父节点的n快速定位问题在哪一步。6.2 删除时合并错方向导致查询错误有时候节点删掉后数据没丢但搜索某个值会走错分支。原因十有八九是合并调整后“区间指针”没对应好。调试时最好的方法是写一个中序遍历输出所有键再写一个查找函数逐个验证1到N是否存在对比结果就能发现是哪两个相邻节点之间的指针断了。6.3 性能测试看起来没提升终于把B树写完了随便测了下却发现比ArrayList扫一遍还慢别慌这是正常的。B树的优势在“磁盘I/O次数”和“大量数据下的有序操作”不在单个内存操作的常数级开销。如果数据量只有几万条且全部常驻内存哈希表或跳跃表可能完胜B树。真正测性能应该模拟磁盘访问比如在节点读取处加一个计数器统计一次查找访问了多少节点。这个节点访问次数才是B树的灵魂指标。7. 读完这一章后我的几点实操感悟第一B树是我手写过的最好“验证正确性”的数据结构之一因为它每一个不变量都非常直接。关键字数下限、叶子同层、区间有序这些约束在代码里都是可以硬编码检查的。这种验证机制对写工程代码也非常有用——把不变量写成assert跑随机测试树出问题的位置一下就暴露了。第二从工程角度看B树的复杂性主要集中在删除。如果你在做系统时不需要删除操作大可以只实现“查找插入”把删除留空用懒删除标记代替。很多存储引擎初期就是这么干的等业务稳定了再补删除。不要为了“完整实现”一次把所有功能都塞进去复杂度会迅速失控。第三真正打动我的是B树的设计动机。它不是为了好“看”而是为了适应硬件的物理特性。数据结构和系统设计在这一刻是真正交汇的你思考的不是“这个数据结构在教科书上怎么定义”而是“在磁盘页4KB、内存缓存有限、并发访问频繁的约束下哪种组织方式失真最小”。搞懂了这一点你再去看任何存储系统都会觉得那些索引方案不再是黑魔法而是在物理约束下做出的最优解。

相关新闻

Kubernetes集群筑基:etcd环境准备与生产级调优指南

Kubernetes集群筑基:etcd环境准备与生产级调优指南

1. 项目概述:为什么K8s环境准备必须从etcd开始讲起 “K8S安装(一) 环境准备及etcd组件安装及etcd管理软件etcdkeeper安装”——这个标题看似平实,但背后藏着Kubernetes集群最底层的逻辑锚点。我带过十几套生产级K8s集群搭建&#…

2026/10/14 14:13:24 阅读更多 →
GNN生产环境部署实战:从模型导出到高并发推理服务

GNN生产环境部署实战:从模型导出到高并发推理服务

1. 从单机到生产:GNN 应用部署的核心挑战很多人在本地把 GNN 模型跑通之后,就觉得大功告成了。我刚开始做图神经网络项目时也是这个心态——在 Jupyter Notebook 里用 PyG 加载 Cora 数据集,训练一个两层的 GCN,准确率跑到 81%&am…

2026/10/14 14:13:24 阅读更多 →
Kubernetes集群基石:etcd分布式共识底座部署与运维实战

Kubernetes集群基石:etcd分布式共识底座部署与运维实战

1. 项目概述:为什么K8s环境准备必须从etcd开始,而不是直接装master节点 “K8S安装(一) 环境准备及etcd组件安装及etcd管理软件etcdkeeper安装”——这个标题里藏着一个被很多新手忽略的关键逻辑: Kubernetes不是从kub…

2026/10/14 14:13:24 阅读更多 →

最新新闻

Firebase JS SDK Realtime Database 的 Database 类:实例获取、内部结构与生命周期全解析

Firebase JS SDK Realtime Database 的 Database 类:实例获取、内部结构与生命周期全解析

开发工具后端 【免费下载链接】firebase-js-sdk Firebase Javascript SDK 项目地址: https://gitcode.com/gh_mirrors/fi/firebase-js-sdk 点击查看 免费下载 本篇技术指南聚焦 firebase-js-sdk 仓库中 firebase/database 模块的核心类 Database(即 Fir…

2026/10/15 2:12:16 阅读更多 →
Positron 中 Claude Agent 客户端工具(Client-provided Tools)的实现剖析:从 Phase 10 计划到 in-process MCP 落地

Positron 中 Claude Agent 客户端工具(Client-provided Tools)的实现剖析:从 Phase 10 计划到 in-process MCP 落地

开发工具代码编辑器数据科学 【免费下载链接】positron Positron, a next-generation data science IDE 项目地址: https://gitcode.com/gh_mirrors/po/positron 点击查看 免费下载 导读:本文以 phase10-plan.md 这份实现计划文档为主线,完整…

2026/10/15 2:12:16 阅读更多 →
大模型评测工具链第二周工程复盘:分层自适应抽样、网络长尾消解与三态自愈调度器

大模型评测工具链第二周工程复盘:分层自适应抽样、网络长尾消解与三态自愈调度器

在现代大模型工程体系中,自动化评测框架往往扮演着“方向盘”与“刹车片”的双重关键角色。没有敏捷、精准且高置信度的评测反馈,模型优化就会沦为无的放矢的盲人摸象;而如果评测调度器本身缺乏弹性与容灾设计,一次未经流控的百万…

2026/10/15 2:12:16 阅读更多 →
Defuddle 返回导航链接清理实战:从 fixture 案例到 content-patterns 源码解析

Defuddle 返回导航链接清理实战:从 fixture 案例到 content-patterns 源码解析

后端 【免费下载链接】defuddle Get the main content of any page as Markdown. 项目地址: https://gitcode.com/gh_mirrors/de/defuddle 点击查看 免费下载 本文以仓库中的 general--back-nav-link.md 测试夹具为入口,剖析 Defuddle 如何在提取网页正…

2026/10/15 2:12:16 阅读更多 →
Lunar 2.8.1 修复解析:显示器 UUID 分配、名称检测与缓存数据库覆盖机制

Lunar 2.8.1 修复解析:显示器 UUID 分配、名称检测与缓存数据库覆盖机制

桌面应用 【免费下载链接】Lunar Intelligent adaptive brightness for your external monitors 项目地址: https://gitcode.com/gh_mirrors/lu/Lunar 点击查看 免费下载 本文围绕 Lunar(macOS 外部显示器智能亮度调节工具)2.8.1 版本的三个…

2026/10/15 2:12:16 阅读更多 →
MLeaksFinder 实践与源码解析:在开发阶段自动定位 iOS 内存泄漏

MLeaksFinder 实践与源码解析:在开发阶段自动定位 iOS 内存泄漏

开发工具质量保障 【免费下载链接】MLeaksFinder Find memory leaks in your iOS app at develop time. 项目地址: https://gitcode.com/gh_mirrors/ml/MLeaksFinder 点击查看 免费下载 MLeaksFinder 是腾讯开源的 iOS 内存泄漏检测工具,其核心思路是&a…

2026/10/15 2:11:16 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战: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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →