ADK 智能体的技能¶
智能体技能 (Skill) 是一个自包含的功能单元,ADK 智能体可以用它执行特定任务。智能体技能封装了执行任务所需的指令、资源和工具,基于Agent Skill 规范。技能的结构允许增量加载,以最小化对智能体操作上下文窗口的影响。
Experimental
技能功能目前处于实验阶段。我们欢迎你通过以下 ADK GitHub 仓库提供反馈: ADK Python、 ADK TypeScript、 ADK Go。
开始使用¶
使用 SkillToolset 类可以将一个或多个技能提供给你的智能体。
你可以在代码中定义技能,也可以从文件系统中加载技能。
import pathlib
from google.adk import Agent
from google.adk.skills import load_skill_from_dir
from google.adk.tools import skill_toolset
weather_skill = load_skill_from_dir(
pathlib.Path(__file__).parent / "skills" / "weather_skill"
)
my_skill_toolset = skill_toolset.SkillToolset(
skills=[weather_skill],
additional_tools=[get_weather_tool],
)
root_agent = Agent(
model="gemini-flash-latest",
name="skill_user_agent",
description="一个可以使用专业技能的智能体。",
instruction=(
"你是一个有用的助手,可以利用技能来执行任务。"
),
tools=[
my_skill_toolset,
],
)
有关包含技能的 ADK 智能体的完整代码示例(包括基于文件和内联技能定义),请参见代码示例 skills_agent。
import {Agent, FunctionTool, SkillToolset, loadSkillFromDir} from '@google/adk';
import * as path from 'node:path';
import {z} from 'zod';
const weatherSkill = await loadSkillFromDir(
path.join(__dirname, 'skills/weather_skill')
);
const getWeatherTool = new FunctionTool({
name: 'get_weather',
description: 'Gets the weather for a given location.',
parameters: z.object({
location: z.string().describe('The city and state, e.g. San Francisco, CA'),
}),
execute: async ({location}) => {
return {
location,
temperature: '72°F',
condition: 'Sunny',
};
},
});
const mySkillToolset = new SkillToolset([weatherSkill], {
additionalTools: [getWeatherTool],
});
const rootAgent = new Agent({
model: 'gemini-flash-latest',
name: 'skill_user_agent',
description: 'An agent that can use specialized skills.',
instruction:
'You are a helpful assistant that can leverage skills to perform tasks.',
tools: [mySkillToolset],
});
export default rootAgent;
import (
"context"
"os"
"google.golang.org/adk/v2/agent/llmagent"
"google.golang.org/adk/v2/tool/skilltoolset/skill"
"google.golang.org/adk/v2/tool/skilltoolset"
"google.golang.org/adk/v2/tool"
)
mySkillToolset, err := skilltoolset.New(ctx, skilltoolset.Config{
Source: skill.NewFileSystemSource(os.DirFS("./skills")),
})
if err != nil {
// 处理错误
}
rootAgent, err := llmagent.New(llmagent.Config{
Name: "skill_user_agent",
Model: model,
Description: "一个可以使用专业技能的智能体。",
Instruction: "你是一个有用的助手,可以利用技能来执行任务。",
Toolsets: []tool.Toolset{mySkillToolset},
})
if err != nil {
// 处理错误
}
有关完整示例,请参见代码示例 skills。
检查你的工作目录
确保你的当前工作目录中存在 `skills/` 目录,并且包含你希望在智能体中使用的技能的子目录。
技能结构¶
技能功能允许你创建模块化的技能指令和资源包,智能体可以按需加载。这种方法有助于你组织智能体的能力,并通过仅在需要时加载指令来优化上下文窗口。技能的结构分为三个层级:
- L1(元数据): 提供用于技能发现的元数据。此信息定义在
SKILL.md文件的 frontmatter 部分,包括技能名称和描述等属性。 - L2(指令): 包含技能的主要指令,在智能体触发技能时加载。此信息定义在
SKILL.md文件的正文部分。 - L3(资源): 包括附加资源,如参考资料、资产和脚本,可按需加载。这些资源组织在以下目录中:
references/:包含扩展指令、工作流或指导的附加 Markdown 文件。assets/:资源材料,如数据库模式、API 文档、模板或示例。scripts/:智能体运行时支持的可执行脚本。
使用技能的系统指令¶
SkillToolset 为智能体提供了一套默认的系统指令,概述了智能体应如何与技能交互。这些指令包含以下要点:
- 你必须在使用技能之前,先使用
load_skill工具读取技能的指令。 - 你必须严格按照技能定义中的指令执行。
- 你必须使用
load_skill_resource工具来查看技能目录中的文件。 - 你必须使用
run_skill_script来运行技能scripts/目录中的脚本。
技能验证¶
技能 SKILL.md 文件的 frontmatter 会经过验证,以确保满足以下要求:
- name:
- 必须为 64 个字符或更少。
- 必须使用小写、kebab-case 格式(a-z、0-9 和连字符)。
- 不得包含前导、尾随或连续的连字符。
- description:
- 不得为空。
- 必须为 1024 个字符或更少。
Skills directory structure¶
以下目录结构展示了在 ADK 智能体项目中包含技能的推荐方式。下面所示的 example-skill/ 目录以及任何并行的技能目录,必须遵循 Agent Skill 规范 的文件结构。只有 SKILL.md 文件是必需的。
my_agent/
agent.py (or agent.ts / main.go)
.env
skills/
example-skill/ # 技能
SKILL.md # 主要指令(必需)
references/
REFERENCE.md # 详细的 API 参考
FORMS.md # 表单填写指南
*.md # 特定领域的信息
assets/
*.* # 模板、图片、数据
scripts/
*.py # 工具脚本(Python)
*.js # 工具脚本(JavaScript)
*.ts # 工具脚本(TypeScript)
技能来源¶
在代码中定义技能¶
你可以在智能体的代码中定义技能,如下所示。
from google.adk.skills import models
greeting_skill = models.Skill(
frontmatter=models.Frontmatter(
name="greeting-skill",
description=(
"一个友好的问候技能,可以向特定的人问好。"
),
),
instructions=(
"步骤 1:读取 'references/hello_world.txt' 文件以了解如何"
"向用户问好。步骤 2:根据参考资料返回问候。"
),
resources=models.Resources(
references={
"hello_world.txt": "你好!很高兴见到你!",
"example.md": "这是一个示例参考资料。",
},
),
)
import {Agent, Skill, SkillToolset} from '@google/adk';
const greetingSkill: Skill = {
frontmatter: {
name: 'greeting-skill',
description: 'A friendly greeting skill that can say hello to a specific person.',
},
instructions:
"Step 1: Read the 'references/hello_world.txt' file to understand how to greet the user. Step 2: Return a greeting based on the reference.",
resources: {
references: {
'hello_world.txt': 'Hello! So glad to have you here!',
'example.md': 'This is an example reference.',
},
},
};
const mySkillToolset = new SkillToolset([greetingSkill]);
const rootAgent = new Agent({
model: 'gemini-flash-latest',
name: 'greeting_agent',
description: 'An agent that uses an inline greeting skill.',
instruction: 'You are a helpful assistant that uses skills to greet people.',
tools: [mySkillToolset],
});
export default rootAgent;
Note
ADK Go 目前不提供内联技能的标准 Source,但未来可能会添加。
要在代码中直接定义技能,你需要自己实现 skill.Source 接口,如下所示。
import (
"context"
"io"
"slices"
"strings"
"google.golang.org/adk/v2/tool/skilltoolset/skill"
)
// 静态内存 skill.Source 的示例实现:
type StaticSource struct{}
func (s *StaticSource) ListFrontmatters(ctx context.Context) ([]*skill.Frontmatter, error) {
return []*skill.Frontmatter{
{Name: "greeting-skill", Description: "一个友好的问候技能,可以向特定的人问好。"},
}, nil
}
func (s *StaticSource) LoadFrontmatter(ctx context.Context, name string) (*skill.Frontmatter, error) {
if name != "greeting-skill" {
return nil, skill.ErrSkillNotFound
}
return &skill.Frontmatter{Name: "greeting-skill", Description: "一个友好的问候技能,可以向特定的人问好。"}, nil
}
func (s *StaticSource) LoadInstructions(ctx context.Context, name string) (string, error) {
if name != "greeting-skill" {
return "", skill.ErrSkillNotFound
}
return "步骤 1:读取 'references/hello_world.txt' 文件以了解如何向用户问好。步骤 2:根据参考资料返回问候。", nil
}
func (s *StaticSource) ListResources(ctx context.Context, name, subpath string) ([]string, error) {
if name != "greeting-skill" {
return nil, skill.ErrSkillNotFound
}
if !slices.Contains([]string{"", ".", "references", "references/"}, subpath) {
return nil, skill.ErrResourceNotFound
}
return []string{"references/hello_world.txt", "references/example.md"}, nil
}
func (s *StaticSource) LoadResource(ctx context.Context, name, resourcePath string) (io.ReadCloser, error) {
if name != "greeting-skill" {
return nil, skill.ErrSkillNotFound
}
switch resourcePath {
case "references/hello_world.txt":
return io.NopCloser(strings.NewReader("你好!很高兴见到你!")), nil
case "references/example.md":
return io.NopCloser(strings.NewReader("这是一个示例参考资料。")), nil
default:
return nil, skill.ErrResourceNotFound
}
}
Note
Source 接口可以由任何数据存储(如数据库)支撑,以支持动态用例,如实时更新和个性化。
从文件系统中读取技能¶
import pathlib
from google.adk.skills import load_skill_from_dir
from google.adk.tools import skill_toolset
greeting_skill = load_skill_from_dir(
pathlib.Path(__file__).parent / "skills" / "greeting-skill"
)
weather_skill = load_skill_from_dir(
pathlib.Path(__file__).parent / "skills" / "weather-skill"
)
my_skill_toolset = skill_toolset.SkillToolset(
skills=[weather_skill, greeting_skill],
)
import (
"os"
"google.golang.org/adk/v2/tool/skilltoolset/skill"
"google.golang.org/adk/v2/tool/skilltoolset"
)
// ...
source := skill.NewFileSystemSource(os.DirFS("./skills"))
// 此示例不使用任何可选的包装器,但如果需要可以使用,例如:
// source, _, err = skill.WithFrontmatterPreloadSource(ctx, source)
// source, _, err = skill.WithCompletePreloadSource(ctx, source)
// 有关这些及其他包装器的更多信息,请参见
// https://pkg.go.dev/google.golang.org/adk/v2/tool/skilltoolset/skill#Source.
skillToolset, err := skilltoolset.New(ctx, skilltoolset.Config{
Source: source,
})
if err != nil {
// 处理错误
}
技能处理与验证¶
当你在智能体中包含技能时,智能体会使用标准化流程与技能交互。此流程包括用于如何使用技能的系统级指令、技能表示的定义格式,以及技能定义的验证规则。
下一步¶
查看以下资源以了解如何使用技能构建智能体:
- Python 中的技能 - 代码示例
- Go 中的技能 - 代码示例
- Agent Skills 规范文档