在上一章中,我们了解了语义内核的一些基本概念,最后建立了一个能够回答一般问题的工作代理,但使用说明具有预定义的语气和目的。
在第二章中,我们将使用插件为我们的图书管理员添加特定技能。
插件是一组暴露给人工智能服务的函数。插件封装了功能,允许助手执行不属于其本机行为的操作。
例如,通过插件,我们可以让助手从 API 或数据库中获取一些数据。此外,助手可以代表用户执行一些操作,通常是通过 API。此外,助手还可以使用插件更新 UI 的某些部分。
正如我之前提到的,插件是由不同的功能组成的。每个函数主要定义为:
语义内核支持不同类型的插件。在这篇文章中,我们将重点关注其中两个:提示插件和原生插件。
提示插件基本上是在具体情况下调用的特定提示。在典型场景中,我们可能有一个复杂的系统提示,我们在其中定义代理的语气、目的和一般行为。然而,我们可能希望代理执行一些具体的操作,我们需要定义一些特定的限制和规则。对于这种情况,我们会尽量避免系统提示增长到无限,以减少幻觉并保持模型响应的相关性和可控性。这是提示插件的完美案例:
提示插件由两个文件定义:
{ "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": "" } ] }
要将提示插件添加到内核中,我们只需指定文件夹即可。例如,如果我们有文件夹结构 /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 作为第二个函数的参数。
在语义内核中,我们必须告诉代理使用函数调用。这是通过定义执行设置并将函数选择行为设置为自动来完成的:
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
基于现有文献和我自己的经验的一些建议:
在本章中,我们使用插件和语义内核规划增强了图书馆员代理的一些特定技能。
还记得我的 GitHub 存储库上已经提供了所有代码吗?用于语义内核的 PyChatbot。
在下一章中,我们将在聊天中添加一些功能,通过创建 检查器来实时检查我们的模型如何调用插件以及如何与插件交互。
以上是使用语义内核构建聊天机器人 - 部分插件的详细内容。更多信息请关注PHP中文网其他相关文章!