skills - Solon AI Skills(技能) 概念介绍
2026年1月22日 下午10:11:09
v3.8.4 后支持
Solon AI Skills(技能)。概念原型参考了 Claude Code Agent Skills 的设计思想:通过结构化的定义(元数据、指令/SOP、脚本/工具)赋予 Agent 特定领域的专家能力。
1、Solon AI Skills 概念介绍
在 Solon AI 体系中,Skill 是 ChatModel / Agent 能力的最小封装单元(就像微信平台的小程序)。它不只是工具的集合,而是一套包含 “感知、约束、执行” 的完整逻辑块。
- 感知(Awareness):通过 isSupported 接口,Skill 能够感知用户的当前 Prompt,并决定自己是否要在本次对话中激活。
- 约束(Instruction):通过 getInstruction 注入特定的 SOP(标准作业程序)。它告诉模型:在调用这些工具时,必须遵循哪些业务规则。
- 执行(Execution):通过 getTools 挂载一组原子工具(FunctionTool),并自动对这些工具进行“染色”。
- 染色(Coloring):借鉴 MCP(Model Context Protocol)思想,自动将 Skill 的元信息注入工具的元数据中。这使得大模型能够清晰地识别工具的“归属感”,从而在推理阶段(Thought)精准地建立指令与工具之间的关联。
核心特性
- 按需激活:支持根据用户意图、权限或上下文动态挂载,有效节省 Token 消耗并降低干扰。
- 指令隔离:每个 Skill 的指令在 System Message 中以独立的 Skill: Name 块呈现,结构清晰,模型依从性极高。
- 原子性与组合性:Skill 之间相互隔离,开发者可以像搭积木一样为 ChatModel 组合不同的技能集。
2、Skill 部署过程概述
在 Solon AI 中,一个 Skill 从定义到发挥作用经历以下生命周期:
- 定义阶段:开发者实现 Skill 接口,编写 getInstruction(SOP 提示词)并关联 FunctionTool(具体执行工具)。
- 注册阶段:通过 ChatModel.Builder 或 ChatConfig 将 Skill 实例添加到全局或特定的模型配置中。
- 触发阶段(Runtime):
- 准入检查:请求发起时,框架遍历 Skill,执行 isSupported(prompt) 过滤无关技能。
- 挂载激活:执行 onAttach 准备上下文环境。
- 指令合并与染色:调用 injectInstruction,框架自动将所有活跃 Skill 的指令拼接到 System Message,同时将 Skill 身份注入到每个工具的 meta 数据中。
- 推理与执行:模型根据“染色”后的工具描述进行推理,在需要时触发工具调用。
3、具体 Skill 接口参考
package org.noear.solon.ai.chat.skill;
import org.noear.solon.Utils;
import org.noear.solon.ai.chat.prompt.ChatPrompt;
import org.noear.solon.ai.chat.tool.FunctionTool;
import org.noear.solon.ai.chat.tool.ToolProvider;
import org.noear.solon.lang.Preview;
import java.util.Collection;
import java.util.stream.Collectors;
public interface Skill extends ToolProvider {
/**
* 名字
*/
default String name() {
return this.getClass().getSimpleName();
}
/**
* 描述
*/
default String description(){
return null;
}
/**
* 技能元信息
*/
default SkillMetadata metadata() {
return new SkillMetadata(this.name(), this.description());
}
/**
* 准入检查:决定该技能在当前环境下是否可用
*/
default boolean isSupported(ChatPrompt prompt) {
return true;
}
/**
* 挂载钩子:技能被激活时触发,可用于初始化 Session
*/
default void onAttach(ChatPrompt prompt) {
}
/**
* 指令注入:转化并注入到 System Message
*/
default String getInstruction(ChatPrompt prompt) {
return null;
}
/**
* 工具注入:转化并注入到工具列表
*/
default Collection<FunctionTool> getTools() {
return null;
}
/**
* 注入指令
*/
/**
* 注入指令并对工具进行“染色”
*/
default void injectInstruction(ChatPrompt prompt, StringBuilder combinedInstruction) {
String ins = getInstruction(prompt);
Collection<FunctionTool> tools = getTools();
// 1. 如果有工具,进行元信息染色(借鉴 MCP 思想)
if (tools != null && !tools.isEmpty()) {
for (FunctionTool tool : tools) {
// 将所属 Skill 的名字注入工具的 meta
tool.metaPut("skill", name());
// 如果需要,也可以把 Skill 的描述或其它元数据注入
if (Utils.isNotEmpty(description())) {
tool.metaPut("skill_desc", description());
}
}
}
// 2. 构建 System Prompt 指令块
if (Utils.isNotEmpty(ins) || (tools != null && !tools.isEmpty())) {
if (combinedInstruction.length() > 0) {
combinedInstruction.append("\n");
}
// 统一头部
combinedInstruction.append("**Skill**: ").append(name());
// 补充 Skill 描述(如果有)
if (Utils.isNotEmpty(metadata().getDescription()) && !name().equals(metadata().getDescription())) {
combinedInstruction.append(" (").append(metadata().getDescription()).append(")");
}
combinedInstruction.append("\n");
// 注入具体指令
if (Utils.isNotEmpty(ins)) {
combinedInstruction.append(ins).append("\n");
}
// 注入工具关联说明(告知模型这些工具受此 Skill 指令约束)
if (tools != null && !tools.isEmpty()) {
String toolNames = tools.stream().map(t -> t.name()).collect(Collectors.joining(", "));
combinedInstruction.append("- **Supported Tools**: ").append(toolNames).append("\n");
}
}
}
}