Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Microsoft Agent Framework – Agent Skills İle AI Agent’ın Yeteneklerini Genişletelim

Merhaba,


Bu içeriğimizde Microsoft Agent Framework‘de, AI Agent’ın yeteneklerini taşınabilir bir şekilde genişletebilmemizi sağlayan Agent Skills özelliğini inceliyor olacağız.

Agent Skills Nedir?

Agent Skills, agent’lara alan uzmanlığı kazandırabilmek için tasarlanmış basit ve açık bir formattır.

Agent Skills, agent’lara özel yetenekler ve alan uzmanlığı kazandırmak için tasarlanmış taşınabilir talimat (instructions) ve kaynak (resources) paketleridir. Bu paketler, açık bir spesifikasyonu takip etmekte ve Progressive Disclosure Pattern‘ı sayesinde agent’ların yalnızca ihtiyaç duydukları bağlamı (context), ihtiyaç duydukları anda yüklemelerini sağlamaktadır.

Agent Skills, AI Agent’ların görevlerinde tutarlı, esnek ve uzmanlaşmış bir şekilde işlevsellik gösterebilmesi için özellikle belirli bir alanın uzman bilgisini paketlemek, agent’ların yeteneklerini çekirdek talimatlarını değiştirmeden genişletmek, çok adımlı görevleri (multi-step tasks) tekrar edilebilir ve denetlenebilir iş akışlarına (workflows) dönüştürmek ve aynı beceriyi farklı Agent Skills uyumlu ürünlerde yeniden kullanabilmek için oldukça ideal bir yapılanmadır.

Markdown Belgesi nedir?
Düz metin kullanılarak yazılan ve basit işaretlerle biçimlendirme yapılan yazı biçimlendirme dosyasıdır. En yaygın kullanım yeri GitHub README dosyalarıdır…

Nasıl Çalışmaktadır?

Her skill’in temelinde bir SKILL.md dosyası mevcuttur. Bu dosya, ilgili skill’in ne yaptığını açıklayan ve nasıl yapılacağını adım adım tarif eden bir markdown belgesidir. Skill’ler isteğe bağlı olarak script’ler, referans dokümanlar ve diğer kaynakları da içerebilmektedir.

Agent Skills, agent’ın ‘ne bileceğini’ ve ‘nasıl davranacağını’ dışarıdan modüler bir paket olarak tanımlanmasını sağlayan ve agent’a core instruction’lara dokunmaksızın yeni yetenekler kazandırmamıza imkan tanıyan bir özelliktir.

Agent Skills, context window’u şişirmemek için yukarıdaki satırlarda da bahsedildiği üzere advertise, load ve read resources aşamalarından oluşan Progressive Disclosure Pattern modelini kullanmaktadır. Tabi burada öncelikle şunu bilmek gerekmektedir; bir agent’ın yapabildiği tüm yeteneklere bizler terminolojik olarak ingilizce karşılığı olan capability demekteyiz. Haliyle temel mantık şöyledir; bir agent tüm capability’leri en baştan bodoslama yüklememekte, önce advertise etmektedir. Yani varlığını duyurmaktadır. Ardından gerekirse yüklemekte (load) ve son olarak da kaynakları kullanmaktadır (read resources)

Bu üç adım Progressive Disclosure’ın teknik implementasyonudur.

  1. Advertise (Capability Duyurma)
    Bu aşamada skill çalışmaz ve yüklenmez! Yalnızca agent’ın bu yeteneğe sahip olduğu duyurulur.

    Yani LLM’e şu mesaj verilir:

    Bu ajan aşağıdaki yeteneklere sahip olabilir:
    – Weather skill
    – Web search skill
    – Email skill

    Ama burada dikkat edilmesi gereken bir durum vardır. O da, başlangıçta sadece capability/skill metadata’sının gösterilmesi yani advertise edilmesidir. Detaylı tool tanımı ve execution bilgisi ancak skill gerçekten kullanılacaksa LLM context’ine eklenecektir.

  2. Load (Skill Yükleme)
    Kullancıdan prompt geldikten sonra bu aşama devreye girer.

    Burada agent akıl yürütme (reasoning) yapar.

    User: Ankara’da hava durumuyla ilgili bilgi ver!

    LLM bu noktada düşünür.

    LLM: WeatherSkill kullanılabilir!

    İşte o anda skill load edilir. Yani runtime’da bir WeatherSkill instance’ı oluşturulur.

    Skill registry → WeatherSkill instance oluştur!
  3. Read resources
    Bu aşamada ise skill yüklendikten sonra agent artık gerçek işi yapabilmektedir. Misal olarak, WeatherSkill.GetWeather("Ankara") şeklinde bir fonksiyon çağrımı gerçekleştirebilir. Bu fonksiyon ardında da herhangi bir API çağrılabilir, database’den veri elde edilebilir, bir dosya okunabilir veya web search gerçekleştirilebilir.

    Bu aşamaya execution layer denmektedir.

