에이전트 기술은 에이전트 에 특수한 기능 및 도메인 전문 지식을 제공하는 지침, 스크립트 및 리소스의 이식 가능한 패키지입니다. 기술은 개방형 사양을 따르고 점진적 공개 패턴을 구현하므로 에이전트는 필요할 때 필요한 컨텍스트만 로드합니다.
다음을 수행하려는 경우 에이전트 기술을 사용합니다.
- 패키지 도메인 전문 지식 - 재사용 가능한 이식 가능한 패키지로 전문 지식(비용 정책, 법적 워크플로, 데이터 분석 파이프라인)을 캡처합니다.
- 에이전트 기능 확장 - 핵심 지침을 변경하지 않고 에이전트에 새로운 기능을 제공합니다.
- 일관성 보장 - 다단계 작업을 반복 가능한 감사 가능한 워크플로로 전환합니다.
- 상호 운용성 지원 - 다양한 Agent Skills 호환 제품에서 동일한 스킬을 재사용할 수 있습니다.
기술 구조
기술은 리소스에 대한 선택적 하위 디렉터리가 있는 파일을 포함하는 SKILL.md 디렉터리입니다.
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 형식
파일에는 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 |
아니오 | 기술이 사용할 수 있는 미리 승인된 도구의 공간으로 구분된 목록입니다. 실험적 - 지원은 에이전트 구현마다 다를 수 있습니다. |
프런트매터 뒤의 markdown 본문에는 단계별 지침, 입력 및 출력 예제, 일반적인 에지 사례 또는 에이전트가 작업을 수행하는 데 도움이 되는 콘텐츠와 같은 기술 지침이 포함되어 있습니다. 500줄 미만으로 유지하고 SKILL.md 자세한 참조 자료를 별도의 파일로 이동합니다.
점진적 공개
에이전트 기술은 4단계 점진적 공개 패턴을 사용하여 컨텍스트 사용을 최소화합니다.
- Advertise (기술당 최대 100개 토큰) - 각 실행이 시작될 때 기술 이름 및 설명이 시스템 프롬프트에 삽입되므로 에이전트는 사용 가능한 기술을 알 수 있습니다.
-
로드 (< 권장 토큰 5,000개) - 작업이 기술의 도메인과 일치하면 에이전트는 도구를 호출
load_skill하여 자세한 지침과 함께 전체 SKILL.md 본문을 검색합니다. -
필요한 경우 리소스 읽기 - 에이전트는 필요한 경우에만 보조 파일(참조, 템플릿, 자산)을 가져오기 위해 도구를 호출
read_skill_resource합니다. -
스크립트 실행 (필요한 경우) - 에이전트는
run_skill_script도구를 호출하여 스킬에 포함된 스크립트를 실행합니다.
이 패턴은 에이전트의 컨텍스트 창을 간결하게 유지하면서 요청 시 심층 도메인 지식에 액세스할 수 있도록 합니다.
비고
load_skill 는 항상 광고됩니다.
read_skill_resource 는 하나 이상의 기술에 리소스가 있는 경우에만 보급됩니다.
run_skill_script 는 하나 이상의 기술에 스크립트가 있는 경우에만 보급됩니다.
에이전트에 기술 제공
기술 작업에는 다음 세 가지 구성 요소가 포함됩니다.
-
공급자 -
AgentSkillsProvider(C#) 또는SkillsProvider(Python)는 에이전트에 기술을 노출하는 컨텍스트 공급자입니다. 시스템 프롬프트에서 사용 가능한 기술을 보급하고 에이전트가 기술을 로드하고, 리소스를 읽고, 스크립트를 실행하는 데 사용하는 도구를 등록합니다. -
소스 - 소스는 공급자에게 기술을 제공합니다. 기술은 다음과 같은 여러 소스 유형에서 제공됩니다.
-
파일 기반 - 파일 시스템 디렉터리의
SKILL.md파일에서 발견된 스킬입니다. -
코드 정의 - (C#) 또는
AgentInlineSkill(Python)을 사용하여InlineSkill코드에서 인라인으로 정의된 기술입니다. -
클래스 기반 - (C#) 또는
AgentClassSkill<T>(Python)에서 파생되는 클래스에ClassSkill캡슐화된 기술입니다. -
MCP 기반 - (C#) 또는
UseMcpSkills(Python)을 통해MCPSkillsSourceMCP(모델 컨텍스트 프로토콜) 서버에서 검색된 기술입니다.
-
파일 기반 - 파일 시스템 디렉터리의
-
작성기 -
AgentSkillsProviderBuilder(C#)는 집계, 중복 제거, 캐싱 및 선택적 필터링을 적용하여 여러 원본을 단일 공급자로 어셈블합니다. Python 원본 클래스(예:AggregatingSkillsSourceFilteringSkillsSourceDeduplicatingSkillsSource직접)를 작성합니다.
다음 섹션에서는 각 소스 형식의 기술을 만드는 방법을 보여 줍니다. 그런 다음 원본을 결합하고 해당 소스에서 공급자를 생성하는 방법을 보여 줍니다.
Harness 에이전트에서 에이전트 기술 사용
일반 에이전트를 사용하여 기술 공급자를 만들고, 에이전트의 컨텍스트 공급자에 추가하고, 필요한 경우 도구 승인 미들웨어를 작성합니다. Harness 에이전트는 공급자를 표준 설정의 일부로 만들거나 포함할 수 있습니다.
HarnessAgent 는 기본적으로 포함 AgentSkillsProvider 되며 파일 기반 기술을 Directory.GetCurrentDirectory()검색합니다. 다른 소스를 사용하려면 다음을 설정합니다 HarnessAgentOptions.AgentSkillsSource.
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
AIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions
{
AgentSkillsSource = new AgentFileSkillsSource(
Path.Combine(AppContext.BaseDirectory, "skills")),
ToolApprovalAgentOptions = new ToolApprovalAgentOptions
{
// Auto-approve load_skill and read_skill_resource, but not run_skill_script.
AutoApprovalRules = [AgentSkillsProvider.ReadOnlyToolsAutoApprovalRule],
},
ChatOptions = new ChatOptions
{
Instructions = "Use the available skills when they match the task.",
},
});
DisableAgentSkillsProvider 기본값은 false입니다. 기본 제공 공급자를 제거하도록 true 설정합니다.
AgentSkillsSource 는 기본 현재 디렉터리 원본을 대체하지만 노출 AgentSkillsProviderOptions되지는 않습니다. 같은 DisableLoadSkillApproval공급자 옵션이 필요한 경우 기본 제공 공급자를 사용하지 않도록 설정하고 구성 AgentSkillsProvider 한 공급자를 추가합니다 HarnessAgentOptions.AIContextProviders.
파일 기반 기술에서 스크립트를 실행하려면 대리자를 AgentFileSkillScriptRunner 두 번째 AgentFileSkillsSource 생성자 인수로 전달합니다. 실행기를 사용하지 않으면 요청 시 스크립트 실행이 실패합니다.
세 가지 기술 도구 모두 기본적으로 승인이 필요합니다. 하네스 도구 승인 미들웨어는 기본적으로 사용하도록 설정되어 있지만 기본 옵션은 도구를 자동으로 승인하지 않습니다. 신뢰하는 기술 원본에만 사용 AgentSkillsProvider.ReadOnlyToolsAutoApprovalRule 하거나 AgentSkillsProvider.AllToolsAutoApprovalRule 사용합니다.
에이전트 기술은 옵트인(opt-in)입니다 create_harness_agent. 파일 기반 검색을 위한 전달 skills_paths :
from pathlib import Path
from agent_framework import SkillsProvider, create_harness_agent
agent = create_harness_agent(
client=client,
agent_instructions="Use the available skills when they match the task.",
skills_paths=Path(__file__).parent / "skills",
# Auto-approve load_skill and read_skill_resource, but not run_skill_script.
auto_approval_rules=[SkillsProvider.read_only_tools_auto_approval_rule],
)
session = agent.create_session()
result = await agent.run("Use the appropriate skill for this task.", session=session)
skills_paths 는 하나 str 또는 Path시퀀스를 허용합니다. 둘 다 skills_provider ( skills_pathsNone 기본값)인 경우 하네스는 .를 SkillsProvider추가하지 않습니다. 두 매개 변수를 결합하여 코드 정의 및 파일 기반 기술을 포함할 수 있습니다.
바로 가기는 skills_paths .SkillsProvider.from_paths()script_runner 파일 기반 기술이 스크립트를 실행해야 하는 경우 공급자를 직접 SkillsProvider.from_paths(..., script_runner=...) 만들어 전달 skills_provider합니다.
세 가지 기술 도구 모두 기본적으로 승인이 필요합니다. Harness는 기본적으로 설치 ToolApprovalMiddleware 되므로 모든 실행에 세션을 전달하고 신뢰할 수 있는 읽기 전용 또는 모든 도구 승인 정책에 사용합니다 auto_approval_rules .
패키지된 Go 하네스는 현재 사용할 수 없습니다. Go 기술 공급자 agent.Config.ContextProviders 를 등록하고 승인 미들웨어를 직접 작성합니다.
파일 기반 기술
생성한 AgentSkillsProvider를 기술을 포함하는 디렉터리를 가리키도록 하고, 이를 에이전트의 컨텍스트 공급자에 추가합니다. 스크립트 실행기를 전달하여 기술 디렉터리에 있는 파일 기반 스크립트를 실행할 수 있습니다.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using OpenAI.Responses;
string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!;
string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// Discover skills from the 'skills' directory
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"));
// Create an agent with the skills provider
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new()
{
Instructions = "You are a helpful assistant.",
},
AIContextProviders = [skillsProvider],
},
model: deploymentName);
경고
DefaultAzureCredential 은 개발에 편리하지만 프로덕션 환경에서 신중하게 고려해야 합니다. 프로덕션 환경에서는 특정 자격 증명(예: ManagedIdentityCredential)을 사용하여 대기 시간 문제, 의도하지 않은 자격 증명 검색 및 대체 메커니즘의 잠재적인 보안 위험을 방지하는 것이 좋습니다.
여러 기술 디렉터리
공급자가 단일 상위 디렉터리를 가리키도록 지정할 수 있습니다. SKILL.md가 포함된 각 하위 디렉터리는 스킬로 자동 검색됩니다:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "all-skills"));
또는 경로 목록을 전달하여 여러 루트 디렉터리를 검색합니다.
var skillsProvider = new AgentSkillsProvider(
[
Path.Combine(AppContext.BaseDirectory, "company-skills"),
Path.Combine(AppContext.BaseDirectory, "team-skills"),
]);
공급자는 최대 2단계 깊이로 검색합니다.
리소스 및 스크립트 검색 사용자 지정
기본적으로 공급자는 확장자가 .md, .json, .yaml, .yml, .csv, .xml, .txt인 리소스와 확장자가 .py, .js, .sh, .ps1, .cs, .csx인 스크립트를 인식합니다. 각 기술 디렉터리 내에서 최대 2개의 수준을 검색합니다. 다음 기본값을 변경하는 데 사용합니다 AgentFileSkillsSourceOptions .
var fileOptions = new AgentFileSkillsSourceOptions
{
AllowedResourceExtensions = [".md", ".txt"],
AllowedScriptExtensions = [".py"],
SearchDepth = 3, // Search up to 3 levels deep (default is 2)
ResourceFilter = context => context.RelativeFilePath.StartsWith("references/"),
ScriptFilter = context => context.RelativeFilePath.StartsWith("scripts/")
|| context.RelativeFilePath.StartsWith("tools/"),
};
// Via constructor
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
fileOptions: fileOptions);
// Via builder
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"), options: fileOptions)
.Build();
ResourceFilter 및 ScriptFilter는 기술 이름과 파일의 상대 경로가 포함된 AgentFileSkillFilterContext를 받으며, 이를 통해 위치, 명명 규칙 또는 사용자 지정 논리에 따라 파일을 제한할 수 있습니다.
스크립트 실행
SubprocessScriptRunner.RunAsync를 스크립트 실행기로 전달하여 파일 기반 스크립트를 실행할 수 있도록 합니다.
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync);
SubprocessScriptRunner.RunAsync 는 다음과 거의 동일합니다.
// Simplified equivalent of what SubprocessScriptRunner.RunAsync does internally
using System.Diagnostics;
using System.Text.Json;
static async Task<object?> RunAsync(
AgentFileSkill skill,
AgentFileSkillScript script,
JsonElement? args,
IServiceProvider? serviceProvider,
CancellationToken cancellationToken)
{
var psi = new ProcessStartInfo("python3")
{
RedirectStandardOutput = true,
UseShellExecute = false,
};
psi.ArgumentList.Add(script.FullPath);
if (args is { ValueKind: JsonValueKind.Array } json)
{
foreach (var element in json.EnumerateArray())
{
psi.ArgumentList.Add(element.GetString()!);
}
}
using var process = Process.Start(psi)!;
string output = await process.StandardOutput.ReadToEndAsync(cancellationToken);
await process.WaitForExitAsync(cancellationToken);
return output.Trim();
}
실행기는 검색된 각 스크립트를 로컬 하위 프로세스로 실행합니다. 파일 기반 스크립트는 문자열의 JSON 배열로 인수를 예상합니다. 각 배열 요소는 위치 명령줄 인수가 됩니다.
경고
SubprocessScriptRunner 은 데모용으로만 제공됩니다. 프로덕션 사용을 위해 다음을 추가하는 것이 좋습니다.
- 샌드박싱(예: 컨테이너 또는 격리된 실행 환경)
- 리소스 제한(CPU, 메모리, 벽시계 시간 제한)
- 실행 스크립트의 입력 유효성 검사 및 허용 목록
- 구조적 로깅 및 감사 추적
파일 기반 기술
팩터리를 SkillsProvider.from_paths() 사용하여 파일이 포함된 SKILL.md 디렉터리에서 기술을 검색하고 에이전트의 컨텍스트 공급자에 공급자를 추가합니다.
import os
from pathlib import Path
# Discover skills from the 'skills' directory
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
)
# Create an agent with the skills provider
endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
deployment = os.environ.get("FOUNDRY_MODEL", "gpt-4o-mini")
client = FoundryChatClient(
project_endpoint=endpoint,
model=deployment,
credential=AzureCliCredential(),
)
agent = Agent(
client=client,
instructions="You are a helpful assistant.",
context_providers=[skills_provider],
)
여러 기술 디렉터리
공급자가 단일 상위 디렉터리를 가리키도록 지정할 수 있습니다. SKILL.md가 포함된 각 하위 디렉터리는 스킬로 자동 검색됩니다:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "all-skills"
)
또는 경로 목록을 전달하여 여러 루트 디렉터리를 검색합니다.
skills_provider = SkillsProvider.from_paths(
skill_paths=[
Path(__file__).parent / "company-skills",
Path(__file__).parent / "team-skills",
]
)
공급자는 최대 2단계 깊이로 검색합니다.
리소스 및 스크립트 검색 사용자 지정
기본적으로 리소스는 references/ 및 assets/ 하위 디렉터리에서, 스크립트는 scripts/에서 agentskills.io specification에 따라 검색됩니다. 인식된 리소스 확장은 .md, .json,.yaml.yml, .csv.xml및 .txt. 각 기술 디렉터리 내에서 최대 2개의 수준을 검색합니다.
resource_extensions, script_extensions, 및 search_depthresource_filterscript_filter 검색을 사용자 지정합니다.
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
resource_extensions=(".md", ".txt"),
script_extensions=(".py", ".sh"),
search_depth=3, # Search up to 3 levels deep (default is 2)
resource_filter=lambda skill_name, path: path.startswith("references/"),
script_filter=lambda skill_name, path: path.startswith("scripts/"),
)
resource_filter 및 script_filter 프레디킷은 스킬 이름과 파일의 상대 경로를 전달받아 위치, 명명 규칙 또는 사용자 지정 로직에 따라 파일을 제한할 수 있습니다. 하위 디렉터리 외에도 기술 루트 수준에서 파일을 포함하는 데 사용합니다 "." .
스크립트 실행
파일 기반 스크립트 실행을 허용하려면 script_runner를 SkillsProvider.from_paths()로 전달해야 합니다. 프로토콜을 충족하는 모든 동기 또는 비동기 호출 가능한 객체를 SkillScriptRunner 사용할 수 있습니다.
from pathlib import Path
from agent_framework import FileSkill, FileSkillScript, SkillsProvider
def my_runner(
skill: FileSkill,
script: FileSkillScript,
args: dict | list[str] | None = None,
) -> str:
"""Run a file-based script as a subprocess."""
import subprocess, sys
script_path = Path(script.full_path)
cmd = [sys.executable, str(script_path)]
if isinstance(args, list):
cmd.extend(args)
result = subprocess.run(
cmd, capture_output=True, text=True, timeout=30, cwd=str(script_path.parent)
)
return result.stdout.strip()
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
script_runner=my_runner,
)
러너는 해결된 FileSkill, FileSkillScript 및 선택적 args 인수를 받습니다. 파일 기반 스크립트는 문자열의 JSON 배열로 인수를 예상합니다. 각 배열 요소는 위치 명령줄 인수가 됩니다. 스크립트는 각 스킬 디렉터리의 .py 하위 디렉터리에 있는 scripts/ 파일에서 자동으로 검색됩니다.
경고
위의 실행기는 데모용으로만 제공됩니다. 프로덕션 사용을 위해 다음을 추가하는 것이 좋습니다.
- 샌드박싱(예: 컨테이너
seccomp또는firejail) - 리소스 제한(CPU, 메모리, 벽시계 시간 제한)
- 실행 스크립트의 입력 유효성 검사 및 허용 목록
- 구조적 로깅 및 감사 추적
비고
스크립트가 포함된 파일 기반 스킬이 제공되지만 script_runner이 설정되지 않은 경우, 스크립트 실행을 시도하면 SkillsProvider이 오류를 발생시킵니다.
파일 기반 기술
Go 에이전트는 agent/skills 패키지를 통해 스킬을 지원합니다. 스킬은 동일한 점진적 노출 패턴을 따릅니다: 알리기 -> 로드 -> 리소스 읽기 -> 스크립트 실행.
디스크의 파일에서 SKILL.md 기술을 검색하고 기술 공급자를 에이전트 컨텍스트 공급자로 등록합니다.
import (
"os"
"github.com/microsoft/agent-framework-go/agent"
"github.com/microsoft/agent-framework-go/provider/foundryprovider"
"github.com/microsoft/agent-framework-go/agent/skills"
"github.com/microsoft/agent-framework-go/agent/skills/fsskills"
)
skillsRoot, _ := os.OpenRoot("skills")
defer skillsRoot.Close()
skillsProvider := skills.NewContextProvider(skills.ContextProviderOptions{
Sources: []skills.Source{
fsskills.NewSourceOptions(fsskills.SourceOptions{}, skillsRoot.FS()),
},
})
a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
Instructions: "You are a helpful assistant.",
Config: agent.Config{
ContextProviders: []agent.ContextProvider{skillsProvider},
},
})
코드 정의 기술
SKILL.md 파일에서 검색된 파일 기반 기술 외에도 AgentInlineSkill을 사용하여 코드에서 기술을 완전하게 정의할 수 있습니다. 코드 정의 기술은 다음과 같은 경우에 유용합니다.
- 기술 콘텐츠는 동적으로 생성됩니다(예: 데이터베이스 또는 환경에서 읽기).
- 기술 정의를 해당 애플리케이션 코드와 함께 보관하려고 합니다.
- 정적 파일을 제공하는 대신 읽기 시간에 논리를 실행하는 리소스가 필요합니다.
- 데이터 에서 런타임에 기술 정의를 생성해야 합니다. 예를 들어 해당 역할 또는 권한에 따라 각 사용자 세션에 대해 개인 설정된 기술을 만들어야 합니다.
- 스킬은 DI 컨테이너에서 서비스를 해결하는 대신 호출 지점 상태(지역 변수, 클로저)를 캡처해야 합니다.
기본 코드 기술
AgentInlineSkill을(를) 이름, 설명 및 지침을 포함하여 생성합니다.
.AddResource()을 사용하여 리소스를 연결합니다.
using Microsoft.Agents.AI;
var codeStyleSkill = new AgentInlineSkill(
name: "code-style",
description: "Coding style guidelines and conventions for the team",
instructions: """
Use this skill when answering questions about coding style, conventions, or best practices for the team.
1. Read the style-guide resource for the full set of rules.
2. Answer based on those rules, quoting the relevant guideline where helpful.
""")
.AddResource(
"style-guide",
"""
# Team Coding Style Guide
- Use 4-space indentation (no tabs)
- Maximum line length: 120 characters
- Use type annotations on all public methods
""");
var skillsProvider = new AgentSkillsProvider(codeStyleSkill);
동적 리소스
런타임에 콘텐츠를 계산하기 위해 .AddResource()에 팩터리 대리자를 전달합니다. 에이전트가 리소스를 읽을 때마다 대리자가 호출됩니다.
var projectInfoSkill = new AgentInlineSkill(
name: "project-info",
description: "Project status and configuration information",
instructions: """
Use this skill for questions about the current project.
1. Read the environment resource for deployment configuration details.
2. Read the team-roster resource for information about team members.
""")
.AddResource("environment", () =>
{
string env = Environment.GetEnvironmentVariable("APP_ENV") ?? "development";
string region = Environment.GetEnvironmentVariable("APP_REGION") ?? "us-east-1";
return $"Environment: {env}, Region: {region}";
})
.AddResource(
"team-roster",
"Alice Chen (Tech Lead), Bob Smith (Backend Engineer)");
코드 정의 스크립트
대리자를 실행 스크립트로 등록하는 데 사용합니다 .AddScript() . 코드 정의 스크립트는 직접 위임 호출로 인프로세스에서 실행됩니다. 스크립트 실행기는 필요하지 않습니다. 대리자의 형식화된 매개 변수는 에이전트가 인수를 전달하는 데 사용하는 JSON 스키마로 자동으로 변환됩니다.
using System.Text.Json;
var unitConverterSkill = new AgentInlineSkill(
name: "unit-converter",
description: "Convert between common units using a conversion factor",
instructions: """
Use this skill when the user asks to convert between units.
1. Review the conversion-table resource to find the correct factor.
2. Use the convert script, passing the value and factor from the table.
3. Present the result clearly with both units.
""")
.AddResource(
"conversion-table",
"""
# Conversion Tables
Formula: **result = value × factor**
| From | To | Factor |
|------------|------------|----------|
| miles | kilometers | 1.60934 |
| kilometers | miles | 0.621371 |
| pounds | kilograms | 0.453592 |
| kilograms | pounds | 2.20462 |
""")
.AddScript("convert", (double value, double factor) =>
{
double result = Math.Round(value * factor, 4);
return JsonSerializer.Serialize(new { value, factor, result });
});
var skillsProvider = new AgentSkillsProvider(unitConverterSkill);
비고
단일 공급자 AgentSkillsProviderBuilder 의 파일 기반 또는 클래스 기반 기술과 코드 정의 기술을 결합하려면 공급자 생성을 참조하세요.
SKILL.md 파일에서 검색된 파일 기반 기술 외에도 InlineSkill 사용하여 Python 코드에서 기술을 완전히 정의할 수 있습니다. 코드 정의 기술은 다음과 같은 경우에 유용합니다.
- 기술 콘텐츠는 동적으로 생성됩니다(예: 데이터베이스 또는 환경에서 읽기).
- 기술 정의를 해당 애플리케이션 코드와 함께 보관하려고 합니다.
- 정적 파일을 제공하는 대신 읽기 시간에 논리를 실행하는 리소스가 필요합니다.
- 데이터 에서 런타임에 기술 정의를 생성해야 합니다. 예를 들어 해당 역할 또는 권한에 따라 각 사용자 세션에 대해 개인 설정된 기술을 만들어야 합니다.
- 스킬은 를 통해 서비스를 확인하는 대신
**kwargs(지역 변수, 클로저)를 캡처해야 합니다.
기본 코드 기술
InlineSkill(이름과 설명 포함) 및 지침 콘텐츠로 SkillFrontmatter 인스턴스를 생성합니다. 선택적으로 InlineSkillResource 인스턴스를 정적 콘텐츠와 함께 연결합니다.
from textwrap import dedent
from agent_framework import InlineSkill, InlineSkillResource, SkillFrontmatter, SkillsProvider
code_style_skill = InlineSkill(
frontmatter=SkillFrontmatter(
name="code-style",
description="Coding style guidelines and conventions for the team",
),
instructions=dedent("""\
Use this skill when answering questions about coding style,
conventions, or best practices for the team.
"""),
resources=[
InlineSkillResource(
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(code_style_skill)
동적 리소스
데코레이터를 @skill.resource 사용하여 함수를 리소스로 등록합니다. 이 함수는 에이전트가 리소스를 읽을 때마다 호출되므로 up-to-date 데이터를 반환할 수 있습니다. 동기화 및 비동기 함수는 모두 지원됩니다.
import os
from agent_framework import InlineSkill, SkillFrontmatter
project_info_skill = InlineSkill(
frontmatter=SkillFrontmatter(
name="project-info",
description="Project status and configuration information",
),
instructions="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)"
데코레이터를 인수@skill.resource 없이 사용하면 함수 이름이 리소스 이름이 되고 문서 문자열이 설명이 됩니다.
@skill.resource(name="...", description="...")를 명시적으로 설정하는 데 사용합니다.
코드 정의 스크립트
데코레이터를 @skill.script 사용하여 함수를 기술에 대한 실행 스크립트로 등록합니다. 코드 정의 스크립트는 프로세스에서 실행되며 스크립트 실행기를 필요로 하지 않습니다. 동기화 및 비동기 함수는 모두 지원됩니다.
from agent_framework import InlineSkill, SkillFrontmatter
unit_converter_skill = InlineSkill(
frontmatter=SkillFrontmatter(
name="unit-converter",
description="Convert between common units using a conversion factor",
),
instructions="Use the convert script to perform unit conversions.",
)
@unit_converter_skill.script(name="convert", description="Convert a value: result = value × factor")
def convert_units(value: float, factor: float) -> str:
"""Convert a value using a multiplication factor."""
import json
result = round(value * factor, 4)
return json.dumps({"value": value, "factor": factor, "result": result})
데코레이터를 인수@skill.script 없이 사용하면 함수 이름이 스크립트 이름이 되고 문서 문자열이 설명이 됩니다. 함수의 형식화된 매개 변수는 에이전트가 인수를 전달하는 데 사용하는 JSON 스키마로 자동으로 변환됩니다.
파일에서 SKILL.md 검색된 파일 기반 기술 외에도 Go 코드에서 기술을 완전히 정의할 수 있습니다.
skill := &skills.Skill{
Frontmatter: skills.Frontmatter{
Name: "unit-converter",
Description: "Convert between common units using a multiplication factor.",
},
GetContent: func(context.Context) (string, error) {
return "Use this skill when the user asks to convert between units.", nil
},
Resources: []skills.Resource{
{
Name: "conversion-table",
Description: "Lookup table of multiplication factors.",
Read: func(context.Context) (any, error) {
return conversionTable, nil
},
},
},
Scripts: []skills.Script{
{
Name: "convert",
Description: "Multiplies a value by a conversion factor. Pass value and factor as positional string arguments: [\"<value>\", \"<factor>\"].",
Run: func(_ context.Context, _ *skills.Skill, args []string) (any, error) {
if len(args) != 2 {
return nil, fmt.Errorf("expected value and factor")
}
value, err := strconv.ParseFloat(args[0], 64)
if err != nil {
return nil, err
}
factor, err := strconv.ParseFloat(args[1], 64)
if err != nil {
return nil, err
}
return map[string]any{
"value": value,
"factor": factor,
"result": value * factor,
}, nil
},
},
},
}
provider := skills.NewContextProvider(skills.ContextProviderOptions{
Skills: []*skills.Skill{skill},
})
GetContent는 에이전트가 load_skill를 호출할 때만 스킬 지침을 로드합니다. 스크립트는 예를 들어 ["26.2", "1.60934"]와 같은 위치 기반의 CLI 스타일 문자열 인수를 받으며, 스크립트에 필요한 방식대로 해당 인수를 구문 분석할 수 있습니다.
팁 (조언)
완전히 실행 가능한 샘플은 스킬 예제를 참조하세요.
클래스 기반 기술
클래스 기반 기술을 사용하면 이름, 설명, 지침, 리소스 및 스크립트와 같은 모든 기술 구성 요소를 단일 C# 클래스로 묶을 수 있습니다. 이렇게 하면 NuGet 패키지로 쉽게 패키징하고 배포할 수 있습니다. 팀은 스킬을 독립적으로 작성하고 배포할 수 있으며, 사용자는 dotnet add package 및 한 번의 .UseSkill() 호출로 이를 추가할 수 있습니다.
AgentClassSkill<T>(T이 당신의 클래스)에서 파생된 후, 속성에 [AgentSkillResource]를 그리고 메서드에 [AgentSkillScript]를 주석으로 추가하여 자동 검색을 수행합니다.
using System.ComponentModel;
using System.Text.Json;
using Microsoft.Agents.AI;
internal sealed class UnitConverterSkill : AgentClassSkill<UnitConverterSkill>
{
public override AgentSkillFrontmatter Frontmatter { get; } = new(
"unit-converter",
"Convert between common units using a multiplication factor. Use when asked to convert miles, kilometers, pounds, or kilograms.");
protected override string Instructions => """
Use this skill when the user asks to convert between units.
1. Review the conversion-table resource to find the correct factor.
2. Use the convert script, passing the value and factor from the table.
3. Present the result clearly with both units.
""";
[AgentSkillResource("conversion-table")]
[Description("Lookup table of multiplication factors for common unit conversions.")]
public string ConversionTable => """
# Conversion Tables
Formula: **result = value × factor**
| From | To | Factor |
|------------|------------|----------|
| miles | kilometers | 1.60934 |
| kilometers | miles | 0.621371 |
| pounds | kilograms | 0.453592 |
| kilograms | pounds | 2.20462 |
""";
[AgentSkillScript("convert")]
[Description("Multiplies a value by a conversion factor and returns the result as JSON.")]
private static string ConvertUnits(double value, double factor)
{
double result = Math.Round(value * factor, 4);
return JsonSerializer.Serialize(new { value, factor, result });
}
}
다음을 사용하여 클래스 기반 기술을 등록합니다.AgentSkillsProvider
var skill = new UnitConverterSkill();
var skillsProvider = new AgentSkillsProvider(skill);
속성 또는 메서드에 [AgentSkillResource] 특성을 적용하면 에이전트가 리소스를 읽을 때 반환 값이 리소스 콘텐츠로 사용됩니다. 읽기 시간에 콘텐츠를 계산해야 하는 경우 메서드를 사용합니다.
[AgentSkillScript] 메서드에 적용되면 에이전트가 스크립트를 호출할 때 메서드가 호출됩니다. 원본 [Description] 을 사용하여 System.ComponentModel 에이전트에 대한 각 리소스 및 스크립트를 설명합니다.
비고
AgentClassSkill<T> 또한 특성 기반 검색이 적합하지 않은 시나리오에서 Resources 및 Scripts를 컬렉션으로 재정의하는 것을 지원합니다.
클래스 기반 기술
클래스 기반 기술을 사용하면 이름, 설명, 지침, 리소스 및 스크립트와 같은 모든 기술 구성 요소를 단일 Python 클래스로 번들로 묶을 수 있습니다. 이 덕분에 이를 PyPI 패키지로 쉽게 패키징하여 배포할 수 있습니다. 팀은 스킬을 독립적으로 작성하고 배포할 수 있으며, 사용자는 pip install 및 단 한 번의 SkillsProvider() 호출로 이를 추가할 수 있습니다.
ClassSkill를 하위 클래스로 만든 다음, 자동으로 검색되도록 @ClassSkill.resource 및 @ClassSkill.script 데코레이터를 사용합니다.
import json
from textwrap import dedent
from agent_framework import ClassSkill, SkillFrontmatter
class UnitConverterSkill(ClassSkill):
"""A unit-converter skill defined as a Python class."""
def __init__(self) -> None:
super().__init__(
frontmatter=SkillFrontmatter(
name="unit-converter",
description=(
"Convert between common units using a multiplication factor. "
"Use when asked to convert miles, kilometers, pounds, or kilograms."
),
),
)
@property
def instructions(self) -> str:
return dedent("""\
Use this skill when the user asks to convert between units.
1. Review the conversion-table resource to find the correct factor.
2. Use the convert script, passing the value and factor from the table.
3. Present the result clearly with both units.
""")
@property
@ClassSkill.resource
def conversion_table(self) -> str:
"""Lookup table of multiplication factors for common unit conversions."""
return dedent("""\
# Conversion Tables
Formula: **result = value × factor**
| From | To | Factor |
|------------|------------|----------|
| miles | kilometers | 1.60934 |
| kilometers | miles | 0.621371 |
| pounds | kilograms | 0.453592 |
| kilograms | pounds | 2.20462 |
""")
@ClassSkill.script(name="convert", description="Multiplies a value by a conversion factor.")
def convert_units(self, value: float, factor: float) -> str:
"""Convert a value using a multiplication factor."""
result = round(value * factor, 4)
return json.dumps({"value": value, "factor": factor, "result": result})
다음을 사용하여 클래스 기반 기술을 등록합니다.SkillsProvider
from agent_framework import SkillsProvider
skill = UnitConverterSkill()
skills_provider = SkillsProvider(skill)
@ClassSkill.resource를 인수 없는 순수 데코레이터로 적용하면 메서드 이름이 리소스 이름이 되고(이때 밑줄은 하이픈으로 변환됨), 독스트링이 설명이 됩니다.
@ClassSkill.resource(name="...", description="...")를 명시적으로 설정하는 데 사용합니다. 동일한 패턴이 적용됩니다.@ClassSkill.script
리소스는 일반 메서드 또는 @property 설명자로 정의할 수 있습니다.
@property를 사용할 때는 @property을 먼저 배치하고 @ClassSkill.resource를 두 번째로 배치합니다. 리소스 반환 값은 첫 번째 액세스 후에 캐시됩니다.
비고
ClassSkill 또한 데코레이터 기반 검색 방식이 적합하지 않은 시나리오에서는 resources 및 scripts 속성을 명시적으로 재정의하여 InlineSkillResource 및 InlineSkillScript 인스턴스를 직접 반환하는 것도 지원합니다.
MCP 기반 기술
비고
MCP 기반 기술에는 NuGet 패키지가 Microsoft.Agents.AI.Mcp 필요합니다. MCP 기술 API는 실험적이며 향후 릴리스에서 변경될 수 있습니다.
스킬은 skill:// URI 체계 아래에서 스킬 리소스를 노출하는 MCP(모델 컨텍스트 프로토콜) 서버에서 찾을 수 있습니다. MCP 서버는 검색 문서를 통해 skill://index.json 기술을 보급하고 프레임워크는 요청 시 기술 콘텐츠를 가져옵니다.
MCP 기반 기술은 다음 두 가지 인덱스 항목 유형을 지원합니다.
-
skill-md- 스킬의SKILL.md및 형제 리소스는 요청 시점에 MCP 서버에서 가져옵니다. -
archive- 스킬은 단일 패키지 아카이브(ZIP, TAR 또는 gzip으로 압축된 TAR) 형태로 배포되며, 이를 로컬에 다운로드하여 압축을 해제합니다.
기본 사용법
UseMcpSkills에서 AgentSkillsProviderBuilder 확장 메서드를 사용하여 MCP 스킬 소스를 추가하려면:
using Microsoft.Agents.AI;
using ModelContextProtocol.Client;
// Connect to the MCP server
await using McpClient client = await McpClient.CreateAsync(
new StdioClientTransport(new()
{
Name = "skills-server",
Command = "dotnet",
Arguments = [skillsServerPath, "--server"],
}));
// Build a skills provider that discovers skills over MCP
var skillsProvider = new AgentSkillsProviderBuilder()
.UseMcpSkills(client)
.Build();
// Create an agent with the MCP skills
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new()
{
Instructions = "You are a helpful assistant. Use available skills to answer the user.",
},
AIContextProviders = [skillsProvider],
},
model: deploymentName);
아카이브형 스킬
아카이브 유형 스킬의 경우, 추출 동작을 구성하려면 AgentMcpSkillsSourceOptions 패키지의 Microsoft.Agents.AI.Mcp를 사용하세요.
var skillsProvider = new AgentSkillsProviderBuilder()
.UseMcpSkills(client, new AgentMcpSkillsSourceOptions
{
ArchiveSkillsDirectory = Path.Combine(AppContext.BaseDirectory, "extracted-skills"),
ArchiveMaxFileCount = 50,
ArchiveMaxSizeBytes = 2 * 1024 * 1024, // 2 MB
})
.Build();
AgentMcpSkillsSourceOptions 는 보관 추출을 제어하기 위해 다음 속성을 노출합니다.
-
ArchiveSkillsDirectory- 추출된 보관 파일의 기본 디렉터리입니다. 여러 원본 간의 충돌을 방지하기 위해 원본 인스턴스별로 생성된 현재 작업 디렉터리 아래에 있는 고유한 하위 디렉터리로 기본값이 지정됩니다. -
ArchiveResourceExtensions- 추출된 보관 파일의 리소스에 대해 허용되는 확장입니다. 기본값은.md,.json,.yaml,.yml.csv,.xml..txt -
ArchiveResourceSearchDepth- 추출된 각 스킬 디렉터리 내에서 리소스를 얼마나 깊이 검색할지입니다. 기본값은2입니다. -
ArchiveMaxFileCount- 보관할당 최대 파일 수입니다. 이 제한을 초과하는 보관 파일은 건너뛰어집니다. 기본값은20입니다. -
ArchiveMaxSizeBytes- 아카이브당 최대 다운로드 크기. 기본값은1 MB입니다. -
ArchiveMaxUncompressedSizeBytes- 보관 파일당 압축되지 않은 최대 크기입니다. 기본값은1 MB입니다.
Important
보관 형식 기술로 번들로 제공되는 스크립트는 실행되지 않습니다. 이는 의도적인 보안 조치입니다. 원격 MCP 서버의 실행 가능한 콘텐츠에는 명시적 신뢰가 필요합니다.
MCP 기반 기술
비고
MCP 기반 기술은 실험적이며 향후 릴리스에서 변경될 수 있습니다.
MCPSkillsSource 기능 플래그에서 FutureWarning을 사용하면 MCP_SKILLS이 생성됩니다.
스킬은 skill:// URI 체계 아래에서 스킬 리소스를 노출하는 MCP(모델 컨텍스트 프로토콜) 서버에서 찾을 수 있습니다. MCP 서버는 skill://index.json 디스커버리 문서를 통해 스킬을 알리고, 프레임워크는 필요할 때 SKILL.md를 통해 각 스킬의 resources/read 본문을 가져옵니다.
MCP ClientSession를 MCPSkillsSource로 래핑하고 SkillsProvider에 전달합니다:
import os
from agent_framework import Agent, MCPSkillsSource, SkillsProvider, ToolApprovalMiddleware
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamable_http_client
mcp_url = os.environ["MCP_SKILLS_SERVER_URL"]
# Connect to the MCP server over streamable HTTP
async with streamable_http_client(url=mcp_url) as (read, write, _), ClientSession(read, write) as session:
await session.initialize()
# MCPSkillsSource reads skill://index.json and creates one skill per
# skill-md entry; SKILL.md bodies are fetched on demand.
skills_provider = SkillsProvider(MCPSkillsSource(client=session))
client = FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ.get("FOUNDRY_MODEL", "gpt-4o-mini"),
credential=AzureCliCredential(),
)
async with Agent(
client=client,
instructions="You are a helpful assistant. Use available skills to answer the user.",
context_providers=[skills_provider],
middleware=[ToolApprovalMiddleware(auto_approval_rules=[SkillsProvider.all_tools_auto_approval_rule])],
) as agent:
response = await agent.run("...")
비고
Python MCPSkillsSource은(는) skill-md 인덱스 항목만 지원합니다(다른 유형의 인덱스 항목은 알림 없이 건너뜁니다). .NET 구현과 달리 보관 형식 기술은 지원하지 않습니다.
skill://index.json가 없거나, 읽을 수 없거나, 비어 있거나, 구문 분석에 실패하면 소스는 빈 목록을 반환합니다.
Important
외부 MCP 서버는 에이전트가 실행할 수 있는 지침 및 스크립트를 포함하여 에이전트에 도달하는 기술 콘텐츠를 제어합니다. 심사 및 신뢰한 서버에만 연결 MCPSkillsSource 하고 해당 응답을 신뢰할 수 없는 입력으로 처리합니다.
스킬 출처
하나의 AgentSkillsProvider는 하나 이상의 소스(AgentSkillsSource를 구현하는 개체)에서 스킬을 검색합니다. 원본은 기술(예: 파일 기반 기술)을 검색하거나 보유하는 AgentFileSkillsSource와 다른 원본의 출력을 변환하는 데코레이터(집계, 중복 제거, 캐싱 및 필터링)의 두 가지 범주로 구분됩니다.
사용자 지정 원본을 만들 수도 있습니다.
모든 소스는 단일 메서드 GetSkillsAsync(AgentSkillsSourceContext context, CancellationToken cancellationToken = default)를 구현합니다. 현재 AgentSkillsSourceContext 요청에 대한 정보를 전달합니다.
-
AgentAIAgent- 기술을 요청하는 인스턴스입니다. -
Session- 호출과 연결된AgentSession또는 세션이 없을 때의null
이 컨텍스트는 원본 파이프라인 전체에서 사용할 수 있으므로 FilteringAgentSkillsSource 조건자 또는 사용자 지정 원본은 논리를 기반으로 할 수 있습니다(예: 요청 에이전트에 따라 다른 기술 집합 반환).
리프 원본
AgentFileSkillsSource
디스크에 있는 SKILL.md 파일에서 스킬을 찾아냅니다. 하나 이상의 디렉터리 경로, 선택적 스크립트 실행기 및 선택 사항 AgentFileSkillsSourceOptions ( 파일 기반 기술에 설명됨)을 허용합니다.
var source = new AgentFileSkillsSource(
[Path.Combine(AppContext.BaseDirectory, "skills")],
scriptRunner: SubprocessScriptRunner.RunAsync,
options: new AgentFileSkillsSourceOptions { SearchDepth = 3 });
AgentInMemorySkillsSource
AgentSkill 인스턴스(코드 정의 또는 클래스 기반)를 메모리에 래핑합니다.
var source = new AgentInMemorySkillsSource([volumeConverterSkill, temperatureConverter]);
결합자
AggregatingAgentSkillsSource
여러 소스를 하나로 결합합니다. 중복 제거 또는 필터링이 적용되지 않은 상태에서 기술은 등록 순서로 반환됩니다.
var aggregated = new AggregatingAgentSkillsSource([fileSource, inMemorySource]);
Decorators
데코레이터는 내부 소스를 래핑하고 출력을 변환합니다. 파이프라인을 구성하도록 체인으로 연결할 수 있습니다.
DeduplicatingAgentSkillsSource
중복 기술 이름(대/소문자를 구분하지 않는 첫 번째 항목 우선)을 제거합니다. 중복된 항목은 경고 레벨로 로그에 기록됩니다.
var deduplicated = new DeduplicatingAgentSkillsSource(innerSource);
CachingAgentSkillsSource
내부 소스에서 반환된 기술 목록을 캐시합니다. 동시 호출자는 캐시 키당 직렬화되므로 한 번에 하나의 인출만 실행됩니다. 선택적 CachingAgentSkillsSourceOptions을(를) 허용합니다:
-
RefreshInterval(TimeSpan?) - 설정되면 캐시된 결과가 이 간격 후에 만료되고 내부 소스가 다시 호출됩니다.null(기본값) 캐시된 결과가 만료되지 않습니다. -
CacheIsolationKeySelector(Func<AgentSkillsSourceContext, string?>?) - 캐시된 결과를 컨텍스트별로 격리하는 캐시 키를 반환합니다(예: 테넌트당). 이 경우null모든 호출자가 단일 캐시 버킷을 공유합니다.
var cached = new CachingAgentSkillsSource(innerSource, new CachingAgentSkillsSourceOptions
{
RefreshInterval = TimeSpan.FromMinutes(5)
});
FilteringAgentSkillsSource
기술을 포함하거나 제외하도록 조건자를 적용합니다. 조건자는 기술과 AgentSkillsSourceContext를 받습니다.
var filtered = new FilteringAgentSkillsSource(
innerSource,
(skill, context) => skill.Frontmatter.Name != "experimental-skill");
사용자 지정 원본
기본 제공 원본이 시나리오를 다루지 않는 경우 사용자 고유의 원본을 구현합니다. 데이터베이스 또는 원격 서비스와 같은 새로운 원본에서 스킬을 생성하는 리프 소스의 경우 AgentSkillsSource의 하위 클래스로 만들고, 다른 소스의 출력을 변환하는 데코레이터의 경우 DelegatingAgentSkillsSource의 하위 클래스로 만드세요.
리프 원본
AgentSkillsSource에서 상속하고 GetSkillsAsync을(를) 구현합니다. 인수 AgentSkillsSourceContext 를 사용하면 원본이 현재 요청에 맞게 결과를 조정할 수 있습니다. 예를 들어 요청 에이전트에 따라 다른 기술 집합을 반환합니다. 소스가 클라이언트나 연결과 같은 리소스를 소유하는 경우 Dispose(bool)를 재정의하세요.
public sealed class TenantSkillsSource : AgentSkillsSource
{
private readonly ISkillStore _store;
public TenantSkillsSource(ISkillStore store)
{
_store = store;
}
public override async Task<IList<AgentSkill>> GetSkillsAsync(
AgentSkillsSourceContext context,
CancellationToken cancellationToken = default)
{
// Use the requesting agent to decide which skills to load.
var tenantId = context.Agent.Name ?? "default";
return await _store.GetSkillsForTenantAsync(tenantId, cancellationToken);
}
}
사용자 지정 데코레이터
DelegatingAgentSkillsSource에서 파생하고 InnerSource.GetSkillsAsync을 호출한 다음 결과를 변환하거나 관찰합니다. 이는 기본 제공 캐싱, 중복 제거 및 필터링 데코레이터에서 사용하는 것과 동일한 패턴입니다. 예를 들어 결과를 변경하지 않고 요청당 반환된 기술 수를 기록하는 데코레이터는 다음과 같습니다.
public sealed class MetricsAgentSkillsSource : DelegatingAgentSkillsSource
{
private readonly ILogger<MetricsAgentSkillsSource> _logger;
public MetricsAgentSkillsSource(
AgentSkillsSource innerSource,
ILogger<MetricsAgentSkillsSource> logger)
: base(innerSource)
{
_logger = logger;
}
public override async Task<IList<AgentSkill>> GetSkillsAsync(
AgentSkillsSourceContext context,
CancellationToken cancellationToken = default)
{
var skills = await base.GetSkillsAsync(context, cancellationToken);
_logger.LogInformation(
"Returned {SkillCount} skills to agent {AgentName}.",
skills.Count,
context.Agent.Name);
return skills;
}
}
사용자 지정 소스 두 개 모두 기본 제공 소스와 마찬가지로 직접 AgentSkillsProvider에 전달하거나 더 큰 파이프라인 안에 중첩할 수 있습니다.
공급자 생성
AgentSkillsProvider 는 에이전트에 기술을 노출하는 구성 요소입니다. 하나 이상의 소스를 래핑하며 load_skill, read_skill_resource, run_skill_script 도구를 등록합니다. 세 가지 방법으로 만들 수 있습니다.
-
AgentSkillsProviderBuilder- 자동 집계, 중복 제거, 캐싱 및 선택적 필터링을 사용하여 여러 기술 유형을 하나의 공급자로 구성합니다. 파일 기반, 코드 정의, 클래스 기반 및 MCP 기반 기술을 결합하는 시나리오에 가장 적합합니다. -
직접 소스 컴퍼지션 - 공용
AgentSkillsSource클래스를 사용하여 원본 파이프라인을 직접 생성합니다. 자동 캐싱 또는 중복 제거가 적용되지 않습니다. 전체 파이프라인을 제어합니다. 순서 지정, 조건부 논리 또는 사용자 지정 데코레이터 동작을 제어해야 하는 경우에 가장 적합합니다. - 편의 생성자 - 파일 경로 또는 기술 인스턴스에서 직접 공급자를 만듭니다. 중복 제거 및 캐싱을 자동으로 적용합니다. 단일 원본 시나리오에 가장 적합합니다.
AgentSkillsProviderBuilder 사용
다음 중 어느 것이 필요한 경우 사용합니다 AgentSkillsProviderBuilder .
-
혼합 기술 유형 - 파일 기반, 코드 정의(
AgentInlineSkill), 클래스 기반(AgentClassSkill) 및 MCP 기반 기술을 단일 공급자에 결합합니다. - 기술 필터링 - 조건자를 사용하여 기술을 포함하거나 제외합니다.
혼합 기술 유형
UseFileSkill, UseSkill, UseMcpSkills, UseFileScriptRunner를 연결하여 하나의 공급자에 여러 스킬 유형을 결합합니다:
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills")) // file-based skills
.UseSkill(volumeConverterSkill) // AgentInlineSkill
.UseSkill(temperatureConverter) // AgentClassSkill
.UseMcpSkills(mcpClient) // MCP-based skills
.UseFileScriptRunner(SubprocessScriptRunner.RunAsync) // runner for file scripts
.Build();
기술 필터링
조건을 충족하는 기술만 포함하는 데 사용합니다 UseFilter . 예를 들어 공유 디렉터리에서 기술을 로드하지만 실험적 기술은 제외합니다.
var approvedSkillNames = new HashSet<string> { "expense-report", "code-style" };
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
.UseFilter((skill, context) => approvedSkillNames.Contains(skill.Frontmatter.Name))
.Build();
소스를 직접 구성
작성기에서 필요한 컨트롤을 제공하지 않는 경우 원본 클래스를 직접 작성하고 결과 파이프라인을 전달합니다 AgentSkillsProvider. 사용 가능한 원본 및 해당 옵션의 전체 목록은 기술 원본 을 참조하세요.
다음 예제에서는 비교 가능한 다중 소스 파이프라인을 빌드하지만 각 데코레이터를 명시적으로 제어할 수 있습니다.
// 1. Create the leaf sources
var fileSource = new AgentFileSkillsSource(
[Path.Combine(AppContext.BaseDirectory, "skills")],
SubprocessScriptRunner.RunAsync);
var inMemorySource = new AgentInMemorySkillsSource(
[volumeConverterSkill, temperatureConverter]);
// 2. Aggregate them into one source
var aggregated = new AggregatingAgentSkillsSource([fileSource, inMemorySource]);
// 3. Add deduplication and caching decorators
var deduplicated = new DeduplicatingAgentSkillsSource(aggregated);
var cached = new CachingAgentSkillsSource(deduplicated);
// 4. Create the provider, transferring source ownership
var skillsProvider = new AgentSkillsProvider(
cached,
options: new AgentSkillsProviderOptions(),
ownsSource: true);
비고
ownsSource이(가) true인 경우 공급자를 삭제하면 전체 원본 파이프라인도 삭제됩니다. 소스 수명 주기를 직접 관리하는 경우 false(으)로 설정합니다.
편의 생성자
단일 원본 시나리오의 경우 생성자를 직접 사용합니다 AgentSkillsProvider . 이러한 구성은 작성기 또는 수동 소스 컴퍼지션 없이 중복 제거 및 캐싱을 자동으로 적용합니다.
파일 경로에서:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
scriptRunner: SubprocessScriptRunner.RunAsync);
스킬 인스턴스에서:
var skillsProvider = new AgentSkillsProvider(volumeConverterSkill, temperatureConverter);
스킬 출처
SkillsProvider는 에서 파생되는 개체인 하나 이상의 SkillsSource에서 기술을 검색합니다. 원본은 기술(예: 파일 기반 기술)을 검색하거나 보유하는 FileSkillsSource와 다른 원본의 출력을 변환하는 데코레이터(집계, 중복 제거, 캐싱 및 필터링)의 두 가지 범주로 구분됩니다.
사용자 지정 원본을 만들 수도 있습니다.
모든 소스는 단일 메서드 async def get_skills(self, context: SkillsSourceContext) -> list[Skill]를 구현합니다. 현재 SkillsSourceContext 요청에 대한 정보를 전달합니다.
-
agent- 기술을 요청하는 에이전트(SupportsAgentRun)입니다. -
session- 호출과 연결된AgentSession또는 세션이 없을 때의None
이 컨텍스트는 전체 소스 파이프라인을 통해 흐르므로 FilteringSkillsSource 조건자 또는 사용자 지정 원본은 논리를 기반으로 할 수 있습니다(예: 요청 에이전트에 따라 다른 기술 집합 반환).
리프 원본
-
FileSkillsSource- 디스크의 파일에서SKILL.md기술을 검색합니다.script_runner설명된 하나 이상의 디렉터리 경로, 선택적resource_extensions및 검색 옵션(script_extensions,search_depth,resource_filter,script_filter,)을 허용합니다. -
InMemorySkillsSource- 메모리에서Skill인스턴스(코드 정의 또는 클래스 기반)를 래핑합니다. -
MCPSkillsSource- MCP 서버에서 기술을 검색합니다( MCP 기반 기술 참조).
from pathlib import Path
from agent_framework import FileSkillsSource, InMemorySkillsSource
file_source = FileSkillsSource(Path(__file__).parent / "skills", script_runner=my_runner)
in_memory_source = InMemorySkillsSource([volume_converter_skill, temperature_converter_skill])
콤비네이터
AggregatingSkillsSource 는 여러 원본을 하나로 결합합니다. 중복 제거 또는 필터링이 적용되지 않은 상태에서 기술은 등록 순서로 반환됩니다.
from agent_framework import AggregatingSkillsSource
aggregated = AggregatingSkillsSource([file_source, in_memory_source])
Decorators
데코레이터는 내부 소스를 래핑하고 출력을 변환합니다. 파이프라인을 구성하도록 체인으로 연결할 수 있습니다.
-
DeduplicatingSkillsSource- 중복 기술 이름(대/소문자를 구분하지 않는 첫 번째 항목 우선)을 제거합니다. 중복된 항목은 경고 레벨로 로그에 기록됩니다. -
CachingSkillsSource- 내부 소스에서 반환된 기술 목록을 캐시합니다. 동일한 캐시 키에 대한 동시 호출자는 단일 기내 인출을 공유하므로 내부 원본은 키당 최대 한 번 쿼리됩니다. 두 가지 선택적 키워드 인수를 허용합니다.-
refresh_interval(timedelta | None) - 설정된 경우 캐시된 목록이 간격보다 오래된 경우 부실로 처리되므로 다음 호출은 내부 원본을 다시 쿼리합니다.None(기본값) 캐시된 결과가 만료되지 않습니다. 프로세스 수명 동안 기술이 변경되는 내부 원본에 유용합니다.(예:MCPSkillsSource.) -
cache_isolation_key_selector(Callable[[SkillsSourceContext], str | None]) - 컨텍스트에서 캐시 키를 파생하여 캐시된 결과(예: 에이전트 또는 테넌트당)를 격리합니다. 키는 카디널리티가 낮고 안정적이어야 합니다.None반환(또는 종료None)은 단일 공유 캐시 버킷을 사용합니다.
-
-
FilteringSkillsSource- 기술을 포함하거나 제외하는 조건자를 적용합니다. 조건자는 스킬과SkillsSourceContext을 받습니다:Callable[[Skill, SkillsSourceContext], bool].
from datetime import timedelta
from agent_framework import (
CachingSkillsSource,
DeduplicatingSkillsSource,
FilteringSkillsSource,
)
deduplicated = DeduplicatingSkillsSource(aggregated)
cached = CachingSkillsSource(
deduplicated,
refresh_interval=timedelta(minutes=5),
cache_isolation_key_selector=lambda context: context.agent.name,
)
filtered = FilteringSkillsSource(
cached,
predicate=lambda skill, context: skill.frontmatter.name != "experimental-skill",
)
사용자 지정 원본
기본 제공 원본이 시나리오를 다루지 않는 경우 사용자 고유의 원본을 구현합니다. 데이터베이스 또는 원격 서비스와 같은 새로운 원본에서 스킬을 생성하는 리프 소스의 경우 SkillsSource의 하위 클래스로 만들고, 다른 소스의 출력을 변환하는 데코레이터의 경우 DelegatingSkillsSource의 하위 클래스로 만드세요.
리프 원본
SkillsSource에서 상속하고 get_skills을(를) 구현합니다. 인수 SkillsSourceContext 를 사용하면 원본이 현재 요청에 따라 결과를 조정할 수 있습니다. 예를 들어 요청 에이전트에 따라 다른 기술 집합을 반환합니다.
from agent_framework import Skill, SkillsSource, SkillsSourceContext
class TenantSkillsSource(SkillsSource):
def __init__(self, store: "SkillStore") -> None:
self._store = store
async def get_skills(self, context: SkillsSourceContext) -> list[Skill]:
# Use the requesting agent to decide which skills to load.
tenant_id = context.agent.name or "default"
return await self._store.get_skills_for_tenant(tenant_id)
사용자 지정 데코레이터
DelegatingSkillsSource에서 파생하고 self.inner_source.get_skills(context)을 호출한 다음 결과를 변환하거나 관찰합니다. 이는 기본 제공 캐싱, 중복 제거 및 필터링 데코레이터에서 사용하는 것과 동일한 패턴입니다. 예를 들어 결과를 변경하지 않고 요청당 반환된 기술 수를 기록하는 데코레이터입니다.
import logging
from agent_framework import DelegatingSkillsSource, Skill, SkillsSourceContext
logger = logging.getLogger(__name__)
class MetricsSkillsSource(DelegatingSkillsSource):
async def get_skills(self, context: SkillsSourceContext) -> list[Skill]:
skills = await self.inner_source.get_skills(context)
logger.info("Returned %d skills to agent %s.", len(skills), context.agent.name)
return skills
사용자 지정 소스 두 개 모두 기본 제공 소스와 마찬가지로 직접 SkillsProvider에 전달하거나 더 큰 파이프라인 안에 중첩할 수 있습니다.
공급자 생성
SkillsProvider 는 에이전트에 기술을 노출하는 구성 요소입니다. 하나 이상의 소스를 래핑하며 load_skill, read_skill_resource, run_skill_script 도구를 등록합니다. 세 가지 방법으로 만들 수 있습니다.
-
기술 인스턴스에서 - 단일
Skill또는 일련의 기술을 생성자에 전달합니다. 코드 정의 및 클래스 기반 기술에 가장 적합합니다. 중복 제거 및 캐싱을 자동으로 적용합니다. -
파일 경로로부터 -
SkillsProvider.from_paths()팩터리를 사용합니다. 단일 소스 파일 기반 기술에 가장 적합합니다. 중복 제거 및 캐싱을 자동으로 적용합니다. -
직접 소스 컴퍼지션 - 공용
SkillsSource클래스를 사용하여 원본 파이프라인을 직접 생성하고 생성자에 전달합니다. 전체 파이프라인을 제어합니다. 순서 지정, 조건부 논리, 캐싱 키 또는 사용자 지정 데코레이터 동작을 제어해야 하는 경우에 가장 적합합니다.
스킬 인스턴스에서
from agent_framework import SkillsProvider
# Single skill or a list of skills - deduplicated and cached automatically.
skills_provider = SkillsProvider(volume_converter_skill)
skills_provider = SkillsProvider([volume_converter_skill, temperature_converter_skill])
파일 경로에서
from pathlib import Path
from agent_framework import SkillsProvider
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
script_runner=my_runner,
)
소스를 직접 구성
모든 권한이 필요한 경우 원본 클래스를 직접 작성하고 결과 파이프라인을 전달합니다 SkillsProvider. 사용 가능한 원본 및 해당 옵션의 전체 목록은 기술 원본 을 참조하세요.
아래 예제에서는 각 데코레이터를 명시적으로 제어하는 다중 소스 파이프라인을 빌드합니다. 이 예제에서는 자리 표시자 개체를 사용합니다.
-
volume_converter_skill-InlineSkill표시된 대로 빌드된 모든 인스턴스입니다. -
temperature_converter_skill-ClassSkill표시된 대로 빌드된 모든 인스턴스입니다. -
my_runner-SkillScriptRunner에 나와 있는 대로 정의된 호출 가능 항목.
from pathlib import Path
from agent_framework import (
AggregatingSkillsSource,
CachingSkillsSource,
DeduplicatingSkillsSource,
FileSkillsSource,
InMemorySkillsSource,
SkillsProvider,
)
# 1. Create the leaf sources
file_source = FileSkillsSource(Path(__file__).parent / "skills", script_runner=my_runner)
in_memory_source = InMemorySkillsSource([volume_converter_skill, temperature_converter_skill])
# 2. Aggregate them, then add deduplication and caching decorators
aggregated = AggregatingSkillsSource([file_source, in_memory_source])
deduplicated = DeduplicatingSkillsSource(aggregated)
cached = CachingSkillsSource(deduplicated)
# 3. Create the provider from the composed pipeline
skills_provider = SkillsProvider(cached)
Important
호출자가 제공한 SkillsSource은 있는 그대로 사용됩니다. 즉, 자동으로 중복 제거되거나 로 감싸지지는 CachingSkillsSource. 단일 공유 버킷에서 컨텍스트 인식 원본을 자동으로 캐싱하면 한 에이전트 또는 테넌트의 기술을 다른 에이전트에 대해 재생할 수 있습니다.
DeduplicatingSkillsSource와 CachingSkillsSource(선택적으로 cache_isolation_key_selector와 함께)는 필요할 때 직접 작성하세요. 자동 중복 제거 및 캐싱은 기술 또는 파일 경로를 직접 전달하는 경우에만 적용됩니다(위의 옵션 1과 2).
혼합 기술 유형
AggregatingSkillsSource를 사용하여 하나의 공급자에서 파일 기반, 코드로 정의된, 클래스 기반 스킬을 결합합니다.
from pathlib import Path
from agent_framework import (
AggregatingSkillsSource,
DeduplicatingSkillsSource,
FileSkillsSource,
InMemorySkillsSource,
SkillsProvider,
)
temperature_converter_skill = TemperatureConverterSkill()
skills_provider = SkillsProvider(
DeduplicatingSkillsSource(
AggregatingSkillsSource([
FileSkillsSource(
Path(__file__).parent / "skills",
script_runner=my_runner,
),
InMemorySkillsSource([volume_converter_skill, temperature_converter_skill]),
])
)
)
기술 필터링
FilteringSkillsSource를 사용해 에이전트에 표시할 스킬을 제어합니다. 조건자는 각 Skill 및 SkillsSourceContext을(를) 받아, 기술을 포함하려면 True를 반환합니다. 예를 들어 공유 디렉터리에서 기술을 로드하지만 실험적 디렉터리를 숨기려면 다음을 수행합니다.
from pathlib import Path
from agent_framework import (
DeduplicatingSkillsSource,
FileSkillsSource,
FilteringSkillsSource,
SkillsProvider,
)
skills_provider = SkillsProvider(
DeduplicatingSkillsSource(
FilteringSkillsSource(
FileSkillsSource(Path(__file__).parent / "skills"),
predicate=lambda skill, context: skill.frontmatter.name != "experimental-tools",
)
)
)
캐싱의 동작 방식
기본적으로 빌더는 기반 소스에서 반환되는 기술 목록을 캐시하는 CachingAgentSkillsSource로 원본 파이프라인을 래핑합니다. 첫 번째 요청에서 기술이 확인되면 후속 요청은 원본을 다시 쿼리하지 않고 캐시된 목록을 다시 사용합니다. 캐싱을 사용하지 않도록 설정하려면(예: 기술 정의가 자주 변경되는 경우 개발 중에) 작성기에서 사용합니다 DisableCaching() .
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
.UseFileScriptRunner(SubprocessScriptRunner.RunAsync)
.DisableCaching()
.Build();
비고
캐싱을 사용하지 않도록 설정하면 기술 콘텐츠가 자주 변경되는 경우 개발 중에 유용합니다. 프로덕션 환경에서 더 나은 성능을 위해 캐싱을 사용하도록 설정(기본값)으로 유지합니다.
캐싱의 동작 방식
기본적으로 기술 도구 및 지침은 첫 번째 빌드 후에 캐시됩니다. 모든 호출에서 강제로 다시 빌드하도록 설정합니다 disable_caching=True .
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
disable_caching=True,
)
disable_caching 는 코드 정의 및 클래스 기반 기술에 대한 생성자에서도 사용할 수 있습니다 SkillsProvider .
캐싱을 계속 활성화한 상태로 유지하면서 스킬을 주기적으로 다시 검색하려면(예: 프로세스 수명 동안 파일 기반 또는 MCP 소스가 변경되는 경우) cache_refresh_interval를 전달합니다. 기본 제공 캐시는 간격보다 오래되면 부실로 처리되므로 다음 실행은 원본을 다시 쿼리합니다.
from datetime import timedelta
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
cache_refresh_interval=timedelta(minutes=5),
)
cache_refresh_interval는 공급자가 내부적으로 생성하는 캐시(스킬 또는 파일 경로 기반)에만 영향을 미칩니다. disable_caching=True인 경우에는 무시되며, 호출자가 제공한 SkillsSource에는 영향을 주지 않습니다(그 경우에는 CachingSkillsSource를 사용해 자체 refresh_interval를 구성하세요).
비고
캐싱을 사용하지 않도록 설정하면 기술 콘텐츠가 자주 변경되는 경우 개발 중에 유용합니다. 프로덕션 환경에서 더 나은 성능을 위해 캐싱을 사용하도록 설정(기본값)으로 유지합니다.
도구 승인
AgentSkillsProvider(load_skill, read_skill_resource, run_skill_script)에 의해 노출되는 모든 도구는 기본적으로 승인이 필요합니다. 도구 호출에 승인이 필요한 경우 에이전트는 즉시 실행하는 대신 일시 중지하고 반환 ToolApprovalRequestContent 합니다. 자동 승인 규칙이 적용된 UseToolApproval 미들웨어를 사용하여 신뢰할 수 있는 작업에 대한 프롬프트를 선택적으로 우회합니다.
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync);
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new() { Instructions = "You are a helpful assistant." },
AIContextProviders = [skillsProvider],
},
model: deploymentName)
.AsBuilder()
.UseToolApproval(new ToolApprovalAgentOptions
{
// Auto-approve read-only skill tools (load_skill, read_skill_resource).
// run_skill_script still requires explicit user approval.
AutoApprovalRules = [AgentSkillsProvider.ReadOnlyToolsAutoApprovalRule],
})
.Build();
스크립트 실행을 포함하여 모든 기술 도구를 자동으로 승인하려면 다음을 수행합니다.
.UseToolApproval(new ToolApprovalAgentOptions
{
AutoApprovalRules = [AgentSkillsProvider.AllToolsAutoApprovalRule],
})
특정 도구에 대한 승인 비활성화
개별 도구에 대한 승인을 사용하지 않도록 설정하고 승인 흐름에서 완전히 제거하는 데 사용합니다 AgentSkillsProviderOptions .
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync,
options: new AgentSkillsProviderOptions
{
DisableLoadSkillApproval = true,
DisableReadSkillResourceApproval = true,
// DisableRunSkillScriptApproval remains false - scripts still require approval
});
일부 도구에 승인이 필요하고 다른 도구가 동일한 응답에 없는 경우 모델은 두 형식을 동시에 호출할 수 있습니다. 사용자에게 나머지 도구에 대해서만 묻는 메시지가 표시되는 동안 승인 없는 도구가 즉시 실행되도록 설정합니다 EnableNonApprovalRequiredFunctionBypassing .
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new() { Instructions = "You are a helpful assistant." },
AIContextProviders = [skillsProvider],
EnableNonApprovalRequiredFunctionBypassing = true,
},
model: deploymentName)
.AsBuilder()
.UseToolApproval()
.Build();
승인 요청 처리
도구에 승인이 필요하고 자동 승인 규칙이 일치하지 않는 경우 에이전트는 계속하기 전에 승인 또는 거부해야 하는 항목을 반환 ToolApprovalRequestContent 합니다.
AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync("Convert 26.2 miles to kilometers", session);
List<ToolApprovalRequestContent> approvalRequests = response.Messages
.SelectMany(m => m.Contents)
.OfType<ToolApprovalRequestContent>()
.ToList();
while (approvalRequests.Count > 0)
{
List<ChatMessage> userInputResponses = approvalRequests
.ConvertAll(request =>
{
var toolCall = (FunctionCallContent)request.ToolCall;
Console.WriteLine($"Approve {toolCall.Name}? (Y/N)");
bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
return new ChatMessage(ChatRole.User, [request.CreateResponse(approved)]);
});
response = await agent.RunAsync(userInputResponses, session);
approvalRequests = response.Messages
.SelectMany(m => m.Contents)
.OfType<ToolApprovalRequestContent>()
.ToList();
}
스크립트 오류 세부 정보
기본적으로 기술 스크립트 실행이 실패하면 예외가 기본 FunctionInvokingChatClient으로 전파됩니다. 해당 IncludeDetailedErrors 속성이 설정된 true경우 예외 메시지가 모델에 전달되어 다른 인수로 다시 시도하여 자체 수정할 수 있습니다.
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(
options: new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new()
{
Instructions = "You are a helpful assistant.",
},
AIContextProviders = [skillsProvider],
},
model: deploymentName,
clientFactory: client => client
.AsBuilder()
.UseFunctionInvocation(configure: (c) => c.IncludeDetailedErrors = true)
.Build());
직접 구성할 FunctionInvokingChatClient 수 없는 경우 대신 설정합니다 AgentSkillsProviderOptions.IncludeDetailedErrors . 기술 공급자 수준에서 예외를 catch하고 오류 메시지를 모델에 직접 반환합니다.
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync,
options: new AgentSkillsProviderOptions
{
IncludeDetailedErrors = true,
});
경고
두 방법 중 하나가 원시 예외 세부 정보를 모델에 공개할 수 있습니다. 예외 메시지에는 연결 문자열, 파일 경로 또는 내부 서비스 이름과 같은 중요한 정보가 포함될 수 있습니다. 또한 스킬 또는 스크립트가 신뢰할 수 없는 출처에서 비롯된 경우, 악의적으로 작성된 스크립트가 프롬프트 인젝션 페이로드가 포함된 메시지와 함께 예외를 발생시킬 수 있습니다.
SkillsProvider(load_skill, read_skill_resource, run_skill_script)에서 제공하는 모든 도구는 기본적으로 승인을 받아야 합니다. 도구 호출에 승인이 필요한 경우 에이전트는 즉시 실행하는 대신 일시 중지하고 승인 요청을 반환합니다 result.user_input_requests . 각 요청을 request.to_function_approval_response(approved=...) 승인하거나 거부하고 응답을 다시 보냅니다.
from textwrap import dedent
from agent_framework import Agent, Content, InlineSkill, Message, SkillFrontmatter, SkillsProvider
deployment_skill = InlineSkill(
frontmatter=SkillFrontmatter(
name="deployment",
description="Tools for deploying application versions to production",
),
instructions=dedent("""\
Use this skill when the user asks to deploy an application.
Run the deploy script with the version and environment parameters.
"""),
)
@deployment_skill.script
def deploy(version: str, environment: str = "staging") -> str:
"""Deploy the application to the specified environment."""
return f"Deployed version {version} to {environment}"
# All skill tools require approval by default.
skills_provider = SkillsProvider(deployment_skill)
async with Agent(
client=client,
instructions="You are a deployment assistant.",
context_providers=[skills_provider],
) as agent:
# Use a session so the agent retains context across approval round-trips
session = agent.create_session()
result = await agent.run("Deploy version 2.5.0 to production", session=session)
# Collect a response for every request and send them in one run so the
# loop always makes progress.
while result.user_input_requests:
approval_responses: list[Content] = []
for request in result.user_input_requests:
if request.function_call is None:
approval_responses.append(request.to_function_approval_response(approved=False))
continue
print(f"Approve {request.function_call.name}? Args: {request.function_call.arguments}")
# In a real application, prompt the user here.
approval_responses.append(request.to_function_approval_response(approved=True))
result = await agent.run(Message(role="user", contents=approval_responses), session=session)
print(result)
도구 호출이 거부되면(approved=False) 에이전트는 사용자가 거부되었다는 알림을 받고 그에 따라 응답할 수 있습니다.
신뢰할 수 있는 도구 자동 승인
호출할 때마다 확인을 요청하는 대신, ToolApprovalMiddleware에서 제공하는 정적 자동 승인 규칙 중 하나를 사용해 SkillsProvider를 설치하세요. 이렇게 하면 스크립트 실행을 요청하는 동안 읽기 전용 도구가 자동으로 실행됩니다.
from agent_framework import Agent, SkillsProvider, ToolApprovalMiddleware
skills_provider = SkillsProvider(deployment_skill)
# Auto-approve read-only skill tools (load_skill, read_skill_resource).
# run_skill_script still requires explicit approval via result.user_input_requests.
approval_middleware = ToolApprovalMiddleware(
auto_approval_rules=[SkillsProvider.read_only_tools_auto_approval_rule],
)
agent = Agent(
client=client,
instructions="You are a deployment assistant.",
context_providers=[skills_provider],
middleware=[approval_middleware],
)
다음 두 가지 규칙을 사용할 수 있습니다.
-
SkillsProvider.read_only_tools_auto_approval_rule- 읽기 전용 도구(load_skill,read_skill_resource)만 승인하고run_skill_script에 대해서는 계속 확인을 요청합니다. -
SkillsProvider.all_tools_auto_approval_rule-run_skill_script를 포함한 모든 스킬 도구를 승인합니다(수동 승인 절차 불필요).
두 규칙 모두 server_label가 포함된 모든 호출을 거부하므로, 이 공급자의 로컬 도구에만 적용되며 동일한 이름의 호스팅된 도구를 자동 승인하지 않습니다. 규칙은 여전히 승인이 필요한 도구에만 적용됩니다. 아래 인수를 통해 disable_*_approval 옵트아웃된 도구는 승인 없이 실행됩니다.
특정 도구에 대한 승인 비활성화
신뢰할 수 있는 스킬의 경우, 개별 도구를 승인 흐름에서 완전히 제외하려면 disable_load_skill_approval, disable_read_skill_resource_approval, 및/또는 disable_run_skill_script_approval를 전달하세요(이 도구들은 approval_mode="never_require"에 등록됨):
skills_provider = SkillsProvider(
deployment_skill,
disable_load_skill_approval=True,
disable_read_skill_resource_approval=True,
# disable_run_skill_script_approval remains False - scripts still require approval
)
이러한 인수는 SkillsProvider.from_paths()에서도 사용할 수 있습니다.
경고
신뢰할 수 있는 원본의 기술 및 스크립트에 대해서만 승인을 사용하지 않도록 설정하거나 스크립트 실행을 자동으로 승인합니다. 기술 지침은 에이전트의 컨텍스트에 삽입되고 run_skill_script 소스에서 제공하는 코드를 실행합니다.
사용자 지정 시스템 프롬프트
기본적으로 기술 공급자는 사용 가능한 기술을 나열하는 시스템 프롬프트를 삽입하고, 에이전트에게 load_skill 및 read_skill_resource를 사용하도록 지시합니다. 이 프롬프트를 사용자 지정할 수 있습니다.
var skillsProvider = new AgentSkillsProvider(
skillPath: Path.Combine(AppContext.BaseDirectory, "skills"),
options: new AgentSkillsProviderOptions
{
SkillsInstructionPrompt = """
You have skills available. Here they are:
{skills}
When a task matches a skill, use load_skill to retrieve instructions,
then read_skill_resource for referenced resources, and run_skill_script for scripts.
"""
});
비고
사용자 지정 템플릿은 생성된 기술 목록의 자리 표시자로 포함되어 {skills} 야 합니다. 리터럴 중괄호는 다음과 같이 {{}}이스케이프되어야 합니다.
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
instruction_template=(
"You have skills available. Here they are:\n{skills}\n"
"{resource_instructions}\n"
"{runner_instructions}"
),
)
비고
사용자 지정 템플릿은 생성된 기술 목록의 {skills} 자리 표시자를 포함해야 합니다. 선택적으로 {resource_instructions}(리소스 도구 힌트) 및 {runner_instructions}(스크립트 도구 힌트) 자리 표시자를 포함할 수 있습니다. 이러한 자리 표시자가 있으면 기본 제공 지침으로 채워지고, 없으면 단순히 렌더링되지 않습니다(해당 도구는 계속 등록된 상태로 유지됨). 리터럴 중괄호는 다음과 같이 {{}}이스케이프되어야 합니다.
서비스 및 런타임 인수 삽입
기술 리소스 및 스크립트 함수는 런타임에 제공되는 외부 애플리케이션 컨텍스트를 받을 수 있습니다.
기술 리소스 및 스크립트 대리자는 에이전트 프레임워크가 IServiceProvider 자동으로 삽입하는 매개 변수를 선언할 수 있습니다. 이를 통해 기술은 요청 시 등록된 애플리케이션 서비스를 해결할 수 있습니다.
설치
애플리케이션 서비스를 등록하고 IServiceProvider을(를) services 매개변수를 통해 에이전트에 전달합니다.
using Microsoft.Extensions.DependencyInjection;
// Register application services
ServiceCollection services = new();
services.AddSingleton<ConversionService>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
// Create the agent and pass the service provider
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(
options: new ChatClientAgentOptions
{
Name = "ConverterAgent",
ChatOptions = new() { Instructions = "You are a helpful assistant." },
AIContextProviders = [skillsProvider],
},
model: deploymentName,
services: serviceProvider);
DI를 사용한 코드 정의 기술
IServiceProvider 또는 AddResource 대리자에서 AddScript를 매개변수로 선언하세요. 그러면 에이전트가 리소스를 읽거나 스크립트를 실행할 때 프레임워크가 이를 자동으로 확인하여 주입합니다.
var distanceSkill = new AgentInlineSkill(
name: "distance-converter",
description: "Convert between distance units (miles and kilometers).",
instructions: """
Use this skill when the user asks to convert between miles and kilometers.
1. Read the distance-table resource for conversion factors.
2. Use the convert script to compute the result.
""")
.AddResource("distance-table", (IServiceProvider sp) =>
{
return sp.GetRequiredService<ConversionService>().GetDistanceTable();
})
.AddScript("convert", (double value, double factor, IServiceProvider sp) =>
{
return sp.GetRequiredService<ConversionService>().Convert(value, factor);
});
DI를 사용하는 클래스 기반 기술
메서드에 [AgentSkillResource] 또는 [AgentSkillScript] 특성을 지정하고 IServiceProvider 매개 변수를 선언하면 프레임워크가 리플렉션을 통해 이러한 멤버를 찾아 서비스 공급자를 자동으로 주입합니다.
internal sealed class WeightConverterSkill : AgentClassSkill<WeightConverterSkill>
{
public override AgentSkillFrontmatter Frontmatter { get; } = new(
"weight-converter",
"Convert between weight units (pounds and kilograms).");
protected override string Instructions => """
Use this skill when the user asks to convert between pounds and kilograms.
1. Read the weight-table resource for conversion factors.
2. Use the convert script to compute the result.
""";
[AgentSkillResource("weight-table")]
[Description("Lookup table of multiplication factors for weight conversions.")]
private static string GetWeightTable(IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredService<ConversionService>().GetWeightTable();
}
[AgentSkillScript("convert")]
[Description("Multiplies a value by a conversion factor and returns the result as JSON.")]
private static string Convert(double value, double factor, IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredService<ConversionService>().Convert(value, factor);
}
}
팁 (조언)
클래스 기반 기술은 생성자를 통해 종속성을 확인할 수도 있습니다. 기술 클래스를 ServiceCollection에 등록하고 new을 직접 호출하는 대신 컨테이너에서 해결합니다.
services.AddSingleton<WeightConverterSkill>();
var weightSkill = serviceProvider.GetRequiredService<WeightConverterSkill>();
이는 기술 클래스 자체에 리소스 및 스크립트 대리자가 사용하는 것 이상으로 삽입된 서비스가 필요할 때 유용합니다.
**kwargs을 자동으로 수락하는 리소스 및 스크립트 함수는 agent.run()로 전달된 런타임 키워드 인수를 받습니다. 이를 통해 기술 함수는 기술 정의에 하드 코딩하지 않고도 구성, 사용자 ID 또는 서비스 클라이언트와 같은 애플리케이션 컨텍스트에 액세스할 수 있습니다.
런타임 인수 전달
프레임워크가 function_invocation_kwargs 리소스 및 스크립트 함수에 전달하는 키워드 인수를 agent.run()에 전달합니다.
response = await agent.run(
"How many kilometers is 26.2 miles?",
function_invocation_kwargs={"precision": 2, "user_id": "alice"},
)
kwargs를 사용하여 코드 정의 기술
리소스 함수가 선언 **kwargs되면 프레임워크는 에이전트가 리소스를 읽을 때마다 런타임 키워드 인수를 전달합니다.
import os
from typing import Any
from agent_framework import InlineSkill, SkillFrontmatter
project_info_skill = InlineSkill(
frontmatter=SkillFrontmatter(
name="project-info",
description="Project status and configuration information",
),
instructions="Use this skill for questions about the current project.",
)
@project_info_skill.resource(name="environment", description="Current environment configuration")
def environment(**kwargs: Any) -> str:
"""Return environment config, optionally scoped to a user."""
user_id = kwargs.get("user_id", "anonymous")
env = os.environ.get("APP_ENV", "development")
return f"Environment: {env}, Caller: {user_id}"
인수가 없는 **kwargs 리소스 함수는 인수 없이 호출되며 런타임 컨텍스트를 수신하지 않습니다.
스크립트 함수가 선언 **kwargs되면 프레임워크는 에이전트에서 제공하는 인수와 args 함께 런타임 키워드 인수를 전달합니다.
import json
from typing import Any
from agent_framework import InlineSkill, SkillFrontmatter
converter_skill = InlineSkill(
frontmatter=SkillFrontmatter(
name="unit-converter",
description="Convert between common units using a conversion factor",
),
instructions="Use the convert script to perform unit conversions.",
)
@converter_skill.script(name="convert", description="Convert a value: result = value × factor")
def convert_units(value: float, factor: float, **kwargs: Any) -> str:
"""Convert a value using a multiplication factor.
Args:
value: The numeric value to convert (provided by the agent).
factor: Conversion factor (provided by the agent).
**kwargs: Runtime keyword arguments from agent.run().
"""
precision = kwargs.get("precision", 4)
result = round(value * factor, precision)
return json.dumps({"value": value, "factor": factor, "result": result})
에이전트는 도구 호출 value을(factor와 args을) 통해 제공합니다. 애플리케이션은 precision을 통해 function_invocation_kwargs을 제공합니다.
**kwargs가 없는 스크립트 함수는 에이전트가 제공하는 인수만 수신합니다.
kwargs를 사용하는 클래스 기반 스킬
클래스 기반 스킬 메서드는 런타임 인수를 받기 위해 **kwargs도 허용할 수 있습니다. 패턴은 동일한 방식으로 작동합니다. 리소스 메서드 또는 스크립트 메서드에서 선언 **kwargs 합니다.
from typing import Any
from agent_framework import ClassSkill, SkillFrontmatter
class WeightConverterSkill(ClassSkill):
def __init__(self) -> None:
super().__init__(
frontmatter=SkillFrontmatter(
name="weight-converter",
description="Convert between weight units (pounds and kilograms).",
),
)
@property
def instructions(self) -> str:
return "Use this skill to convert between pounds and kilograms."
@ClassSkill.resource(name="weight-table")
def get_weight_table(self, **kwargs: Any) -> str:
"""Weight conversion factors, scoped to caller context."""
user_id = kwargs.get("user_id", "anonymous")
return f"Weight table for {user_id}: | lbs | kg | 0.453592 |"
@ClassSkill.script(name="convert")
def convert(self, value: float, factor: float, **kwargs: Any) -> str:
"""Convert a weight value."""
import json
precision = kwargs.get("precision", 4)
result = round(value * factor, precision)
return json.dumps({"value": value, "factor": factor, "result": result})
보안 모범 사례
에이전트 기술은 프로젝트에 가져오는 타사 코드처럼 처리되어야 합니다. 기술 지침은 에이전트의 컨텍스트에 삽입되고 기술에 스크립트가 포함될 수 있으므로 오픈 소스 종속성에 동일한 수준의 검토 및 거버넌스를 적용하는 것이 필수적입니다.
-
사용하기 전에 검토 - 배포하기 전에 모든 기술 콘텐츠(
SKILL.md, 스크립트 및 리소스)를 읽습니다. 스크립트의 실제 동작이 명시된 의도와 일치하는지 확인합니다. 안전 지침을 우회하거나, 데이터를 유출하거나, 에이전트 구성 파일을 수정하려는 악의적인 지침을 확인합니다. - 원본 신뢰 - 신뢰할 수 있는 작성자 또는 심사된 내부 참가자의 기술만 설치합니다. 명확한 출처, 버전 제어 및 활성 유지 관리 기술을 선호합니다. 인기 있는 패키지를 모방하려고 의도적으로 비슷하게 만든 기술 명칭이 있는지 주의하십시오.
- 샌드박싱 - 격리된 환경에서 실행 스크립트를 포함하는 기술을 실행합니다. 파일 시스템, 네트워크 및 시스템 수준 액세스를 기술에 필요한 것으로만 제한합니다. 잠재적으로 중요한 작업을 실행하기 전에 명시적 사용자 확인이 필요합니다.
- 감사 및 로깅 - 로드되는 기능, 읽히는 리소스 및 실행되는 스크립트를 기록합니다. 이렇게 하면 문제가 발생할 경우 에이전트 동작을 특정 기술 콘텐츠로 다시 추적할 수 있는 감사 내역을 제공합니다.
기술 및 워크플로를 사용해야 하는 경우
에이전트 기술 및 에이전트 프레임워크 워크플로는 모두 에이전트가 수행할 수 있는 작업을 확장하지만 근본적으로 다른 방식으로 작동합니다. 요구 사항에 가장 적합한 방법을 선택합니다.
- 제어 - 기술을 사용하여 AI는 지침을 실행하는 방법을 결정합니다. 이는 에이전트가 창의적이거나 적응형이 되도록 하려는 경우에 이상적입니다. 워크플로를 사용하면 실행 경로를 명시적으로 정의합니다. 결정적이고 예측 가능한 동작이 필요한 경우 워크플로를 사용합니다.
- 복원력 - 기술은 단일 에이전트 턴 내에서 실행됩니다. 문제가 발생하면 전체 작업을 다시 시도해야 합니다. 워크플로는 검사점을 지원하므로 실패 후 마지막으로 성공한 단계에서 다시 시작할 수 있습니다. 전체 프로세스를 다시 실행하는 비용이 높은 경우 워크플로를 선택합니다.
- 부작용 - 작업이 멱등적이거나 위험이 낮은 경우 스킬이 적합합니다. 단계가 재시도 시 반복해서는 안 되는 부작용(이메일 보내기, 결제 청구)을 생성하는 경우 워크플로를 선호합니다.
- 복잡성 - 기술은 한 에이전트가 처리할 수 있는 집중적인 단일 도메인 작업에 가장 적합합니다. 워크플로는 여러 에이전트, 사용자 승인 또는 외부 시스템 통합을 조정하는 다단계 비즈니스 프로세스에 더 적합합니다.
팁 (조언)
일반적인 기준으로: AI가 작업을 수행하는 방법을 파악하려면 기술을 사용하세요. 실행되는 단계와 순서를 보장해야 하는 경우 워크플로를 사용합니다.