Compare commits

...

4 Commits

Author SHA1 Message Date
朱潮
3280c46460 SKILLS_SUBDIR改成PROJECT_NAME 2026-04-19 09:48:15 +08:00
朱潮
7c72a52bb7 SKILLS_SUBDIR改成PROJECT_NAME 2026-04-19 09:47:49 +08:00
朱潮
0addc55fa2 SKILLS_SUBDIR改成PROJECT_NAME 2026-04-19 09:45:09 +08:00
朱潮
0f7d0e0bac 修改skill目录 2026-04-19 09:24:02 +08:00
41 changed files with 14 additions and 12 deletions

View File

@ -39,7 +39,8 @@ Skill 系统支持两种来源:官方 skills (`./skills/`) 和用户 skills (`
- ⚠️ `competitor-news-intel` 的 payload 校验应按命令拆分collect/analyze/run不要共用一套最小校验 - ⚠️ `competitor-news-intel` 的 payload 校验应按命令拆分collect/analyze/run不要共用一套最小校验
- ⚠️ `competitor-news-intel``collect/run` 依赖 `BAIDU_API_KEY`;无该环境变量时应返回稳定错误 JSON不要静默降级 - ⚠️ `competitor-news-intel``collect/run` 依赖 `BAIDU_API_KEY`;无该环境变量时应返回稳定错误 JSON不要静默降级
- ⚠️ `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 > 用户参数

View File

@ -29,6 +29,7 @@ services:
- "8001:8001" - "8001:8001"
environment: environment:
# 应用配置 # 应用配置
- PROJECT_NAME=linggan
- BACKEND_HOST=http://api-dev.gbase.ai - BACKEND_HOST=http://api-dev.gbase.ai
- MAX_CONTEXT_TOKENS=262144 - MAX_CONTEXT_TOKENS=262144
- DEFAULT_THINKING_ENABLE=true - DEFAULT_THINKING_ENABLE=true

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')
@ -437,7 +437,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:
@ -510,7 +510,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

Before

Width:  |  Height:  |  Size: 758 B

After

Width:  |  Height:  |  Size: 758 B

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -332,15 +332,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:
@ -401,10 +401,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
@ -413,8 +413,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")