Bu model, Microsoft Agent Framework içinde Agent Skills ve resource discovery mantığını açıklamak için oldukça yerindedir. Ayrıca bu modelin advertise aşaması sayesinde token maliyeti oldukça düşürülmekte ve güvenli bir skill çağrım süreci gerçekleştirilmektedir.

┌──────────────────────────┐
│ Agent Start │
└─────────────┬────────────┘


┌──────────────────────────┐
│ 1. Advertise Capabilities│
│ │
│ Agent hangi yeteneklere │
│ sahip olduğunu duyurur │
│ │
│ – Weather │
│ – Email │
│ – WebSearch │
│ – FileSystem │
└─────────────┬────────────┘


┌──────────────────────────┐
│ 2. User Prompt │
│ │
│ “Ankara’da hava durumu?” │
└─────────────┬────────────┘


┌──────────────────────────┐
│ 3. Agent Reasoning │
│ │
│ LLM düşünür: │
│ “Weather capability │
│ gerekli.” │
└─────────────┬────────────┘


┌──────────────────────────┐
│ 4. Load Skill │
│ │
│ WeatherSkill runtime’da │
│ yüklenir │
│ │
│ Tool schema artık │
│ LLM contextinde │
└─────────────┬────────────┘


┌──────────────────────────┐
│ 5. Read Resources │
│ (Skill Execution) │
│ │
│ Weather API çağrılır │
│ Veri alınır │
└─────────────┬────────────┘


┌──────────────────────────┐
│ 6. Agent Response │
│ │
│ “Ankara’da sıcaklık │
│ 25°C ve güneşli.” │
└──────────────────────────┘
Şimdi buradaki akıştan ve yapılan çalışmanın mahiyetinden akla (haklı olarak) Model Context Protocol yahut Semantic Kernel‘daki Plugin yapılanması geliyor olabilir… Ki evet, esasında işlevsel olarak aynı kategoriye sahip ilişkisel teknikler olsalar da aynı şeyler değildirler!

MCP, Agent Skill ve Semantic Kernel’daki Plugin mantığı aynı problemin farklı katmanlardaki çözümleridir…

Malumunuz MCP, adı üzerinde bir protokoldür ve esas amacı AI modellerinin dış sistemlerle standart bir şekilde konuşmasını sağlamaktır.

Semantic Kernel’daki Plugin yapılanması ise AI’a kod fonksiyonlarını tool olarak tanıtma mekanizmasıdır. Yani Plugin’i bir fonksiyonlar koleksiyonu olarak düşünebiliriz.

Agent Skills ise agent için bir capability paketidir. İçinde sadece fonksiyon değil; prompt, workflow logic, resource bağlantıları ve farklı agent çağrıları gibi başka şeyler de olabilir.

Skill, Plugin’den daha kapsamlı bir capability paketidir.

Ve kritik bir gerçek vardır ki, artık modern agent mimarileri şu seyre doğru meyletmektedirler:

LLM


Agent Runtime


Skills


MCP Tools
Ve hatta yakın gelecekte beklenen özelliklerin arasında, programmatic skill oluşturma (API üzerinden runtime’da skill kaydetme) ve skill içindeki script’lerin doğrudan çalıştırılması da söz konusu olacaktır.

Bunlardan kaynaklı, yarın Agent Skill ile MCP tool yapılarının daha baskın olacağını şimdiden söylemekte fayda vardır.

SKILL.md dosyasının formatı nasıldır?

SKILL.md, bir Agent Skill’in tanım dosyasıdır. En basit haliyle içeriği aşağıdaki gibidir:

# Weather Skill

## Description
Provides weather information for a given city.

## When to Use
Use this skill when the user asks about:
– current weather
– temperature
– forecast

## Inputs
– city: Name of the city

## Outputs
– weather summary
– temperature

## Resources
– weather_api.md

Bu dosya agent’a şunu anlatır: “bu skill ne işe yarar, ne zaman kullanılmalıdır ve hangi kaynakları kullanmaktadır…”

Burada Progressive Disclosure için önemli kısım genelde ## Resources bölümüdür. Buradan anlayacağımız şudur ki, Microsoft Agent Framework’te bir skill kendisine ait diğer markdown dosyalarını resources bölümü üzerinden referans gösterebilmektedir. Zaten agent ilk başladığında advertise aşamasında sadece SKILL.md’i görecektir. Ardından kullanıcı prompt’u geldiğinde ve skill yüklenmesi gerektiğinde, resources altında listelenen md dosyaları load edilecek ve okunacaktır.

