ppt skill: description 收紧路由,避免 "生成方案" 被误命中

skills/ppt/SKILL.md:3 原文含 "方案" / "生成" 字样,Claude 路由时把
"生成一个方案" 也命中到 PPT skill。改成显式白名单
(PPT/幻灯片/演示文稿/.pptx/slide/deck)+ 显式反例
("生成方案/写报告/出文档/做纪要" 不触发)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-05-27 15:10:21 +08:00
parent c4229bede4
commit 8109f20345
2 changed files with 3 additions and 2 deletions

View File

@ -2,7 +2,7 @@
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`
最后更新:2026-05-27(skill 热更新:`/v1/skills` 每次现扫,加 / 删 skill 目录无需重启 web)
最后更新:2026-05-27(ppt skill description 收紧路由,避免 "生成方案" 被误命中)
---
@ -23,6 +23,7 @@
### 2026-05-27
- **ppt skill description 收紧路由**:`skills/ppt/SKILL.md:3` 原文 "做汇报 PPT、把材料/会议纪要/方案转为幻灯片、生成演示稿" 含 "方案" / "生成" 字样,Claude 路由时把 "生成一个方案" 也命中到 PPT skill。改成显式白名单(PPT/幻灯片/演示文稿/.pptx/slide/deck)+ 显式反例("生成方案 / 写报告 / 出文档 / 做纪要" 不触发 —— 那是文档任务)。`DESIGN.md` 不动;`RUN.md` 不动(纯 skill 元数据)。
- **skill 热更新:`/v1/skills` 每次现扫**:此前 `web/app.py` lifespan 启动时 `app.state.skill_registry = SkillRegistry(...)` 扫一次,`GET /v1/skills` 从这份静态快照读 → 加新 skill 目录(放到 `skills/<name>/SKILL.md`)必须重启 web 才能在 dev SPA 新建任务弹窗下拉看见,为未来"允许用户安装自己 skill"埋了一刀。改法:删 lifespan 那行 + 注释,`/v1/skills` 路由内每次 `SkillRegistry(ROOT / cfg["skills_dir"])` 现扫。实测 SkillRegistry 构造 ~3ms / 次(9 个 skill,iterdir + 9 次 read_text + yaml frontmatter),整个 HTTP e2e ~20ms 完全淹没在 JWT + DB 噪声里,且 `/v1/skills` 只在"新建任务弹窗打开"触发,非热路径。**`core/agent_builder.py::build_agent` 早已是每次新建 SkillRegistry**(每发新消息重扫),所以 agent 内部 `load_skill` 工具与 system prompt discovery block 一直是热的;此次仅修补前端下拉这一处静态快照。Smoke 验证:`skills/_smoke_hot_reload/SKILL.md` 临时创建 → `/v1/skills` 9→10 看见、删除 → 10→9 消失,全程未重启进程。否决:(a) 加 `POST /v1/skills/reload` 显式触发 —— 多 API + 用户得记得调,3ms / 次的优化收益为 0;(b) watchdog 文件系统监听 —— 加依赖 + 容器 bind mount inotify 偶尔不稳 + 工程量过重,与方案 A 在用户体感上无差异;(c) `SkillRegistry` 加 mtime cache —— 智能化复杂度换 ms 级 IO 节省,§7.9 "不为不存在的瓶颈预付架构成本"同款判定。**未来"用户自带 skill"独立维度**(届时 `workspace/users/<uid>/.skills/` 与全局 `skills/` 多 root 叠加),跟当前热更新不耦合,等真做时再加多 root 支持。`DESIGN.md` 不动(无架构变化);`RUN.md` 不动(无 CLI / env 变化)。
- **dev SPA 「导出对话记录」/「清空对话」按钮 disable 逻辑改成只要选中 task 就常亮**:`web/static/dev.html` `renderChatMeta` 里原本按 `t.n_messages === 0` 一并禁用两键(`:1812`/`:1815`)。bug:用户「清空对话」→ `clearMessages` 返回 `n_messages=0` → 两键 disable;之后发新消息走 SSE 流(`sendMessage` `:2210`),后端 task.n_messages 累加但前端 `state.taskMeta.n_messages` 没刷,renderChatMeta 也不会再跑,两键一直灰。改法:不按 n_messages 门禁,导出常亮、清空仅在 run running/cancelling 期间禁(后端 409,confirm 后再报错 UX 差);0 条时点导出生成空 docx、点清空 confirm 显 0 条 —— 都不会出错,语义一致更省心。`deleteTask` 路径里把"无 task 选中时两键显式 disable"逻辑保留(那时 chat-meta 退到"未选中任务"占位,常亮反而误导)。否决:(a) 修真正的 n_messages 同步问题(SSE 收 done 时回拉 taskMeta) —— 一次额外 GET,且 streaming 期间频繁拉一致性更易飘;(b) 把 export 也按 running 禁 —— export 是只读快照,run 中导出当前可见的部分对话完全合理。`DESIGN.md` 不动(无架构变化);`RUN.md` 不动(无 CLI/env 变化)。
- **dev SPA embed + task_id 模式模型下拉不显示修复**:`web/static/dev.html` `enterApp()``loadModels()` 是 fire-and-forget(`:1512` 无 await),非 embed 模式下用户手动点 task 列表行时 `/v1/models` 早已 resolve,所以下拉正常;embed 模式 + URL 带 `task_id``embedHandleMessage` 收到 token → `enterApp()` 后立刻 `selectTask(EMBED_INITIAL_TASK_ID)`(`:3766-3771`),此时 `state.models` 还是 `[]`,而 `renderModelDropdown` 在 models 为空时直接 `return ""`(`:1817`)→ 顶上模型下拉缺失(同理影响生图 / 生视频下拉)。修法在 `loadModels()` 尾部加 `if (state.taskMeta) renderChatMeta();` 一行,让 models / image_models / video_models 全部 resolve 后,若当前已有 task 选中就补一次 chat-meta 重渲;`state.taskMeta` 不存在时 `renderChatMeta` 本就 no-op,无副作用。一并覆盖"loadModels 接口慢/失败再恢复"的场景。否决:(a) 在 embed 初始 task 分支单独 `loadModels().then(selectTask)` —— 要跟 `enterApp` 里 fire 出的 loadModels 共享同一个 promise,改起来啰嗦;(b) `renderModelDropdown` 内部 fallback 自己拉一次 models —— 把数据获取塞进渲染函数,违反单一职责。`DESIGN.md` 不动(无架构变化);`RUN.md` 不动(无 CLI/env 变化)。

View File

@ -1,6 +1,6 @@
---
name: ppt
description: 生成 PowerPoint 演示文稿 (.pptx)。当用户要求做汇报 PPT、把材料/会议纪要/方案转为幻灯片、生成演示稿时使用
description: 生成 PowerPoint 演示文稿 (.pptx) 文件。**仅当**用户明确点名 PPT / 幻灯片 / 演示文稿 / .pptx / slide / deck 之一时才用。⛔ 不要触发:用户只说"生成方案 / 写报告 / 出文档 / 做纪要"而没明确要 PPT 形式 —— 那是文档任务,不是 PPT 任务
---
# PPT