SKILLS_SUBDIR改成PROJECT_NAME

This commit is contained in:
朱潮 2026-04-19 09:45:09 +08:00
parent fd7d838e09
commit 0addc55fa2
4 changed files with 15 additions and 15 deletions

View File

@ -18,16 +18,16 @@ Skill 系统支持两种来源:官方 skills (`./skills/`) 和用户 skills (`
## 最近重要事项 ## 最近重要事项
- 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-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/{PROJECT_NAME}`,并按目录顺序去重
- 2026-04-18: `/api/v1/skill/list` 的官方库改为同时读取 `skills/common``skills/{SKILLS_SUBDIR}`,并按目录顺序去重 - 2026-04-18: `_extract_skills_to_robot` 改为通过环境变量 `PROJECT_NAME` 选择官方 skills 子目录,默认使用 `skills/common`
- 2026-04-18: `_extract_skills_to_robot` 改为通过环境变量 `SKILLS_SUBDIR` 选择官方 skills 子目录,默认使用 `skills/common`
- 2025-02-11: 初始化 skill 功能 memory - 2025-02-11: 初始化 skill 功能 memory
## Gotchas开发必读 ## Gotchas开发必读
- ⚠️ `create_robot_project` 的 autoload 去重是“包含匹配”,只要传入的 skill 字符串里包含 autoload skill 名,就不会重复自动加载 - ⚠️ `create_robot_project` 的 autoload 去重是“包含匹配”,只要传入的 skill 字符串里包含 autoload skill 名,就不会重复自动加载
- ⚠️ `_extract_skills_to_robot` 只会从 `skills/{SKILLS_SUBDIR}` 读取官方 skills默认是 `common` - ⚠️ `_extract_skills_to_robot` 只会从 `skills/{PROJECT_NAME}` 读取官方 skills默认是 `common`
- ⚠️ 执行脚本必须使用绝对路径 - ⚠️ 执行脚本必须使用绝对路径
- ⚠️ MCP 配置优先级Skill MCP > 默认 MCP > 用户参数 - ⚠️ MCP 配置优先级Skill MCP > 默认 MCP > 用户参数
- ⚠️ 上传大小限制50MBZIP解压后最大 500MB - ⚠️ 上传大小限制50MBZIP解压后最大 500MB

View File

@ -10,7 +10,7 @@ from typing import List, Optional
from dataclasses import dataclass from dataclasses import dataclass
from fastapi import APIRouter, HTTPException, Query, UploadFile, File, Form from fastapi import APIRouter, HTTPException, Query, UploadFile, File, Form
from pydantic import BaseModel from pydantic import BaseModel
from utils.settings import SKILLS_DIR, SKILLS_SUBDIR from utils.settings import SKILLS_DIR, PROJECT_NAME
import aiofiles import aiofiles
logger = logging.getLogger('app') logger = logging.getLogger('app')
@ -438,7 +438,7 @@ def get_official_skills(base_dir: str) -> List[SkillItem]:
official_skills_dirs = [ official_skills_dirs = [
os.path.join(skills_root_dir, "common"), os.path.join(skills_root_dir, "common"),
os.path.join(skills_root_dir, SKILLS_SUBDIR), os.path.join(skills_root_dir, PROJECT_NAME),
] ]
for official_skills_dir in official_skills_dirs: for official_skills_dir in official_skills_dirs:
@ -511,7 +511,7 @@ async def list_skills(
SkillListResponse containing all skills SkillListResponse containing all skills
Notes: Notes:
- Official skills are read from /skills/common and /skills/{SKILLS_SUBDIR} - Official skills are read from /skills/common and /skills/{PROJECT_NAME}
- User skills are read from /projects/uploads/{bot_id}/skills directory - User skills are read from /projects/uploads/{bot_id}/skills directory
- User skills are marked with user_skill: true - User skills are marked with user_skill: true
""" """

View File

@ -331,15 +331,15 @@ def create_robot_project(dataset_ids: List[str], bot_id: str, force_rebuild: boo
skills = list(skills or []) skills = list(skills or [])
if os.path.isabs(settings.SKILLS_DIR): if os.path.isabs(settings.SKILLS_DIR):
autoload_skills_dir = Path(settings.SKILLS_DIR) / "autoload" / settings.SKILLS_SUBDIR autoload_skills_dir = Path(settings.SKILLS_DIR) / "autoload" / settings.PROJECT_NAME
else: else:
autoload_skills_dir = project_path.parent / settings.SKILLS_DIR / "autoload" / settings.SKILLS_SUBDIR autoload_skills_dir = project_path.parent / settings.SKILLS_DIR / "autoload" / settings.PROJECT_NAME
if autoload_skills_dir.exists(): if autoload_skills_dir.exists():
for item in sorted(autoload_skills_dir.iterdir()): for item in sorted(autoload_skills_dir.iterdir()):
if not item.is_dir() or any(_skill_matches_autoload(skill, item.name) for skill in skills): if not item.is_dir() or any(_skill_matches_autoload(skill, item.name) for skill in skills):
continue continue
skill_path = f"@skills/autoload/{settings.SKILLS_SUBDIR}/{item.name}" skill_path = f"@skills/autoload/{settings.PROJECT_NAME}/{item.name}"
skills.append(skill_path) skills.append(skill_path)
logger.info(f"Auto loaded skill '{skill_path}' from {autoload_skills_dir}") logger.info(f"Auto loaded skill '{skill_path}' from {autoload_skills_dir}")
else: else:
@ -399,10 +399,10 @@ def _extract_skills_to_robot(bot_id: str, skills: List[str], project_path: Path)
- 如果是完整路径 "projects/uploads/xxx/skills/rag-retrieve_2.zip"直接使用该路径 - 如果是完整路径 "projects/uploads/xxx/skills/rag-retrieve_2.zip"直接使用该路径
- 如果是简单名称 "rag-retrieve"从以下目录按优先级顺序查找 - 如果是简单名称 "rag-retrieve"从以下目录按优先级顺序查找
1. projects/uploads/{bot_id}/skills/ 1. projects/uploads/{bot_id}/skills/
2. skills/{SKILLS_SUBDIR}/ 2. skills/{PROJECT_NAME}/
- 如果是以 @ 开头的仓库相对路径 "@skills/autoload/support/rag-retrieve"则从仓库根目录直接解析 - 如果是以 @ 开头的仓库相对路径 "@skills/autoload/support/rag-retrieve"则从仓库根目录直接解析
搜索目录优先级先搜索 projects/uploads/{bot_id}/skills/再搜索 skills/common最后搜索 skills/{SKILLS_SUBDIR} 搜索目录优先级先搜索 projects/uploads/{bot_id}/skills/再搜索 skills/common最后搜索 skills/{PROJECT_NAME}
Args: Args:
bot_id: 机器人 ID bot_id: 机器人 ID
@ -411,8 +411,8 @@ def _extract_skills_to_robot(bot_id: str, skills: List[str], project_path: Path)
""" """
# skills 源目录(按优先级顺序) # skills 源目录(按优先级顺序)
repo_root = Path(__file__).resolve().parent.parent repo_root = Path(__file__).resolve().parent.parent
official_skills_dir = repo_root / "skills" / settings.SKILLS_SUBDIR official_skills_dir = repo_root / "skills" / settings.PROJECT_NAME
autoload_skills_dir = repo_root / "skills" / "autoload" / settings.SKILLS_SUBDIR autoload_skills_dir = repo_root / "skills" / "autoload" / settings.PROJECT_NAME
if not official_skills_dir.exists(): if not official_skills_dir.exists():
logger.warning(f"Official skills directory does not exist: {official_skills_dir}") logger.warning(f"Official skills directory does not exist: {official_skills_dir}")
skills_source_dirs = [ skills_source_dirs = [

View File

@ -24,7 +24,7 @@ TOOL_CACHE_AUTO_RENEW = os.getenv("TOOL_CACHE_AUTO_RENEW", "true") == "true"
# Project Settings # Project Settings
PROJECT_DATA_DIR = os.getenv("PROJECT_DATA_DIR", "./projects/data") PROJECT_DATA_DIR = os.getenv("PROJECT_DATA_DIR", "./projects/data")
SKILLS_DIR = os.getenv("SKILLS_DIR", "./skills") SKILLS_DIR = os.getenv("SKILLS_DIR", "./skills")
SKILLS_SUBDIR = os.getenv("SKILLS_SUBDIR", "support") PROJECT_NAME = os.getenv("PROJECT_NAME", "support")
# Tokenizer Settings # Tokenizer Settings
TOKENIZERS_PARALLELISM = os.getenv("TOKENIZERS_PARALLELISM", "true") TOKENIZERS_PARALLELISM = os.getenv("TOKENIZERS_PARALLELISM", "true")