Daha gerçekçi bir SKILL.md için aşağıdaki yapılanmayı inceleyiniz;

SKILL.md email_api.md
# Email Sender Skill

## Description
Allows the agent to send emails to recipients.

## Capabilities
– send email
– attach files

## When to Use
Use this skill when:
– the user asks to send an email
– the user asks to share information via email

## Inputs
– recipient
– subject
– body

## Outputs
– confirmation message

## Resources
– email_api.md
– email_examples.md

# Email API

POST /send-email

Parameters:
– recipient
– subject
– body

Example:

{
“recipient”: “user@example.com”,
“subject”: “Report”,
“body”: “Here is the report”
}

Güvenlik Açısından Dikkat edilmesi Gerekenler

Agent Skill’leri, projelerimize eklediğimiz üçüncü parti kodlar gibi düşünmeli ve aynı güvenlik disiplini uygulanmalıdır. Çünkü, skill’lerin içeriği agent’ın context’ine enjekte edilmektedir ve bazı skill’ler script çalıştırabilmektedir. Bu yüzden güvenlik açısından dikkatli olmak gerekmektedir. Bunun için aşağıdaki bir kaç maddeyi göz önüne almakta fayda görmekteyim;

  • Bir Skill’i kullanmadan önce incelenmelidir!
    Bir skill’i projeye eklemeden önce içeriği(SKILL.md, script dosyaları, resource .md dosyaları) mutlaka kontrol edilmelidir.

    Typosquatting saldırısı nedir?
    Popüler bir paket/skill adının yazımına çok benzeyen sahte bir isim kullanılarak insanları kandırma saldırısıdır.

    Misal olarak;
    weather-skill adında gerçek bir paketin

    • wether-skill
    • weather-sk1ll
    • weather_skill
    • weatherr-skill

    şeklinde sahte paketleri olması bir Typosquatting tuzağıdır!

    Bu tuzakla hedef yazılımda zararlı kodlar çalıştırılabileceği gibi daha da tehlikelisi agent dünyasında prompt injection durumu söz konusu olabilir!

    Özellikle;

    • Script gerçekten söylediği işi yapıyor mu?
    • Güvenliği aşmaya çalışan talimatlar var mı?
    • Veri sızdırmaya çalışan şeyler söz konusu mu?
    • Agent config dosyalarını değiştirmeye çalışıyor mu?

    gözden geçirilmelidir…

    Unutmayın, skill içeriği zararlı prompt veya kod içerebilmektedir!

  • Kaynak güvenilir olmalıdır!
    Skill’leri güvenilir kaynaklardan yüklemeye özen gösterilmelidir. Özellikle bilinen geliştiricilerin oluşturduğu skill’ler ya da kurum içinde kullanılanlar tercih edilmelidir.

    Ki özellikle Typosquatting saldırılarına dikkat edilmelidir!

  • İzolasyon önemlidir!
    Script çalıştıran skill’lerin izole ortam da çalışması önem arz etmektedir. Özellikle dosya sistemine erişimin sınırlı olduğu, network erişiminin ve sistem komutlarının kısıtlı olduğu ortam olmasına özen gösterilmelidir.

    Hatta; dosya silme, veri gönderme veyahut sistem komutu işleme gibi hassas işlemler çalıştırılmadan önce kullanıcı onayı alınması en doğru yaklaşımdır.

  • Tüm süreç kayıt altına alınmalıdır!
    Agent’ın ne yaptığı kayıt altına alınmalıdır! Özellikle hangi skill yüklenmiş, hangi resource okunmuş ve hangi script çalıştırılmış tüm bunlar loglanmalıdır!

Skills vs. Workflows | Hangisi Ne Zaman Kullanılmalı?

Skills yahut workflows… İkisi de agent’ın yapabileceklerini genişletmektedir amma velakin çalışma şekiller tamamen farklılık göstermektedir.

Skill’de, hangi agent’ın hangi yeteneğe sahip olduğu tarafımızca tanımlanırken, nasıl kullanılacağının kararı AI tarafından verilmektedir. Haliyle akışın kontrolü AI’dadır.

Workflow’da ise akış, agent’ın müdahale edemeyeceği şekilde ve tüm kontrol bizde olacak biçimde tarafımızca tasarlanmaktadır. Dolayısıyla öngörülebilir bir davranış durumu söz konusudur ve tüm süreç deterministiktir.

Bundan kaynaklı skill; hava durumunu getirme, metni özetleme, kod analizi gerçekleştirme vs. gibi küçük ve tek odaklı işler için ideal’ken, workflow ise bir sipariş süreci yahut kredi başvuru süreci gibi çok adımlı süreçler için daha kullanışlıdır. Çünkü bir süreç, tek bir skill ile çözülemeyeceği için workflow daha uygun bir yaklaşım olacaktır.

Skill, AI’ın istediği gibi kullanabildiği küçük bir yetenekken, workflow ise bir işlev için adım adım tasarlanmış bir süreçtir.

FileAgentSkillsProvider Nedir?

FileAgentSkillsProvider, dosya sistemindeki skill klasörlerini tarayıp SKILL.md dosyalarını agent’a yükleyen bir provider’dır.

Çalışma mantığı nasıldır?
Agent Framework’te skill’ler genelde aşağıdakine benzer dosya sisteminde tutulmaktadırlar;

skills/
└── user-skills/
├── SKILL.md
└── resources/
├── API_REFERENCE.md
├── ERROR_CODES.md
└── OUTPUT_FORMATS.md
FileAgentSkillsProvider, bu dosya yapısını tarar ve içerisindeki SKILL.md dosyalarını bulur. Ardından bir skill manifest oluşturup, agent’a advertise eder ve böylece agent artık bu yeteneklerden haberdar olmuş olur.

var skillsProvider = new FileAgentSkillsProvider(skillPath: Path.Combine(AppContext.BaseDirectory, "skills"));

Normal şartlarda FileAgentSkillsProvider, skill’leri LLM’e otomatik bir system prompt ile tanıtmaktadır. Bizler istendiği taktirde bu skill’lerin agent’a nasıl tanıtılacağını belirleyen system propt şablonuna da müdahale edebilir ve nasıl kullanılacaklarına dair bir yönlendirmede bulunabiliriz.

var skillsProvider = new FileAgentSkillsProvider(
    skillPath: Path.Combine(AppContext.BaseDirectory, "skills"),
    options: new FileAgentSkillsProviderOptions
    {
        SkillsInstructionPrompt = """
            Aşağıdaki yeteneklere sahip bir yapay zekâ ajanısın:

            {{skills}}

            Bu yetenekleri yalnızca kullanıcının isteği onlarla örtüştüğünde kullan.
            Bir yeteneği kullanmadan önce her zaman ilgili kaynak dokümantasyonunu takip et.
        """
    });

Dikkat ederseniz Agent Skills, esasında tamamen prompt tabanlı çalışan bir özelliktir.

Bir LLM’in Agent Skill özelliğini kullanabilmesi için tool özelliğini destekliyor olması gerekmektedir!

Örnek Uygulama

Evet, şimdi sıra bu özelliği deneyimlemeye geldi diyebiliriz. Burada OpenRouter platformu üzerinden Google: Gemini 2.5 Flash Lite Preview 09-2025 modelini kullanarak JSONPlaceholder‘a özel geliştireceğimiz skill’leri sürece dahil eden bir AI Agent çalışması gerçekleştiriyor olacağız. Bu skill’ler ile AI Agent’a, JSONPlaceholder’ın bizlere sağladığı verilere has sorular yöneltebilecek ve agent’ın yeteneklerini böylece zenginleştirmiş olacağız. Bunun için aşağıdaki adımları sırasıyla takip etmeniz yeterli olacaktır:

  • Adım 1 (SKILL.md Dosyasının Oluşturulması)
    İlk olarak, AI Agent’lara yetenek kazandıracağımız dosya olan SKILL.md dosyasını ve kaynaklarını tasarlayarak başlayalım.

    SKILL.md içeriğini görmek için tıklayınız…

    name: user-skills
    description: JSONPlaceholder API üzerinden kullanıcı bilgilerini sorgular, listeler ve detay getirir.
    Kullanıcı arama, listeleme veya profil sorgulama istendiğinde kullan.

    ## Description

    Bu skill, harici REST API’den kullanıcı verilerini çekerek anlamlı bir şekilde sunar.
    Detaylı API referansı, hata kodları ve çıktı formatları için resources/ klasörüne bakılır.

    ## Capabilities

    – Tüm kullanıcıları listele
    – ID’ye göre tekil kullanıcı getir
    – Kullanıcıyı isme veya e-postaya göre filtrele
    – Kullanıcının şirket ve adres bilgilerini göster

    ## When to Use

    – “Tüm kullanıcıları listele” veya “kullanıcıları göster” istendiğinde
    – “X isimli kullanıcıyı bul” gibi tekil sorgularda
    – “ID’si 3 olan kullanıcının bilgileri nedir?” sorusunda
    – Kullanıcı e-postası veya şirket bilgisi sorulduğunda

    ## Inputs

    – `user_id` (opsiyonel): Tekil kullanıcı için numerik ID (1-10)
    – `name_filter` (opsiyonel): İsme göre filtreleme için metin
    – `email_filter` (opsiyonel): E-postaya göre filtreleme için metin
    – Hiçbiri verilmezse tüm kullanıcılar listelenir

    ## Outputs

    Çıktı formatlarının tamamı için `resources/OUTPUT_FORMATS.md` dosyasına bak.

    ## Resources

    – `resources/API_REFERENCE.md` — Endpoint listesi, request/response örnekleri
    – `resources/ERROR_CODES.md` — Olası hata kodları ve çözüm önerileri
    – `resources/OUTPUT_FORMATS.md` — Başarılı ve hatalı yanıt formatları

    ## Instructions

    1. Kullanıcının ne istediğini belirle: listeleme mi, tekil sorgu mu, filtreleme mi?
    2. API detayları için `resources/API_REFERENCE.md` dosyasını oku.
    3. İsteğe uygun endpoint’i çağır:
    – Listeleme → GET /users
    – Tekil → GET /users/{id}
    – Filtre → GET /users sonrası client-side filtrele
    4. Hata alırsan `resources/ERROR_CODES.md` dosyasına bak ve kullanıcıyı bilgilendir.
    5. Yanıtı `resources/OUTPUT_FORMATS.md` formatına göre düzenle ve Türkçe sun.

    API_REFERENCE.md içeriğini görmek için tıklayınız…
    ## API Referansı

    Base URL: `https://jsonplaceholder.typicode.com`

    ### Tüm Kullanıcıları Listele
    “`
    GET /users
    “`

    Response örneği:
    “`json
    [
    {
    “id”: 1,
    “name”: “Leanne Graham”,
    “username”: “Bret”,
    “email”: “Sincere@april.biz”,
    “phone”: “1-770-736-0988”,
    “address”: { “city”: “Gwenborough” },
    “company”: { “name”: “Romaguera-Crona” }
    }
    ]
    “`

    ### Tekil Kullanıcı Getir
    “`
    GET /users/{id}
    “`

    – `id`: 1 ile 10 arasında integer
    – Geçersiz ID için HTTP 404 döner

    ### Notlar

    – Authentication gerektirmez
    – Rate limit yoktur (test API)
    – Tüm yanıtlar JSON formatındadır

    ERROR_CODES.md içeriğini görmek için tıklayınız…
    ## Hata Kodları ve Çözümler

    ### HTTP 404 — Kullanıcı Bulunamadı
    – Sebep: Geçersiz veya mevcut olmayan user_id
    – Geçerli ID aralığı: 1-10
    – Çözüm: Kullanıcıya geçerli aralığı hatırlat

    ### HTTP 500 — Sunucu Hatası
    – Sebep: API geçici olarak erişilemez
    – Çözüm: Birkaç saniye bekleyip tekrar dene

    ### Bağlantı Hatası — Network Error
    – Sebep: İnternet bağlantısı yok veya API adresi değişmiş
    – Çözüm: Bağlantıyı kontrol et, base URL’i doğrula

    ### Boş Sonuç — Filtre Eşleşmedi
    – Sebep: Verilen isim veya e-posta hiçbir kayıtla eşleşmedi
    – Çözüm: Daha kısa veya farklı bir arama terimi dene

    OUTPUT_FORMATS.md içeriğini görmek için tıklayınız…
    ## Çıktı Formatları

    ### Tekil Kullanıcı (Başarılı)
    “`json
    {
    “id”: 1,
    “name”: “Leanne Graham”,
    “email”: “Sincere@april.biz”,
    “phone”: “1-770-736-0988”,
    “company”: “Romaguera-Crona”,
    “city”: “Gwenborough”
    }
    “`

    ### Kullanıcı Listesi (Başarılı)
    “`json
    [
    {
    “id”: 1,
    “name”: “Leanne Graham”,
    “email”: “Sincere@april.biz”,
    “company”: “Romaguera-Crona”
    }
    ]
    “`

    ### Hata Durumu
    “`json
    {
    “error”: “Kullanıcı bulunamadı”,
    “user_id”: 99
    }
    “`

    ### Boş Sonuç
    “`json
    {
    “result”: [],
    “message”: “Arama kriterinizle eşleşen kullanıcı bulunamadı.”
    }
    “`

    Dikkat ederseniz, SKILL.md ve resources dosyaları ifade ettikleri yetenekler açısından tüm detaylarıyla tasarlanmıştır. Özellikle kullanıcılarla ilgili prompt’ta istekler geldiği taktirde JSONPlaceholder’a hangi endpoint üzerinden, nasıl istekte bulunulacağı API_REFERENCE.md dosyasında detaylıca ifade edilmektedir. Ve hatta ilgili dosyaya göz atarsanız hedef kaynağın; authentication gerektirmediği, rate limiting kontrolünün olmadığı ve tüm yanıtlara karşın JSON formatında netice verdiği şeklinde bir seviyede detaylara kadar temas edildiğini göreceksiniz. Bunların dışında ERROR_CODES.md dosyasında olası hataların tanımları ve OUTPUT_FORMATS.md dosyasında da kaynakta gelecek cevapların formatları bildirilmiştir.

    Microsoft Agent Framework - Agent Skills İle AI Agent'ın Yeteneklerini GenişletelimDevam etmeden bir noktaya tekrar dikkatinizi çekmek istiyorum. O da, yukarıdaki satırlarda ifade edildiği üzere, Agent Skills özelliğinin burada da görüldüğü gibi prompt tabanlı çalıştığına şahit olmaktayız. Evet, formatı her ne kadar markdown belgesi olsa da, geri kalan esasında güzel ve izah edici bir prompt’tan ibaret olan dosyalardan bahsediyoruz.

    Velhasıl… Uygulamada skill dosyalarını yandaki görseldeki gibi bir klasör yapısında tuttuğumuzu da söylemekte fayda görmekteyim.

  • Adım 2 (AI Agent’ın Tasarlanması)
    Şimdi de aşağıdaki gibi AI Agent’ı tasarlayalım.

    Öncelikle konfigürasyon değerlerimizi oluşturalım:

    var configurations = (
        model: "google/gemini-2.5-flash-lite-preview-09-2025",
        endpoint: "https://openrouter.ai/api/v1",
        key: "sk-or-v1-beb*****4e2b02897c8161"
        );
    

    Ardından assistantAgent adından bir agent’ı yapılandıralım:

    builder.Services.AddKeyedSingleton<AIAgent>("assistantAgent", (IServiceProvider serviceProvider, object o) =>
    {
        var chatClient = new ChatClient(
            model: configurations.model,
            credential: new ApiKeyCredential(configurations.key),
            options: new OpenAIClientOptions
            {
                Endpoint = new Uri(configurations.endpoint)
            });
    
        return chatClient.AsAIAgent(new ChatClientAgentOptions
        {
            Name = "assistantAgent",
            ChatOptions = new()
            {
                Instructions = @"
                    - Sen yardımsever ve Türkçe konuşan bir asistansın. Kısa ve öz cevaplar ver!
                    - Görevleri uygun skill'leri kullanarak yerine getir!
                "
            }
        });
    });
    

    Evet… Görüldüğü üzere AI modeli kullanan bir AI Agent yapılandırmasında bulunmuş vaziyetteyiz.

  • Adım 3 (Prompt Endpoint’inin Geliştirilmesi)
    Şimdi de bu AI Agent’a kullanıcı prompt’larını eriştirecek ve LLM’i çalıştırıp sonucu bizlere getirecek endpoint’i tasarlayalım:

    app.MapPost("/", async ([FromBody] PromptRequest propmtVM, [FromKeyedServices("assistantAgent")] AIAgent assistantAgent) =>
    {
        if (propmtVM is null)
            return Results.BadRequest();
    
        var response = await assistantAgent.RunAsync(propmtVM.Prompt);
    
        return TypedResults.Ok(response.Text);
    });
    

    Evet, artık bu aşamadan sonra yaptığımız çalışmadaki eksiklikleri tamamlamaya başlayabiliriz…

  • Adım 4 (FileAgentSkillsProvider İle Skill Dosyalarını AI Agent’a Aktaralım)
    Oluşturduğumuz ‘skills’ klasöründeki SKILL.md dosyasını (ya da dosyalarını) FileAgentSkillsProvider ile AI Agent’a aktaralım:

    Bunun için önce dosyaları bulalım ve ardından aşağıdaki gibi IoC container’a ekleyelim:

    var skillsProvider = new FileAgentSkillsProvider(skillPath: Path.Combine(AppContext.BaseDirectory, "skills"));
    builder.Services.AddSingleton(skillsProvider);
    

    Devamında ise bu skill’leri 2. adımda yapılandırdığımız AI Agent’a AIContextProviders property’si üzerinden aşağıdaki gibi aktaralım:

    builder.Services.AddKeyedSingleton<AIAgent>("assistantAgent", (IServiceProvider serviceProvider, object o) =>
    {
        var chatClient = new ChatClient(
            model: configurations.model,
            credential: new ApiKeyCredential(configurations.key),
            options: new OpenAIClientOptions
            {
                Endpoint = new Uri(configurations.endpoint)
            });
    
        return chatClient.AsAIAgent(new ChatClientAgentOptions
        {
            Name = "assistantAgent",
            ChatOptions = new()
            {
                Instructions = @"
                    - Sen yardımsever ve Türkçe konuşan bir asistansın. Kısa ve öz cevaplar ver!
                    - Görevleri uygun skill'leri kullanarak yerine getir!
                "
            },
            AIContextProviders = [
                serviceProvider.GetRequiredService<FileAgentSkillsProvider>()
                ]
        });
    
  • Adım 5 (AI Model’e HTTP Request Tool’u Kazandırma)
    Şimdi, bu noktaya kadar yaptığımız çalışmaları derleyip çalıştırdığımızda, şöyle bir eksiklikle karşılaşacağız. Diyelim ki, aşağıdaki prompt ile bir istekte bulunduk:

    “Prompt”: “bana tüm kullanıcı bilgilerini ‘ad – soyad’ olarak getir.”

    Bize vereceği cevap:

    “Cevap”: API çağrısını yapamadığım için size verileri getiremiyorum.
    Lütfen doğrudan bir API çağrısı yapmamı sağlayacak bir komut verin

    olacaktır. Neden mi? Çünkü, model prompt’tan SKILL.md‘deki yetenekleri kullanması ve belirtilen API’a istek göndermesi gerektiğini anlamaktadır. Ancak HTTP isteğini fiziksel olarak gerçekleştirememektedir. Çünkü modelin internete erişimi yoktur! Böyle bir duruma karşın bizler modele HTTP isteklerini yürütebileceği bir tool kazandırabiliriz!

    Bunun için aşağıdaki gibi içerisinde gerekli davranışları sergileyen çalışmaları barındıran UserTools adında bir sınıf oluşturalım.

        public static class UserTools
        {
            static public Func<string, Task<dynamic?>> GetRequest =>
                 [Description("Verilen URL'e GET isteği atar ve JSON olarak sonucu döndürür.")] static async ([Description("GET isteğinde bulunulacak URL")] string url) =>
                 {
                     using var httpClient = new HttpClient();
                     return await httpClient.GetFromJsonAsync<dynamic?>(url);
                 };
        }
    

    Ve ardından bu tool’u yine 2. adımda yapılandırdığımız AI Agent’a aşağıdaki gibi ekleyelim:

    builder.Services.AddKeyedSingleton<AIAgent>("assistantAgent", (IServiceProvider serviceProvider, object o) =>
    {
        var chatClient = new ChatClient(
            model: configurations.model,
            credential: new ApiKeyCredential(configurations.key),
            options: new OpenAIClientOptions
            {
                Endpoint = new Uri(configurations.endpoint)
            })
        .AsIChatClient()
        .AsBuilder()
        .UseFunctionInvocation() // ← bu olmazsa tool çağrısı execute edilmez
        .Build();
    
        return chatClient.AsAIAgent(new ChatClientAgentOptions
        {
            Name = "assistantAgent",
            ChatOptions = new()
            {
                Instructions = @"
                    - Sen yardımsever ve Türkçe konuşan bir asistansın. Kısa ve öz cevaplar ver!
                    - Görevleri uygun skill'leri kullanarak yerine getir!
                ",
                Tools = [
                    AIFunctionFactory.Create(UserTools.GetRequest)
                ]
            },
            AIContextProviders = [
                serviceProvider.GetRequiredService<FileAgentSkillsProvider>()
                ]
        });
    });
    

    Dikkat ederseniz tool 25. satırda eklenmektedir. Ancak 10 ila 13. satır aralığına da göz atarsanız ekstradan eklenmiş bazı yapılandırmaları da göreceksiniz. Burada, özellikle LLM’in verdiği tool çağrılarını gerçekten çalıştıran bir middleware eklenmektedir. Yani bir nevi AI Agent’ın pipeline’ını genişlettiğimizi söyleyebiliriz.

    Peki burada ne yapıyoruz?

    .AsBuilder() metodu ile AI Agent’ın pipeline’ını middleware eklenebilecek hale getiriyoruz.

    .UseFunctionInvocation() metoduyla da LLM’in ürettiği function call / tool call çıktıları yakalanmakta ve gerçekten çalıştırılmaktadır. Bu metot oldukça kritiktik! Nedeni ise LLM’in sadece niyet bildirmesi, her hangi bir tool’u execute etmemesidir. Eğer bu metot çağrılmasaydı LLM’in hangi tool’un execute edilmesi gerektiğine dair muradı yine söz konusu olacaktı, ancak tool çalıştırılmayacaktı!

    Ve son olarak da .Build() metodu ile de yeni yapılandırılan pipeline finalize edilmekte ve artık bu AI Agent tarafından tool’lar nihai olarak kullanılabilir hale getirilmektedir.

  • Adım 6 (Test Etme)
    En son olarak artık yaptığımız bu çalışmayı test edelim. Misal olarak; bir önceki adımda sorduğumuz soruya karşılık:

    “Cevap”: “Leanne Graham\nErvin Howell\nClementine Bauch\nPatricia Lebsack\nChelsey Dietrich\n
    Mrs. Dennis Schulist\nKurtis Weissnat\nNicholas Runolfsdottir V\nGlenna Reichert\nClementina DuBuque”

    cevabını alabiliriz. Çünkü artık AI modelimiz, bir API isteğinde bulunması gerektiğini anladığında mevcut tool’larından bunu yapabilecek UserTools.GetRequest tool’unu kullanabiliyor. Hatta sizler prompt işlenmesi sürecinde bu tool’a break-point koyarak LLM tarafından bu kodların tetiklenip tetiklenmediğini test edebilirsiniz… Bu da size ödev olsun 😉
    Son olarak aşağıdaki gibi bir prompt ile testi hafif kompleksleştirelim:

    “Prompt”: “kullanıcılardan birbirlerine geometrik olarak en yakın olan ikisini bana getir!”

    El cevap:

    “Cevap”: “Öncelikle `user-skills` becerisi için talimatları yüklemem gerekiyor.\n\r\nKullanıcıların
    coğrafi olarak en yakın ikisini bulmak için koordinatlara (enlem/boylam) ihtiyacım var. Bu bilgi, API’de
    nasıl alınır, öğrenmek için `user-skills` kaynağını okumalıyım.\n\r\nKoordinat bilgisi için gerekli kaynak
    dosyası okunamadı. Tüm kullanıcıları çekip, koordinatları inceleyeyim.\n\r\nKullanıcı koordinatları:
    \n\n1. Leanne Graham (1): lat: -37.3159, lng: 81.1496\n2. Ervin Howell (2): lat: -43.9509, lng: -34.4618\n3.
    Clementine Bauch (3): lat: -68.6102, lng: -47.0653\n4. Patricia Lebsack (4): lat: 29.4572, lng: -164.2990\n5.
    Chelsey Dietrich (5): lat: -31.8129, lng: 62.5342\n6. Mrs. Dennis Schulist (6): lat: -71.4197, lng: 71.7478\n7.
    Kurtis Weissnat (7): lat: 24.8918, lng: 21.8984\n8. Nicholas Runolfsdottir V (8): lat: -14.3990,
    lng: -120.7677\n9. Glenna Reichert (9): lat: 24.6463, lng: -168.8889\n10. Clementina DuBuque (10):
    lat: -38.2386, lng: 57.2232\n\nÖklid mesafesini kullanarak en yakın çifti buldum: **Ervin Howell (2)**
    ve **Clementine Bauch (3)** birbirine en yakındır.”

    Bakın, görüldüğü üzere kullanıcıların verileri üzerinden birbirlerine geometrik olarak en yakın olan ikisini getirtmek gibi kompleks bir işi gerçekleştirtmiş bulunuyoruz 🙂 Ne kadar da güzel değil mi?

Örnek çalışmamız işte bu kadar 😉

Nihai olarak;
Microsoft Agent Framework’ün Agent Skills özelliği sayesinde AI Agent’larımızı çekirdek yapılarına dokunmadan, modüler ve taşınabilir yetenek paketleriyle zenginleştirme imkanına kavuşuyor, Progressive Disclosure Pattern ile de token maliyetlerini optimize ederken, SKILL.md tabanlı açık spesifikasyon sayesinde de hem geliştirici hem de güvenlik odaklı genişletilebilir bir zeminde çalışma imkanı edinmiş oluyoruz.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Örnek çalışmaya aşağıdaki GitHub reposundan erişebilirsiniz.
https://github.com/gncyyldz/Microsoft.Agent.Framework.Agent.Skills.Example

Bu repository, ilgili konuya dair örnek çalışmanın kaynak kodlarını ve mimari yapısını içermektedir. Detaylar için GitHub üzerinden incelemede bulunabilirsiniz.


GitHub’da Görüntüle →

Bunlar da hoşunuza gidebilir...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir