Skill
Skill Middleware 为 Eino ADK Agent 提供 Skill 支持,使 Agent 能够动态发现和使用预定义的技能来完成任务。
什么是 Skill
Skill 是包含指令、脚本和资源的文件夹,Agent 可以按需发现和使用这些 Skill 来扩展自身能力。核心是 SKILL.md 文件,包含元数据(至少需要 name 和 description)和指导 Agent 执行任务的说明。
my-skill/
├── SKILL.md # 必需:指令 + 元数据
├── scripts/ # 可选:可执行代码
├── references/ # 可选:参考文档
└── assets/ # 可选:模板、资源
Skill 使用**渐进式展示(Progressive Disclosure)**来高效管理上下文:
- 发现(Discovery):Agent 仅加载每个可用 Skill 的 name 和 description,足以判断何时可能需要使用该 Skill
- 激活(Activation):当任务匹配某个 Skill 时,Agent 将完整的
SKILL.md内容读入上下文 - 执行(Execution):Agent 遵循指令执行任务,按需加载其他文件或执行捆绑代码
💡 Ref: https://agentskills.io/home
接口介绍
FrontMatter
Skill 的元数据结构,从 SKILL.md 的 YAML frontmatter 中解析。用于在发现阶段快速展示 Skill 信息:
type FrontMatter struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
Context ContextMode `yaml:"context"`
Agent string `yaml:"agent"`
Model string `yaml:"model"`
}
| 字段 | 类型 | 说明 |
Name | string | Skill 的唯一标识符。建议使用简短、有意义的名称(如pdf-processing、 web-research) |
Description | string | Skill 的功能描述。Agent 判断是否使用该 Skill 的关键依据,应清晰说明适用场景和能力 |
Context | ContextMode | 上下文模式。可选值:fork(隔离上下文)、 fork_with_context(复制历史消息)。留空表示内联模式 |
Agent | string | 指定使用的 Agent 名称,配合Context使用,通过 AgentHub获取对应 Agent。留空使用默认 Agent |
Model | string | 指定使用的模型名称,通过ModelHub获取对应模型实例 |
ContextMode
const (
ContextModeFork ContextMode = "fork" // 隔离上下文
ContextModeForkWithContext ContextMode = "fork_with_context" // 复制历史消息
)
| 模式 | 说明 |
| 内联(默认) | Skill 内容直接作为工具结果返回,由当前 Agent 继续处理 |
fork_with_context | 创建新 Agent,复制当前对话历史,独立执行 Skill 任务后返回结果 |
fork | 创建新 Agent,使用隔离上下文(仅包含 Skill 内容),独立执行后返回结果 |
Skill
完整的 Skill 结构,包含元数据和指令内容:
type Skill struct {
FrontMatter
Content string
BaseDirectory string
}
| 字段 | 类型 | 说明 |
FrontMatter | FrontMatter | 嵌入的元数据结构 |
Content | string | SKILL.md 中 frontmatter 之后的正文内容,包含详细指令、工作流程、示例等 |
BaseDirectory | string | Skill 目录的绝对路径,Agent 可用此路径访问目录中的其他资源文件 |
Backend
Skill 后端接口,将技能的存储与使用解耦:
type Backend interface {
List(ctx context.Context) ([]FrontMatter, error)
Get(ctx context.Context, name string) (Skill, error)
}
| 方法 | 说明 |
List | 列出所有可用技能的元数据。Agent 启动时调用,用于构建技能工具的描述 |
Get | 根据名称获取完整的技能内容。Agent 决定使用某个技能时调用 |
NewBackendFromFilesystem
基于 filesystem.Backend 接口的后端实现,扫描指定目录下的一级子目录读取技能:
type BackendFromFilesystemConfig struct {
Backend filesystem.Backend
BaseDir string
}
func NewBackendFromFilesystem(ctx context.Context, config *BackendFromFilesystemConfig) (Backend, error)
| 字段 | 类型 | 必需 | 说明 |
Backend | filesystem.Backend | 是 | 文件系统后端实现,用于文件操作 |
BaseDir | string | 是 | 技能根目录路径。扫描此目录下的一级子目录,查找包含SKILL.md文件的目录 |
工作方式:
- 扫描
BaseDir下的一级子目录 - 查找每个子目录中的
SKILL.md文件 - 解析 YAML frontmatter 获取元数据
- 深层嵌套的
SKILL.md文件会被忽略
filesystem.Backend 接口有两种实现可供选择,详见 FileSystem Backend 文档。
AgentHub 和 ModelHub
当 Skill 使用 Context 模式(fork / fork_with_context)时,需要通过 AgentHub 和 ModelHub 提供 Agent 实例和模型实例。
💡 以下展示非泛型别名类型(即
*schema.Message特化)。泛型版本TypedAgentHub[M]、TypedModelHub[M]可用于*schema.AgenticMessage场景,接口签名一致,仅消息类型参数不同。
// AgentHubOptions 传递给 AgentHub.Get 的选项
type AgentHubOptions = TypedAgentHubOptions[*schema.Message]
type TypedAgentHubOptions[M adk.MessageType] struct {
// Model 为技能 frontmatter 中指定的模型实例(通过 ModelHub 解析)。
// nil 表示技能未指定模型覆盖,实现方应使用默认模型。
Model model.BaseModel[M]
}
// AgentHub 为 Context 模式提供 Agent 实例
type AgentHub = TypedAgentHub[*schema.Message]
type TypedAgentHub[M adk.MessageType] interface {
// Get 根据名称返回 Agent。name 为空时应返回默认 Agent。
Get(ctx context.Context, name string, opts *TypedAgentHubOptions[M]) (adk.TypedAgent[M], error)
}
// ModelHub 根据名称解析模型实例
type ModelHub = TypedModelHub[*schema.Message]
type TypedModelHub[M adk.MessageType] interface {
Get(ctx context.Context, name string) (model.BaseModel[M], error)
}
💡 注意:
AgentHubOptions.Model和ModelHub.Get的返回类型为model.BaseModel[M],而非旧版文档中的model.ToolCallingChatModel。
SubAgentInput 和 SubAgentOutput
这两个结构体在自定义 fork 模式行为时使用:
type SubAgentInput = TypedSubAgentInput[*schema.Message]
type TypedSubAgentInput[M adk.MessageType] struct {
Skill Skill
Mode ContextMode
RawArguments string // 原始 JSON 参数
SkillContent string // 构建好的 Skill 内容
History []M // 对话历史(仅 fork_with_context 模式)
ToolCallID string // 工具调用 ID(仅 fork_with_context 模式)
}
type SubAgentOutput = TypedSubAgentOutput[*schema.Message]
type TypedSubAgentOutput[M adk.MessageType] struct {
Skill Skill
Mode ContextMode
RawArguments string
Messages []M // 子 Agent 产生的所有消息
Results []string // 提取的 assistant 消息文本内容
}
初始化
Config
type Config = TypedConfig[*schema.Message]
type TypedConfig[M adk.MessageType] struct {
Backend Backend
SkillToolName *string
AgentHub TypedAgentHub[M]
ModelHub TypedModelHub[M]
CustomSystemPrompt SystemPromptFunc
CustomToolDescription ToolDescriptionFunc
CustomToolParams func(ctx context.Context, defaults map[string]*schema.ParameterInfo) (map[string]*schema.ParameterInfo, error)
BuildContent func(ctx context.Context, skill Skill, rawArgs string) (string, error)
BuildForkMessages func(ctx context.Context, in TypedSubAgentInput[M]) ([]M, error)
FormatForkResult func(ctx context.Context, in TypedSubAgentOutput[M]) (string, error)
}
| 字段 | 类型 | 必需 | 默认值 | 说明 |
Backend | Backend | 是 | - | 技能后端实现,负责技能的存储和检索 |
SkillToolName | *string | 否 | "skill" | 技能工具名称。如已有同名工具,可自定义避免冲突 |
AgentHub | TypedAgentHub[M] | 否 | - | 提供 Agent 实例。使用context: fork或 fork_with_context时必填 |
ModelHub | TypedModelHub[M] | 否 | - | 提供模型实例。Context 模式下传给 AgentHub;内联模式下通过 WrapModel 切换后续 ChatModel 调用的模型 |
CustomSystemPrompt | SystemPromptFunc | 否 | 内置提示词 | 自定义系统提示词。签名:func(ctx, toolName) string |
CustomToolDescription | ToolDescriptionFunc | 否 | 内置描述 | 自定义工具描述。签名:func(ctx, skills []FrontMatter) string |
CustomToolParams | func | 否 | 仅skill参数 | 自定义工具参数 schema。接收默认参数,返回自定义参数,始终保留skill为必填 |
BuildContent | func | 否 | 默认格式化 | 自定义 Skill 内容生成,可在内容中注入额外上下文 |
BuildForkMessages | func | 否 | 见下文 | 自定义 fork 模式下传给子 Agent 的初始消息。默认:fork→ [UserMessage(content)], fork_with_context→ [history..., ToolMessage(content, callID)] |
FormatForkResult | func | 否 | 拼接内容 | 自定义子 Agent 结果格式化。默认将 assistant message 内容拼接后返回 |
NewMiddleware
func NewMiddleware(ctx context.Context, config *Config) (adk.ChatModelAgentMiddleware, error)
创建 Skill Middleware,返回 adk.ChatModelAgentMiddleware,传入 ChatModelAgentConfig.Handlers 使用。
💡 泛型版本
NewTyped[M](ctx, config)返回adk.TypedChatModelAgentMiddleware[M],可用于*schema.AgenticMessage类型的 Agent。
使用示例
// 1. 创建 Backend
backend, err := skill.NewBackendFromFilesystem(ctx, &skill.BackendFromFilesystemConfig{
Backend: fsBackend,
BaseDir: "/path/to/skills",
})
if err != nil {
return err
}
// 2. 创建 Middleware
handler, err := skill.NewMiddleware(ctx, &skill.Config{
Backend: backend,
AgentHub: myAgentHub, // 可选,仅 fork 模式需要
ModelHub: myModelHub, // 可选,仅使用 model 字段时需要
})
if err != nil {
return err
}
// 3. 传入 Agent 的 Handlers
agent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
// ... 其他配置
Handlers: []adk.ChatModelAgentMiddleware{handler},
})
