8.6 KiB
8.6 KiB
Skill 功能
负责范围:技能包管理服务 - 核心实现 最后更新:2026-05-23
当前状态
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。
核心文件
routes/skill_manager.py- Skill 上传/删除/列表 APIagent/plugin_hook_loader.py- Hook 系统实现agent/deep_assistant.py-CustomSkillsMiddlewareagent/prompt_loader.py- PrePrompt hooks + MCP 配置合并skills/- 官方 skills 目录skills_developing/- 开发中 skillsagent/subagent_loader.py- 扫描 skillagents/*.md加载子 agent(2026-05 引入)agent/mcp_trace_meta.py- 对ClientSession.call_tool做 monkey-patch,向rag_retrieve/table_rag_retrieve的 MCP_meta注入trace_id(2026-05 引入)
最近重要事项
- 2026-05-12: 跨 6→10 个 skill 变体批量精修
retrieval-policy*.md,统一 onprem/support/autoload 各路径下的 policy 口径(be96f24,7b4f03d) - 2026-05-11: 新增子 agent (SubAgent) 支持——skill 包通过
agents/*.md暴露子 agent,由SubAgentMiddleware加载;附pmda-drug-infoskill 示例(5b634bc) - 2026-05-11:
pmda-drug-info的pmda_server.py大改为 mock 实现(a92096a) - 2026-05-11:
retrieval-policy.md跨 4 个 skill 变体内容同步更新(e6d1698) - 2026-05-08: 通过 monkey-patch
ClientSession.call_tool,把 trace_id 透传到rag_retrieve/table_rag_retrieve的 MCP_meta(1f06450) - 2026-05-06: support 分支新增
kfs-answerskill(a9227b8) - 2026-05-06: 修复 Daytona 沙箱增量同步漏掉符号链接的问题——
find -type f不覆盖 symlink、tar.add默认不 dereference 导致悬空软链;并统一 dataset 路径为复数datasets/(3c0fa49) - 2026-04-24: 非流式响应路径上
_execute_post_agent_hooks改为asyncio.create_task非阻塞执行;同时临时注释停用ToolOutputLengthMiddleware(45a9494) - 2026-04-23: PrePrompt hook 内容改为通过
{hook_content}占位符注入系统提示词模板,不再在 prompt 末尾追加(51fbf01) - 2026-04-23: Daytona 沙箱接入——
init_agent并行加载 + 返回元组增加sandbox字段;skills_sources在沙箱模式下变为/workspace/skills,agent_dir_path变为/workspace(c9e0789,8446dab) - 2026-04-22:
skills/developing/下新增rag-retrieve-no-citation与novare-context两个开发中 skill(7a30e52) - 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:
/api/v1/skill/list的官方库改为同时读取skills/common和skills/{PROJECT_NAME},并按目录顺序去重 - 2026-04-18:
_extract_skills_to_robot改为通过环境变量PROJECT_NAME选择官方 skills 子目录,默认使用skills/common - 2025-02-11: 初始化 skill 功能 memory
Gotchas(开发必读)
- ⚠️
create_robot_project的 autoload 去重是“包含匹配”,只要传入的 skill 字符串里包含 autoload skill 名,就不会重复自动加载 - ⚠️
_extract_skills_to_robot只会从skills/{PROJECT_NAME}读取官方 skills,默认是common - ⚠️ 执行脚本必须使用绝对路径
- ⚠️ MCP 配置优先级:Skill MCP > 默认 MCP > 用户参数
- ⚠️ 上传大小限制:50MB(ZIP),解压后最大 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 目录结构
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 格式
{
"name": "skill-name",
"description": "描述",
"hooks": {
"PrePrompt": [{"type": "command", "command": "python hooks/pre_prompt.py"}],
"PostAgent": [...],
"PreSave": [...]
},
"mcpServers": {
"server-name": {
"command": "...",
"args": [...]
}
}
}
Skill 加载优先级
- Skill MCP 配置
- 用户传入参数(覆盖已有同名配置)
安全措施
- ZipSlip 防护:检查解压路径
- 路径遍历防护:验证
bot_id和skill_name格式 - 大小限制:上传 50MB,解压后 500MB
- 压缩比限制:最大 100:1
设计原则
- 渐进式加载:按需加载,避免一次性读取所有
- 绝对路径优先:执行脚本必须使用绝对路径
- 通用化设计:脚本应参数化,解决一类问题
- 安全优先:完整的上传验证链
配置项
SKILLS_DIR=./skills # 官方 skills 目录
BACKEND_HOST=xxx # RAG API 主机
MASTERKEY=xxx # 认证密钥
索引
- 设计决策:
decisions/ - 变更历史:
changelog/ - 相关文档:
docs/