qwen_agent/.features/skill/MEMORY.md
朱潮 cb649d83ee Merge branch 'developing' into bot_manager
# Conflicts:
#	.features/skill/MEMORY.md
#	poetry.lock
#	requirements.txt
2026-06-08 20:07:30 +08:00

180 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Skill 功能
> 负责范围:技能包管理服务 - 核心实现
> 最后更新2026-05-26
## 当前状态
Skill 系统支持两种来源:官方 skills (`./skills/`) 和用户 skills (`projects/uploads/{bot_id}/skills/`)。支持 Hook 系统和 MCP 服务器配置,通过 SKILL.md 或 plugin.json 定义元数据。
2026-04 起 skill 包可在 `agents/*.md` 下定义子 agent`SubAgentMiddleware` 加载);启用 Daytona 沙箱时 skill 加载路径变为沙箱内的 `/workspace/skills`
MCP UI 类 skill 已按 MCP Apps 模式改造:工具返回数据,静态 HTML App 由 host 加载后通过 postMessage 接收数据渲染。
目前已新增一批**纯 `SKILL.md` 型业务 skill MVP**,用于研究、摘要、报告和情报编排,底层文件处理与外部检索能力继续复用既有 skill。
## 核心文件
- `routes/skill_manager.py` - Skill 上传/删除/列表 API
- `agent/plugin_hook_loader.py` - Hook 系统实现
- `agent/deep_assistant.py` - `CustomSkillsMiddleware`
- `agent/prompt_loader.py` - PrePrompt hooks + MCP 配置合并
- `routes/mcp_resources.py` - MCP App 静态 HTML resource REST 入口
- `skills/` - 官方 skills 目录
- `skills_developing/` - 开发中 skills
- `agent/subagent_loader.py` - 扫描 skill `agents/*.md` 加载子 agent2026-05 引入)
- `agent/mcp_trace_meta.py` - 对 `ClientSession.call_tool` 做 monkey-patch`rag_retrieve` / `table_rag_retrieve` 的 MCP `_meta` 注入 `trace_id`2026-05 引入)
## 最近重要事项
- [2026-05-26](changelog/2026-Q2.md): skill 引入 `category` 字段——`routes/skill_manager.py` 在 `SkillItem` / `SkillValidationResult` 增加 `category`,从 `plugin.json``SKILL.md` frontmatter 解析official skill 默认 `"other"`、user skill 默认 `"custom"`;并通过 batch 给 common/developing/onprem/support 路径下大量 skill 元数据补 `category``data-dashboard` / `mcp-ui` 归类 `Interactive UI``203dcf4`, `3ada55a`, `9658588`
- [2026-05-26](changelog/2026-Q2.md): developing 分支大合并新增多个 skill`ai-ppt-generator`(百度 AI PPT、`nfc-medicine-lookup`NFC 药品检索)、`ppt-outline`PPT 大纲 / HTML 演示文稿)、`z-card-image`(配图 / 卡片图),同时 `skills/linggan/*` 系列 skill 经合并回归(`3ada55a`
- [2026-05-23](changelog/2026-Q2.md): 新增 MCP App 型 `skills/developing/ecommerce-storefront/`——含 `product-list` / `order-confirm` 两个 HTML App + 自带 `ecommerce_server.py` MCP server同时落地 `docs/mcp-app-training.md`(约 1063 行)作为 MCP App 培训材料(`9d001c8`
- [2026-05-21](changelog/2026-Q2.md): Daytona 沙箱模式下 `init_agent` 在沙箱内写入 `BASH_ENV` 文件,注入 `ASSISTANT_ID` / `USER_IDENTIFIER` / `TRACE_ID` / `ENABLE_SELF_KNOWLEDGE``config.shell_env` 的 shell 环境变量(`776acc2`
- [2026-05-12](changelog/2026-Q2.md): 跨 6→10 个 skill 变体批量精修 `retrieval-policy*.md`,统一 onprem/support/autoload 各路径下的 policy 口径(`be96f24`, `7b4f03d`
- [2026-05-11](changelog/2026-Q2.md): 新增子 agent (SubAgent) 支持——skill 包通过 `agents/*.md` 暴露子 agent`SubAgentMiddleware` 加载;附 `pmda-drug-info` skill 示例(`5b634bc`
- [2026-05-11](changelog/2026-Q2.md): `pmda-drug-info``pmda_server.py` 大改为 mock 实现(`a92096a`
- [2026-05-11](changelog/2026-Q2.md): `retrieval-policy.md` 跨 4 个 skill 变体内容同步更新(`e6d1698`
- [2026-05-08](changelog/2026-Q2.md): 通过 monkey-patch `ClientSession.call_tool`,把 trace_id 透传到 `rag_retrieve` / `table_rag_retrieve` 的 MCP `_meta``1f06450`
- [2026-05-06](changelog/2026-Q2.md): support 分支新增 `kfs-answer` skill`a9227b8`
- [2026-05-06](changelog/2026-Q2.md): 修复 Daytona 沙箱增量同步漏掉符号链接的问题——`find -type f` 不覆盖 symlink、`tar.add` 默认不 dereference 导致悬空软链;并统一 dataset 路径为复数 `datasets/``3c0fa49`
- [2026-04-24](changelog/2026-Q2.md): 非流式响应路径上 `_execute_post_agent_hooks` 改为 `asyncio.create_task` 非阻塞执行;同时临时注释停用 `ToolOutputLengthMiddleware``45a9494`
- [2026-04-23](changelog/2026-Q2.md): PrePrompt hook 内容改为通过 `{hook_content}` 占位符注入系统提示词模板,不再在 prompt 末尾追加(`51fbf01`
- [2026-04-23](changelog/2026-Q2.md): Daytona 沙箱接入——`init_agent` 并行加载 + 返回元组增加 `sandbox` 字段;`skills_sources` 在沙箱模式下变为 `/workspace/skills``agent_dir_path` 变为 `/workspace``c9e0789`, `8446dab`
- [2026-04-22](changelog/2026-Q2.md): `skills/developing/` 下新增 `rag-retrieve-no-citation``novare-context` 两个开发中 skill`7a30e52`
- 2026-05-20: `mcp-ui``data-dashboard` 改为 MCP Apps 标准模式App HTML 放在 skill 的 `apps/` 目录,由 host 加载后 postMessage 数据
- 2026-04-20: 为 `rag-retrieve` 新增 `retrieval-policy-forbidden-self-knowledge.md`,禁止知识问答场景使用模型自身知识补全答案,要求严格基于检索证据作答
- 2026-04-19: 环境变量 `SKILLS_SUBDIR` 重命名为 `PROJECT_NAME`,用于选择 `skills/{PROJECT_NAME}``skills/autoload/{PROJECT_NAME}` 目录
- 2026-04-19: `create_robot_project` 的 autoload 去重和 stale 清理补强autoload 目录也纳入 managed 清理,避免 `rag-retrieve-only` 场景下旧的 `rag-retrieve` 残留
- 2026-04-18: `create_robot_project` 改为自动加载 `skills/autoload/{SKILLS_SUBDIR}` 下所有 skill并跳过已显式传入的同名 skill
- 2026-04-18: `/api/v1/skill/list` 的官方库改为同时读取 `skills/common``skills/{SKILLS_SUBDIR}`,并按目录顺序去重
- 2026-04-18: `_extract_skills_to_robot` 改为通过环境变量 `SKILLS_SUBDIR` 选择官方 skills 子目录,默认使用 `skills/common`
- 2025-02-11: 初始化 skill 功能 memory
## Gotchas开发必读
- ⚠️ MCP App resource REST 读取路径是 `projects/robot/{bot_id}/skills/{server_name}/apps/{resource_name}.html`,前端 bot_id 应由 `ChatView` 从当前 bot 传给 `ChatMessage`,不要在子组件里重新调用 `useBotManager()`
- ⚠️ `langchain-mcp-adapters` 会丢失 `EmbeddedResource` 的 uri/_metaMCP App payload 需作为 text JSON 传递给前端识别
- ⚠️ 纯 `SKILL.md` 型业务 skill 适合先承载 workflow、输入模板、输出模板需要稳定文件产出或自动化时再补 `scripts/`
- ⚠️ 新业务 skill 应复用既有基础能力 skill`baidu-search`、`xlsx`、`docx`、`pdf`、`schedule-job`、`imap-smtp-email`),避免重复定义底层工具能力
- ⚠️ 新增脚本优先采用 `Python + argparse + JSON stdout`,比 `argv[1] JSON` 更适合自动化链路
- ⚠️ `auto-daily-summary` 需要特别注意中文分句、action 边界截断、risk 窗口裁剪,否则容易把整句/整段吞进去
- ⚠️ `competitor-news-intel` 的 payload 校验应按命令拆分collect/analyze/run不要共用一套最小校验
- ⚠️ `competitor-news-intel``collect/run` 依赖 `BAIDU_API_KEY`;无该环境变量时应返回稳定错误 JSON不要静默降级
- ⚠️ `create_robot_project` 的 autoload 去重是“包含匹配”,只要传入的 skill 字符串里包含 autoload skill 名,就不会重复自动加载
- ⚠️ `_extract_skills_to_robot` 只会从 `skills/{PROJECT_NAME}` 读取官方 skills默认是 `common`
- ⚠️ 执行脚本必须使用绝对路径
- ⚠️ MCP 配置优先级Skill MCP > 默认 MCP > 用户参数
- ⚠️ 上传大小限制50MBZIP解压后最大 500MB
- ⚠️ 压缩比例检查:最大 100:1防止 zip 炸弹)
- ⚠️ 符号链接检查:禁止解压包含符号链接的文件
- ⚠️ **子 agent 同名静默 last-wins**`subagent_loader._parse_agent_md` 跨 skill 扫描 `agents/*.md` 时,按 `name` 字段去重,**后扫描到的覆盖先扫描的**,只打 warning 不报错。多 skill 都暴露子 agent 时需自觉错开命名。
- ⚠️ **`SubAgentMiddleware` 中间件顺序**:必须插在 `CustomFilesystemMiddleware` 之后、`AnthropicPromptCachingMiddleware` 之前——这是匹配 `deepagents.create_deep_agent` 的官方顺序,调整 `create_custom_cli_agent` 中的中间件顺序时不能随意挪动这一段。
- ⚠️ **Daytona 模式下 skill 路径不同**`DAYTONA_ENABLED=true` 时 `enable_skills``skills_sources``/workspace/skills`(沙箱内),同时 system prompt 的 `agent_dir_path``/workspace`;写死本地路径的 hook / 脚本需要兼容两种环境。
- ⚠️ **PostAgent hook 非流式分支已 fire-and-forget**`routes/chat.py` 用 `asyncio.create_task` 启动 hook调用方不会等待也不会感知到 hook 的异常——hook 失败只会被自己的 logger 捕获。
- ⚠️ **MCP `_meta.trace_id` 是全局 monkey-patch 注入**`agent/mcp_trace_meta.patch_mcp_client_session_trace_meta()` 在 `get_tools_from_mcp()` 入口调用一次后,会把 `mcp.ClientSession.call_tool` 永久包装;仅对工具名在 `{"rag_retrieve", "table_rag_retrieve"}` 集合内的调用注入 `_meta.trace_id`,扩展白名单要直接改 `_TRACE_META_TOOL_NAMES` 常量。
- ⚠️ **PrePrompt hook 内容位置由模板决定**:自 2026-04-23 起 hook 产出通过 `{hook_content}` 占位符注入 `prompt/system_prompt.md`,不再追加在 prompt 末尾;自定义模板必须包含 `{hook_content}` 占位符否则 hook 内容会丢失。
- ⚠️ **`init_agent` 返回值已变 3 元素**Daytona 改造后 `init_agent` 返回 `(agent, checkpointer, sandbox)`;调用方解构必须更新。
- ⚠️ **skill `category` 默认值**API 返回的 `SkillItem.category`——official skill fallback 为 `"other"`、user skill fallback 为 `"custom"`;前端做分类视图时需要同时识别这两个 sentinel不要假设官方/用户 skill 用同一套缺省值。
- ⚠️ **`category` 字段双入口**:同一 skill 可以同时在 `.claude-plugin/plugin.json``SKILL.md` frontmatter 写 `category``get_skill_metadata` 优先走 `parse_plugin_json`,若 skill 包没有 plugin.json 才回落到 `parse_skill_frontmatter`——两者写不一致时以 plugin.json 为准。
- ⚠️ **Daytona shell_env 是文件注入而非 process env**`init_agent` 通过 `cat > $REMOTE_BASH_ENV_PATH` 写入 `export VAR=...` 行,沙箱内必须由 shellbash`BASH_ENV` 加载才能生效;非 daytona 模式或不走 bash 启动的脚本拿不到这些变量。扩展注入项需直接改 `init_agent` 里的 `_shell_env` 字典。
## Skill 目录结构
```
skill-name/
├── SKILL.md # 核心指令文档(必需)
├── skill.yaml # 元数据配置(可选)
├── .claude-plugin/
│ └── plugin.json # Hook 和 MCP 配置(可选)
└── scripts/ # 可执行脚本(可选)
└── script.py
```
## Hook 系统
| Hook 类型 | 执行时机 | 用途 |
|-----------|---------|------|
| `PrePrompt` | system_prompt 加载时 | 动态注入用户上下文 |
| `PostAgent` | agent 执行后 | 处理响应结果 |
| `PreSave` | 保存消息前 | 内容过滤/修改 |
## API 接口
| 端点 | 方法 | 功能 |
|------|------|------|
| `GET /api/v1/skill/list` | - | 返回官方 + 用户 skills |
| `POST /api/v1/skill/upload` | - | ZIP 上传,解压到用户目录 |
| `DELETE /api/v1/skill/remove` | - | 删除用户 skill |
## 内置 Skills
| Skill 名称 | 功能描述 |
|-----------|---------|
| `excel-analysis` | Excel 数据分析、透视表、图表 |
| `managing-scripts` | 管理可复用脚本库 |
| `rag-retrieve` | RAG 知识库检索 |
| `jina-ai` | Jina AI Reader/Search |
| `user-context-loader` | Hook 机制示例 |
## plugin.json 格式
```json
{
"name": "skill-name",
"description": "描述",
"hooks": {
"PrePrompt": [{"type": "command", "command": "python hooks/pre_prompt.py"}],
"PostAgent": [...],
"PreSave": [...]
},
"mcpServers": {
"server-name": {
"command": "...",
"args": [...]
}
}
}
```
## Skill 加载优先级
1. Skill MCP 配置
2. 用户传入参数(覆盖已有同名配置)
## 安全措施
- ZipSlip 防护:检查解压路径
- 路径遍历防护:验证 `bot_id``skill_name` 格式
- 大小限制:上传 50MB解压后 500MB
- 压缩比限制:最大 100:1
## 设计原则
- **渐进式加载**:按需加载,避免一次性读取所有
- **绝对路径优先**:执行脚本必须使用绝对路径
- **通用化设计**:脚本应参数化,解决一类问题
- **安全优先**:完整的上传验证链
## 配置项
```bash
SKILLS_DIR=./skills # 官方 skills 目录
BACKEND_HOST=xxx # RAG API 主机
MASTERKEY=xxx # 认证密钥
```
## 索引
- 设计决策:`decisions/`
- 变更历史:`changelog/`
- 相关文档:`docs/`