Aracılığıyla paylaş


Eklenti olarak yerel kod ekleme

Yapay zeka aracısına yerel olarak desteklenmeyen özellikler sağlamanın en kolay yolu, yerel kodu bir eklentiye sarmaktır. Bu, yapay zeka aracılarınızın özelliklerini genişletmek için uygulama geliştiricisi olarak mevcut becerilerinizden yararlanmanızı sağlar.

Semantik Çekirdek, arka planda sağladığınız açıklamaları yansımayla birlikte kullanarak yapay zeka aracısına eklentiyi anlamsal olarak açıklar. Bu, yapay zeka aracısının eklentinin özelliklerini ve eklentiyle nasıl etkileşim kuracaklarını anlamasını sağlar.

LLM'ye doğru bilgileri sağlama

Eklentiyi yazarken, eklentinin ve işlevlerinin özelliklerini anlamak için yapay zeka aracısına doğru bilgileri sağlamanız gerekir. Buna aşağıdakiler dahildir:

  • Eklentinin adı
  • İşlevlerin adları
  • İşlevlerin açıklamaları
  • İşlevlerin parametreleri
  • Parametrelerin şeması

Anlam Çekirdeğinin değeri, bu bilgilerin çoğunu kodun kendisinden otomatik olarak oluşturabilmesidir. Geliştirici olarak bu, yapay zeka aracısının bunları anlayabilmesi için işlevlerin ve parametrelerin anlamsal açıklamalarını sağlamanız gerektiği anlamına gelir. Bununla birlikte, kodunuz için düzgün bir şekilde açıklama ekleyip açıklama eklerseniz, büyük olasılıkla bu bilgilere zaten sahipsinizdir.

Aşağıda yapay zeka aracınıza yerel kod sağlamanın iki farklı yolunu ve bu anlamsal bilgileri sağlamayı inceleyeceğiz.

Sınıf kullanarak eklenti tanımlama

Yerel eklenti oluşturmanın en kolay yolu, bir sınıfla başlamak ve ardından özniteliğiyle KernelFunction ek açıklamalı yöntemler eklemektir. Ayrıca, yapay zeka aracısına işlevi anlamak için gerekli bilgileri sağlamak için ek açıklamayı serbestçe kullanmanız Description da önerilir.

public class LightsPlugin
{
   private readonly List<LightModel> _lights;

   public LightsPlugin(LoggerFactory loggerFactory, List<LightModel> lights)
   {
      _lights = lights;
   }

   [KernelFunction("get_lights")]
   [Description("Gets a list of lights and their current state")]
   [return: Description("An array of lights")]
   public async Task<List<LightModel>> GetLightsAsync()
   {
      return _lights;
   }

   [KernelFunction("change_state")]
   [Description("Changes the state of the light")]
   [return: Description("The updated state of the light; will return null if the light does not exist")]
   public async Task<LightModel?> ChangeStateAsync(LightModel changeState)
   {
      // Find the light to change
      var light = _lights.FirstOrDefault(l => l.Id == changeState.Id);

      // If the light does not exist, return null
      if (light == null)
      {
         return null;
      }

      // Update the light state
      light.IsOn = changeState.IsOn;
      light.Brightness = changeState.Brightness;
      light.Color = changeState.Color;

      return light;
   }
}
from typing import List, Optional, Annotated

class LightsPlugin:
    def __init__(self, lights: List[LightModel]):
        self._lights = lights

    @kernel_function
    async def get_lights(self) -> Annotated[List[LightModel], "An array of lights"]:
        """Gets a list of lights and their current state."""
        return self._lights

    @kernel_function
    async def change_state(
        self,
        change_state: LightModel
    ) -> Annotated[Optional[LightModel], "The updated state of the light; will return null if the light does not exist"]:
        """Changes the state of the light."""
        for light in self._lights:
            if light["id"] == change_state["id"]:
                light["is_on"] = change_state.get("is_on", light["is_on"])
                light["brightness"] = change_state.get("brightness", light["brightness"])
                light["hex"] = change_state.get("hex", light["hex"])
                return light
        return None
public class LightsPlugin {

    // Mock data for the lights
    private final Map<Integer, LightModel> lights = new HashMap<>();

