夜雨聆风学习资料网

ARTICLE · 1092632

从本地数据揭秘WorkBuddy:插件四层加载 — 安装 ≠ 启用 ≠ 加载 ≠ 实例化

从本地数据揭秘WorkBuddy:插件四层加载 — 安装 ≠ 启用 ≠ 加载 ≠ 实例化

"

系列第 5 期。从 ~/.workbuddy/plugins/ 的真实本地数据出发,拆解 WorkBuddy 插件系统的四层加载机制。

引子:48 个插件,只有 10 个被"启用"

打开 ~/.workbuddy/settings.json,enabledPlugins 字段赫然在列:

{

  "weixinpay@workbuddy-builtin": true,

  "tencent-docs-plugin@workbuddy-builtin": true,

  "tencent-pptx@workbuddy-builtin": true,

  "agent-browser@codebuddy-plugins-official": true,

  "find-skills@codebuddy-plugins-official": true,

  "sheetagent@workbuddy-builtin": true,

  "tencent-docx@workbuddy-builtin": true,

  "document-skills@cb_teams_marketplace": true,

  "finance-data@cb_teams_marketplace": true,

  "playwright-cli@codebuddy-plugins-official": true

}

10 个 true。

但打开同级的 plugins/installed_plugins.json,里面是 48 个已安装插件——28 个 skill-、4 个 interactionmode-、3 个 welcomemode-*、1 个 prompt-common,加上 12 个复合能力包。

38 个已安装但未启用的插件,难道就是"死代码"?

不是。它们中的大多数,此刻正在为你工作——只是不走"启用"这条路。

这篇文章从本地文件的真实数据出发,拆解 WorkBuddy 插件系统的四层加载机制:安装 → 启用 → 加载 → 实例化。理解这四层,才能理解一个拥有 48 个插件的 Agent 操作系统,为什么冷启动不会爆炸。

01

数据现场:四个文件,四层真相

先看数据。四个本地文件,分别对应四个加载阶段。

第一层:安装(Installation)

文件:plugins/installed_plugins.json

{

  "version": 2,

  "plugins": {

    "find-skills@codebuddy-plugins-official": [{

      "scope": "user",

      "installPath": "~/.workbuddy/plugins/cache/codebuddy-plugins-official/find-skills/1.0.0",

      "version": "1.0.0",

      "installedAt": "2026-08-24T07:38:32.237Z",

      "lastUpdated": "2026-09-13T05:31:42.328Z"

    }],

    "skill-ardot-slides@workbuddy-builtin": [{

      "scope": "user",

      "installPath": "~/.workbuddy/plugins/cache/workbuddy-builtin/skill-ardot-slides/5.5.6-...",

      "version": "5.5.6-wb.38337834...",

      "installedAt": "...",

      "lastUpdated": "..."

    }],

    ...

  }

}

关键结构:version: 2,plugins 是一个 dict(不是数组),键是 name@source,值是版本记录数组。这意味着同一个插件可以并存多个版本。

48 个已安装插件,按类型分布:

类型
数量
示例
skill-*
28
ardot-slides、buddy-image-processing、wb-finance-skill
interactionmode-*
4
ask、craft、plan、expert
welcomemode-*
3
code、design、work
prompt-common
1
全局常驻提示片段
复合能力包
12
weixinpay、sheetagent、tencent-docx、agent-browser 等

安装 = 文件落盘。插件包从市场(官方 zip、内置 directory、本地专家目录)下载到 plugins/cache/<source>/<name>/<version>/,在 installed_plugins.json 登记一条记录。到此为止,插件只是一堆躺在磁盘上的文件。

第二层:启用(Enablement)

文件:settings.json → enabledPlugins

{

  "weixinpay@workbuddy-builtin": true,

  "tencent-docs-plugin@workbuddy-builtin": true,

  ...

  "playwright-cli@codebuddy-plugins-official": true

}

10 个 true。仔细看这 10 个插件,有一个共同特征:它们全是"主动能力型"。

启用的插件
能力类型
weixinpay
MCP server + 原生 CLI + skill
sheetagent
MCP server + 编排 skill
tencent-docx / tencent-pptx / tencent-docs-plugin
复合文档套件(多 Stage agent + skill)
agent-browser / playwright-cli
浏览器自动化
find-skills
技能发现
document-skills / finance-data
市场安装的领域技能包

*没有一个是 skill-、interactionmode-、welcomemode- 或 prompt-common。**

这不是巧合。enabledPlugins 闸门只管"主动能力型"插件——需要启动 MCP server、注册连接器、注入 agent 的插件。被动常驻的提示片段和按需加载的 skill 包,根本不走这个闸门。

第三层:加载(Loading)

文件:plugins/cache/<source>/<name>/<version>/.in_use/<pid>

~/.workbuddy/plugins/cache/workbuddy-builtin/

├── weixinpay/1.6.109/.in_use/

│   ├── 24239        ← 空文件,每个 agent 进程一个

│   └── 43783

├── tencent-docx/5.5.6-.../.in_use/

│   ├── 24239

│   └── 43783

├── interactionmode-craft/0.1.4/.in_use/

│   └── (当前为空——因为 craft 是默认模式,锁在活跃会话中)

├── prompt-common/0.1.2/.in_use/

│   └── (同上)

...

.in_use/<pid> 是运行时 PID 锁。每启动一个 agent 进程,框架就为当前激活的插件在该目录下创建一个以进程 PID 命名的空文件;进程退出即删。

这个机制揭示了第三层加载的真相:被动常驻片段(welcomemode / interactionmode / prompt-common)不经过 enabledPlugins 闸门,而是通过 .in_use PID 锁标记"谁在用它"。

实测数据:

插件
.in_use
 锁数
说明
weixinpay
2
主动能力型,启用 + 加载
tencent-pptx
2
同上
tencent-docx
2
同上
tencent-docs-plugin
2
同上
sheetagent
2
同上
welcomemode-work
1
被动常驻,不经 enabledPlugins
prompt-common
1
被动常驻,不经 enabledPlugins
interactionmode-craft
1
被动常驻(默认模式),不经 enabledPlugins

*28 个 skill- 插件呢?** 它们既不在 enabledPlugins 里,也没有 .in_use 锁。因为它们走的是第四层。

第四层:实例化(Instantiation)

文件:interactionmode-craft/0.1.4/.workbuddy-plugin/ 下的 interaction.md

tools:

  - Read

  - Write

  - Edit

  - Bash

  - ...

  - Defer(SkillManage)

  - Defer(LSP)

  - Defer(ImageGen)

  - Defer(VideoGen)

  - Defer(TeamCreate)

  - Defer(TeamDelete)

  - Defer(conversation_search)

  - Defer(workbuddy_cloudstudio_deploy)

8 处 Defer(...) 声明。这是延迟加载的提示层表达:这些重能力在冷启动时不加载,只有当模型在 function_call 中第一次请求该工具名时,框架才拉起对应的能力包或 MCP server。

实测证据:在全工程 74 个会话 9300 次 function_call 中,DeferExecuteTool(延迟执行工具)被调用了 26 次——这就是第四层实例化的运行时痕迹。

