首页 >后端开发 >Python教程 >使用语义内核构建聊天机器人 - 部分插件

使用语义内核构建聊天机器人 - 部分插件

Linda Hamilton
Linda Hamilton原创
2024-12-06 07:33:15624浏览

在上一章中,我们了解了语义内核的一些基本概念,最后建立了一个能够回答一般问题的工作代理,但使用说明具有预定义的语气和目的。

在第二章中,我们将使用插件为我们的图书管理员添加特定技能。

什么是插件?

插件是一组暴露给人工智能服务的函数。插件封装了功能,允许助手执行不属于其本机行​​为的操作。

例如,通过插件,我们可以让助手从 API 或数据库中获取一些数据。此外,助手可以代表用户执行一些操作,通常是通过 API。此外,助手还可以使用插件更新 UI 的某些部分。

正如我之前提到的,插件是由不同的功能组成的。每个函数主要定义为:

  • 描述:函数的目的以及何时应该调用它。它将帮助模型决定何时调用它,正如我们将在函数调用.
  • 部分中看到的那样
  • 输入变量:用于参数化函数,以便可以重用。

语义内核支持不同类型的插件。在这篇文章中,我们将重点关注其中两个:提示插件原生插件

提示插件

提示插件基本上是在具体情况下调用的特定提示。在典型场景中,我们可能有一个复杂的系统提示,我们在其中定义代理的语气、目的和一般行为。然而,我们可能希望代理执行一些具体的操作,我们需要定义一些特定的限制和规则。对于这种情况,我们会尽量避免系统提示增长到无限,以减少幻觉并保持模型响应的相关性和可控性。这是提示插件的完美案例:

  1. 系统提示:语气、目的和一般行为。
  2. 摘要提示:包括如何进行摘要的规则和限制。例如,它不应超过两段。

提示插件由两个文件定义:

  • config.json:配置文件,包括描述、变量和执行设置:
{
    "schema": 1,
    "description": "Plugin description",
    "execution_settings": {
        "default": {
            "max_tokens": 200,
            "temperature": 1,
            "top_p": 0.0,
            "presence_penalty": 0.0,
            "frequency_penalty": 0.0
        }
    },
    "input_variables": [
        {
            "name": "parameter_1",
            "description": "Parameter description",
            "default": ""
        }
    ]
}
  • skprompt.txt:纯文本提示内容。可以使用语法 {{$parameter_1}} 访问配置文件中的变量。

要将提示插件添加到内核中,我们只需指定文件夹即可。例如,如果我们有文件夹结构 /plugins/plugin_name/skprompt.txt,则插件注册如下:

{
    "schema": 1,
    "description": "Plugin description",
    "execution_settings": {
        "default": {
            "max_tokens": 200,
            "temperature": 1,
            "top_p": 0.0,
            "presence_penalty": 0.0,
            "frequency_penalty": 0.0
        }
    },
    "input_variables": [
        {
            "name": "parameter_1",
            "description": "Parameter description",
            "default": ""
        }
    ]
}

原生插件

本机插件允许模型调用本机代码(python、C# 或 Java)。插件被表示为一个类,其中任何函数都可以使用注释定义为可从代理调用。开发人员必须通过注释向模型提供一些信息:名称、描述和参数。

要定义Native Plugin,我们只需创建类并添加相应的注释:

self.kernel.add_plugin(parent_directory="./plugins", plugin_name="plugin_name")

要将本机插件添加到内核中,我们需要创建该类的新实例:

from datetime import datetime
from typing import Annotated
from semantic_kernel.functions.kernel_function_decorator import kernel_function

class MyFormatterPlugin():

    @kernel_function(name='format_current_date', description='Call to format current date to specific strftime format') # Define the function as invokable
    def formate_current_date(
        self,
        strftime_format: Annotated[str, 'Format, must follow strftime syntax'] # Describe the arguments
    ) -> Annotated[str, 'Current date on the specified format']: # Describe the return value
    return datetime.today().strftime(strftime_format)

函数调用

语义内核中的函数调用,或者说规划,是模型调用内核中注册的函数的一种方式。

对于每条用户消息,模型都会创建一个计划来决定如何回复。首先,它使用聊天历史记录和函数的信息来决定必须调用哪个函数(如果有)。一旦被调用,它将函数的结果附加到历史记录中,并决定是否已完成用户消息中的任务或需要更多步骤。如果没有完成,则会从第一步重新开始,直到完成任务,或者需要用户的帮助。

由于这个循环,模型可以串联对不同函数的调用。例如,我们可能有一个函数返回 user_session(包括用户的 id),另一个函数需要 current_user_id 作为参数。该模型将制定一个计划,调用第一个函数来检索用户会话,解析响应并使用 user_id 作为第二个函数的参数。

Building a chatbot with Semantic Kernel - Part Plugins

在语义内核中,我们必须告诉代理使用函数调用。这是通过定义执行设置并将函数选择行为设置为自动来完成的:

self.kernel.add_plugin(MyFormatterPlugin(), plugin_name="my_formatter_plugin")

需要强调的是,描述越详细,使用的代币就越多,因此成本就越高。在良好的详细描述和使用的标记之间找到平衡是关键。

我们图书馆员的插件

现在已经清楚了什么是函数及其用途,让我们看看如何为我们的图书馆员代理充分利用它。

出于学习目的,我们将定义一个原生插件和一个提示插件

  • 图书存储库插件:它是一个本机插件,用于从存储库检索图书。

  • 诗歌创作插件:这是一个提示插件,用于从一本书的第一句话创建一首诗。

图书存储库插件

我们使用开放图书馆 API 来检索图书信息。该插件返回搜索的前 5 个结果,包括书名、作者和书的第一句话。

具体来说,我们使用以下端点来检索信息:https://openlibrary.org/search.json?q={user-query}&fields=key,title,author_name,first_sentence&limit=5。

首先,我们定义代表系统中一本书的 BookModel:

{
    "schema": 1,
    "description": "Plugin description",
    "execution_settings": {
        "default": {
            "max_tokens": 200,
            "temperature": 1,
            "top_p": 0.0,
            "presence_penalty": 0.0,
            "frequency_penalty": 0.0
        }
    },
    "input_variables": [
        {
            "name": "parameter_1",
            "description": "Parameter description",
            "default": ""
        }
    ]
}

现在,是该功能的时间了。我们使用函数和参数的清晰描述。在本例中,我们使用复杂的对象作为响应,但模型稍后可以在进一步响应中使用它。

self.kernel.add_plugin(parent_directory="./plugins", plugin_name="plugin_name")

最后,我们可以将此插件添加到内核中:

from datetime import datetime
from typing import Annotated
from semantic_kernel.functions.kernel_function_decorator import kernel_function

class MyFormatterPlugin():

    @kernel_function(name='format_current_date', description='Call to format current date to specific strftime format') # Define the function as invokable
    def formate_current_date(
        self,
        strftime_format: Annotated[str, 'Format, must follow strftime syntax'] # Describe the arguments
    ) -> Annotated[str, 'Current date on the specified format']: # Describe the return value
    return datetime.today().strftime(strftime_format)

诗歌创作者插件

我们将这个插件定义为具有一些特定限制的提示插件。提示符及其配置如下所示:

/plugins/poem-plugin/poem-creator/config.json:

self.kernel.add_plugin(MyFormatterPlugin(), plugin_name="my_formatter_plugin")

/plugins/poem-plugin/poem-creator/skprompt.txt:

# Create the settings
settings = AzureChatPromptExecutionSettings()

# Set the behavior as automatic
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()

# Pass the settings to the agent
self.agent = ChatCompletionAgent(
    service_id='chat_completion',
    kernel=self.kernel,
    name='Assistant',
    instructions="The prompt",
    execution_settings=settings
)

将插件添加到内核非常简单:

class BookModel(TypedDict):
    author: str
    title: str
    first_sentence: str

良好做法

基于现有文献和我自己的经验的一些建议:

  • 即使在 .NET 或 Java 中也可以使用 python 语法来描述您的函数。由于经过训练的数据,模型通常在 Python 上更加熟练?
  • 保持功能的重点,特别是描述。一种功能,一种目的。不要尝试创建一个函数来制造太多东西,这会适得其反?
  • 简单的论点,而且数量很少。它们越简单、越少,从模型到函数的调用就越可靠?
  • 如果您有很多函数,请仔细检查描述,以确保不存在可能使模型感到困惑的潜在冲突?
  • 询问模型(通过chatgpt或类似的)关于功能描述的反馈。他们通常很容易找到改进。顺便说一句,这也适用于一般提示的开发❓
  • 测试,测试,再测试。特别是对于商业软件案例,可靠性是关键。确保模型能够使用您通过注释提供给模型的信息来调用预期的函数?

概括

在本章中,我们使用插件和语义内核规划增强了图书馆员代理的一些特定技能。

还记得我的 GitHub 存储库上已经提供了所有代码吗?用于语义内核的 PyChatbot。

在下一章中,我们将在聊天中添加一些功能,通过创建 检查器来实时检查我们的模型如何调用插件以及如何与插件交互。

以上是使用语义内核构建聊天机器人 - 部分插件的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn