[Go to site: main page, start]

Skip to content

ADK 智能体的技能

Supported in ADKPython v1.25.0TypeScript v0.6.1Go v1.2.0Experimental

智能体技能 (Skill) 是一个自包含的功能单元,ADK 智能体可以用它执行特定任务。智能体技能封装了执行任务所需的指令、资源和工具,基于Agent Skill 规范。技能的结构允许增量加载,以最小化对智能体操作上下文窗口的影响。

实验性

技能功能是实验性的。我们欢迎通过相应的 ADK GitHub 仓库提供反馈。

开始使用

使用 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

理解技能

技能功能允许你创建模块化的技能指令和资源包,智能体可以按需加载。这种方法有助于你组织智能体的能力,并通过仅在需要时加载指令来优化上下文窗口。技能的结构分为三个层级:

  • L1(元数据): 提供用于技能发现的元数据。此信息定义在 SKILL.md 文件的 frontmatter 部分,包括技能名称和描述等属性。
  • L2(指令): 包含技能的主要指令,在智能体触发技能时加载。此信息定义在 SKILL.md 文件的正文部分。
  • L3(资源): 包括附加资源,如参考资料、资产和脚本,可按需加载。这些资源组织在以下目录中:
    • references/:包含扩展指令、工作流或指导的附加 Markdown 文件。
    • assets/:资源材料,如数据库模式、API 文档、模板或示例。
    • scripts/:智能体运行时支持的可执行脚本。

技能目录结构

以下目录结构展示了在 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 {
    // 处理错误
}

下一步

查看以下资源以了解如何使用技能构建智能体: