代理技能 是指令、脚本和资源的可移植包,可提供代理的专用功能和域专业知识。 技能遵循开放规范并实现渐进式披露模式,以便代理在需要时仅加载所需的上下文。
在需要时使用代理技能:
- 封装领域专业知识 - 将专业知识(费用策略、法律工作流、数据分析管道)捕获为可重用且可移植的包。
- 扩展代理功能 - 为代理提供新功能,而无需更改其核心指令。
- 确保一致性 - 将多步骤任务转换为可重复的可审核工作流。
- 启用互作性 - 在不同的代理技能兼容产品中重复使用相同的技能。
技能结构
技能是一个目录,包含一个 文件,并且可以选择包括用于存放资源的子目录:
expense-report/
├── SKILL.md # Required — frontmatter + instructions
├── scripts/
│ └── validate.py # Executable code agents can run
├── references/
│ └── POLICY_FAQ.md # Reference documents loaded on demand
└── assets/
└── expense-report-template.md # Templates and static resources
SKILL.md 格式
该文件 必须包含 YAML 前置数据,后跟 Markdown 内容:
---
name: expense-report
description: File and validate employee expense reports according to company policy. Use when asked about expense submissions, reimbursement rules, or spending limits.
license: Apache-2.0
compatibility: Requires python3
metadata:
author: contoso-finance
version: "2.1"
---
| 字段 | 必选 | Description |
|---|---|---|
name |
是的 | 最多 64 个字符。 仅小写字母、数字和连字符。 不得以连字符开头或结尾,不得包含连续连字符。 必须与父目录名称匹配。 |
description |
是的 | 技能的作用以及何时使用它。 最多 1024 个字符。 应包含帮助代理识别相关任务的关键字。 |
license |
否 | 许可证名称或对捆绑许可证文件的引用。 |
compatibility |
否 | 最多 500 个字符。 指示环境要求(预期产品、系统包、网络访问等)。 |
metadata |
否 | 其他元数据的任意键值映射。 |
allowed-tools |
否 | 技能可以使用的预先批准的工具的以空格分隔的列表。 实验性 — 代理实现之间的支持可能有所不同。 |
frontmatter 后面的 Markdown 正文包含技能说明- 分步指导、输入和输出示例、常见边缘情况或任何帮助代理执行任务的内容。 保留 500 行以下,并将详细的参考资料移动到单独的文件中。
渐进式披露
代理技能使用三阶段渐进式披露模式来最大程度地减少上下文使用情况:
- 宣传 (每个技能大约 100 个标识符)——技能名称和描述在每次运行开始时被注入系统提示符,从而让代理了解哪些技能是可用的。
- 加载 ( 建议使用 5000 个令牌) - 当任务与技能的域匹配时,代理会调用 该工具来检索完整的 SKILL.md 正文,其中包含详细说明。
- 读取资源 (根据需要) - 代理仅在需要时调用 该工具以提取补充文件(引用、模板、资产)。
此模式使代理的上下文窗口保持精简状态,同时允许它按需访问深层域知识。
向代理提供技能
代理框架包括一个技能提供程序,用于发现文件系统目录中的技能,并将其作为上下文提供程序提供给代理。 它会以递归方式(最多两个级别深度)搜索配置的路径下的文件,验证其格式和资源,并向代理提供两个工具:、。
注释
尚不支持脚本执行,并将在将来的版本中添加。
基本设置
创建一个指向包含您技能的目录的,并将其添加到代理的上下文提供者中。
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
// Discover skills from the 'skills' directory
var skillsProvider = new FileAgentSkillsProvider(
skillPath: Path.Combine(AppContext.BaseDirectory, "skills"));
// Create an agent with the skills provider
AIAgent agent = new AzureOpenAIClient(
new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient(deploymentName)
.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new()
{
Instructions = "You are a helpful assistant.",
},
AIContextProviders = [skillsProvider],
});
调用代理
配置后,代理会自动发现可用的技能,并在任务匹配时使用这些技能:
// The agent loads the expense-report skill and reads the FAQ resource
AgentResponse response = await agent.RunAsync(
"Are tips reimbursable? I left a 25% tip on a taxi ride.");
Console.WriteLine(response.Text);
基本设置
创建一个指向包含您技能的目录的,并将其添加到代理的上下文提供者中。
from pathlib import Path
from agent_framework import SkillsProvider
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity.aio import AzureCliCredential
# Discover skills from the 'skills' directory
skills_provider = SkillsProvider(
skill_paths=Path(__file__).parent / "skills"
)
# Create an agent with the skills provider
agent = AzureOpenAIChatClient(credential=AzureCliCredential()).as_agent(
name="SkillsAgent",
instructions="You are a helpful assistant.",
context_providers=[skills_provider],
)
调用代理
配置后,代理会自动发现可用的技能,并在任务匹配时使用这些技能:
# The agent loads the expense-report skill and reads the FAQ resource
response = await agent.run(
"Are tips reimbursable? I left a 25% tip on a taxi ride."
)
print(response.text)
多个技能目录
可以通过传递路径列表来搜索多个目录:
var skillsProvider = new FileAgentSkillsProvider(
skillPaths: [
Path.Combine(AppContext.BaseDirectory, "company-skills"),
Path.Combine(AppContext.BaseDirectory, "team-skills"),
]);
skills_provider = SkillsProvider(
skill_paths=[
Path(__file__).parent / "company-skills",
Path(__file__).parent / "team-skills",
]
)
每个路径可以指向单个技能文件夹(包含一个 )或具有技能子目录的父文件夹。 提供程序最多搜索两个级别。
自定义系统提示
默认情况下,技能提供程序会注入系统提示,其中列出了可用的技能,并指示代理使用 和 。 可以自定义此提示:
var skillsProvider = new FileAgentSkillsProvider(
skillPath: Path.Combine(AppContext.BaseDirectory, "skills"),
options: new FileAgentSkillsProviderOptions
{
SkillsInstructionPrompt = """
You have skills available. Here they are:
{0}
Use the `load_skill` function to get skill instructions.
Use the `read_skill_resource` function to read skill files.
"""
});
注释
自定义模板必须包含 插入技能列表的占位符。 文本大括号必须转义为 和 。
skills_provider = SkillsProvider(
skill_paths=Path(__file__).parent / "skills",
instruction_template=(
"You have skills available. Here they are:\n{skills}\n"
"Use the `load_skill` function to get skill instructions.\n"
"Use the `read_skill_resource` function to read skill files."
),
)
注释
自定义模板必须包含 插入技能列表的占位符。
代码定义的技能
除了从 SKILL.md 文件中发现的基于文件的技能之外,还可以在Python代码中完全定义技能。 代码定义的技能在以下情况下非常有用:
- 技能内容是动态生成的(例如,从数据库或环境读取)。
- 你希望将技能定义与使用它们的应用程序代码一起保留。
- 你需要在读取时执行逻辑的资源,而不是提供静态文件。
基本代码技能
使用名称、描述和指导内容创建实例。 (可选)附加 包含静态内容的实例:
from textwrap import dedent
from agent_framework import Skill, SkillResource, SkillsProvider
code_style_skill = Skill(
name="code-style",
description="Coding style guidelines and conventions for the team",
content=dedent("""\
Use this skill when answering questions about coding style,
conventions, or best practices for the team.
"""),
resources=[
SkillResource(
name="style-guide",
content=dedent("""\
# Team Coding Style Guide
- Use 4-space indentation (no tabs)
- Maximum line length: 120 characters
- Use type annotations on all public functions
"""),
),
],
)
skills_provider = SkillsProvider(skills=[code_style_skill])
动态资源
使用 修饰器将函数注册为资源。 每次代理读取资源时都会调用此函数,因此可以返回最新的数据。 支持同步和异步函数:
import os
from agent_framework import Skill
project_info_skill = Skill(
name="project-info",
description="Project status and configuration information",
content="Use this skill for questions about the current project.",
)
@project_info_skill.resource
def environment() -> str:
"""Get current environment configuration."""
env = os.environ.get("APP_ENV", "development")
region = os.environ.get("APP_REGION", "us-east-1")
return f"Environment: {env}, Region: {region}"
@project_info_skill.resource(name="team-roster", description="Current team members")
def get_team_roster() -> str:
"""Return the team roster."""
return "Alice Chen (Tech Lead), Bob Smith (Backend Engineer)"
在没有参数的情况下使用修饰器时(),函数名称将成为资源名称,docstring 将成为说明。 用于 显式设置它们。
组合基于文件的技能和代码定义的技能
同时将两个元素传递给一个对象。 首先发现基于文件的技能;如果代码定义的技能与现有基于文件的技能同名,则跳过代码定义的技能:
from pathlib import Path
from agent_framework import Skill, SkillsProvider
my_skill = Skill(
name="my-code-skill",
description="A code-defined skill",
content="Instructions for the skill.",
)
skills_provider = SkillsProvider(
skill_paths=Path(__file__).parent / "skills",
skills=[my_skill],
)
安全最佳做法
代理技能应像引入项目的任何第三方代码一样对待。 由于技能指令注入到代理的上下文中,并且技能可以包括脚本,因此对开放源代码依赖项应用相同的评审和管理级别至关重要。
- 使用前查看 — 在部署之前读取所有技能内容(、脚本和资源)。 验证脚本的实际行为是否与其已声明的意向匹配。 检查尝试绕过安全准则、泄露数据或修改代理配置文件的对抗说明。
- 源信任 - 仅安装受信任的作者或经过审核的内部贡献者的技能。 首选具有明确来源、版本控制和主动维护的技能。 留意通过错拼的方式模仿常用包的技能名称。
- 沙盒 - 运行包含独立环境中的可执行脚本的技能。 仅将文件系统、网络和系统级访问限制为技能所需的内容。 在执行潜在敏感操作前,需要明确用户确认。
- 审核和日志记录 - 记录加载哪些技能、读取哪些资源以及执行哪些脚本。 这为你提供了一个审核线索,用于跟踪代理行为,如果出现问题,可追溯回特定技能内容。
何时使用技能与工作流
代理技能和 代理框架工作流 都扩展了代理可以执行的作,但它们的工作方式基本不同。 选择最符合要求的方法:
- 控制 - 借助技能,AI 决定如何执行指令。 当希望代理具有创造性或自适应性时,这是理想的选择。 使用工作流,可以显式定义执行路径。 如果需要确定性、可预测的行为,请使用工作流。
- 复原能力 - 技能在单个代理轮次内运行。 如果出现故障,则必须重试整个操作。 工作流支持检查点设置,因此可以在失败后从最后一个成功步骤继续。 当重新执行整个进程的成本很高时,请选择工作流。
- 副作用处理 - 技能适用于操作为幂等或低风险的情况。 当步骤产生副作用(发送电子邮件、收费付款)时,首选工作流,这些副作用不应在重试时重复。
- 复杂性 - 技能最适合一个代理可以处理的集中的单域任务。 工作流更适用于协调多个代理、人工审批或外部系统集成的多步骤业务流程。
小窍门
经验法则:如果希望 AI 弄清楚 如何 完成任务,请使用技能。 如果需要保证 执行哪些 步骤以及按何种顺序执行,请使用工作流。
后续步骤
上下文提供器
相关内容
- 代理技能规范
- 上下文提供器
- 工具概述