28 个 skill- 也走类似路径:它们通过运行时 Skill 工具按需注入。模型读 <available_skills> 列表(由 loader 扫描 skills//SKILL.md 生成),按 description 判定是否触发;命中后本地读 SKILL.md 注入上下文。匹配发生在云端 LLM 的推理层,不在本地 embedding。

02

四层串联:一张图看完整生命周期

把四层叠在一起,一个插件从安装到真正被使用,要过四道闸门:

安装(Installation)

│  installed_plugins.json 登记 48 个

│  插件文件落盘 plugins/cache/<source>/<name>/<version>/

│

├─ 启用(Enablement)

│  │  settings.json → enabledPlugins: 仅 10 个 true

│  │  闸门条件:是否为"主动能力型"(需起 MCP / 注册连接器 / 注入 agent)

│  │

│  ├─ 被动常驻型(welcomemode / interactionmode / prompt-common)

│  │  │  不走 enabledPlugins 闸门

│  │  │  靠 .in_use/<pid> PID 锁标记"谁在用"

│  │  │  每个 agent 进程启动时自动加载

│  │  │

│  │  └─ 加载(Loading)

│  │     片段注入 system prompt(Jinja include)

│  │     工具白名单生效(interaction.md → function calling schema)

│  │

│  └─ 主动能力型(weixinpay / sheetagent / tencent-docx / ...)

│     │  enabledPlugins = true → 注册进运行时

│     │  MCP server 启动 / 连接器注入 / agent 注册

│     │

│     └─ 实例化(Instantiation)

│        部分能力 defer_loading:首次 function_call 才拉起

│        DeferExecuteTool 26 次 = 延迟实例化的运行时痕迹

│

└─ 按需加载型(28 个 skill-*)

   │  不走 enabledPlugins,不走 .in_use

   │  靠 Skill 工具 + 目录约定发现 SKILL.md

   │  云端 LLM 读 <available_skills> 列表 → 按 description 触发

   │

   └─ 实例化

      命中后读 SKILL.md 注入上下文

      后续该 skill 内的工具 / 脚本 / 命令可用

核心洞察:四层加载的本质是资源消耗的逐级延迟。

层
触发时机
资源消耗
插件数
安装
用户从市场安装
磁盘空间
48
启用
用户手动开启
冷启动时注册(MCP server / 连接器)
10
加载
agent 进程启动
内存(system prompt 片段注入)
~10 + 被动常驻
实例化
模型首次 function_call
CPU + 网络(拉起 MCP server / 读 SKILL.md)
按需

如果 48 个插件全在"启用"层——冷启动要起所有 MCP server、注册所有连接器、注入所有 agent。34 个被排除在启用闸门之外,不是它们没用,而是它们不需要在冷启动时就位。

03

两种血统标记:.workbuddy-plugin vs .codebuddy-plugin

在 plugins/cache/workbuddy-builtin/ 下走一圈,会发现两种隐藏目录:

interactionmode-craft/0.1.4/.workbuddy-plugin/plugin.json   ← 瘦 schema

welcomemode-code/0.1.7/.workbuddy-plugin/plugin.json        ← 瘦 schema

prompt-common/0.1.2/.workbuddy-plugin/plugin.json           ← 瘦 schema

skill-ardot-slides/5.5.6-.../.codebuddy-plugin/plugin.json  ← 全 schema

weixinpay/1.6.109/.codebuddy-plugin/plugin.json             ← 全 schema

sheetagent/5.5.6-.../.codebuddy-plugin/plugin.json          ← 全 schema

两种标记对应两种插件 schema:

标记
适用类型
schema
说明
.workbuddy-plugin
interactionmode / welcomemode / prompt-common
瘦
纯提示片段,只有 category/description
.codebuddy-plugin
skill-* / 复合能力包
全
完整能力声明:skills/mcpServers/commands/hooks/workbuddy.kind

.codebuddy-plugin 是 CodeBuddy 时代的产品血统戳。这些插件的描述里还写着"CodeBuddy"/"CodeBuddy Code"——WorkBuddy 是 CodeBuddy 的 rebrand。两个标记共存,是向后兼容的体现。

关键机制:plugin.json 的 skills/mcpServers 键是可选的。loader 同时做目录约定发现——扫 skills/*/SKILL.md、扫 .mcp.json。weixinpay 的 plugin.json 只有 6 行,却是功能最强的插件(3 skill + MCP server + 原生国密 CLI + 供应链签名),真能力在目录结构里,不在 manifest 声明里。

04

被动常驻 vs 按需加载:为什么 skill-* 不进 enabledPlugins?

这是本文最核心的问题。

28 个 skill-* 插件,覆盖了从设计(ardot 6 件套)到金融(wb-finance-skill)、从文档(tencent-docs-routing)到地图合规(geo-map-compliance-guard)的广泛能力。它们全部已安装,但全部不在 enabledPlugins 里。

为什么?

因为 skill 的本质是知识包,不是运行时服务。

维度
主动能力型(enabledPlugins)
知识包(skill-*)
运行时开销
MCP server 进程 / 连接器注册
0(不调用时不占资源)
加载时机
冷启动
模型首次触发
注入方式
注册进工具 schema
SKILL.md 文本注入上下文
退出方式
需显式禁用
上下文窗口滑出即失效
典型代表
weixinpay(MCP + 原生 CLI)
ardot-slides(设计知识)

如果一个 skill 在冷启动时就注入 system prompt,48 个插件的 SKILL.md 全文加起来可能吃掉数万 token 的上下文窗口——还没开始干活,窗口就满了。

WorkBuddy 的选择是:skill 不进 enabledPlugins,靠运行时 Skill 工具按需注入。模型在 <available_skills> 列表里看到 28 个 skill 的 description(一行文字),按任务需要选择触发;命中后才读完整 SKILL.md 注入上下文。

这就是为什么 38 个插件不在 enabledPlugins 里却仍然可用——它们走的是不同的加载路径,不是"未启用",而是"不需要启用"。

05

对比:其他框架怎么做?

框架
插件加载机制
分层?
WorkBuddy
四层:安装 → 启用 → 加载 → 实例化
✅ 四层独立闸门
Hermes
安装 = 启用 = 加载,skill 文件直接读
❌ 无分层
OpenCode
有插件概念,但无四层分层
❌ 无分层
Aider
无插件系统
❌
Claude Code
有 MCP 扩展,但无安装/启用分离
❌

Hermes 的 skill 系统最接近"扁平加载"——~/.hermes/skills/ 下的文件直接被读取使用。简单,但当 skill 数量膨胀到 28 个以上时,冷启动的上下文消耗会成为瓶颈。

WorkBuddy 的四层加载,本质上是在回答一个问题:当你的 Agent 拥有 48 个插件时,怎么保证冷启动不爆炸?

答案是:让大部分插件在不同阶段才"醒来"。

06

深层设计:能力生命周期管理

把四层加载抽象一下,WorkBuddy 实际上在做能力的生命周期管理——和 JVM 的分代内存管理异曲同工。

JVM
WorkBuddy
对象分配(堆)
安装(磁盘落盘)
年轻代(Eden)
启用(enabledPlugins 注册)
老年代(Tenured)
加载(.in_use PID 锁常驻)
延迟加载(Lazy Loading)
实例化(Defer 首次触发)

JVM 不会把所有对象都放进年轻代;WorkBuddy 也不会把所有插件都放进启用层。资源是有限的,按需分配才是正道。

这种设计还有一个隐含好处:插件的升级和回滚可以独立进行。installed_plugins.json 的值是版本记录数组,同一插件可以并存多版本;lastUpdated 字段支持增量更新检查。升级一个 skill 不需要重启整个框架——下次触发时自然加载新版本。

07

工程启示:造 Agent 工具时,从第一天就分层

如果你正在造一个 Agent 工具,WorkBuddy 的四层加载机制给出了一条清晰的工程启示:

不要把"安装"和"启用"混为一谈。

◆安装 = 文件落盘(磁盘成本)

◆启用 = 运行时注册(启动成本)

◆加载 = 上下文注入(上下文成本)

◆实例化 = 实际拉起(运行时成本)

四种成本性质不同,混在一起会让冷启动时间随插件数量线性增长。分开管理,才能让 Agent 在拥有丰富能力的同时保持轻量启动。

具体建议:

01被动片段(提示词、行为协议)→ 加载层,不进启用层

02知识包(skill、领域知识)→ 实例化层,不进启用层也不进加载层

03运行时服务(MCP server、连接器)→ 启用层,冷启动注册

04重能力(图像生成、LSP、部署)→ 启用层 + defer_loading,首次触发才拉起

结语

48 个已安装,10 个启用,~10 个加载,8 个 defer + 28 个 skill 按需实例化。

WorkBuddy 的插件系统不是一个简单的"开/关"模型,而是一个四级节流阀——控制着 Agent 能力从磁盘到上下文到运行时的逐级流动。

这不是过度设计。这是当一个 Agent 操作系统拥有 48 个插件时,保持冷启动不爆炸的唯一方式。

本系列从 ~/.workbuddy/ 下的真实本地文件出发。

相关学习资料