Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A csevegés befejezésének leghatékonyabb funkciója a függvények meghívása a modellből. Így létrehozhat egy csevegőrobotot, amely képes kezelni a meglévő kódját, így automatizálhatja az üzleti folyamatokat, kódrészleteket hozhat létre stb.
A Szemantic Kernel használatával leegyszerűsítjük a függvényhívások használatát azáltal, hogy automatikusan leírják a függvényeket és azok paramétereit a modellre, majd kezelik a modell és a kód közötti oda-vissza kommunikációt.
Függvényhívás használatakor azonban érdemes tisztában lenni azzal, hogy mi történik valójában a színfalak mögött, hogy optimalizálhassa a kódot, és a lehető legtöbbet hozhassa ki ebből a funkcióból.
Hogyan működik az automatikus függvényhívás
Feljegyzés
Az alábbi szakasz azt ismerteti, hogyan működik az automatikus függvényhívás a Szemantikus Kernelben. Az automatikus függvényhívás az alapértelmezett viselkedés a Szemantikus Kernelben, de igény szerint manuálisan is meghívhat függvényeket. A manuális függvényhívással kapcsolatos további információkért tekintse meg a függvényhívásról szóló cikket.
Ha olyan modellre irányuló kérelmet küld, amelyen engedélyezve van a függvényhívás, a Szemantikus Kernel a következő lépéseket hajtja végre:
| # | Lépés | Leírás |
|---|---|---|
| 1 | Függvények szerializálása | A kernelben elérhető összes függvény (és bemeneti paramétere) JSON-sémával szerializálva van. |
| 2 | Üzenetek és függvények küldése a modellnek | A szerializált függvényeket (és az aktuális csevegési előzményeket) a rendszer a bemenet részeként elküldi a modellnek. |
| 3 | A modell feldolgozza a bemenetet | A modell feldolgozza a bemenetet, és választ hoz létre. A válasz lehet csevegőüzenet vagy egy vagy több függvényhívás. |
| 4 | A válasz kezelése | Ha a válasz egy csevegőüzenet, a rendszer visszaadja a hívónak. Ha azonban a válasz függvényhívás, a Szemantikus Kernel kinyeri a függvény nevét és paramétereit. |
| 5 | A függvény meghívása | A kinyert függvény neve és paraméterei a kernelben lévő függvény meghívására szolgálnak. |
| 6 | A függvény eredményének visszaadása | A függvény eredményét a rendszer a csevegési előzmények részeként visszaküldi a modellnek. A 2–6. lépést a rendszer addig ismétli, amíg a modell egy csevegőüzenetet nem ad vissza, vagy el nem éri a maximális iterációs számot. |
Az alábbi ábra a függvényhívás folyamatát szemlélteti:
Az alábbi szakasz egy konkrét példát használ a függvényhívás gyakorlati működésének szemléltetésére.
Példa: Pizza rendelése
Tegyük fel, hogy van egy beépülő modulja, amely lehetővé teszi a felhasználó számára, hogy pizzát rendeljen. A beépülő modul a következő függvényekkel rendelkezik:
-
get_pizza_menu: A rendelkezésre álló pizzák listáját adja vissza -
add_pizza_to_cart: Hozzáad egy pizzát a felhasználó kosarához -
remove_pizza_from_cart: Eltávolít egy pizzát a felhasználó kosarából -
get_pizza_from_cart: Egy pizza konkrét adatait adja vissza a felhasználó kosarában -
get_cart: A felhasználó aktuális kosárját adja vissza -
checkout: A felhasználó kosarának ellenőrzése
A C#-ban a beépülő modul a következőképpen nézhet ki:
public class OrderPizzaPlugin(
IPizzaService pizzaService,
IUserContext userContext,
IPaymentService paymentService)
{
[KernelFunction("get_pizza_menu")]
public async Task<Menu> GetPizzaMenuAsync()
{
return await pizzaService.GetMenu();
}
[KernelFunction("add_pizza_to_cart")]
[Description("Add a pizza to the user's cart; returns the new item and updated cart")]
public async Task<CartDelta> AddPizzaToCart(
PizzaSize size,
List<PizzaToppings> toppings,
int quantity = 1,
string specialInstructions = ""
)
{
Guid cartId = userContext.GetCartId();
return await pizzaService.AddPizzaToCart(
cartId: cartId,
size: size,
toppings: toppings,
quantity: quantity,
specialInstructions: specialInstructions);
}
[KernelFunction("remove_pizza_from_cart")]
public async Task<RemovePizzaResponse> RemovePizzaFromCart(int pizzaId)
{
Guid cartId = userContext.GetCartId();
return await pizzaService.RemovePizzaFromCart(cartId, pizzaId);
}
[KernelFunction("get_pizza_from_cart")]
[Description("Returns the specific details of a pizza in the user's cart; use this instead of relying on previous messages since the cart may have changed since then.")]
public async Task<Pizza> GetPizzaFromCart(int pizzaId)
{
Guid cartId = await userContext.GetCartIdAsync();
return await pizzaService.GetPizzaFromCart(cartId, pizzaId);
}
[KernelFunction("get_cart")]
[Description("Returns the user's current cart, including the total price and items in the cart.")]
public async Task<Cart> GetCart()
{
Guid cartId = await userContext.GetCartIdAsync();
return await pizzaService.GetCart(cartId);
}
[KernelFunction("checkout")]
[Description("Checkouts the user's cart; this function will retrieve the payment from the user and complete the order.")]
public async Task<CheckoutResponse> Checkout()
{
Guid cartId = await userContext.GetCartIdAsync();
Guid paymentId = await paymentService.RequestPaymentFromUserAsync(cartId);
return await pizzaService.Checkout(cartId, paymentId);
}
}
Ezt a beépülő modult a következő módon adhatja hozzá a kernelhez:
IKernelBuilder kernelBuilder = new KernelBuilder();
kernelBuilder..AddAzureOpenAIChatCompletion(
deploymentName: "NAME_OF_YOUR_DEPLOYMENT",
apiKey: "YOUR_API_KEY",
endpoint: "YOUR_AZURE_ENDPOINT"
);
kernelBuilder.Plugins.AddFromType<OrderPizzaPlugin>("OrderPizza");
Kernel kernel = kernelBuilder.Build();
Feljegyzés
A rendszer csak az KernelFunction attribútummal rendelkező függvényeket szerializálja és elküldi a modellnek. Ez lehetővé teszi, hogy a segédfüggvények ne legyenek láthatóak a modell számára.
A Pythonban a beépülő modul a következőképpen nézhet ki:
from semantic_kernel.functions import kernel_function
class OrderPizzaPlugin:
def __init__(self, pizza_service, user_context, payment_service):
self.pizza_service = pizza_service
self.user_context = user_context
self.payment_service = payment_service
@kernel_function
async def get_pizza_menu(self):
return await self.pizza_service.get_menu()
@kernel_function(
description="Add a pizza to the user's cart; returns the new item and updated cart"
)
async def add_pizza_to_cart(self, size: PizzaSize, toppings: List[PizzaToppings], quantity: int = 1, special_instructions: str = ""):
cart_id = await self.user_context.get_cart_id()
return await self.pizza_service.add_pizza_to_cart(cart_id, size, toppings, quantity, special_instructions)
@kernel_function(
description="Remove a pizza from the user's cart; returns the updated cart"
)
async def remove_pizza_from_cart(self, pizza_id: int):
cart_id = await self.user_context.get_cart_id()
return await self.pizza_service.remove_pizza_from_cart(cart_id, pizza_id)
@kernel_function(
description="Returns the specific details of a pizza in the user's cart; use this instead of relying on previous messages since the cart may have changed since then."
)
async def get_pizza_from_cart(self, pizza_id: int):
cart_id = await self.user_context.get_cart_id()
return await self.pizza_service.get_pizza_from_cart(cart_id, pizza_id)
@kernel_function(
description="Returns the user's current cart, including the total price and items in the cart."
)
async def get_cart(self):
cart_id = await self.user_context.get_cart_id()
return await self.pizza_service.get_cart(cart_id)
@kernel_function(
description="Checkouts the user's cart; this function will retrieve the payment from the user and complete the order."
)
async def checkout(self):
cart_id = await self.user_context.get_cart_id()
payment_id = await self.payment_service.request_payment_from_user(cart_id)
return await self.pizza_service.checkout(cart_id, payment_id)
Ezt a beépülő modult a következő módon adhatja hozzá a kernelhez:
from semantic_kernel import Kernel
kernel = Kernel()
# Create the services needed for the plugin: pizza_service, user_context, and payment_service
# ...
# Add the plugin to the kernel
kernel.add_plugin(OrderPizzaPlugin(pizza_service, user_context, payment_service), plugin_name="OrderPizza")
Feljegyzés
A rendszer csak a kernel_function dekoratőrrel rendelkező függvényeket szerializálja és elküldi a modellnek. Ez lehetővé teszi, hogy a segédfüggvények ne legyenek láthatóak a modell számára.
Fenntartott paraméternevek az automatikus függvényhíváshoz
Ha automatikus függvényhívást használ a KernelFunctionsben, bizonyos paraméternevek fenntartottak , és speciális kezelést kapnak. Ezek a fenntartott nevek lehetővé teszik a függvény végrehajtásához szükséges kulcsobjektumok automatikus elérését.
Fenntartott nevek
A következő paraméternevek vannak fenntartva:
kernelserviceexecution_settingsarguments
Hogyan működnek?
A függvényhívás során a metódus gather_function_parameters az egyes paramétereket vizsgálja meg. Ha a paraméter neve megegyezik az egyik fenntartott névvel, az adott objektumokkal lesz feltöltve:
-
kernel: Kernel objektummal injektálva. -
service: Feltöltve a megadott argumentumok alapján kiválasztott AI-szolgáltatás által. -
execution_settings: A függvény végrehajtásához tartozó beállításokat tartalmaz. -
arguments: A meghívás során átadott kernelargumentumok teljes készletét fogadja.
Ez a kialakítás biztosítja, hogy ezek a paraméterek automatikusan kezelhetők legyenek, így nincs szükség manuális kinyerésre vagy hozzárendelésre.
Használati példa
Vegye figyelembe a következő példát:
class SimplePlugin:
@kernel_function(name="GetWeather", description="Get the weather for a location.")
async def get_the_weather(self, location: str, arguments: KernelArguments) -> str:
# The 'arguments' parameter is reserved and automatically populated with KernelArguments.
return f"Received user input: {location}, the weather is nice!"
Egyéni fenntartott paraméternevek az automatikus függvényhíváshoz
Ezt a viselkedést testre is szabhatja. Ehhez megjegyzést kell fűznie a függvényhívás definíciójából kizárni kívánt paraméterhez, például a következőhöz:
class SimplePlugin:
@kernel_function(name="GetWeather", description="Get the weather for a location.")
async def get_the_weather(self, location: str, special_arg: Annotated[str, {"include_in_function_choices": False}]) -> str:
# The 'special_arg' parameter is reserved and you need to ensure it either has a default value or gets passed.
A függvény meghívásakor győződjön meg arról, hogy átadja a special_arg paramétert, különben hibát fog okozni.
response = await kernel.invoke_async(
plugin_name=...,
function_name="GetWeather",
location="Seattle",
special_arg="This is a special argument"
)
Vagy adja hozzá az KernelArguments objektumhoz, hogy automatikus függvényhívással használhassa egy ügynökben, például:
arguments = KernelArguments(special_arg="This is a special argument")
response = await agent.get_response(
messages="what's the weather in Seattle?"
arguments=arguments)
A Java-ban a beépülő modul a következőképpen nézhet ki:
public class OrderPizzaPlugin {
private final PizzaService pizzaService;
private final HttpSession userContext;
private final PaymentService paymentService;
public OrderPizzaPlugin(
PizzaService pizzaService,
UserContext userContext,
PaymentService paymentService)
{
this.pizzaService = pizzaService;
this.userContext = userContext;
this.paymentService = paymentService;
}
@DefineKernelFunction(name = "get_pizza_menu", description = "Get the pizza menu.", returnType = "com.pizzashop.Menu")
public Mono<Menu> getPizzaMenuAsync()
{
return pizzaService.getMenu();
}
@DefineKernelFunction(
name = "add_pizza_to_cart",
description = "Add a pizza to the user's cart",
returnDescription = "Returns the new item and updated cart",
returnType = "com.pizzashop.CartDelta")
public Mono<CartDelta> addPizzaToCart(
@KernelFunctionParameter(name = "size", description = "The size of the pizza", type = com.pizzashopo.PizzaSize.class, required = true)
PizzaSize size,
@KernelFunctionParameter(name = "toppings", description = "The toppings to add to the the pizza", type = com.pizzashopo.PizzaToppings.class)
List<PizzaToppings> toppings,
@KernelFunctionParameter(name = "quantity", description = "How many of this pizza to order", type = Integer.class, defaultValue = "1")
int quantity,
@KernelFunctionParameter(name = "specialInstructions", description = "Special instructions for the order",)
String specialInstructions
)
{
UUID cartId = userContext.getCartId();
return pizzaService.addPizzaToCart(
cartId,
size,
toppings,
quantity,
specialInstructions);
}
@DefineKernelFunction(name = "remove_pizza_from_cart", description = "Remove a pizza from the cart.", returnType = "com.pizzashop.RemovePizzaResponse")
public Mono<RemovePizzaResponse> removePizzaFromCart(
@KernelFunctionParameter(name = "pizzaId", description = "Id of the pizza to remove from the cart", type = Integer.class, required = true)
int pizzaId)
{
UUID cartId = userContext.getCartId();
return pizzaService.removePizzaFromCart(cartId, pizzaId);
}
@DefineKernelFunction(
name = "get_pizza_from_cart",
description = "Returns the specific details of a pizza in the user's cart; use this instead of relying on previous messages since the cart may have changed since then.",
returnType = "com.pizzashop.Pizza")
public Mono<Pizza> getPizzaFromCart(
@KernelFunctionParameter(name = "pizzaId", description = "Id of the pizza to get from the cart", type = Integer.class, required = true)
int pizzaId)
{
UUID cartId = userContext.getCartId();
return pizzaService.getPizzaFromCart(cartId, pizzaId);
}
@DefineKernelFunction(
name = "get_cart",
description = "Returns the user's current cart, including the total price and items in the cart.",
returnType = "com.pizzashop.Cart")
public Mono<Cart> getCart()
{
UUID cartId = userContext.getCartId();
return pizzaService.getCart(cartId);
}
@DefineKernelFunction(
name = "checkout",
description = "Checkouts the user's cart; this function will retrieve the payment from the user and complete the order.",
returnType = "com.pizzashop.CheckoutResponse")
public Mono<CheckoutResponse> Checkout()
{
UUID cartId = userContext.getCartId();
return paymentService.requestPaymentFromUser(cartId)
.flatMap(paymentId -> pizzaService.checkout(cartId, paymentId));
}
}
Ezt a beépülő modult a következő módon adhatja hozzá a kernelhez:
OpenAIAsyncClient client = new OpenAIClientBuilder()
.credential(openAIClientCredentials)
.buildAsyncClient();
ChatCompletionService chat = OpenAIChatCompletion.builder()
.withModelId(modelId)
.withOpenAIAsyncClient(client)
.build();
KernelPlugin plugin = KernelPluginFactory.createFromObject(
new OrderPizzaPlugin(pizzaService, userContext, paymentService),
"OrderPizzaPlugin"
);
Kernel kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, chat)
.withPlugin(plugin)
.build();
Feljegyzés
A rendszer csak a DefineKernelFunction széljegyzetet tartalmazó függvényeket szerializálja, és elküldi a modellnek. Ez lehetővé teszi, hogy a segédfüggvények ne legyenek láthatóak a modell számára.
1) A függvények szerializálása
Amikor létrehoz egy kernelt a OrderPizzaPluginkövetkezővel, a rendszermag automatikusan szerializálja a függvényeket és azok paramétereit. Erre azért van szükség, hogy a modell megértse a függvényeket és azok bemeneteit.
A fenti beépülő modul esetében a szerializált függvények a következőképpen néznek ki:
[
{
"type": "function",
"function": {
"name": "OrderPizza-get_pizza_menu",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
},
{
"type": "function",
"function": {
"name": "OrderPizza-add_pizza_to_cart",
"description": "Add a pizza to the user's cart; returns the new item and updated cart",
"parameters": {
"type": "object",
"properties": {
"size": {
"type": "string",
"enum": ["Small", "Medium", "Large"]
},
"toppings": {
"type": "array",
"items": {
"type": "string",
"enum": ["Cheese", "Pepperoni", "Mushrooms"]
}
},
"quantity": {
"type": "integer",
"default": 1,
"description": "Quantity of pizzas"
},
"specialInstructions": {
"type": "string",
"default": "",
"description": "Special instructions for the pizza"
}
},
"required": ["size", "toppings"]
}
}
},
{
"type": "function",
"function": {
"name": "OrderPizza-remove_pizza_from_cart",
"parameters": {
"type": "object",
"properties": {
"pizzaId": {
"type": "integer"
}
},
"required": ["pizzaId"]
}
}
},
{
"type": "function",
"function": {
"name": "OrderPizza-get_pizza_from_cart",
"description": "Returns the specific details of a pizza in the user's cart; use this instead of relying on previous messages since the cart may have changed since then.",
"parameters": {
"type": "object",
"properties": {
"pizzaId": {
"type": "integer"
}
},
"required": ["pizzaId"]
}
}
},
{
"type": "function",
"function": {
"name": "OrderPizza-get_cart",
"description": "Returns the user's current cart, including the total price and items in the cart.",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
},
{
"type": "function",
"function": {
"name": "OrderPizza-checkout",
"description": "Checkouts the user's cart; this function will retrieve the payment from the user and complete the order.",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
}
]
Itt néhány dolgot érdemes megjegyezni, amelyek hatással lehetnek a csevegés befejezésének teljesítményére és minőségére:
A függvényséma részletessége – A modellhez használandó függvények szerializálása nem ingyenes. Minél részletesebb a séma, annál több tokent kell feldolgoznia a modellnek, ami lelassíthatja a válaszidőt és növelheti a költségeket.
Tipp.
Tartsa a függvényeket a lehető legegyszerűbbnek. A fenti példában láthatja, hogy nem minden függvény rendelkezik leírásokkal, ahol a függvény neve magától értetődő. Ez szándékosan csökkenti a tokenek számát. A paraméterek is egyszerűek maradnak; mindent, amit a modellnek nem kell tudnia (például a
cartIdvagypaymentId) rejtve marad. Ezeket az információkat ehelyett belső szolgáltatások biztosítják.Feljegyzés
Az egyetlen dolog, ami miatt nem kell aggódnia, a visszatérési típusok összetettsége. Megfigyelheti, hogy a visszatérési típusok nincsenek szerializálva a sémában. Ennek az az oka, hogy a modellnek nem kell tudnia a visszatérési típust a válasz létrehozásához. A 6. lépésben azonban látni fogjuk, hogy a túl részletes visszatérési típusok milyen hatással lehetnek a csevegés befejezésének minőségére.
Paramétertípusok – A sémával megadhatja az egyes paraméterek típusát. Ez fontos ahhoz, hogy a modell megértse a várt bemenetet. A fenti példában a
sizeparaméter egy szám, atoppingsparaméter pedig számtömb. Ez segít a modellnek pontosabb válaszokat létrehozni.Tipp.
Lehetőség szerint kerülje a paramétertípus használatát
string. A modell nem tudja kikövetkeztetni a sztring típusát, ami nem egyértelmű válaszokhoz vezethet. Ehelyett használjon számokat vagy más típusokat (példáulint, ,floatés összetett típusokat), ahol lehetséges.Kötelező paraméterek – Megadhatja azt is, hogy mely paraméterek szükségesek. Ez fontos ahhoz, hogy a modell megértse, mely paraméterek szükségesek a függvény működéséhez. A 3. lépés későbbi részében a modell ezeket az információkat használja a függvény meghívásához szükséges minimális információ megadására.
Tipp.
A paramétereket csak akkor jelölje meg kötelezőként, ha ténylegesen szükség van rájuk. Ez segít a modellnek gyorsabban és pontosabban meghívni a függvényeket.
Függvényleírások – A függvény leírása nem kötelező, de segíthet a modellnek pontosabb válaszok létrehozásában. A leírások meg tudják mondani a modellnek, hogy mit várjon a választól, mivel a visszatérési típus nem szerializálva van a sémában. Ha a modell nem megfelelően használ függvényeket, leírásokat is hozzáadhat, amelyek példákat és útmutatást nyújtanak.
A függvényben például a
get_pizza_from_cartleírás arra utasítja a felhasználót, hogy használja ezt a függvényt ahelyett, hogy a korábbi üzenetekre támaszkodik. Ez azért fontos, mert előfordulhat, hogy a kosár módosult az utolsó üzenet óta.Tipp.
Leírás hozzáadása előtt kérdezze meg magától, hogy a modellnek szüksége van-e ezekre az információkra a válasz létrehozásához. Ha nem, fontolja meg, hogy hagyja ki a részletesség csökkentése érdekében. Később bármikor hozzáadhat leírásokat, ha a modell nem tudja megfelelően használni a függvényt.
Beépülő modul neve – Ahogy a szerializált függvényekben látható, mindegyik függvénynek van tulajdonsága
name. A Szemantic Kernel a beépülő modul nevét használja a függvények névterének elnevezéséhez. Ez azért fontos, mert lehetővé teszi több, azonos nevű függvényekkel rendelkező beépülő modul használatát. Előfordulhat például, hogy több keresési szolgáltatás beépülő moduljai is vannak, amelyek mindegyike sajátsearchfunkcióval rendelkezik. A függvények elnevezésével elkerülheti az ütközéseket, és egyszerűbbé teheti a modell számára, hogy megértse, melyik függvényt hívja meg.Ennek ismeretében olyan beépülő modulnevet kell választania, amely egyedi és leíró. A fenti példában a beépülő modul neve .
OrderPizzaEz egyértelművé teszi, hogy a funkciók a pizza rendelésével kapcsolatosak.Tipp.
A beépülő modul nevének kiválasztásakor azt javasoljuk, hogy távolítsa el a felesleges szavakat, például a "beépülő modul" vagy a "szolgáltatás" szót. Ez segít csökkenteni a részletességet, és megkönnyíti a beépülő modul nevét a modell számára.
Feljegyzés
Alapértelmezés szerint a függvénynév elválasztó értéke .
-Bár ez a legtöbb modell esetében működik, némelyiknek eltérő követelményei lehetnek, például a Gemini. Ezt a rendszermag automatikusan elvégzi, de a szerializált függvényekben kissé eltérő függvényneveket láthat.
2) Üzenetek és függvények küldése a modellnek
A függvények szerializálása után a rendszer elküldi őket a modellnek az aktuális csevegési előzményekkel együtt. Ez lehetővé teszi, hogy a modell megértse a beszélgetés kontextusát és az elérhető függvényeket.
Ebben a forgatókönyvben el tudjuk képzelni, hogy a felhasználó megkéri az asszisztenst, hogy vegyen fel egy pizzát a kosárba:
ChatHistory chatHistory = [];
chatHistory.AddUserMessage("I'd like to order a pizza!");
chat_history = ChatHistory()
chat_history.add_user_message("I'd like to order a pizza!")
ChatHistory chatHistory = new ChatHistory();
chatHistory.addUserMessage("I'd like to order a pizza!");
Ezután elküldhetjük ezt a csevegési előzményt és a szerializált függvényeket a modellnek. A modell ezeket az információkat fogja használni a válasz legjobb módjának meghatározásához.
IChatCompletionService chatCompletion = kernel.GetRequiredService<IChatCompletionService>();
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
ChatResponse response = await chatCompletion.GetChatMessageContentAsync(
chatHistory,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel)
Feljegyzés
A példa a FunctionChoiceBehavior.Auto() viselkedést használja, amely az elérhető kevés egyike. Az egyéb függvényválasztási viselkedésekkel kapcsolatos további információkért tekintse meg a függvényválasztási viselkedésekről szóló cikket.
chat_completion = kernel.get_service(type=ChatCompletionClientBase)
execution_settings = AzureChatPromptExecutionSettings()
execution_settings.function_choice_behavior = FunctionChoiceBehavior.Auto()
response = await chat_completion.get_chat_message_content(
chat_history=history,
settings=execution_settings,
kernel=kernel,
)
Feljegyzés
A példa a FunctionChoiceBehavior.Auto() viselkedést használja, amely az elérhető kevés egyike. Az egyéb függvényválasztási viselkedésekkel kapcsolatos további információkért tekintse meg a függvényválasztási viselkedésekről szóló cikket.
ChatCompletionService chatCompletion = kernel.getService(I)ChatCompletionService.class);
InvocationContext invocationContext = InvocationContext.builder()
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(false));
List<ChatResponse> responses = chatCompletion.getChatMessageContentsAsync(
chatHistory,
kernel,
invocationContext).block();
Fontos
A függvényhívás használatához a kernelt át kell adni a szolgáltatásnak. Ennek az az oka, hogy a beépülő modulok regisztrálva vannak a kernelben, és a szolgáltatásnak tudnia kell, hogy mely beépülő modulok érhetők el.
3) A modell feldolgozza a bemenetet
A csevegési előzmények és a szerializált függvények segítségével a modell meg tudja határozni a legjobb választ. Ebben az esetben a modell felismeri, hogy a felhasználó pizzát szeretne rendelni. A modell valószínűleg meg szeretné hívni a add_pizza_to_cart függvényt, de mivel a méretet és a feltöltéseket kötelező paraméterként határoztuk meg, a modell az alábbi információkat fogja kérni a felhasználótól:
Console.WriteLine(response);
chatHistory.AddAssistantMessage(response);
// "Before I can add a pizza to your cart, I need to
// know the size and toppings. What size pizza would
// you like? Small, medium, or large?"
print(response)
chat_history.add_assistant_message(response)
# "Before I can add a pizza to your cart, I need to
# know the size and toppings. What size pizza would
# you like? Small, medium, or large?"
responses.forEach(response -> System.out.printlin(response.getContent());
chatHistory.addAll(responses);
// "Before I can add a pizza to your cart, I need to
// know the size and toppings. What size pizza would
// you like? Small, medium, or large?"
Mivel a modell azt szeretné, hogy a felhasználó a következőre válaszoljon, a Szemantic Kernel leállítja az automatikus függvényhívást, és visszaadja a vezérlést a felhasználónak. Ezen a ponton a felhasználó válaszolhat a megrendelni kívánt pizza méretével és feltéteivel:
chatHistory.AddUserMessage("I'd like a medium pizza with cheese and pepperoni, please.");
response = await chatCompletion.GetChatMessageContentAsync(
chatHistory,
kernel: kernel)
chat_history.add_user_message("I'd like a medium pizza with cheese and pepperoni, please.")
response = await chat_completion.get_chat_message_content(
chat_history=history,
settings=execution_settings,
kernel=kernel,
)
chatHistory.addUserMessage("I'd like a medium pizza with cheese and pepperoni, please.");
responses = chatCompletion.GetChatMessageContentAsync(
chatHistory,
kernel,
null).block();
Most, hogy a modell rendelkezik a szükséges információkkal, meghívhatja a add_pizza_to_cart függvényt a felhasználó bemenetével. A színfalak mögött egy új üzenet jelenik meg a csevegési előzményekben, amely így néz ki:
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "OrderPizzaPlugin-add_pizza_to_cart",
"arguments": "{\n\"size\": \"Medium\",\n\"toppings\": [\"Cheese\", \"Pepperoni\"]\n}"
}
}
]
Tipp.
Érdemes megjegyezni, hogy minden szükséges argumentumot a modellnek kell létrehoznia. Ez azt jelenti, hogy a válasz létrehozásához tokeneket kell elkölteni. Kerülje az olyan argumentumokat, amelyek sok tokent igényelnek (például GUID). Figyelje meg például, hogy egy int-t használunk a pizzaId-hez. Sokkal egyszerűbb megkérni a modellt, hogy küldjön egy-két számjegyből álló számot, mint GUID-t kérni.
Fontos
Ez a lépés teszi olyan erőssé a függvényhívást. Korábban az AI-alkalmazások fejlesztőinek külön folyamatokat kellett létrehozniuk a szándék és a pontkitöltési függvények kinyeréséhez. Függvényhívás esetén a modell eldöntheti , hogy mikor hívja meg a függvényt, és milyen információkat adjon meg.
4) A válasz kezelése
Amikor a Szemantikus Kernel megkapja a választ a modelltől, ellenőrzi, hogy a válasz függvényhívás-e. Ha igen, a Szemantic Kernel kinyeri a függvény nevét és paramétereit. Ebben az esetben a függvény neve OrderPizzaPlugin-add_pizza_to_cart, és az argumentumok a pizza mérete és feltétjei.
Az ilyen információk birtokában a Szemantikus Kernel átalakítja a bemeneteket a megfelelő típusokba, és átadja őket a add_pizza_to_cart-ben található OrderPizzaPlugin függvénynek. Ebben a példában az argumentumok JSON-sztringként kezdődnek, de a Szemantikus Kernel deszerializálja őket egy PizzaSize felsorolt típusra és egy List<PizzaToppings>.
Feljegyzés
A szemantikus kernel használatának egyik fő előnye, hogy a bemeneteket a megfelelő típusokba alakítja. A modell minden része JSON-objektumként jelenik meg, de a Szemantikus Kernel automatikusan deszerializálhatja ezeket az objektumokat a függvények megfelelő típusaiba.
A bemenetek rendezése után a Szemantic Kernel a függvényhívást is hozzáadja a csevegési előzményekhez:
chatHistory.Add(
new() {
Role = AuthorRole.Assistant,
Items = [
new FunctionCallContent(
functionName: "add_pizza_to_cart",
pluginName: "OrderPizza",
id: "call_abc123",
arguments: new () { {"size", "Medium"}, {"toppings", ["Cheese", "Pepperoni"]} }
)
]
}
);
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent
from semantic_kernel.contents.utils.author_role import AuthorRole
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.ASSISTANT,
items=[
FunctionCallContent(
name="OrderPizza-add_pizza_to_cart",
id="call_abc123",
arguments=str({"size": "Medium", "toppings": ["Cheese", "Pepperoni"]})
)
]
)
)
A Java Szemantikus Kernel másképp kezeli a függvényhívásokat, mint a C# és Python, amikor az automatikus hívási eszköz viselkedése hamis. Nem ad hozzá függvényhívási tartalmat a csevegési előzményekhez; ehelyett az alkalmazás felelős a függvényhívások meghívásáért. Ugorjon a következő, "A függvény meghívása" szakaszra, például a Függvényhívások Java-ban való kezelésére, ha az automatikus meghívás hamis.
5) A függvény meghívása
Miután a Szemantic Kernel rendelkezik a megfelelő típusokkal, végre meghívhatja a függvényt add_pizza_to_cart . Mivel a beépülő modul függőséginjektálást használ, a függvény olyan külső szolgáltatásokkal kommunikálhat, mint a pizzaServiceuserContext pizza hozzáadása a felhasználó kosarához.
Azonban nem minden függvény lesz sikeres. Ha a függvény meghiúsul, a Szemantic Kernel képes kezelni a hibát, és alapértelmezett választ ad a modellre. Ez lehetővé teszi a modell számára, hogy megértse, mi történt, és úgy dönt, hogy újrapróbálkozik vagy választ ad a felhasználónak.
Tipp.
Annak biztosítása érdekében, hogy a modell önhibázható legyen, fontos, hogy olyan hibaüzeneteket adjon meg, amelyek egyértelműen közlik, hogy mi történt, és hogyan javítható ki. Ez segíthet a modellnek a függvényhívás helyes információval való újrapróbálkozásában.
Feljegyzés
A Szemantic Kernel alapértelmezés szerint automatikusan meghívja a függvényeket. Ha azonban inkább manuálisan szeretné kezelni a függvényhívást, engedélyezheti a manuális függvényhívási módot. Ennek módjával kapcsolatos további részletekért tekintse meg a függvényhívási cikket.
6) A függvény eredményének visszaadása
A függvény meghívása után a rendszer visszaküldi a függvény eredményét a modellnek a csevegési előzmények részeként. Ez lehetővé teszi, hogy a modell megértse a beszélgetés kontextusát, és egy későbbi választ hozzon létre.
A színfalak mögött a Szemantic Kernel egy új üzenetet ad hozzá a csevegési előzményekhez az eszközszerepkörből, amely így néz ki:
chatHistory.Add(
new() {
Role = AuthorRole.Tool,
Items = [
new FunctionResultContent(
functionName: "add_pizza_to_cart",
pluginName: "OrderPizza",
id: "0001",
result: "{ \"new_items\": [ { \"id\": 1, \"size\": \"Medium\", \"toppings\": [\"Cheese\",\"Pepperoni\"] } ] }"
)
]
}
);
from semantic_kernel.contents import ChatMessageContent, FunctionResultContent
from semantic_kernel.contents.utils.author_role import AuthorRole
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.TOOL,
items=[
FunctionResultContent(
name="OrderPizza-add_pizza_to_cart",
id="0001",
result="{ \"new_items\": [ { \"id\": 1, \"size\": \"Medium\", \"toppings\": [\"Cheese\",\"Pepperoni\"] } ] }"
)
]
)
)
Ha az automatikus meghívás le van tiltva az eszköz hívási viselkedésében, a Java-alkalmazásnak meg kell hívnia a függvényhívásokat, és üzenetként AuthorRole.TOOL hozzá kell adnia a függvény eredményét a csevegési előzményekhez.
messages.stream()
.filter (it -> it instanceof OpenAIChatMessageContent)
.map(it -> ((OpenAIChatMessageContent<?>) it).getToolCall())
.flatMap(List::stream)
.forEach(toolCall -> {
String content;
try {
// getFunction will throw an exception if the function is not found
var fn = kernel.getFunction(toolCall.getPluginName(),
toolCall.getFunctionName());
FunctionResult<?> fnResult = fn
.invokeAsync(kernel, toolCall.getArguments(), null, null).block();
content = (String) fnResult.getResult();
} catch (IllegalArgumentException e) {
content = "Unable to find function. Please try again!";
}
chatHistory.addMessage(
AuthorRole.TOOL,
content,
StandardCharsets.UTF_8,
FunctionResultMetadata.build(toolCall.getId()));
});
Figyelje meg, hogy az eredmény egy JSON-sztring, amelyet a modellnek ezután fel kell dolgoznia. A modellnek, ahogyan korábban is, a tokeneket kell elköltenie ezen információk felhasználásához. Ezért fontos, hogy a visszatérési típusok a lehető legegyszerűbbek maradjanak. Ebben az esetben a visszaadott érték csak a kosárhoz hozzáadott új elemeket tartalmazza, nem pedig a teljes kosár tartalmát.
Tipp.
Legyen lehetőleg olyan tömör a válaszaival. Ha lehetséges, csak azokat az információkat adja vissza, amelyekre a modellnek szüksége van, vagy összegezze az adatokat egy másik LLM-kéréssel, mielőtt visszaküldené.
Ismételje meg a 2–6. lépést
Miután visszaadta az eredményt a modellnek, a folyamat megismétlődött. A modell feldolgozza a legújabb csevegési előzményeket, és választ hoz létre. Ebben az esetben a modell megkérdezheti a felhasználót, hogy fel szeretne-e venni egy másik pizzát a kosárba, vagy ki szeretné-e venni.
Párhuzamos függvényhívások
A fenti példában bemutattuk, hogyan hívhat meg egy LLM egyetlen függvényt. Ez gyakran lassú lehet, ha több függvényt kell egymás után meghívnia. A folyamat felgyorsításához több LLM támogatja a párhuzamos függvényhívásokat. Ez lehetővé teszi, hogy az LLM egyszerre több függvényt hívjon meg, felgyorsítva a folyamatot.
Ha például egy felhasználó több pizzát szeretne rendelni, az LLM egyszerre hívhatja meg az add_pizza_to_cart egyes pizzák függvényét. Ez jelentősen csökkentheti az LLM-hez való oda-vissza utazások számát, és felgyorsíthatja a rendelési folyamatot.
Következő lépések
Most, hogy megismerte a függvényhívás működését, a következő lépéssel megtudhatja, hogyan konfigurálhatja a függvényhívás különböző aspektusait, amelyek jobban megfelelnek az adott forgatókönyveknek: