Eklenti nedir?
Eklentiler Semantik Çekirdeğin önemli bir bileşenidir. Microsoft 365'te ChatGPT veya Copilot uzantılarından gelen eklentileri zaten kullandıysanız, bunları zaten biliyorsunuz demektir. Eklentilerle mevcut API'lerinizi yapay zeka tarafından kullanılabilecek bir koleksiyonda kapsülleyebilirsiniz. Bu, yapay zekanıza aksi takdirde yapamayacağı eylemleri gerçekleştirme olanağı sunmanızı sağlar.
Semantik Çekirdek arka planda, LLM'lere izin vermek, planlama yapmak ve API'lerinizi çağırmak için en son LLM'lerin çoğuna ait yerel bir özellik olan işlev çağrısını kullanır. İşlev çağrısıyla, LLM'ler belirli bir işlevi isteyebilir (örneğin, çağırabilir). Semantik Çekirdek daha sonra isteği kod tabanınızdaki uygun işleve sıralar ve LLM'nin son yanıtı oluşturabilmesi için sonuçları LLM'ye geri döndürür.
Tüm yapay zeka SDK'larının eklentilere benzer bir kavramı yoktur (çoğu yalnızca işlevlere veya araçlara sahiptir). Ancak kurumsal senaryolarda eklentiler, kurumsal geliştiricilerin zaten hizmet ve API'leri nasıl geliştirdiğini yansıtan bir işlev kümesini kapsüllediğinden değerlidir. Eklentiler de bağımlılık ekleme ile düzgün bir şekilde yürütülmektedir. Eklentinin oluşturucusunun içinde, eklentinin çalışmasını gerçekleştirmek için gereken hizmetleri (örneğin, veritabanı bağlantıları, HTTP istemcileri vb.) ekleyebilirsiniz. Eklenti olmayan diğer SDK'larla bunu başarmak zordur.
Eklentinin anatomisi
Üst düzey bir eklenti, yapay zeka uygulamalarına ve hizmetlerine açık olabilecek bir işlev grubudur. Eklentilerdeki işlevler daha sonra kullanıcı isteklerini gerçekleştirmek için bir yapay zeka uygulaması tarafından düzenlenebilir. Anlam Çekirdeği'nin içinde, işlev çağrısı ile bu işlevleri otomatik olarak çağırabilirsiniz.
Not
Diğer platformlarda işlevler genellikle "araçlar" veya "eylemler" olarak adlandırılır. Anlam Çekirdeği'nde genellikle kod tabanınızda yerel işlevler olarak tanımlandığından "işlevler" terimini kullanırız.
Ancak yalnızca işlevleri sağlamak bir eklenti yapmak için yeterli değildir. İşlev çağrısıyla otomatik düzenlemeyi desteklemek için eklentilerin nasıl davrandıklarını gösteren ayrıntıları da sağlaması gerekir. İşlevin girişinden, çıkışından ve yan etkilerinden gelen her şeyin yapay zekanın anlayabileceği şekilde açıklanması gerekir, aksi takdirde yapay zeka işlevi doğru şekilde çağırmaz.
Örneğin, sağdaki örnek WriterPlugin
eklenti, her işlevin ne yaptığını açıklayan anlamsal açıklamalara sahip işlevlere sahiptir. LlM daha sonra bu açıklamaları kullanarak kullanıcının isteklerini yerine getirmek için çağrılabilecek en iyi işlevleri seçebilir.
Sağdaki resimde LLM, sağlanan anlamsal açıklamalar sayesinde kullanıcıların sorularını karşılamak için ve StoryGen
işlevlerini çağıracakShortPoem
.
Farklı eklenti türlerini içeri aktarma
Eklentileri Anlam Çekirdeği'ne aktarmanın iki birincil yolu vardır: yerel kod veya OpenAPI belirtimi kullanma. Önceki, mevcut kod tabanınızda zaten sahip olduğunuz bağımlılıklardan ve hizmetlerden yararlanabilen eklentiler yazmanıza olanak tanır. İkincisi, eklentileri farklı programlama dillerinde ve platformlarda paylaşılabilen bir OpenAPI belirtiminden içeri aktarmanıza olanak tanır.
Aşağıda yerel eklentiyi içeri aktarma ve kullanma ile ilgili basit bir örnek sağlıyoruz. Bu farklı eklenti türlerini içeri aktarma hakkında daha fazla bilgi edinmek için aşağıdaki makalelere bakın:
İpucu
Başlarken yerel kod eklentileri kullanmanızı öneririz. Uygulamanız büyüdükçe ve platformlar arası ekiplerde çalışırken eklentileri farklı programlama dillerinde ve platformlarda paylaşmak için OpenAPI belirtimlerini kullanmayı düşünebilirsiniz.
Farklı eklenti işlevleri türleri
Bir eklentide genellikle iki farklı işlev türüne sahip olursunuz: bunlar artırılmış nesil (RAG) için veri alan ve görevleri otomatik hale getiren işlevlerdir. Her tür işlevsel olarak aynı olsa da, bunlar genellikle Anlam Çekirdeği kullanan uygulamalarda farklı şekilde kullanılır.
Örneğin, alma işlevleriyle performansı geliştirmek için stratejiler kullanmak isteyebilirsiniz (örneğin, özetleme için önbelleğe alma ve daha ucuz ara modelleri kullanma). Görev otomasyonu işlevlerinde görevlerin doğru şekilde tamamlandığından emin olmak için döngüdeki insan onay işlemlerini uygulamak isteyebilirsiniz.
Farklı eklenti işlevleri türleri hakkında daha fazla bilgi edinmek için aşağıdaki makalelere bakın:
Eklentileri kullanmaya başlama
Anlam Çekirdeği içinde eklentileri kullanmak her zaman üç adımlı bir işlemdir:
- Eklentinizi tanımlama
- Eklentiyi çekirdeğinize ekleme
- Ardından, işlev çağrısı ile bir istemde eklentinin işlevlerini çağırın
Aşağıda Anlam Çekirdeği içinde eklentinin nasıl kullanılacağına yönelik üst düzey bir örnek sağlayacağız. Eklentileri oluşturma ve kullanma hakkında daha ayrıntılı bilgi için yukarıdaki bağlantılara bakın.
1) Eklentinizi tanımlayın
Eklenti oluşturmanın en kolay yolu bir sınıf tanımlamak ve öznitelik ile yöntemlerine KernelFunction
açıklama eklemektir. Bu, Semantic Kernel'in bunun bir yapay zeka tarafından çağrılabilen veya istemde başvurulabilen bir işlev olduğunu bilmesini sağlayın.
Eklentileri openAPI belirtiminden de içeri aktarabilirsiniz.
Aşağıda, ışıkların durumunu alabilen ve durumunu değiştirebilen bir eklenti oluşturacağız.
İpucu
LLM'lerin çoğu işlev çağrısı için Python ile eğitildiğinden, C# veya Java SDK'sını kullanıyor olsanız bile işlev adları ve özellik adları için yılan büyük/küçük harf kullanılması önerilir.
using System.ComponentModel;
using Microsoft.SemanticKernel;
public class LightsPlugin
{
// Mock data for the lights
private readonly List<LightModel> lights = new()
{
new LightModel { Id = 1, Name = "Table Lamp", IsOn = false, Brightness = 100, Hex = "FF0000" },
new LightModel { Id = 2, Name = "Porch light", IsOn = false, Brightness = 50, Hex = "00FF00" },
new LightModel { Id = 3, Name = "Chandelier", IsOn = true, Brightness = 75, Hex = "0000FF" }
};
[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("get_state")]
[Description("Gets the state of a particular light")]
[return: Description("The state of the light")]
public async Task<LightModel?> GetStateAsync([Description("The ID of the light")] int id)
{
// Get the state of the light with the specified ID
return lights.FirstOrDefault(light => light.Id == id);
}
[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(int id, LightModel LightModel)
{
var light = lights.FirstOrDefault(light => light.Id == id);
if (light == null)
{
return null;
}
// Update the light with the new state
light.IsOn = LightModel.IsOn;
light.Brightness = LightModel.Brightness;
light.Hex = LightModel.Hex;
return light;
}
}
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 byte? Brightness { get; set; }
[JsonPropertyName("hex")]
public string? Hex { get; set; }
}
from typing import TypedDict, Annotated
class LightModel(TypedDict):
id: int
name: str
is_on: bool | None
brightness: int | None
hex: str | None
class LightsPlugin:
lights: list[LightModel] = [
{"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"},
]
@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 get_state(
self,
id: Annotated[int, "The ID of the light"]
) -> Annotated[LightModel | None], "The state of the light"]:
"""Gets the state of a particular light."""
for light in self.lights:
if light["id"] == id:
return light
return None
@kernel_function
async def change_state(
self,
id: Annotated[int, "The ID of the light"],
new_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"] == id:
light["is_on"] = new_state.get("is_on", light["is_on"])
light["brightness"] = new_state.get("brightness", light["brightness"])
light["hex"] = new_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));
lights.put(2, new LightModel(2, "Porch light", false));
lights.put(3, new LightModel(3, "Chandelier", true));
}
@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 = "id", description = "The ID of the light to change") int id,
@KernelFunctionParameter(name = "isOn", description = "The new state of the light") boolean isOn) {
System.out.println("Changing light " + id + " " + isOn);
if (!lights.containsKey(id)) {
throw new IllegalArgumentException("Light not found");
}
lights.get(id).setIsOn(isOn);
return lights.get(id);
}
}
İşlev, dönüş değeri ve parametreler için açıklamalar sağladığımıza dikkat edin. Bu, yapay zekanın işlevin ne yaptığını ve nasıl kullanılacağını anlaması açısından önemlidir.
İpucu
Yapay zeka onları çağırmada sorun yaşıyorsa işlevleriniz için ayrıntılı açıklamalar sağlamaktan çekinmeyin. Birkaç örnek, işlevin ne zaman kullanılacağına (ve kullanılmayacağına) ilişkin öneriler ve gerekli parametrelerin nereden alınacağı konusunda rehberlik yararlı olabilir.
2) Eklentiyi çekirdeğinize ekleyin
Eklentinizi tanımladıktan sonra eklentinin yeni bir örneğini oluşturup çekirdeğin eklenti koleksiyonuna ekleyerek eklentiyi çekirdeğinize ekleyebilirsiniz.
Bu örnek, yöntemiyle AddFromType
bir sınıfı eklenti olarak eklemenin en kolay yolunu gösterir. Eklenti eklemenin diğer yolları hakkında bilgi edinmek için yerel eklenti ekleme makalesine bakın.
var builder = new KernelBuilder();
builder.Plugins.AddFromType<LightsPlugin>("Lights")
Kernel kernel = builder.Build();
kernel = Kernel()
kernel.add_plugin(
LightsPlugin(),
plugin_name="Lights",
)
// Import the LightsPlugin
KernelPlugin lightPlugin = KernelPluginFactory.createFromObject(new LightsPlugin(),
"LightsPlugin");
// Create a kernel with Azure OpenAI chat completion and plugin
Kernel kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, chatCompletionService)
.withPlugin(lightPlugin)
.build();
3) Eklentinin işlevlerini çağırma
Son olarak, yapay zekanın işlev çağrısını kullanarak eklentinizin işlevlerini çağırmasını sağlayabilirsiniz. Aşağıda, bir ışığı açmak için işlevi çağırmadan önce eklentiden Lights
işlevi çağırmak get_lights
için yapay zekanın nasıl eş eksene change_state
alındığını gösteren bir örnek verilmiştir.
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
// Create a kernel with Azure OpenAI chat completion
var builder = Kernel.CreateBuilder().AddAzureOpenAIChatCompletion(modelId, endpoint, apiKey);
// Build the kernel
Kernel kernel = builder.Build();
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// Add a plugin (the LightsPlugin class is defined below)
kernel.Plugins.AddFromType<LightsPlugin>("Lights");
// Enable planning
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
// Create a history store the conversation
var history = new ChatHistory();
history.AddUserMessage("Please turn on the lamp");
// Get the response from the AI
var result = await chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel);
// Print the results
Console.WriteLine("Assistant > " + result);
// Add the message from the agent to the chat history
history.AddAssistantMessage(result);
import asyncio
from semantic_kernel import Kernel
from semantic_kernel.functions import kernel_function
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase
from semantic_kernel.contents.chat_history import ChatHistory
from semantic_kernel.functions.kernel_arguments import KernelArguments
from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import (
AzureChatPromptExecutionSettings,
)
async def main():
# Initialize the kernel
kernel = Kernel()
# Add Azure OpenAI chat completion
chat_completion = AzureChatCompletion(
deployment_name="your_models_deployment_name",
api_key="your_api_key",
base_url="your_base_url",
)
kernel.add_service(chat_completion)
# Add a plugin (the LightsPlugin class is defined below)
kernel.add_plugin(
LightsPlugin(),
plugin_name="Lights",
)
# Enable planning
execution_settings = AzureChatPromptExecutionSettings()
execution_settings.function_call_behavior = FunctionChoiceBehavior.Auto()
# Create a history of the conversation
history = ChatHistory()
history.add_message("Please turn on the lamp")
# Get the response from the AI
result = await chat_completion.get_chat_message_content(
chat_history=history,
settings=execution_settings,
kernel=kernel,
)
# Print the results
print("Assistant > " + str(result))
# Add the message from the agent to the chat history
history.add_message(result)
# Run the main function
if __name__ == "__main__":
asyncio.run(main())
// Enable planning
InvocationContext invocationContext = new InvocationContext.Builder()
.withReturnMode(InvocationReturnMode.LAST_MESSAGE_ONLY)
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
.build();
// Create a history to store the conversation
ChatHistory history = new ChatHistory();
history.addUserMessage("Turn on light 2");
List<ChatMessageContent<?>> results = chatCompletionService
.getChatMessageContentsAsync(history, kernel, invocationContext)
.block();
System.out.println("Assistant > " + results.get(0));
Yukarıdaki kodla aşağıdakine benzer bir yanıt almanız gerekir:
Role | İleti |
---|---|
🔵Kullanıcı | Lütfen lambayı açın |
🔴Yardımcı (işlev çağrısı) | Lights.get_lights() |
🟢Araç | [{ "id": 1, "name": "Table Lamp", "isOn": false, "brightness": 100, "hex": "FF0000" }, { "id": 2, "name": "Porch light", "isOn": false, "brightness": 50, "hex": "00FF00" }, { "id": 3, "name": "Chandelier", "isOn": true, "brightness": 75, "hex": "0000FF" }] |
🔴Yardımcı (işlev çağrısı) | Lights.change_state(1, { "isOn": true }) |
🟢Araç | { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" } |
🔴Asistan | Lamba artık açık |
İpucu
Bir eklenti işlevini doğrudan çağırabilirsiniz ancak bu önerilmez çünkü hangi işlevlerin çağrılacağı yapay zekanın karar vermesi gerekir. Hangi işlevlerin çağrıldığı üzerinde açık denetime ihtiyacınız varsa, eklentiler yerine kod tabanınızda standart yöntemleri kullanmayı göz önünde bulundurun.