WorkBuddy 专家包:AI 错题本管家开发全程复盘
我给孩子做了一个本地优先的「AI 错题本」桌面引擎(拍照转录、错题管理、练习卷生成),一直缺一个顺手的对话入口。WorkBuddy 的专家包机制正好补上这块:让大模型当管家,用自然语言驱动本地引擎------拍照录入、诊断薄弱点、讲解错题。
这篇文章复盘整个开发过程:专家包到底是什么、怎么从零到发布、以及三个让我返工三次的坑。如果你也想给 WorkBuddy 写专家包,看完这篇可以直接上手。
一、30 秒理解专家包
WorkBuddy 专家包的本质是:一个纯文本目录 + 一份注册记录,不含任何可执行代码。
bash
wrongbook-expert/
├── .codebuddy-plugin/plugin.json # 元数据:卡片展示、快捷指令、技能声明、版本号
├── agents/wrongbook-expert.md # 人设:YAML frontmatter + 正文规则(谁、能做什么、怎么做的 SOP)
├── skills/wrongbook-skill/SKILL.md # 技能:按需加载的操作规程(分步命令,模型照着执行)
├── avatars/expert.png # 头像(512×512、≤500KB)
└── README.md
它的工作原理是把 WorkBuddy 还原成一个 Agent 运行时:模型 + 一组工具(终端、文件读写、技能加载)。专家包就是注入给模型的提示词程序 ------人设定义「你是谁」,技能定义「怎么做」,模型在 agent loop 里读规则、调终端执行 curl、观察返回、走下一步。
所以专家包天生适合一种架构:提示词程序(专家包) + 本地引擎(HTTP 服务) 。对话、编排、推理交给模型(白嫖 WorkBuddy 的算力额度);存储、OCR、长耗时任务交给本地引擎(127.0.0.1:8899)。专家包是零代码的"遥控器 + 伴学大脑",引擎是干重活的。
我的错题本引擎正好已有 Web UI 和 REST 接口,于是分工非常干净:
javascript
┌─ WorkBuddy(Agent 运行时)────────────┐ ┌─ AI错题本引擎(Flask, :8899)────┐
│ 模型 + 工具 │ curl │ 本地 JSON 存储 │
│ └─ 专家包 = 注入的提示词 │ ───→ │ 拍照转录管线(用户自配 API Key) │
│ agents/*.md(人设 + 三个 SOP) │ │ Web UI(录入 / 人审视图 / 工作台)│
│ skills/*.md(启动 / 看护 / 停止) │ └──────────────────────────────────┘
└────────────────────────────────────────┘
二、标准开发流程:一条命令起步
WorkBuddy 内置了脚手架脚本,从零到注册可见只要五步:
bash
# 官方脚本目录
SCRIPTS="/Applications/WorkBuddy.app/Contents/Resources/app.asar.unpacked/resources/plugins/workbuddy-builtin/skills/expert-manager/scripts"
# 专家包唯一合法位置
EXPERTS="${WORKBUDDY_CONFIG_DIR:-$HOME/.workbuddy}/plugins/marketplaces/my-experts/plugins"
# 1. 生成骨架(Agent 型:plugin.json + agents/*.md + avatars + README,全带 [TODO])
python3 "$SCRIPTS/init_expert.py" wrongbook-expert --type agent --path "$EXPERTS"
# 2. 填内容(编辑 plugin.json / agents/*.md / skills/)
# 3. 校验(0 error 才能继续)
python3 "$SCRIPTS/validate_expert.py" "$EXPERTS/wrongbook-expert"
# 4. 注册(写入 marketplace.json,专家才会在「我的专家」里出现)
python3 "$SCRIPTS/register_expert.py" "$EXPERTS/wrongbook-expert"
# 5. 重启 WorkBuddy → 新建对话测试
几个硬性校验规则,初学者最容易栽在这里:
categoryId只认 12 个枚举值(内置样例用的15-Education是非法值 ,别照抄;教育类我用09-OperationsHR)displayDescription.zh限 40--50 字;tags和quickPrompts恰好 3 个 ;defaultInitPrompt必须与第一条快捷指令完全一致- 命名五处一致:目录名 =
name=agentName=plugin= agents 下的 MD 文件名,创建后严禁修改 - frontmatter 里禁止写
tools字段(工具由系统统一分配)
三、四个核心能力的实现
1. 启动服务:探测 → 记忆路径 → 看护
技能 wrongbook-skill 的 SOP:
curl /api/license探测 8899 是否已在运行(响应含app_version即本程序;被占用但不是本程序 → 报错终止,防灾)- 读取
~/.workbuddy/wrongbook-app-path里记忆的安装路径 - 没有路径 → 引导用户把 App 图标拖进聊天框
- 后台任务拉起引擎 + 看护循环(下文细讲)
- 返回
http://127.0.0.1:8899工作台链接
2. 跨端照片录入:状态机 + 轮询
手机 WorkBuddy 发照片(一次最多 9 张),专家投递给引擎,电脑 Web 端完成定稿:
css
手机拍照 → POST /api/intake ──→ [arrived 仅存照片,秒回,不调 LLM]
│ Web 页每 3s 轮询发现新单
▼
照片自动显示到上传区 + 全屏遮罩逐张转录(i/N 进度)
│ POST /api/sheets/<sid>/transcribe
▼
[pending 已转录待提交] → 人审视图勾选/标错因 →「提交」
▼
[processed 已入库]
两个设计点值得说:
- 投递接口只存照片不转录。转录一张要 20--60 秒,放在投递阶段多张必超时;挪到 Web 端做,还能复用页面上的年级上下文和进度遮罩。
- 人审是刻意保留的把关环节。模型 OCR 经常把图形抓错、漏题、识别倒置------引擎只做初稿,「人审视图」里人工核对、手动框选图形、标注错因后才真正入库。
3. 学情诊断:禁止瞎编
诊断 SOP 的第一条是「不要瞎编,必须先 curl /api/questions 拉真实数据」,然后基于 question/kps/reason 字段做推理------先统计、再指漏洞、最后给复习建议。这比让模型自由发挥靠谱得多。
四、踩坑实录(这部分最值钱)
以下五个坑,官方指南都没写,全部是我用返工换来的。
坑 1:版本号缓存------改了技能不生效的最大元凶
现象:改了 SKILL.md,重新校验、重新注册、重启 WorkBuddy,模型还是按旧流程执行。
真相:运行时读的不是你的源目录,而是按版本号拷贝的快照:
javascript
~/.workbuddy/plugins/cache/<市场>/<专家名>/<版本号>/
register_expert.py 只更新 marketplace.json 元数据,不刷新这份拷贝 。版本号不变,重启一百次也是旧内容。我在缓存目录里甚至找到了前一天误提交又被我删掉的 #SKILL.md# 垃圾文件------快照有多老可想而知。
正确姿势 :每次实质性修改,把 plugin.json 的 version 升一位(1.0.0 → 1.1.0 → ...),再校验注册重启;顽固时手动删除缓存里对应的旧版本目录。
坑 2:旧对话冻结旧技能
修完技能后,在一个早就存在的对话里测试,模型依然按旧流程走。因为技能内容在对话创建时被快照进上下文------旧对话永远带着旧版。
正确姿势 :每次改完技能,重启 WorkBuddy + 新建对话测试。旧对话测出来的"没生效"不作数。
坑 3:技能命名必须全库唯一
我最初给技能起名 workbench,结果机器上另一个专家包(降噪陪学)也有一个 workbench。会话里按名加载技能时互相污染,模型加载到的内容随缓存状态漂移。技能名改成 wrongbook-skill 这种带前缀的唯一名后,问题根除。
坑 4:沙箱------后台任务里跑不了"重"程序
我想让「打开错题本」在 WorkBuddy 里显示后台任务条(像其他专家那样可随时停止),于是把引擎二进制直接放进后台任务运行。结果:引擎启动即退出。
原因:后台任务的进程继承 WorkBuddy 沙箱 ,而沙箱禁止对个人目录(~/Library)的 rename/删除操作------引擎启动时的授权校验恰好要原子替换授权文件(临时文件 + rename 覆盖),被拦 → 异常没人接 → 进程退出。
最终方案是看护模式:
bash
# 后台任务只跑这个循环(带 run_in_background: true):
APP="<引擎路径>"; echo $$ > ~/.workbuddy/wrongbook-watch.pid; open "$APP"; \
while curl -s -m 2 http://127.0.0.1:8899/api/license >/dev/null 2>&1; do sleep 3; done; \
rm -f ~/.workbuddy/wrongbook-watch.pid; echo "引擎已退出"
- 引擎本体用
open拉起 → 走 launchd,在沙箱外运行,权限完整; - 后台任务只做看护循环:引擎活着任务就活着(任务条持续可见),引擎退出任务自然结束;
- 顺手把引擎的 JSON 落盘加了降级:
os.replace被拒时回退就地覆写,授权校验失败不再阻断启动。
坑 5:小模型对"示例"的遵循度远高于"描述"
"必须带 run_in_background: true 参数"这句话写三遍,模型还是会忘。把 SKILL.md 改成给一个可以照抄的工具调用 JSON 示例 ,遵循率立刻上来了。写技能时记住:你是在给一个不太听话的实习生写操作手册,能给它模板就不要给它道理。
杂项坑
- 头像从产品 logo 直接拿来用会超规格(我的是 1024×765、536KB),
sips居中裁剪 + 缩放到 512×512 才合规; - 引擎的崩溃要自己兜住:启动校验、心跳、激活全链路 try/except,沙箱/只读环境下按本地凭证继续运行,而不是进程退出。
五、一个亮点设计:看护联动(删任务 = 关服务)
看护模式有个天然的别扭点:后台任务只是个监测循环,用户点任务条的 🗑 删除按钮,只能杀掉看护循环,杀不到沙箱外的引擎------"删了任务服务还在",违反直觉。
解法是令牌联动:
- 看护任务启动引擎前,把自己的 PID 写入令牌文件
~/.workbuddy/wrongbook-watch.pid; - 引擎(v1.4.2+)启动时读取令牌并武装看护检查:每 5 秒探测看护进程是否存活;
- 看护消失连续两次(用户点了 🗑,或 WorkBuddy 会话结束)→ 引擎自动优雅退出、释放端口。
效果:删任务 = 关服务,10 秒内生效。同时有三重防护保证不误杀:
- 令牌 120 秒时效:过期令牌(WorkBuddy 崩溃残留)自动清除并解除联动;
- 普通双击启动(无令牌)永不自动退出,引擎独立生命周期不受影响;
- 引擎正常退出时看护循环自然结束、清理令牌,任务条随之消失。
六、发布:两条交付线
最终交付物是两个文件,用户侧各装一次:
- 引擎 App :
AI错题本-v1.4.2-mac.zip,解压拖进 Applications(PyInstaller 打包,build_mac.sh一键完成回归门禁 → 构建 → 资源复制 → 白名单校验 → 压缩); - 专家包 ZIP :
wrongbook-expert.zip(241KB,5 个纯文本文件 + 头像),解压到专家目录、跑一次注册脚本即可。
之后改引擎发新版不影响专家包;改专家包(提示词迭代)也不需要重新分发引擎------发布分离,双端独立升级。
七、迭代工作流(直接抄)
bash
source packaging/workbuddy-demo/expert-env.sh # SCRIPTS / EXPERTS / NAME / EXPERT 四个变量
# 1. 改源目录内容(SKILL.md / agent MD / plugin.json)
# 2. ⚠️ bump version:plugin.json 版本号升一位(否则改了白改!)
python3 "$SCRIPTS/validate_expert.py" "$EXPERT"
python3 "$SCRIPTS/register_expert.py" "$EXPERT"
python3 "$SCRIPTS/package_expert.py" "$EXPERT" packaging/workbuddy-expert # 分发 ZIP
# 3. 重启 WorkBuddy + 新建对话测试
结语
做完这个专家包,我对"Agent 时代的软件形态"有了更具体的体感:
- 专家包是提示词程序------它没有传统意义上的代码,但它有状态机(草稿单三态)、有 I/O 契约(curl 接口)、有容错分支(防灾探测、路径回退)。写它更像写一份给聪明但字面理解的实习生的操作手册;
- 模型能力的边界要用工程补:OCR 会错,就加人审视图;模型会忘参数,就给可照抄的示例;进程会被沙箱杀,就用看护循环 + 令牌联动把生命周期还给用户;
- 本地引擎 + 平台模型是绝配:数据留在本机、长任务不占对话额度、对话体验由大模型兜底。
如果你也在做一个有本地服务的工具,不妨试试给它配一个 WorkBuddy 专家包------五步起步,最大的坑我都替你踩完了。
环境:WorkBuddy 专家包规范 v2.0(Agent 型)、macOS;文中命令与行为均在 2026-11 实测。