Mi az a beépülő modul?
A beépülő modulok a Szemantic Kernel kulcsfontosságú összetevői. Ha már használt beépülő modulokat a ChatGPT vagy a Copilot bővítményekből a Microsoft 365-ben, már ismeri őket. Beépülő modulokkal a meglévő API-kat beágyazhatja egy AI által használható gyűjteménybe. Ez lehetővé teszi, hogy a saját MI-je végrehajthasson olyan műveleteket, amelyeket egyébként nem tudna elvégezni.
A szemantikus kernel a háttérben függvényt használja, amely a legtöbb legújabb LLM natív funkciója, ahívásával teszi lehetővé az LLM-eket, végrehajtja tervezési és meghívja az API-kat. Függvényhívás esetén az LLM-ek kérhetnek (azaz meghívhatnak) egy adott függvényt. A Szemantic Kernel ezután a kódbázis megfelelő függvényének küldi el a kérést, és visszaadja az eredményeket az LLM-nek, hogy az LLM végleges választ generáljon.
Nem minden AI SDK-nak van hasonló fogalma a beépülő modulokhoz (legtöbben csak függvényekkel vagy eszközökkel rendelkeznek). A nagyvállalati forgatókönyvekben azonban a beépülő modulok értékesek, mivel olyan funkciókat foglalnak magukba, amelyek tükrözik, hogy a nagyvállalati fejlesztők hogyan fejlesztenek már szolgáltatásokat és API-kat. A beépülő modulok a függőséginjektálással is jól játszanak. A beépülő modul konstruktorán belül injektálhatja a beépülő modul működéséhez szükséges szolgáltatásokat (pl. adatbázis-kapcsolatok, HTTP-ügyfelek stb.). Ez nehezen valósítható meg más SDK-kkal, amelyek nem rendelkeznek beépülő modulokkal.
A beépülő modul anatómiája
Általánosságban véve egy beépülő modul a függvények csoportja, amelyek a mesterséges intelligencia alkalmazások és szolgáltatások számára elérhetők. A beépülő modulokon belüli függvényeket ezután egy AI-alkalmazás vezényelheti a felhasználói kérések végrehajtásához. A Szemantic Kernelben ezeket a függvényeket automatikusan meghívhatja függvényhívással.
Jegyzet
Más platformokon a függvényeket gyakran "eszközöknek" vagy "műveleteknek" is nevezik. A Szemantikus Kernelben a "függvények" kifejezést használjuk, mivel ezek általában natív függvényekként vannak definiálva a kódbázisban.
Csak a függvények biztosítása azonban nem elég egy beépülő modul létrehozásához. Az automatikus vezénylés funkcióhívással való használatához a beépülő moduloknak olyan részleteket is meg kell adniuk, amelyek szemantikailag írják le, hogyan viselkednek. A függvény bemenetéből, kimenetéből és mellékhatásaiból származó összes adatot úgy kell leírni, hogy az AI megértse, ellenkező esetben az AI nem fogja megfelelően meghívni a függvényt.
A jobb oldali WriterPlugin
minta beépülő modul például szemantikai leírásokkal ellátott függvényekkel rendelkezik, amelyek az egyes függvények működését írják le. Az LLM ezután ezeket a leírásokat használva kiválaszthatja a legjobb függvényeket, amelyek meghívhatók a felhasználó kérésének teljesítéséhez.
A jobb oldali képen egy LLM valószínűleg meghívja a ShortPoem
és StoryGen
függvényeket, hogy kielégítsék a felhasználók által kért kéréseket a megadott szemantikai leírásoknak köszönhetően.
Különböző típusú beépülő modulok importálása
A beépülő modulok szemantikus kernelbe való importálásának két elsődleges módja van: natív kód vagy OpenAPI-specifikáció használata. Az előbbi lehetővé teszi, hogy olyan beépülő modulokat szerkesszen a meglévő kódbázisban, amelyek kihasználhatják a már meglévő függőségeket és szolgáltatásokat. Ez utóbbi lehetővé teszi beépülő modulok importálását egy OpenAPI-specifikációból, amely különböző programozási nyelvek és platformok között osztható meg.
Az alábbiakban egy egyszerű példát mutatunk be egy natív beépülő modul importálására és használatára. Az ilyen típusú beépülő modulok importálásával kapcsolatos további információkért tekintse meg az alábbi cikkeket:
Borravaló
Első lépésként natív kód beépülő modulokat javasoljuk. Ahogy az alkalmazás kiforrott, és amikor platformfüggetlen csapatok között dolgozik, érdemes lehet megfontolni az OpenAPI-specifikációk használatát a beépülő modulok különböző programozási nyelvek és platformok közötti megosztásához.
A bővítmény funkciók különböző típusai
A pluginon belül általában két különféle függvényt fog használni: azokat, amelyek adatokat kérnek le a visszakeresés alapú generáláshoz (RAG), és azokat, amelyek automatizálják a feladatokat. Bár az egyes típusok funkcionálisan azonosak, általában másként használják őket a Szemantikus Kernelt használó alkalmazásokban.
Lekérési függvények esetében például érdemes stratégiákat alkalmazni a teljesítmény javítására (például gyorsítótárazás és költséghatékonyabb köztes modellek alkalmazása az összegzéshez). A feladatautomatizálási funkciókkal azonban valószínűleg emberi jóváhagyási folyamatokat kell implementálnia, hogy a tevékenységek megfelelően befejeződjenek.
A beépülő modulfüggvények különböző típusairól az alábbi cikkekben olvashat bővebben:
Ismerkedés a beépülő modulokkal
A pluginok használata a Szemantikus Kernelben mindig három lépésből áll:
- A beépülő modul definiálása
- Beépülő modul hozzáadása a kernelhez
- Ezután vagy meghívhatja a beépülő modul függvényeit egy prompt keretében függvényhívással, vagy...
Az alábbiakban egy magas szintű példát mutatunk be arra, hogyan használhat beépülő modult a Szemantic Kernelben. A beépülő modulok létrehozásával és használatával kapcsolatos részletesebb információkért tekintse meg a fenti hivatkozásokat.
1) A beépülő modul definiálása
A beépülő modul létrehozásának legegyszerűbb módja egy osztály definiálása és a metódusok jegyzetelése a KernelFunction
attribútummal. Ez a Szemantikus Kernel tudhatja, hogy ez egy olyan függvény, amelyet meghívhat egy MI, vagy hivatkozhat rá egy kérdésben.
Beépülő modulokat is importálhat egy OpenAPI-specifikációból.
Az alábbiakban létrehozunk egy bővítményt, amely lekéri a lámpák állapotát, és módosíthatja annak állapotát.
Borravaló
Mivel a legtöbb LLM-et Pythonra képezték ki a függvényhívásokhoz, ajánlott a kígyó-esetet használni a függvény- és tulajdonságnevekhez, még akkor is, ha a C# vagy a Java SDK-t használja.
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")]
public async Task<List<LightModel>> GetLightsAsync()
{
return lights
}
[KernelFunction("get_state")]
[Description("Gets the state of a particular 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")]
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) -> List[LightModel]:
"""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"]
) -> Optional[LightModel]:
"""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
) -> Optional[LightModel]:
"""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);
}
}
Figyelje meg, hogy leírást adunk a függvényhez és a paraméterekhez. Ez fontos ahhoz, hogy az AI megértse a függvény működését és használatát.
Borravaló
Ne féljen részletes leírást adni a függvényekről, ha egy AI-nek problémái vannak a meghívásukkal. Néhány példa, a függvény használatának (és nem használatának) időpontjára vonatkozó javaslatok, valamint a szükséges paraméterek beszerzésére vonatkozó útmutatás mind hasznosak lehetnek.
2) Adja hozzá a beépülő modult a kernelhez
Miután definiálta a beépülő modult, hozzáadhatja a kernelhez úgy, hogy létrehoz egy új beépülő modulpéldányt, és hozzáadja a kernel beépülő modulgyűjteményéhez.
Ez a példa bemutatja az osztály beépülő modulként való hozzáadásának legegyszerűbb módját a AddFromType
metódussal. A beépülő modulok hozzáadásának egyéb módjairól a natív beépülő modulok hozzáadásáról cikkben olvashat.
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) A beépülő modul funkcióinak meghívása
Végül az AI meghívhatja a beépülő modul függvényeit a függvényhívás használatával. Az alábbi példa bemutatja, hogyan lehet a get_lights
függvényt hívni a Lights
beépülő modulból, mielőtt a change_state
függvényt hívnánk a fény bekapcsolásához.
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_choice_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));
A fenti kóddal a következőhöz hasonló választ kell kapnia:
Szerep | Üzenet |
---|---|
🔵 felhasználói | Kapcsolja be a lámpát |
🔴 Assistant (függvényhívás) | Lights.get_lights() |
🟢 eszköz | [{ "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" }] |
🔴 Assistant (függvényhívás) | Lights.change_state(1; { "isOn": true }) |
🟢 eszköz | { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" } |
🔴 Asszisztens | A lámpa be van kapcsolva |
Borravaló
Bár közvetlenül is meghívhat beépülő modulfüggvényeket, ez nem ajánlott, mert az AI-nek kell eldöntenie, hogy melyik függvényt hívja meg. Ha explicit módon kell szabályoznia, hogy mely függvények legyenek meghívva, fontolja meg a standard metódusok használatát a kódbázisban beépülő modulok helyett.
Általános javaslatok beépülő modulok készítéséhez
Figyelembe véve, hogy minden forgatókönyv egyedi követelményekkel rendelkezik, különböző beépülő modulterveket használ, és több LLM-et is tartalmazhat, kihívást jelent a beépülő modul tervezéséhez egy méretre illeszkedő útmutatót nyújtani. Az alábbiakban azonban általános ajánlásokat és irányelveket talál, amelyek biztosítják, hogy a beépülő modulok AI-barátak legyenek, és az LLM-ek könnyen és hatékonyan használhassák őket.
Csak a szükséges beépülő modulokat importálja
Csak az adott forgatókönyvhöz szükséges függvényeket tartalmazó beépülő modulok importálása. Ez a megközelítés nemcsak a felhasznált bemeneti tokenek számát csökkenti, hanem minimalizálja a forgatókönyvben nem használt függvények helytelen hívásainak előfordulását is. Összességében ennek a stratégiának javítania kell a függvényhívás pontosságát, és csökkentenie kell a hamis pozitív értékek számát.
Emellett az OpenAI azt javasolja, hogy egyetlen API-hívásban ne használjon 20-nál több eszközt; ideális esetben legfeljebb 10 eszköz. Az OpenAI szerint: "Azt javasoljuk, hogy egyetlen API-hívásban legfeljebb 20 eszközt használjon. A fejlesztők általában csökkentik a modell azon képességét, hogy a megfelelő eszközt választhassák ki, ha 10–20 eszköz van meghatározva."* További információt OpenAI függvényhívási útmutató.
Beépülő modulok AI-baráttá tétele
Az LLM beépülő modulok megértésének és felhasználásának javítása érdekében ajánlott az alábbi irányelveket követni:
Használjon leíró és tömör függvényneveket: Győződjön meg arról, hogy a függvénynevek egyértelműen kifejezik a céljukat, hogy a modell megértse, mikor érdemes kijelölni az egyes függvényeket. Ha egy függvény neve nem egyértelmű, érdemes átnevezni az egyértelműség kedvéért. Ne használjon rövidítéseket vagy betűszavakat a függvénynevek rövidítésére. Használja a
DescriptionAttribute
, hogy csak szükség esetén adjon további kontextust és utasításokat, minimalizálva a tokenhasználatot.Függvényparaméterek minimalizálása: Korlátozza a függvényparaméterek számát, és amikor csak lehetséges, használjon primitív típusokat. Ez a megközelítés csökkenti a tokenek fogyasztását, és leegyszerűsíti a függvény szignatúráját, megkönnyítve, hogy az LLM hatékonyabban illessze össze a függvényparamétereket.
Névfüggvény paraméterei egyértelműen: Leíró nevek hozzárendelése a függvényparaméterekhez a rendeltetésük tisztázása érdekében. Ne használjon rövidítéseket vagy rövidítéseket a paraméternevek lerövidítéséhez, mivel ez segít az LLM-nek a paraméterekkel kapcsolatos érvelésben és a pontos értékek megadásában. A függvénynevekhez hasonlóan csak akkor használja a
DescriptionAttribute
, ha szükséges a tokenhasználat minimalizálása érdekében.
A függvények száma és feladataik közötti megfelelő egyensúly megtalálása
Egyfelől az egyetlen felelősségi körrel rendelkező függvények használata jó gyakorlat, amely lehetővé teszi, hogy a függvények több forgatókönyvben is egyszerűek és újrafelhasználhatók legyenek. Másrészt az egyes függvényhívások többletterheléssel járnak a hálózati menetidő késése, valamint a felhasznált bemeneti és kimeneti jogkivonatok száma tekintetében: a bemeneti jogkivonatok a függvénydefiníció és a hívás eredményét az LLM-nek küldik, míg a kimeneti jogkivonatokat a rendszer a függvényhívás modellből való fogadásakor használja fel.
Másik lehetőségként egyetlen, több feladatkörrel rendelkező függvény is implementálható a felhasznált jogkivonatok számának csökkentése és a hálózati többletterhelés csökkentése érdekében, bár ez más forgatókönyvekben az újrafelhasználhatóság csökkentésének költsége.
Azonban számos felelősség egyetlen függvénybe való összevonása növelheti a függvényparaméterek számát és összetettségét, valamint visszatérési típusát. Ez az összetettség olyan helyzetekhez vezethet, amikor a modell nehezen felel meg a függvényparamétereknek, ami nem fogadott paramétereket vagy helytelen típusú értékeket eredményez. Ezért elengedhetetlen, hogy a megfelelő egyensúlyt teremtsük a hálózati terhelés csökkentéséhez szükséges függvények száma és az egyes függvények felelősségi köre között, biztosítva, hogy a modell pontosan egyezzen a függvényparaméterekkel.
Szemantikus kernelfüggvények átalakítása
Használja a szemantikus kernelfüggvények átalakítási technikáit az Szemantikus kernelfüggvények átalakítása blogbejegyzésben leírtak szerint:
Függvény viselkedésének módosítása: Előfordulhat, hogy egy függvény alapértelmezett viselkedése nem felel meg a kívánt eredménynek, és nem lehetséges módosítani az eredeti függvény implementációját. Ilyen esetekben létrehozhat egy új függvényt, amely az eredetit burkolja, és ennek megfelelően módosítja annak működését.
Környezeti információk megadása: Függvények olyan paramétereket igényelhetnek, amelyeket az LLM nem tud vagy nem tud következtetni. Ha például egy függvénynek az aktuális felhasználó nevében kell eljárnia, vagy hitelesítési adatokat igényel, ez a környezet általában a gazdaalkalmazás számára érhető el, az LLM számára azonban nem. Ilyen esetekben átalakíthatja a függvényt úgy, hogy meghívja az eredetit, miközben megadja a szükséges környezeti információkat az üzemeltetési alkalmazásból, valamint az LLM által megadott argumentumokat.
Paraméterek listájának, típusainak és nevének módosítása: Ha az eredeti függvény összetett aláírással rendelkezik, amelyet az LLM nehezen tud értelmezni, a függvényt egyszerűbb aláírássá alakíthatja, amelyet az LLM könnyebben megérthet. Ez magában foglalhatja a paraméterek nevének, típusának, a paraméterek számának megváltoztatását, valamint az összetett paraméterek laposítását vagy visszaalakítását, többek között a kiigazításokat.
Helyi állapot kihasználása
A viszonylag nagy vagy bizalmas adathalmazokon( például dokumentumokon, cikkeken vagy bizalmas információkat tartalmazó e-maileken) működő beépülő modulok tervezésekor érdemes lehet helyi állapotot használni az eredeti adatok vagy köztes eredmények tárolására, amelyeket nem kell elküldeni az LLM-nek. Az ilyen forgatókönyvek függvényei elfogadhatnak és visszaadhatnak egy állapotazonosítót, amely lehetővé teszi az adatok helyi keresését és elérését ahelyett, hogy a tényleges adatokat átadná az LLM-nek, csak a következő függvényhívás argumentumaként kapja vissza.
Az adatok helyi tárolásával bizalmasan és biztonságosan tárolhatja az adatokat, miközben elkerülheti a szükségtelen tokenhasználatot a függvényhívások során. Ez a megközelítés nem csak az adatvédelmet javítja, hanem a nagy méretű vagy bizalmas adathalmazok feldolgozásának általános hatékonyságát is javítja.
Függvény visszaadási típusséma megadása AI-modellnek
A Függvények megadása visszatérési típusséma llm szakaszában ismertetett technikák egyikével adja meg a függvény visszatérési típussémát az AI-modellnek.
Egy jól definiált visszatérési típusú séma használatával az AI-modell pontosan azonosítja a kívánt tulajdonságokat, kiküszöbölve a lehetséges pontatlanságokat, amelyek akkor fordulhatnak elő, ha a modell hiányos vagy nem egyértelmű információkon alapuló feltételezéseket készít a séma hiányában. Következésképpen ez javítja a függvényhívások pontosságát, ami megbízhatóbb és pontosabb eredményekhez vezet.