    public LightsPlugin() {
        lights.put(1, new LightModel(1, "Table Lamp", false, LightModel.Brightness.MEDIUM, "#FFFFFF"));
        lights.put(2, new LightModel(2, "Porch light", false, LightModel.Brightness.HIGH, "#FF0000"));
        lights.put(3, new LightModel(3, "Chandelier", true, LightModel.Brightness.LOW, "#FFFF00"));
    }

    @DefineKernelFunction(name = "get_lights", description = "Gets a list of lights and their current state")
    public List<LightModel> getLights() {
        System.out.println("Getting lights");
        return new ArrayList<>(lights.values());
    }

    @DefineKernelFunction(name = "change_state", description = "Changes the state of the light")
    public LightModel changeState(
            @KernelFunctionParameter(
                    name = "model",
                    description = "The new state of the model to set. Example model: " +
                            "{\"id\":99,\"name\":\"Head Lamp\",\"isOn\":false,\"brightness\":\"MEDIUM\",\"color\":\"#FFFFFF\"}",
                    type = LightModel.class) LightModel model
    ) {
        System.out.println("Changing light " + model.getId() + " " + model.getIsOn());
        if (!lights.containsKey(model.getId())) {
            throw new IllegalArgumentException("Light not found");
        }

        lights.put(model.getId(), model);

        return lights.get(model.getId());
    }
}

İpucu

LLM'ler ağırlıklı olarak Python kodu üzerinde eğitildiğinden, işlev adları ve parametreleri (C# veya Java kullanıyor olsanız bile) için snake_case kullanmanız önerilir. Bu, yapay zeka aracısının işlevi ve parametrelerini daha iyi anlamasına yardımcı olur.

İşlevinizin giriş değişkeni olarak karmaşık bir nesnesi varsa, Anlam Çekirdeği de bu nesne için bir şema oluşturur ve bunu yapay zeka aracısına geçirir. İşlevlere benzer şekilde, yapay zeka için belirgin olmayan özellikler için ek açıklamalar sağlamanız Description gerekir. Sınıfın ve numaralandırmanın LightState tanımı aşağıdadır Brightness .

using System.Text.Json.Serialization;

public class LightModel
{
   [JsonPropertyName("id")]
   public int Id { get; set; }

   [JsonPropertyName("name")]
   public string? Name { get; set; }

   [JsonPropertyName("is_on")]
   public bool? IsOn { get; set; }

   [JsonPropertyName("brightness")]
   public enum? Brightness { get; set; }

   [JsonPropertyName("color")]
   [Description("The color of the light with a hex code (ensure you include the # symbol)")]
   public string? Color { get; set; }
}

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Brightness
{
   Low,
   Medium,
   High
}
from typing import TypedDict

class LightModel(TypedDict):
    id: int
    name: str
    is_on: bool | None
    brightness: int | None
    hex: str | None
public class LightModel {

    private int id;
    private String name;
    private Boolean isOn;
    private Brightness brightness;
    private String color;


    public enum Brightness {
        LOW,
        MEDIUM,
        HIGH
    }

    public LightModel(int id, String name, Boolean isOn, Brightness brightness, String color) {
        this.id = id;
        this.name = name;
        this.isOn = isOn;
        this.brightness = brightness;
        this.color = color;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Boolean getIsOn() {
        return isOn;
    }

    public void setIsOn(Boolean isOn) {
        this.isOn = isOn;
    }

    public Brightness getBrightness() {
        return brightness;
    }

    public void setBrightness(Brightness brightness) {
        this.brightness = brightness;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

Not

Bu bir "eğlenceli" örnek olsa da, eklentinin parametrelerinin ne kadar karmaşık olabileceğini gösteren iyi bir iş çıkardı. Bu tek durumda, dört farklı özellik türüne sahip karmaşık bir nesnemiz vardır: tamsayı, dize, boole ve sabit listesi. Semantik Çekirdeğin değeri, bu nesne için şemayı otomatik olarak oluşturup yapay zeka aracısına geçirip yapay zeka aracısı tarafından oluşturulan parametreleri doğru nesneye sıralayabilir.

Eklenti sınıfınızı yazmayı tamamladıktan sonra veya AddFromObject yöntemlerini kullanarak bunu çekİrDEK'e AddFromType<> ekleyebilirsiniz.

İpucu

İşlev oluştururken kendinize her zaman "Bu işlevi kullanmak için yapay zekaya nasıl ek yardım verebilirim?" sorusunu sorun. Bu, belirli giriş türlerini kullanmayı (mümkün olduğunda dizelerden kaçınma), açıklamalar ve örnekler sağlamayı içerebilir.

yöntemini kullanarak AddFromObject eklenti ekleme

yöntemi, AddFromObject eklentinin nasıl derlendiğini doğrudan denetlemek istemeniz durumunda eklenti sınıfının bir örneğini doğrudan eklenti koleksiyonuna eklemenize olanak tanır.

Örneğin, sınıfının oluşturucu LightsPlugin ışık listesini gerektirir. Bu durumda, eklenti sınıfının bir örneğini oluşturabilir ve eklenti koleksiyonuna ekleyebilirsiniz.

List<LightModel> lights = new()
   {
      new LightModel { Id = 1, Name = "Table Lamp", IsOn = false, Brightness = Brightness.Medium, Color = "#FFFFFF" },
      new LightModel { Id = 2, Name = "Porch light", IsOn = false, Brightness = Brightness.High, Color = "#FF0000" },
      new LightModel { Id = 3, Name = "Chandelier", IsOn = true, Brightness = Brightness.Low, Color = "#FFFF00" }
   };

kernel.Plugins.AddFromObject(new LightsPlugin(lights));

yöntemini kullanarak AddFromType<> eklenti ekleme

yöntemi kullanılırken AddFromType<> çekirdek otomatik olarak bağımlılık ekleme özelliğini kullanarak eklenti sınıfının bir örneğini oluşturur ve eklenti koleksiyonuna ekler.

Oluşturucunuz eklentiye hizmet veya diğer bağımlılıkların eklenip eklenmediğini gerektiriyorsa bu yararlı olur. Örneğin, sınıfımız LightsPlugin bir günlükçü ve ışık listesi yerine buna bir hafif hizmet eklemek isteyebilir.

public class LightsPlugin
{
   private readonly Logger _logger;
   private readonly LightService _lightService;

   public LightsPlugin(LoggerFactory loggerFactory, LightService lightService)
   {
      _logger = loggerFactory.CreateLogger<LightsPlugin>();
      _lightService = lightService;
   }

   [KernelFunction("get_lights")]
   [Description("Gets a list of lights and their current state")]
   [return: Description("An array of lights")]
   public async Task<List<LightModel>> GetLightsAsync()
   {
      _logger.LogInformation("Getting lights");
      return lightService.GetLights();
   }

   [KernelFunction("change_state")]
   [Description("Changes the state of the light")]
   [return: Description("The updated state of the light; will return null if the light does not exist")]
   public async Task<LightModel?> ChangeStateAsync(LightModel changeState)
   {
      _logger.LogInformation("Changing light state");
      return lightService.ChangeState(changeState);
   }
}

Bağımlılık Ekleme ile, çekirdeği oluşturmadan önce gerekli hizmetleri ve eklentileri çekirdek oluşturucuya ekleyebilirsiniz.

var builder = Kernel.CreateBuilder();

// Add dependencies for the plugin
builder.Services.AddLogging(loggingBuilder => loggingBuilder.AddConsole().SetMinimumLevel(LogLevel.Trace));
builder.Services.AddSingleton<LightService>();

// Add the plugin to the kernel
builder.Plugins.AddFromType<LightsPlugin>("Lights");

// Build the kernel
Kernel kernel = builder.Build();

İşlev koleksiyonu kullanarak eklenti tanımlama

Daha az yaygın ama yine de kullanışlı olan, işlev koleksiyonunu kullanarak bir eklenti tanımlamaktır. Bu özellikle çalışma zamanında bir dizi işlevden dinamik olarak bir eklenti oluşturmanız gerekiyorsa kullanışlıdır.

Bu işlemi kullanmak için işlev fabrikasını kullanarak eklentiye eklemeden önce tek tek işlevler oluşturmanız gerekir.

kernel.Plugins.AddFromFunctions("time_plugin",
[
    KernelFunctionFactory.CreateFromMethod(
        method: () => DateTime.Now,
        functionName: "get_time",
        description: "Get the current time"
    ),
    KernelFunctionFactory.CreateFromMethod(
        method: (DateTime start, DateTime end) => (end - start).TotalSeconds,
        functionName: "diff_time",
        description: "Get the difference between two times in seconds"
    )
]);

Bağımlılık Ekleme ile yerel kod eklemeye yönelik ek stratejiler

Bağımlılık Ekleme ile çalışıyorsanız, çekirdekte eklentiler oluşturmak ve eklemek için ek stratejiler alabilirsiniz. Aşağıda Bağımlılık Ekleme'yi kullanarak eklenti eklemeye dair bazı örnekler verilmiştir.

Eklenti koleksiyonu ekleme

İpucu

Eklenti koleksiyonu değişebilir olduğundan her kullanımdan sonra atılması için eklenti koleksiyonunuzu geçici bir hizmet haline getirmenizi öneririz. Her kullanım için yeni bir eklenti koleksiyonu oluşturmak ucuzdur, bu nedenle performansla ilgili bir sorun olmamalıdır.

var builder = Host.CreateApplicationBuilder(args);

// Create native plugin collection
builder.Services.AddTransient((serviceProvider)=>{
   KernelPluginCollection pluginCollection = [];
   pluginCollection.AddFromType<LightsPlugin>("Lights");

   return pluginCollection;
});

// Create the kernel service
builder.Services.AddTransient<Kernel>((serviceProvider)=> {
   KernelPluginCollection pluginCollection = serviceProvider.GetRequiredService<KernelPluginCollection>();

   return new Kernel(serviceProvider, pluginCollection);
});

İpucu

Çekirdek makalesinde belirtildiği gibi, çekirdek son derece hafiftir, bu nedenle geçici olarak her kullanım için yeni bir çekirdek oluşturmak bir performans sorunu değildir.

Eklentilerinizi tekil olarak oluşturma

Eklentiler değiştirilebilir değildir, bu nedenle bunları tekil olarak oluşturmak genellikle güvenlidir. Bu, eklenti fabrikasını kullanarak ve sonuçta elde edilen eklentiyi hizmet koleksiyonunuz için ekleyerek yapılabilir.

var builder = Host.CreateApplicationBuilder(args);

// Create singletons of your plugin
builder.Services.AddKeyedSingleton("LightPlugin", (serviceProvider, key) => {
    return KernelPluginFactory.CreateFromType<LightsPlugin>();
});

// Create a kernel service with singleton plugin
builder.Services.AddTransient((serviceProvider)=> {
    KernelPluginCollection pluginCollection = [
      serviceProvider.GetRequiredKeyedService<KernelPlugin>("LightPlugin")
    ];

    return new Kernel(serviceProvider, pluginCollection);
});

yöntemini kullanarak add_plugin eklenti ekleme

add_plugin yöntemi, çekİrdeğe bir eklenti örneği eklemenize olanak tanır. Aşağıda sınıfını nasıl oluşturabileceğinize LightsPlugin ve çekirdeğine nasıl ekleyebileceğinize ilişkin bir örnek verilmiştir.

# Create the kernel
kernel = Kernel()

# Create dependencies for the plugin
lights = [
    {"id": 1, "name": "Table Lamp", "is_on": False, "brightness": 100, "hex": "FF0000"},
    {"id": 2, "name": "Porch light", "is_on": False, "brightness": 50, "hex": "00FF00"},
    {"id": 3, "name": "Chandelier", "is_on": True, "brightness": 75, "hex": "0000FF"},
]

# Create the plugin
lights_plugin = LightsPlugin(lights)

# Add the plugin to the kernel
kernel.add_plugin(lights_plugin)

yöntemini kullanarak createFromObject eklenti ekleme

yöntemi, createFromObject ek açıklamalı yöntemlerle bir Nesneden çekirdek eklentisi oluşturmanıza olanak tanır.

// Import the LightsPlugin
KernelPlugin lightPlugin = KernelPluginFactory.createFromObject(new LightsPlugin(),
        "LightsPlugin");

Bu eklenti daha sonra bir çekirdekte eklenebilir.

// Create a kernel with Azure OpenAI chat completion and plugin
Kernel kernel = Kernel.builder()
        .withAIService(ChatCompletionService.class, chatCompletionService)
        .withPlugin(lightPlugin)
        .build();

Sonraki adımlar

Eklenti oluşturmayı öğrendiğinize göre artık bunları yapay zeka aracınızla nasıl kullanacağınızı öğrenebilirsiniz. Eklentilerinize eklediğiniz işlevlerin türüne bağlı olarak, izlemeniz gereken farklı desenler vardır. Alma işlevleri için alma işlevlerini kullanma makalesine bakın. Görev otomasyonu işlevleri için , görev otomasyonu işlevlerini kullanma makalesine bakın.