· · ·
目前版本是1.4,2.0正式开源。记得收藏哦
📋 目录
1. 概述
2. 核心概念
3. 架构设计
4. 核心组件详解
5. 工作流程
6. 使用案例
7. 最佳实践
8. 常见问题
概述
什么是 Skills Middleware?
我们在代码 skills.py 实现了 Anthropic 的 Agent Skills 模式,这是一个用于加载和管理 AI Agent 技能的中间件系统。它采用 渐进式披露(Progressive Disclosure)设计模式,让 AI Agent 能够:
● 📚 从多个来源加载技能
● 🔍 按需查看技能详情
● 🎯 智能匹配任务与技能
● 🔄 动态更新技能库
核心特性
核心概念
1. Skill(技能)
技能是一个包含特定领域知识和工作流程的目录结构:
/skills/user/web-research/
├── SKILL.md # 必需:技能定义文件
└── helper.py # 可选:辅助脚本
SKILL.md 文件格式
---name: web-researchdescription: Structured approach to conducting thorough web researchlicense: MITcompatibility: Requires web-search toolmetadata:author: John Doeversion: 1.0.0allowed-tools: web-search web-fetch---# Web Research Skill## When to Use- User asks you to research a topic- Need to gather information from multiple sources## Workflow1. Identify key search terms2. Use web-search tool to find sources3. Analyze and synthesize information4. Present findings in structured format## Examples...
2. Source(来源)
来源是技能目录的路径,用于组织和分层管理技能:
sources =[
"/skills/base/",# 基础技能(优先级最低)
"/skills/user/",# 用户技能
"/skills/project/",# 项目技能
"/skills/team/",# 团队技能(优先级最高)
]
优先级规则:后加载的来源会覆盖先加载的同名技能(Last One Wins)
3. Backend(后端)
后端是存储技能文件的抽象层,支持多种实现:
4. Progressive Disclosure(渐进式披露)
这是一种 UX 设计模式,应用在 AI Agent 上:
传统方式:一次性加载所有技能的完整内容 → Token 浪费
渐进式披露:
1. 首先展示技能列表(名称 + 描述)
2. Agent 判断是否需要某个技能
3. 按需读取完整的 SKILL.md 文件
示例对比:
❌ 传统方式(浪费 ~5000 tokens)
System Prompt:
- web-research 技能完整内容(2000 tokens)
- data-analysis 技能完整内容(1500 tokens)
- code-review 技能完整内容(1500 tokens)
✅ 渐进式披露(仅 ~200 tokens)
System Prompt:
- web-research: Structured approach to web research
-> Read /skills/user/web-research/SKILL.md for details
- data-analysis: Analyze datasets and generate insights
-> Read /skills/user/data-analysis/SKILL.md for details
架构设计
数据流
1. Agent 启动
↓
2. before_agent() 被调用
↓
3. 遍历所有 sources
↓
4. Backend.ls_info() 列出技能目录
↓
5. Backend.download_files() 批量下载 SKILL.md
↓
6. _parse_skill_metadata() 解析 YAML frontmatter
↓
7. 存入 state.skills_metadata
↓
8. wrap_model_call() 注入到 system prompt
↓
9. Agent 看到技能列表,按需读取详情
核心组件详解
1. SkillMetadata(技能元数据)
class SkillMetadata(TypedDict):name: str # 技能标识符description: str # 技能描述path: str # SKILL.md 文件路径license: str | None # 许可证compatibility: str | None # 兼容性要求metadata: dict[str, str] # 自定义元数据allowed_tools: list[str] # 预批准的工具列表
字段详解
名称验证规则
# ✅ 有效名称"web-research""data-analysis-v2""code-review"# ❌ 无效名称"Web-Research" # 不能有大写"web_research" # 不能用下划线"web--research" # 不能有连续连字符"-web-research" # 不能以连字符开头"web-research-" # 不能以连字符结尾
2. SkillsMiddleware(技能中间件)
这是核心类,实现了 AgentMiddleware 接口。
初始化参数
def __init__(self,*,backend: BACKEND_TYPES, # 后端实例或工厂函数sources: list[str] # 技能来源路径列表) -> None:
backend 参数详解:
# 方式 1: 直接传入后端实例(用于 FilesystemBackend)from just_ask.backends.filesystem import FilesystemBackendbackend = FilesystemBackend(root_dir="/path/to/skills")middleware = SkillsMiddleware(backend=backend, sources=[...])# 方式 2: 使用工厂函数(用于 StateBackend)from just_ask.backends.state import StateBackendmiddleware = SkillsMiddleware(backend=lambda rt: StateBackend(rt), # rt 是 ToolRuntimesources=[...])
为什么 StateBackend 需要工厂函数?
● StateBackend 需要访问运行时上下文(Runtime)
● 工厂函数延迟实例化,在运行时才创建 Backend
核心方法
before_agent() - 加载技能元数据
def before_agent(self,state: SkillsState,runtime: Runtime,config: RunnableConfig) -> SkillsStateUpdate | None:
执行时机:每次 Agent 交互前
作用:
1. 检查 state.skills_metadata 是否已存在
2. 如果不存在,从所有 sources 加载技能
3. 返回 SkillsStateUpdate 更新状态
优化点:
● 如果 skills_metadata 已存在,直接返回 None(避免重复加载)
● 使用字典去重,后加载的技能覆盖先加载的同名技能
wrap_model_call() - 注入技能到提示词
def wrap_model_call(self,request: ModelRequest,handler: Callable[[ModelRequest], ModelResponse]) -> ModelResponse:
执行时机:每次调用模型前
作用:
1. 从 request.state 获取 skills_metadata
2. 格式化技能列表
3. 注入到 system_prompt
4. 调用原始 handler
注入格式示例:
## Skills System
You have access to a skills library...
**User Skills**: `/skills/user/` (higher priority)
**Available Skills:**
- **web-research**: Structured approach to conducting thorough web research
-> Read `/skills/user/web-research/SKILL.md` for full instructions
- **data-analysis**: Analyze datasets and generate insights
-> Read `/skills/user/data-analysis/SKILL.md` for full instructions
3. 辅助函数
_validate_skill_name() - 验证技能名称
def _validate_skill_name(name: str, directory_name: str) -> tuple[bool, str]:
验证规则:
1. 不能为空
2. 最大 64 字符
3. 只能包含小写字母、数字和单个连字符
4. 不能以连字符开头或结尾
5. 必须与目录名匹配
返回值:(is_valid, error_message)
_parse_skill_metadata() - 解析技能元数据
def _parse_skill_metadata(content: str,skill_path: str,directory_name: str) -> SkillMetadata | None:
解析流程:
1. 检查文件大小(最大 10MB,防止 DoS 攻击)
2. 使用正则提取 YAML frontmatter(--- 分隔符之间)
3. 使用 yaml.safe_load() 解析 YAML
4. 验证必需字段(name, description)
5. 验证名称格式(警告但不阻止加载)
6. 截断过长的描述(最大 1024 字符)
7. 解析 allowed-tools(空格分隔)
8. 返回 SkillMetadata 对象
错误处理:
● 文件过大 → 跳过并记录警告
● 无 frontmatter → 跳过
● YAML 解析失败 → 跳过
● 缺少必需字段 → 跳过
● 名称不符合规范 → 警告但继续加载(向后兼容)
_list_skills() - 列出技能(同步)
def _list_skills(backend: BackendProtocol, source_path: str) -> list[SkillMetadata]:
执行流程:
1. 调用 backend.ls_info(source_path) 列出所有子目录
2. 过滤出目录(is_dir=True)
3. 为每个目录构造 SKILL.md 路径
4. 批量下载所有 SKILL.md 文件(backend.download_files())
5. 解析每个文件的元数据
6. 返回成功解析的技能列表
性能优化:
● 使用批量下载而非逐个下载
● 跳过下载失败的文件(可能不是技能目录)
_alist_skills() - 列出技能(异步)
与 _list_skills() 相同,但使用异步 API:
● backend.als_info()
● backend.adownload_files()
工作流程
完整执行流程
文本流程图:
┌─────────────────────────────────────────────────────────┐
│ 1. Agent 初始化 │
│ agent = create_agent( │
│ model=model, │
│ middleware=[skills_middleware] │
│ ) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 2. 用户发起请求 │
│ agent.invoke({"messages": [...]}, config) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 3. before_agent() 钩子触发 │
│ - 检查 state.skills_metadata 是否存在 │
│ - 如果不存在,加载技能: │
│ ├── 遍历 sources: ["/skills/base/", ...] │
│ ├── 调用 _list_skills(backend, source) │
│ │ ├── backend.ls_info() 列出目录 │
│ │ ├── backend.download_files() 批量下载 │
│ │ └── _parse_skill_metadata() 解析 │
│ └── 合并所有技能(后加载覆盖先加载) │
│ - 返回 SkillsStateUpdate │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 4. 状态更新 │
│ state.skills_metadata = [ │
│ {"name": "web-research", ...}, │
│ {"name": "data-analysis", ...} │
│ ] │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 5. wrap_model_call() 钩子触发 │
│ - 从 request.state 获取 skills_metadata │
│ - 格式化技能列表: │
│ "- **web-research**: Description │
│ -> Read /path/to/SKILL.md for details" │
│ - 注入到 system_prompt │
│ - 调用原始 handler(modified_request) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 6. 模型看到技能列表 │
│ System Prompt: │
│ """ │
│ ## Skills System │
│ Available Skills: │
│ - web-research: ... │
│ -> Read /skills/user/web-research/SKILL.md │
│ """ │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 7. Agent 判断是否需要技能 │
│ 用户: "帮我研究量子计算的最新进展" │
│ Agent 思考: 这需要 web-research 技能 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 8. Agent 读取技能详情 │
│ 使用 view 工具读取: │
│ /skills/user/web-research/SKILL.md │
│ │
│ 获得完整的工作流程和最佳实践 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 9. Agent 执行技能 │
│ 按照 SKILL.md 中的步骤: │
│ 1. 识别关键搜索词 │
│ 2. 使用 web-search 工具 │
│ 3. 分析和综合信息 │
│ 4. 以结构化格式呈现 │
└─────────────────────────────────────────────────────────┘
技能覆盖机制
当多个 sources 包含同名技能时,后加载的覆盖先加载的:
sources = ["/skills/base/", # 包含 web-research v1.0"/skills/user/", # 包含 web-research v2.0(用户自定义)]# 加载过程:all_skills = {}# 第一轮:加载 /skills/base/all_skills["web-research"] = SkillMetadata(name="web-research", version="1.0", ...)# 第二轮:加载 /skills/user/all_skills["web-research"] = SkillMetadata(name="web-research", version="2.0", ...)# ↑ 覆盖了 v1.0# 最终结果:使用 v2.0
应用场景:
● 基础技能库 + 用户自定义技能
● 通用技能 + 项目特定技能
● 默认配置 + 团队定制
使用案例
案例 1:基础使用 - 文件系统后端
from langchain.agents import create_agentfrom langchain.chat_models import init_chat_modelfrom just_ask.backends.filesystem import FilesystemBackendfrom just_ask.middleware.skills import SkillsMiddleware# 1. 初始化模型model = init_chat_model("deepseek:deepseek-chat")# 2. 创建文件系统后端backend = FilesystemBackend(root_dir="/path/to/skills")# 3. 创建技能中间件skills_middleware = SkillsMiddleware(backend=backend,sources=["/skills/base/", # 基础技能"/skills/user/", # 用户技能])# 4. 创建 Agentagent = create_agent(model=model,tools=[],middleware=[skills_middleware])# 5. 使用 Agentresponse = agent.invoke({"messages": [{"role": "user", "content": "帮我研究 AI Agent 的最新进展"}]})print(response["messages"][-1].content)
目录结构:
/path/to/skills/
├── skills/
│ ├── base/
│ │ ├── web-research/
│ │ │ ├── SKILL.md
│ │ │ └── search_helper.py
│ │ └── data-analysis/
│ │ └── SKILL.md
│ └── user/
│ └── custom-research/
│ └── SKILL.md
案例 2:内存后端 - 临时技能
from langchain.agents import create_agentfrom langchain.chat_models import init_chat_modelfrom just_ask.backends.state import StateBackendfrom just_ask.middleware.skills import SkillsMiddlewaremodel = init_chat_model("deepseek:deepseek-chat")# 使用工厂函数创建 StateBackendskills_middleware = SkillsMiddleware(backend=lambda rt: StateBackend(rt), # 延迟实例化sources=["/skills/session/"])agent = create_agent(model=model,tools=[],middleware=[skills_middleware])# 在运行时动态添加技能# (需要通过 StateBackend 的 API 添加文件)
适用场景:
● 会话级临时技能
● 测试环境
● 不需要持久化的场景
案例 3:多层技能系统
from langchain.agents import create_agentfrom langchain.chat_models import init_chat_modelfrom just_ask.backends.filesystem import FilesystemBackendfrom just_ask.middleware.skills import SkillsMiddlewaremodel = init_chat_model("deepseek:deepseek-chat")backend = FilesystemBackend(root_dir="/company/skills")# 四层技能系统skills_middleware = SkillsMiddleware(backend=backend,sources=["/skills/global/", # 全局基础技能(优先级 1)"/skills/department/", # 部门技能(优先级 2)"/skills/team/", # 团队技能(优先级 3)"/skills/personal/", # 个人技能(优先级 4,最高)])agent = create_agent(model=model,tools=[],middleware=[skills_middleware])
优势:
● 全局技能可被所有人使用
● 部门技能针对特定业务
● 团队技能适应团队工作流
● 个人技能满足个性化需求
● 高优先级技能可覆盖低优先级同名技能
案例 4:带工具的技能
创建一个包含辅助脚本的技能:
目录结构:
/skills/user/code-review/
├── SKILL.md
├── check_style.py
└── analyze_complexity.py
SKILL.md:
---name: code-reviewdescription: Comprehensive code review workflowallowed-tools: view launch-processmetadata:author: DevTeamversion: 2.0.0---# Code Review Skill## When to Use- User asks to review code- Need to check code quality## Workflow1. **Read the code**```Use view tool to read the target file```2. **Run style checker**```bashpython /skills/user/code-review/check_style.py <file_path>```3. **Analyze complexity**```bashpython /skills/user/code-review/analyze_complexity.py <file_path>```4. **Provide feedback**- List issues found- Suggest improvements- Highlight good practices## ExampleUser: "Review my Python script at src/main.py"Agent:1. Read src/main.py2. Run style checker: `python /skills/.../check_style.py src/main.py`3. Run complexity analyzer4. Provide comprehensive feedback
使用示例:
from langchain.agents import create_agentfrom langchain.chat_models import init_chat_modelfrom just_ask.backends.filesystem import FilesystemBackendfrom just_ask.middleware.skills import SkillsMiddlewaremodel = init_chat_model("deepseek:deepseek-chat")backend = FilesystemBackend(root_dir="/path/to/skills")skills_middleware = SkillsMiddleware(backend=backend,sources=["/skills/user/"])agent = create_agent(model=model,tools=[], # Agent 会使用内置的 view 和 launch-process 工具middleware=[skills_middleware])# Agent 会自动发现 code-review 技能并使用辅助脚本response = agent.invoke({"messages": [{"role": "user", "content": "Review my code at src/main.py"}]})
案例 5:动态技能更新
from langchain.agents import create_agentfrom langchain.chat_models import init_chat_modelfrom just_ask.backends.filesystem import FilesystemBackendfrom just_ask.middleware.skills import SkillsMiddlewareimport osmodel = init_chat_model("deepseek:deepseek-chat")backend = FilesystemBackend(root_dir="/path/to/skills")skills_middleware = SkillsMiddleware(backend=backend,sources=["/skills/dynamic/"])agent = create_agent(model=model,tools=[],middleware=[skills_middleware])# 第一次调用 - 加载现有技能response1 = agent.invoke({"messages": [{"role": "user", "content": "What skills do you have?"}]})# 动态添加新技能os.makedirs("/path/to/skills/skills/dynamic/new-skill", exist_ok=True)with open("/path/to/skills/skills/dynamic/new-skill/SKILL.md", "w") as f:f.write("""---name: new-skilldescription: A newly added skill---# New SkillThis skill was added dynamically!""")# 第二次调用 - 需要新的会话才能看到新技能# (因为 before_agent 会检查 skills_metadata 是否已存在)# 解决方案:使用新的 thread_id 或清空状态
注意:技能在 before_agent() 中加载,如果 state.skills_metadata 已存在,不会重新加载。要刷新技能列表,需要:
1. 使用新的会话(新 thread_id)
2. 清空状态
3. 重启 Agent
案例 6:自定义系统提示模板
from just_ask.middleware.skills import SkillsMiddleware# 创建自定义中间件类class CustomSkillsMiddleware(SkillsMiddleware):def __init__(self, **kwargs):super().__init__(**kwargs)# 自定义系统提示模板self.system_prompt_template = """## 🎯 专业技能库你拥有以下专业技能:{skills_list}**使用指南**:1. 识别任务类型2. 选择合适的技能3. 阅读技能文档(路径已在上方列出)4. 严格按照技能工作流执行**技能来源**:{skills_locations}"""# 使用自定义中间件skills_middleware = CustomSkillsMiddleware(backend=backend,sources=["/skills/user/"])
最佳实践
1. 技能设计原则
✅ 好的技能设计
---name: api-integrationdescription: Step-by-step guide for integrating third-party APIs---# API Integration Skill## When to Use- Integrating a new API- Troubleshooting API issues## Prerequisites- API documentation URL- Authentication credentials## Workflow### Step 1: Read API DocumentationUse web-fetch to retrieve API docs### Step 2: Test Authentication```pythonimport requestsresponse = requests.get(api_url, headers={"Authorization": f"Bearer {token}"})```### Step 3: Implement Core Functionality...## Common Pitfalls- Forgetting to handle rate limits- Not validating responses## Examples...
优点:
●清晰的使用场景
●明确的前置条件
●分步骤的工作流
●包含常见的陷阱
❌ 不好的技能设计
---name: do-stuffdescription: Does various things---# Do StuffJust do whatever the user asks.
问题:
● 描述模糊
● 没有明确的工作流
● 缺少示例
● 不符合命名规范(太宽泛)
2. 技能组织策略
按领域组织
/skills/
├── base/
│ ├── web-research/
│ ├── data-analysis/
│ └── code-review/
├── domain/
│ ├── finance/
│ │ ├── stock-analysis/
│ │ └── risk-assessment/
│ └── healthcare/
│ ├── medical-research/
│ └── patient-data-analysis/
└── project/
└── project-specific-skill/
按团队组织
/skills/
├── global/ # 全公司共享
├── engineering/ # 工程团队
├── marketing/ # 市场团队
└── sales/ # 销售团队
3. 性能优化
减少技能数量
# ❌ 过多技能(100+ 个)sources = ["/skills/all/"] # 包含 100+ 个技能# ✅ 精选技能(10-20 个)sources = ["/skills/core/", # 10 个核心技能"/skills/project/" # 5 个项目特定技能]
原因:
● 技能列表会注入到每次模型调用的 system prompt
● 过多技能会消耗大量 tokens
● Agent 难以选择合适的技能
使用批量下载
_list_skills() 已经使用了批量下载:
# ✅ 批量下载(高效)paths = [skill1_path, skill2_path, skill3_path]responses = backend.download_files(paths) # 一次调用# ❌ 逐个下载(低效)for path in paths:response = backend.download_file(path) # 多次调用
4. 安全考虑
文件大小限制
MAX_SKILL_FILE_SIZE = 10 * 1024 * 1024 # 10MBif len(content) > MAX_SKILL_FILE_SIZE:logger.warning("Skipping %s: content too large", skill_path)return None
防止:DoS 攻击(恶意上传超大文件)
路径安全
使用 PurePosixPath 确保路径安全:
from pathlib import PurePosixPath# ✅ 安全的路径操作skill_dir = PurePosixPath(skill_dir_path)skill_md_path = str(skill_dir / "SKILL.md")# ❌ 不安全的字符串拼接skill_md_path = skill_dir_path + "/SKILL.md" # 可能有路径遍历风险
YAML 安全解析
# ✅ 使用 safe_load(安全)frontmatter_data = yaml.safe_load(frontmatter_str)# ❌ 使用 load(不安全,可执行任意代码)
5. 错误处理
优雅降级
# 技能加载失败不应导致 Agent 崩溃try:skill_metadata = _parse_skill_metadata(content, skill_path, directory_name)if skill_metadata:skills.append(skill_metadata)except Exception as e:logger.warning("Failed to parse skill %s: %s", skill_path, e)# 继续处理其他技能
详细日志
logger.warning("Skipping %s: no valid YAML frontmatter found", skill_path)logger.warning("Invalid YAML in %s: %s", skill_path, e)logger.warning("Skipping %s: missing required 'name' or 'description'", skill_path)
好处:
● 帮助调试技能配置问题
● 不影响其他技能的加载
常见问题
Q1: 技能没有被加载?
可能原因:
1. 目录结构不正确
❌ /skills/user/SKILL.md # 缺少技能目录✅ /skills/user/my-skill/SKILL.md # 正确
2. SKILL.md 缺少 frontmatter
❌ # My SkillThis is my skill.✅ ---name: my-skilldescription: My skill description---# My Skill
3. 名称不匹配
目录名: /skills/user/web-research/YAML name: web_research ❌ 不匹配应该是:YAML name: web-research ✅
4. Backend 路径配置错误
# 如果使用 FilesystemBackendbackend = FilesystemBackend(root_dir="/path/to/skills")# sources 应该相对于 root_dirsources = ["/skills/user/"] # 实际路径: /path/to/skills/skills/user/
调试方法:
import logginglogging.basicConfig(level=logging.WARNING)# 运行 Agent,查看日志输出agent.invoke({"messages": [...]})
Q2: 技能列表为空?
检查清单:
1. Backend 是否正确初始化
# 检查 backend 是否能列出文件items = backend.ls_info("/skills/user/")print(items) # 应该看到技能目录
2. Sources 路径是否正确
# 确保路径存在sources = ["/skills/user/"] # 检查这个路径在 backend 中是否存在
3. 是否有权限访问文件
# 检查文件权限ls -la /path/to/skills/skills/user/
Q3: 技能被覆盖了?
这是预期行为!后加载的 source 会覆盖先加载的同名技能。
示例:
sources = ["/skills/base/", # 包含 web-research v1.0"/skills/user/", # 包含 web-research v2.0]# 结果:使用 v2.0(user 覆盖 base)
解决方案:
● 重命名技能以避免冲突
● 调整 sources 顺序
● 使用不同的技能名称
Q4: 如何刷新技能列表?
问题:添加新技能后,Agent 看不到。
原因:before_agent() 只在 skills_metadata 不存在时加载技能。
解决方案:
1. 使用新的会话
# 每次使用新的 thread_idconfig1 = {"configurable": {"thread_id": "session_1"}}config2 = {"configurable": {"thread_id": "session_2"}} # 新会话会重新加载
2. 清空状态(如果使用 StateGraph)
# 手动清空 skills_metadatastate["skills_metadata"] = None
3. 重启 Agent
# 重新创建 Agent 实例agent = create_agent(...)
Q5: 如何限制 Agent 只使用特定技能?
方法 1:使用 allowed_tools(实验性)
---name: restricted-skill description: A skill with tool restrictions allowed-tools: web-search view---
注意:这是实验性功能,可能不被所有 Agent 实现支持。
方法 2:在 system prompt 中明确指定
agent = create_agent(model=model,tools=[],middleware=[skills_middleware],system_prompt="""You should ONLY use the following skills:- web-research- data-analysisDo NOT use any other skills.""")
方法 3:过滤技能列表
class FilteredSkillsMiddleware(SkillsMiddleware):def __init__(self, allowed_skills: list[str], **kwargs):super().__init__(**kwargs)self.allowed_skills = allowed_skillsdef before_agent(self, state, runtime, config):result = super().before_agent(state, runtime, config)if result:# 过滤技能result["skills_metadata"] = [skill for skill in result["skills_metadata"]if skill["name"] in self.allowed_skills]return result# 使用middleware = FilteredSkillsMiddleware(allowed_skills=["web-research", "data-analysis"],backend=backend,sources=["/skills/user/"])
Q6: 技能文件太大怎么办?
问题:SKILL.md 文件超过 10MB 限制。
解决方案:
1. 拆分技能
❌ /skills/user/mega-skill/SKILL.md (15MB)
✅ /skills/user/skill-part-1/SKILL.md (5MB)
/skills/user/skill-part-2/SKILL.md (5MB)
/skills/user/skill-part-3/SKILL.md (5MB)
2. 使用外部文件
---name: my-skilldescription: My skill with external docs---# My SkillFor detailed documentation, see:- [Part 1](./docs/part1.md)- [Part 2](./docs/part2.md)Agent can read these files using the view tool.
3. 修改限制(不推荐)
# 在 skills.py 中修改
MAX_SKILL_FILE_SIZE = 50 * 1024 * 1024 # 50MB
Q7: 如何调试技能加载?
启用详细日志:
import logging# 设置日志级别logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')# 只启用 skills 模块的日志logger = logging.getLogger('just_ask.middleware.skills')logger.setLevel(logging.DEBUG)
手动测试技能加载:
from just_ask.backends.filesystem import FilesystemBackendfrom just_ask.middleware.skills import _list_skillsbackend = FilesystemBackend(root_dir="/path/to/skills")skills = _list_skills(backend, "/skills/user/")print(f"Loaded {len(skills)} skills:")for skill in skills:print(f" - {skill['name']}: {skill['description']}")print(f" Path: {skill['path']}")
Q8: 如何在技能中使用环境变量?
在 SKILL.md 中引用:
---name: api-callerdescription: Call external APIs---# API Caller Skill## SetupEnsure the following environment variables are set:- `API_KEY`: Your API key- `API_URL`: API endpoint URL## Usage```pythonimport osapi_key = os.getenv("API_KEY")api_url = os.getenv("API_URL")
Q9: 技能可以调用其他技能吗?
可以!
在 SKILL.md 中引用其他技能:
---name: advanced-researchdescription: Advanced research combining multiple skills---# Advanced Research Skill## Workflow1. **Use web-research skill**Read `/skills/user/web-research/SKILL.md` and follow its workflowto gather initial information.2. **Use data-analysis skill**Read `/skills/user/data-analysis/SKILL.md` and analyze thegathered data.3. **Synthesize results**Combine insights from both skills.
Agent 会:
1. 读取 advanced-research 技能
2. 发现需要 web-research 技能
3. 读取 web-research 技能
4. 执行 web-research 工作流
5. 继续执行 advanced-research 的后续步骤
高级主题
1. 自定义 Backend 实现
如果需要从自定义存储加载技能(如数据库、S3),可以实现 BackendProtocol:
from just_ask.backends.protocol import BackendProtocol, DownloadResponseclass DatabaseBackend(BackendProtocol):def __init__(self, db_connection):self.db = db_connectiondef ls_info(self, path: str) -> list[dict]:"""列出目录内容"""# 从数据库查询results = self.db.query("SELECT name, is_directory FROM files WHERE parent_path = ?",(path,))return [{"path": f"{path}/{row['name']}", "is_dir": row['is_directory']}for row in results]def download_files(self, paths: list[str]) -> list[DownloadResponse]:"""批量下载文件"""responses = []for path in paths:content = self.db.query("SELECT content FROM files WHERE path = ?",(path,))if content:responses.append(DownloadResponse(content=content[0]['content'].encode('utf-8'),error=None))else:responses.append(DownloadResponse(content=None,error="File not found"))return responses# 实现其他必需方法...
2. 动态技能生成
使用 LLM 动态生成技能:
from langchain.chat_models import init_chat_modeldef generate_skill(task_description: str) -> str:"""使用 LLM 生成技能定义"""model = init_chat_model("gpt-4")prompt = f"""Generate a SKILL.md file for the following task:{task_description}Follow the Agent Skills specification format."""response = model.invoke(prompt)return response.content# 生成技能skill_content = generate_skill("Analyze stock market trends")# 保存到文件系统with open("/skills/user/stock-analysis/SKILL.md", "w") as f:f.write(skill_content)
3. 技能推荐系统
根据用户任务推荐合适的技能:
from langchain.chat_models import init_chat_modelclass SkillRecommender:def __init__(self, skills_metadata: list[SkillMetadata]):self.skills = skills_metadataself.model = init_chat_model("gpt-4")def recommend(self, user_task: str) -> list[str]:"""推荐技能"""skills_list = "\n".join([f"- {s['name']}: {s['description']}"for s in self.skills])prompt = f"""User task: {user_task}Available skills:{skills_list}Which skills would be most helpful? Return skill names only."""response = self.model.invoke(prompt)# 解析响应,提取技能名称return response.content.strip().split("\n")
总结
核心要点
1. 渐进式披露:先展示元数据,按需加载详情,节省 tokens
2. 多源分层:支持从多个来源加载技能,实现优先级覆盖
3. 后端抽象:不依赖文件系统,可移植到不同存储
4. 规范兼容:遵循 Agent Skills 规范,与社区标准一致
5. 安全可靠:文件大小限制、安全的 YAML 解析、优雅的错误处理
适用场景
● ✅ 需要复杂工作流的 AI Agent
● ✅ 多团队协作的技能管理
● ✅ 需要版本控制和分层管理的技能库
● ✅ 需要动态更新技能的系统
不适用场景
● ❌ 简单的单次对话(过度设计)
● ❌ 技能数量极少(<3 个)
● ❌ 不需要结构化工作流的场景
下一步
1. 创建第一个技能:从简单的 web-research 技能开始
2. 测试渐进式披露:观察 Agent 如何按需加载技能
3. 构建技能库:逐步积累常用技能
4. 优化工作流:根据实际使用情况调整技能内容
参考资源
● Agent Skills 规范
● LangChain 中间件文档
● LangGraph 文档
版本: 1.4.0
最后更新: 2026-01-13
作者: 但问智能团队
|
|

