{"id":2014,"date":"2024-03-04T11:24:02","date_gmt":"2024-03-04T19:24:02","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/semantic-kernel\/?p=2014"},"modified":"2024-03-15T08:14:05","modified_gmt":"2024-03-15T15:14:05","slug":"now-in-beta-explore-the-enhanced-python-sdk-for-semantic-kernel","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/now-in-beta-explore-the-enhanced-python-sdk-for-semantic-kernel\/","title":{"rendered":"Now in Beta: Explore the Enhanced Python SDK for Semantic Kernel"},"content":{"rendered":"<p class=\"code-line\" dir=\"auto\" data-line=\"2\">The Semantic Kernel team is excited to announce we are on the brink of releasing v1.0.0 of our Python SDK. In our journey towards this significant milestone, the latest beta release (0.9.0b1) has brought essential breaking changes, aligning our Python SDK&#8217;s capabilities with those of our .NET SDK. Our commitment to Pythonic best practices shines through in this update, with enhancements designed to improve readability and simplicity. This update not only signifies our efforts to synchronize the Python SDK with its .NET counterpart but also paves the way for exciting developments detailed below, setting the stage for a series of targeted enhancements poised to elevate the Python SDK experience for developers.<\/p>\n<p dir=\"auto\" data-line=\"2\">In the upcoming months, our dedication to enriching the Python SDK will be our focus, ensuring it receives the same caliber of feature enhancements and usability improvements that were introduced to the .NET SDK in our recent push towards v1.0.0. For a closer look at what we have planned for Python, we encourage you to explore our original Python <a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/road-to-v1-0-for-the-python-semantic-kernel-sdk\/\">roadmap blog<\/a> and our active <a href=\"https:\/\/github.com\/orgs\/microsoft\/projects\/866\/views\/3?sliceBy%5Bvalue%5D=python\">Python backlog<\/a>.<\/p>\n<h2 id=\"key-updates-in-090beta1\" class=\"code-line\" dir=\"auto\" style=\"margin-top: 2rem;\" data-line=\"4\">Key Updates in 0.9.0b1<\/h2>\n<p>Several changes have occurred in 0.9.0b1. Below are the most important changes to the SDK, along with links to the relevant PRs. As identified in our Python roadmap blog, we prioritized the main breaking changes for this release so internal and external contributors could have a stable SDK to contribute to.<\/p>\n<ol class=\"code-line\" dir=\"auto\" data-line=\"6\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"6\">Method Renaming and Alignment: Methods have been renamed for consistency with the .NET SDK, such as the kernel run to invoke, and the removal of _async suffixes to align with Azure Python SDK practices.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"7\">Kernel Arguments Overhaul: The introduction of a flexible kernel arguments system, replacing SKContext, allows for more dynamic configurations.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"8\">The Kernel Function decorator was improved and the\u00a0<code>function_context_parameter<\/code>\u00a0was removed making way for the use of Python&#8217;s Annotations. Kernel Function arguments are handled via Kernel Arguments.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"9\">Enhanced Function Results Handling: A new class for handling function results, offering straightforward methods for accessing values and metadata.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"10\"><span class=\"ui-provider a b c d e f g h i j k l m n o p q r s t u v w x y z ab ac ae af ag ah ai aj ak\" dir=\"ltr\">AI Service Selector: this feature allows for the dynamic resolution of prompt templates to the correct model by providing a default implementation and enabling user-defined custom selectors<\/span>. <a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"11\">Kernel Function Methodology Revamp: Simplification and restructuring of how kernel functions are handled, improving usability.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5159\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5159\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5159\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"12\">Plugin System Refinement: Transition from &#8220;skills&#8221; to &#8220;plugins&#8221; for enhanced clarity and consistency.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/4595\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/4595\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/4595\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"13\">Config and Template Updates: Major updates to prompt template configuration to match the .NET SDK, supporting more versatile execution settings.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"14\">Introduction of Chat History Class: This update deprecates older chat management approaches in favor of a more robust and flexible system.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"15\">Memory Connector Handling Improvements: By removing the kernel&#8217;s memory attribute, the SDK now supports multiple memory connectors through plugins.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5143\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5143\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5143\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"16\">Enhanced Argument and Template Handling: Introduces named arguments for function calls and improves template parsing for better validation.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5077\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"17\">Pythonic Exception Handling: Refactoring of exception handling to provide clearer error messages and full stack traces.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5231\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5231\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5231\">PR<\/a><\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"18\">Updated Python Samples: Migration and update of Python samples to reflect these latest changes, now available in the main Semantic Kernel repository. Jupyter Notebooks and Kernel Syntax Examples were also updated. We will be adding more examples as we move towards v1.0.0.\u00a0<a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5235\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5235\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/pull\/5235\">PR<\/a><\/li>\n<\/ol>\n<h2 id=\"upcoming-features\" class=\"code-line\" dir=\"auto\" style=\"margin-top: 2rem;\" data-line=\"20\">Upcoming Features<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"22\">As we progress towards the v1.0.0 release, we will focus on the following features next. We&#8217;re excited about the next round of enhancements because they greatly improve the productivity of developers that use Semantic Kernel and will allow Python developers to start using the same prompt resources as their .NET counterparts.<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"24\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"24\">Automatic function calling via kernel functions.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"25\">A new stepwise planner for function calling.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"26\">Enhancements to function hooks\/filters for alignment with .NET SDK.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"27\">Introduction of YAML template parsing.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"28\">Support for Handlebars and Jinja2 templating languages.*<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"29\">Implementation of the Handlebars planner.<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"31\">Our full Python public backlog is available\u00a0<a title=\"https:\/\/github.com\/orgs\/microsoft\/projects\/866\/views\/3?sliceBy%5Bvalue%5D=python\" href=\"https:\/\/github.com\/orgs\/microsoft\/projects\/866\/views\/3?sliceBy%5Bvalue%5D=python\" data-href=\"https:\/\/github.com\/orgs\/microsoft\/projects\/866\/views\/3?sliceBy%5Bvalue%5D=python\">here<\/a>.<\/p>\n<p dir=\"auto\" data-line=\"31\">* We are working on investigation and planning for this work, and don&#8217;t yet know which one we will introduce first and if we will have support for one or both.<\/p>\n<h2 id=\"migration-overview-for-upgrading\" class=\"code-line\" dir=\"auto\" style=\"margin-top: 2rem;\" data-line=\"33\">Migration Overview for Upgrading<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"35\">For users upgrading from older versions to 0.9.0b1, it&#8217;s essential to note the breaking changes, especially around method renaming, argument handling, and configuration updates. We recommend reviewing the detailed PR links provided to understand the changes fully. Additionally, ensure your codebase is updated to reflect these new patterns, particularly in areas related to kernel methods, plugin management, and template configurations.<\/p>\n<p dir=\"auto\" data-line=\"35\">To help with migration, we&#8217;ve identified several common scenarios that developers have implemented on the previous SDK. The following section provides before and after code snippets to make it easier to identify the breaking changes as you upgrade to the Beta.<\/p>\n<h3 style=\"margin-top: 1rem;\">01. Configuring the kernel<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"41\">Previously, when you created a service, the name of the service lived outside of the actual connection, which made it difficult to reuse.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">kernel.add_chat_service(\r\n    \"chat_completion\",\r\n    AzureChatCompletion(\r\n        deployment,\r\n        endpoint,\r\n        api_key,\r\n    ),\r\n)<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"52\">In the Beta update, we&#8217;ve moved the service ID into the connection so that the same connection can be reused by multiple kernels with the same name. Additionally, we&#8217;ve introduced the <code>kernel.add_service<\/code>\u00a0to add <em>any<\/em> AI service.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">kernel.add_service(\r\n    AzureChatCompletion(\r\n        service_id=\"chat_completion\",\r\n        deployment_name=deployment,\r\n        endpoint=endpoint,\r\n        api_key=api_key,\r\n    ),\r\n)<\/code><\/pre>\n<p>All arguments have been made named to offer enhanced flexibility in constructors. The service_id also plays a more important role as part of the execution settings and is used to help distinguish between execution settings for different types of models. The service_id is used for the base AI service selector.<\/p>\n<h3 style=\"margin-top: 1rem;\">02. Running a function via the kernel<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"67\">Previously, you would use the <code>run_async<\/code> method to call a function using a kernel.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">poemResult = await kernel.run_async(writer_plugin[\"ShortPoem\"], input_str=str(currentTime))<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"71\">This has been updated to <code>invoke<\/code> so that the same verb is used throughout Semantic Kernel. We&#8217;ve also removed the &#8220;async&#8221; suffix to make it more idiomatic with Python.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">poemResult = await kernel.invoke(write_plugin[\"ShortPoem\"], input=currentTime)<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"75\">Please note that <code>poemResult<\/code> is of type <a title=\"https:\/\/github.com\/microsoft\/semantic-kernel\/blob\/main\/python\/semantic_kernel\/functions\/function_result.py\" href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/blob\/main\/python\/semantic_kernel\/functions\/function_result.py\" data-href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/blob\/main\/python\/semantic_kernel\/functions\/function_result.py\">FunctionResult<\/a>.<\/p>\n<h3 style=\"margin-top: 1rem;\">03. Creating a function from a prompt<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"79\">Previously, creating a semantic function was tightly coupled with OpenAI request settings like <code>max_tokens<\/code> and <code>temperature<\/code>.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">semantic_function = kernel.create_semantic_function(\r\n    prompt,\r\n    function_name=\"Chat\",\r\n    description=\"Chat with the assistant\",\r\n    max_tokens=4000,\r\n    temperature=0.3,\r\n)<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"89\">We&#8217;ve updated it so that the execution settings can differ per service type. In the following example, we demonstrate how the execution settings type can be pulled from the service within the kernel. As we complete YAML prompt serialization, this code will become even simpler so that you as a developer don&#8217;t have to explicitly wire this up. You&#8217;ll simply provide the YAML file with the prompt and execution settings and Semantic Kernel will automatically create the function for you.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">chat_function = kernel.create_function_from_prompt(\r\n    prompt=prompt,\r\n    plugin_name=\"Summarize_Conversation\",\r\n    function_name=\"Chat\",\r\n    execution_settings=kernel.get_service(service_id).instantiate_prompt_execution_settings(\r\n        service_id=service_id,\r\n        max_tokens=4000,\r\n        temperature=0.3,\r\n    ),\r\n)<\/code><\/pre>\n<p>The prompt_execution_settings can be one of the following: a single settings object, a list of settings objects or a dictionary of PromptExecutionSetting to be able to handle multiple models.<\/p>\n<h3 style=\"margin-top: 1rem;\">04. Configuring Memory as a Plugin<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"109\">Previously, the kernel could only have a single memory provider. The <code>TextMemoryPlugin<\/code> could then automagically find this single memory provider when being added to a kernel. Unfortunately, this was limiting because many customers required multiple search indexes to be usable within a kernel.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\"># An embeddings generator is created as a part of register_memory \r\n# and the kernel has only one memory store attribute\r\nkernel.register_memory_store(VolatileMemoryStore())\r\nkernel.import_plugin(TextMemoryPlugin())<\/code><\/pre>\n<p>The register_memory_store in turn called the following code in the kernel:<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">def use_memory(\r\n    self,\r\n    storage: MemoryStoreBase,\r\n    embeddings_generator: Optional[EmbeddingGeneratorBase] = None,\r\n) -&gt; None:\r\n    if embeddings_generator is None:\r\n        service_id = self.get_text_embedding_generation_service_id()\r\n        if not service_id:\r\n            raise ValueError(\"The embedding service id cannot be `None` or empty\")\r\n        embeddings_service = self.get_ai_service(EmbeddingGeneratorBase, service_id)\r\n        if not embeddings_service:\r\n            raise ValueError(f\"AI configuration is missing for: {service_id}\")\r\n        embeddings_generator = embeddings_service(self)\r\n    if storage is None:\r\n        raise ValueError(\"The storage instance provided cannot be `None`\")\r\n    if embeddings_generator is None:\r\n        raise ValueError(\"The embedding generator cannot be `None`\")\r\n    self.register_memory(SemanticTextMemory(storage, embeddings_generator))\r\n\r\ndef register_memory(self, memory: SemanticTextMemoryBase) -&gt; None:\r\n    self.memory = memory<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"116\">Afterwards, we changed the relationship so that a single kernel could have multiple <code>TextMemoryPlugin<\/code> objects added, each with their own memory store. This is powerful, because it allows you as a developer to have multiple memories for things like documents, short-term memory, and long term memory.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">embedding_gen = OpenAITextEmbedding(\r\n    service_id=\"ada\", ai_model_id=\"text-embedding-ada-002\", api_key=api_key, org_id=org_id\r\n)\r\nkernel.add_service(embedding_gen)\r\n\r\nmemory = SemanticTextMemory(storage=VolatileMemoryStore(), embeddings_generator=embedding_gen)\r\nkernel.import_plugin_from_object(TextMemoryPlugin(memory), \"TextMemoryPlugin\")<\/code><\/pre>\n<h3 style=\"margin-top: 1rem;\">05. Utilizing Chat History as part of a prompt<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"129\">Previously, if you wanted to include a chat history within a prompt, you&#8217;d have to do string manipulation to join it together. Additionally, these pattern didn&#8217;t take advantage of the roles in the Chat Completion APIs provided by OpenAI and other model providers.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">prompt = \"\"\"{{$history}}\r\nUser: {{$request}}\r\nAssistant:  \"\"\"\r\n\r\nhistory = []\r\nvariables = ContextVariables()\r\nvariables[\"request\"] = request\r\nvariables[\"history\"] = \"\\n\".join(history)\r\nsemantic_function = kernel.create_semantic_function(\r\n    prompt,\r\n    function_name=\"Chat\",\r\n    description=\"Chat with the assistant\",\r\n    max_tokens=4000,\r\n    temperature=0.3,\r\n)\r\nresult = await kernel.run_async(\r\n    semantic_function,\r\n    input_vars=variables,\r\n)\r\n\r\n# Add the request to the history\r\nhistory.append(\"User: \" + request)\r\nhistory.append(\"Assistant\" + result.result)<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"155\">Subsequently, integrating a chat history object into a prompt becomes significantly simpler. Semantic Kernel can effortlessly incorporate it as a complex object, ensuring seamless integration into the prompt. During this operation, it will also leverage the roles defined in the Chat Completion service to produce better outcomes.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">history = ChatHistory()\r\n\r\nprompt = \"{{$history}}\"\r\n\r\nchat_function = kernel.create_function_from_prompt(\r\n    prompt=prompt,\r\n    plugin_name=\"chatGPT\",\r\n    function_name=\"Chat\",\r\n    prompt_template_config=chat_prompt_template_config,\r\n)\r\n\r\nhistory.add_user_message(request)\r\n\r\nresult = await kernel.invoke(\r\n    chat_function,\r\n    request=request,\r\n    history=history,\r\n)\r\n\r\nhistory.add_assistant_message(str(result))<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"155\"><code class=\"language-py\"><\/code><\/p>\n<h3 style=\"margin-top: 1rem;\">06. Creating a Plugin with Kernel Functions<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"181\">Previously, annotating a plugin with semantic meaning was very verbose.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">class MathPlugin:\r\n    @sk_function(\r\n        description=\"Adds two numbers together\",\r\n        name=\"Add\",\r\n    )\r\n    @sk_function_context_parameter(\r\n        name=\"input\",\r\n        description=\"The first number to add\",\r\n    )\r\n    @sk_function_context_parameter(\r\n        name=\"number2\",\r\n        description=\"The second number to add\",\r\n    )\r\n    def add(self, context: SKContext) -&gt; str:\r\n        return str(float(context[\"input\"]) + float(context[\"number2\"]))\r\n\r\n    @sk_function(\r\n        description=\"Subtract two numbers\",\r\n        name=\"Subtract\",\r\n    )\r\n    @sk_function_context_parameter(\r\n        name=\"input\",\r\n        description=\"The first number to subtract from\",\r\n    )\r\n    @sk_function_context_parameter(\r\n        name=\"number2\",\r\n        description=\"The second number to subtract away\",\r\n    )\r\n    def subtract(self, context: SKContext) -&gt; str:\r\n        return str(float(context[\"input\"]) - float(context[\"number2\"]))\r\n\r\nmath_plugin = kernel.import_plugin(\r\n    MathPlugin(), \r\n    plugin_name=\"MathPlugin\"\r\n)\r\n\r\nresult = await kernel.run_async(\r\n    math_plugin[\"Sqrt\"],\r\n    input_str=\"12\",\r\n)<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"224\">We now allow annotations to be added directly to the input parameters so that it&#8217;s easier to read and use.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">class MathPlugin:\r\n    @kernel_function(name=\"Add\")\r\n    def add(\r\n        self,\r\n        number1: Annotated[float, \"the first number to add\"],\r\n        number2: Annotated[float, \"the second number to add\"],\r\n    ) -&gt; Annotated[float, \"the output is a float\"]:\r\n        return float(number1) + float(number2)\r\n\r\n    @kernel_function(\r\n        description=\"Subtracts value to a value\",\r\n        name=\"Subtract\",\r\n    )\r\n    def subtract(\r\n        self,\r\n        number1: Annotated[float, \"the first number\"],\r\n        number2: Annotated[float, \"the number to subtract\"],\r\n    ) -&gt; Annotated[float, \"the output is a float\"]:\r\n        return float(number1) - float(number2)\r\n\r\nmath_plugin = kernel.import_plugin_from_object(\r\n    plugin_instance=MathPlugin(), \r\n    plugin_name=\"MathPlugin\"\r\n)\r\n\r\nresult = await kernel.invoke(\r\n    math_plugin[\"Add\"],\r\n    number1=5,\r\n    number2=5,\r\n)<\/code><\/pre>\n<p>We now support types other than strings, including custom objects (preferably based on Pydantic BaseModels.<\/p>\n<h3 style=\"margin-top: 1rem;\">07. Using Kernel Arguments<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"260\">Previously, developers had to juggle <code>SKContext<\/code> and <code>ContextVariables<\/code>. Many times, it was confusing when to use one or the other.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">chat_prompt=\"{{$request}}\"\r\nhistory = []\r\nvariables = ContextVariables()\r\nrequest = \"some input\"\r\nvariables[\"request\"] = request\r\nvariables[\"history\"] = \"\\n\".join(history)\r\n\r\nresult = await kernel.run_async(\r\n    chat_func,\r\n    input_vars=variables,\r\n)\r\n\r\n# Add the request to the history\r\nhistory.append(\"User: \" + request)\r\nhistory.append(\"Assistant\" + result.result)<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"278\">We&#8217;ve simplified this use of variables by introducing <code>KernelArguments<\/code>. You can create them much more easily, as keyword arguments passed to the KernelArgument object, and then pass the KernelArgument object into the <code>invoke<\/code> function.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">chat_prompt = \"{{$request}}\"\r\nchat_history = ChatHistory()\r\nchat_history.add_system_message(\r\n    \"You are a helpful, funny chatbot.\"\r\n)\r\n\r\n# Kernel Arguments can be specified as a concrete object\r\nargs = KernelArguments(arg1=val1, arg2=val2)\r\nresult = await kernel.invoke(func, args)\r\n<\/code><\/pre>\n<p>Additionally, if you don&#8217;t want to create a <code>KernelArgument<\/code> object, you can simply pass in inputs and values as <code>kwargs<\/code> so that you can further simplify your code.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">result = await kernel.invoke(\r\n    functions=chat_func,\r\n    request=\"some input\",\r\n    chat_history=chat_history,\r\n)\r\nhistory.add_user_message(request)\r\nhistory.add_assistant_message(str(result))<\/code><\/pre>\n<h3 style=\"margin-top: 1rem;\">08. Configure Multiple Prompt Execution Settings<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"302\">Previously, each prompt could only have a single set of execution settings attached to it. This was limiting for developers who wanted to use the same prompt across multiple models with different settings.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">prompt_template_config=PromptTemplateConfig(\r\n    execution_settings=PromptExecutionSettings(service_id=\"id1\", temperature=0.0),\r\n),<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"308\">Now, you can author multiple execution settings and assign them to a prompt. This is helpful if you want to test different settings in production.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">prompt_template_config=PromptTemplateConfig(\r\n    template=\"{{$request}}\",\r\n    execution_settings=[\r\n        OpenAIPromptExecutionSettings(service_id=\"id1\", temperature=0.0, num_of_responses=2),\r\n        GooglePalmPromptExecutionSettings(service_id=\"id2\", temperature=1.0, candidate_count=2),\r\n    ],\r\n),<\/code><\/pre>\n<h3 style=\"margin-top: 1rem;\">09. Then vs. Now: A Comprehensive Example<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"322\">To see how the different capabilities layer onto each other, we&#8217;ve provided the following example for building a simple chat bot. The first block of code is how you&#8217;d previously author the sample.<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">system_message = \"\"\"\r\nYou are a chat bot. Your name is Mosscap and\r\nyou have one goal: figure out what people need.\r\nYour full name, should you need to know it, is\r\nSplendid Speckled Mosscap. You communicate\r\neffectively, but you tend to answer with long\r\nflowery prose.\r\n\"\"\"\r\n# Create a kernel\r\nkernel = Kernel()\r\n\r\n# Create a chat service\r\nchat_service = AzureChatCompletion(\r\n    **azure_openai_settings_from_dot_env_as_dict(include_api_version=True)\r\n)\r\n\r\n# Add the chat service to the kernel\r\nkernel.add_chat_service(\"chat-gpt\", chat_service)\r\n\r\n# Define the chat request settings\r\nreq_settings = kernel.get_prompt_execution_settings_from_service(\r\n    ChatCompletionClientBase, \r\n    \"chat-gpt\",\r\n)\r\nreq_settings.max_tokens = 2000\r\nreq_settings.temperature = 0.7\r\nreq_settings.top_p = 0.8\r\n\r\n# Configure the prompt config, template, and function config\r\nprompt_config = PromptTemplateConfig(execution_settings=req_settings)\r\nprompt_template = ChatPromptTemplate(\r\n    \"{{$user_input}}\", \r\n    kernel.prompt_template_engine, \r\n    prompt_config\r\n)\r\nprompt_template.add_system_message(system_message)\r\nprompt_template.add_user_message(\"Hi there, who are you?\")\r\nprompt_template.add_assistant_message(\"I am Mosscap, a chat bot. I'm trying to figure out what people need.\")\r\nfunction_config = SemanticFunctionConfig(prompt_config, prompt_template)\r\n\r\n# Register the semantic function with the kernel\r\nchat_function = kernel.register_semantic_function(\"ChatBot\", \"Chat\", function_config)\r\n\r\n# Define an SK Context variables object to handle user input\r\ncontext_vars = ContextVariables()\r\nuser_input = input(\"User:&gt; \")\r\ncontext_vars[\"user_input\"] = user_input\r\n\r\n# Run the chat function with the user's input\r\nanswer = await kernel.run_async(chat_function, input_vars=context_vars)\r\n\r\n# Display the result\r\nprint(f\"Mosscap:&gt; {answer}\")<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"378\">After the changes introduced in the Beta release, you&#8217;d now write something like the following:<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">system_message = \"\"\"\r\nYou are a chat bot. Your name is Mosscap and\r\nyou have one goal: figure out what people need.\r\nYour full name, should you need to know it, is\r\nSplendid Speckled Mosscap. You communicate\r\neffectively, but you tend to answer with long\r\nflowery prose.\r\n\"\"\"\r\n\r\n# Create a Kernel\r\nkernel = Kernel()\r\n\r\n# Define a service ID that ties to the AI service\r\nservice_id = \"chat-gpt\"\r\nchat_service = AzureChatCompletion(\r\n    service_id=service_id, **azure_openai_settings_from_dot_env_as_dict(include_api_version=True)\r\n)\r\n\r\n# Add the AI service to the kernel\r\nkernel.add_service(chat_service)\r\n\r\n# Get the Prompt Execution Settings\r\nreq_settings = kernel.get_service(service_id).instantiate_prompt_execution_settings(\r\n    service_id=service_id, \r\n    max_tokens=2000,\r\n    temperature=0.7,\r\n    top_p=0.8,\r\n)\r\n\r\n# Create the prompt template config and specify any required input variables\r\nprompt_template_config = PromptTemplateConfig(\r\n    template={{$chat_history}}{{$input}},\r\n    name=\"chat\",\r\n    input_variables=[\r\n        InputVariable(name=\"input\", description=\"The user input\", is_required=True),\r\n        InputVariable(name=\"chat_history\", description=\"The history of the conversation\", is_required=True),\r\n    ],\r\n    execution_settings=req_settings, # The execution settings will be tied to the configured service_id\r\n)\r\n\r\n# Create the chat function from the prompt template config\r\nchat_function = kernel.create_function_from_prompt(\r\n    plugin_name=\"chat_bot\",\r\n    function_name=\"chat\",\r\n    prompt_template_config=prompt_template_config\r\n)\r\n\r\n# Define a chat history object\r\nhistory = ChatHistory(system_message=system_message)\r\n\r\n# Add the desired messages\r\nhistory.add_user_message(\"Hi there, who are you?\")\r\nhistory.add_assistant_message(\"I am Mosscap, a chat bot. I'm trying to figure out what people need.\")\r\n\r\n# Gather the user's input\r\nuser_input = input(\"User:&gt; \")\r\n\r\n# Invoke the chat function, passing the kernel arguments as kwargs\r\nresponse = await kernel.invoke(\r\n    chat_function,\r\n    request=user_input,\r\n    chat_history=history,\r\n)\r\n\r\n# View the response\r\nprint(f\"Mosscap:&gt; {response}\")\r\n\r\n# Add the user's input and the assistant's messages to the on-going chat history\r\nhistory.add_user_message(user_input)\r\nhistory.add_assistant_message(str(response))<\/code><\/pre>\n<p>Note: there are several ways to set the system message now. The first is to explicitly add the system message to the chat history either by history.add_system_message or as part of the ChatHistory constructor with keyword arguments, as shown above. The other way is to provide a system message through the template that is configured as part of the PromptTemplateConfig. <span class=\"ui-provider a b c d e f g h i j k l m n o p q r s t u v w x y z ab ac ae af ag ah ai aj ak\" dir=\"ltr\">Everything the template parser sees in the template before the ChatHistory object will be turned into a system_message, while everything between or after a ChatHistory is turned into user messages.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Semantic Kernel team is excited to announce we are on the brink of releasing v1.0.0 of our Python SDK. In our journey towards this significant milestone, the latest beta release (0.9.0b1) has brought essential breaking changes, aligning our Python SDK&#8217;s capabilities with those of our .NET SDK. Our commitment to Pythonic best practices shines [&hellip;]<\/p>\n","protected":false},"author":150043,"featured_media":2060,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[34,1],"tags":[],"class_list":["post-2014","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python-2","category-semantic-kernel"],"acf":[],"blog_post_summary":"<p>The Semantic Kernel team is excited to announce we are on the brink of releasing v1.0.0 of our Python SDK. In our journey towards this significant milestone, the latest beta release (0.9.0b1) has brought essential breaking changes, aligning our Python SDK&#8217;s capabilities with those of our .NET SDK. Our commitment to Pythonic best practices shines [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/2014","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/users\/150043"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/comments?post=2014"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/2014\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/2060"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=2014"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=2014"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=2014"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}