从 OpenAPI 规范添加插件

通常,企业中已有一组执行实际工作的 API。 这些应用可由人类与之交互的其他自动化服务或电源前端应用程序使用。 在语义内核中,可以添加这些与插件完全相同的 API,以便代理也可以使用它们。

OpenAPI 规范示例

例如,允许更改灯泡状态的 API。 此 API 的 OpenAPI 规范可能如下所示:

{
   "openapi": "3.0.1",
   "info": {
      "title": "Light API",
      "version": "v1"
   },
   "paths": {
      "/Light": {
         "get": {
            "tags": [
               "Light"
            ],
            "summary": "Retrieves all lights in the system.",
            "operationId": "get_all_lights",
            "responses": {
               "200": {
                  "description": "Returns a list of lights with their current state",
                  "application/json": {
                     "schema": {
                        "type": "array",
                        "items": {
                              "$ref": "#/components/schemas/LightStateModel"
                        }
                     }
                  }
               }
            }
         }
      },
      "/Light/{id}": {
         "post": {
               "tags": [
                  "Light"
               ],
               "summary": "Changes the state of a light.",
               "operationId": "change_light_state",
               "parameters": [
                  {
                     "name": "id",
                     "in": "path",
                     "description": "The ID of the light to change from the get_all_lights tool.",
                     "required": true,
                     "style": "simple",
                     "schema": {
                           "type": "string"
                     }
                  }
               ],
               "requestBody": {
                  "description": "The new state of the light and change parameters.",
                  "content": {
                     "application/json": {
                           "schema": {
                              "$ref": "#/components/schemas/ChangeStateRequest"
                           }
                     }
                  }
               },
               "responses": {
                  "200": {
                     "description": "Returns the updated light state",
                     "content": {
                           "application/json": {
                              "schema": {
                                 "$ref": "#/components/schemas/LightStateModel"
                              }
                           }
                     }
                  },
                  "404": {
                     "description": "If the light is not found"
                  }
               }
         }
      }
   },
   "components": {
      "schemas": {
         "ChangeStateRequest": {
               "type": "object",
               "properties": {
                  "isOn": {
                     "type": "boolean",
                     "description": "Specifies whether the light is turned on or off.",
                     "nullable": true
                  },
                  "hexColor": {
                     "type": "string",
                     "description": "The hex color code for the light.",
                     "nullable": true
                  },
                  "brightness": {
                     "type": "integer",
                     "description": "The brightness level of the light.",
                     "format": "int32",
                     "nullable": true
                  },
                  "fadeDurationInMilliseconds": {
                     "type": "integer",
                     "description": "Duration for the light to fade to the new state, in milliseconds.",
                     "format": "int32",
                     "nullable": true
                  },
                  "scheduledTime": {
                     "type": "string",
                     "description": "Use ScheduledTime to synchronize lights. It's recommended that you asynchronously create tasks for each light that's scheduled to avoid blocking the main thread.",
                     "format": "date-time",
                     "nullable": true
                  }
               },
               "additionalProperties": false,
               "description": "Represents a request to change the state of the light."
         },
         "LightStateModel": {
               "type": "object",
               "properties": {
                  "id": {
                     "type": "string",
                     "nullable": true
                  },
                  "name": {
                     "type": "string",
                     "nullable": true
                  },
                  "on": {
                     "type": "boolean",
                     "nullable": true
                  },
                  "brightness": {
                     "type": "integer",
                     "format": "int32",
                     "nullable": true
                  },
                  "hexColor": {
                     "type": "string",
                     "nullable": true
                  }
               },
               "additionalProperties": false
         }
      }
   }
}

此规范提供 AI 所需的所有内容来了解 API 以及如何与之交互。 API 包括两个终结点:一个用于获取所有灯光,另一个终结点用于更改光线的状态。 它还提供以下内容:

  • 终结点及其参数的语义说明
  • 参数的类型
  • 预期响应

由于 AI 代理可以理解此规范,因此可以将它作为插件添加到代理。

提示

如果有现有的 OpenAPI 规范,可能需要进行更改,以便 AI 更容易理解它们。 例如,可能需要在说明中提供指导。 有关如何使 OpenAPI 规范 AI 友好的详细信息,请参阅 有关添加 OpenAPI 插件的提示和技巧。

添加 OpenAPI 插件

使用几行代码,可以将 OpenAPI 插件添加到代理。 以下代码片段演示如何从上面的 OpenAPI 规范中添加浅色插件:

await kernel.ImportPluginFromOpenApiAsync(
   pluginName: "lights",
   uri: new Uri("https://example.com/v1/swagger.json"),
   executionParameters: new OpenApiFunctionExecutionParameters()
   {
      // Determines whether payload parameter names are augmented with namespaces.
      // Namespaces prevent naming conflicts by adding the parent parameter name
      // as a prefix, separated by dots
      EnablePayloadNamespacing = true
   }
);
await kernel.add_plugin_from_openapi(
   plugin_name="lights",
   openapi_document_path="https://example.com/v1/swagger.json",
   execution_settings=OpenAPIFunctionExecutionParameters(
         # Determines whether payload parameter names are augmented with namespaces.
         # Namespaces prevent naming conflicts by adding the parent parameter name
         # as a prefix, separated by dots
         enable_payload_namespacing=True,
   ),
)
String yaml = EmbeddedResourceLoader.readFile("petstore.yaml", ExamplePetstoreImporter.class);

KernelPlugin plugin = SemanticKernelOpenAPIImporter
   .builder()
   .withPluginName("petstore")
   .withSchema(yaml)
   .withServer("http://localhost:8090/api/v3")
   .build();

Kernel kernel = ExampleOpenAPIParent.kernelBuilder()
   .withPlugin(plugin)
   .build();

之后,可以在代理中使用插件,就像它是本机插件一样。

添加 OpenAPI 插件的提示和技巧

由于 OpenAPI 规范通常专为人类设计,可能需要进行一些更改,以便 AI 更容易理解。 下面是帮助你执行此操作的一些提示和技巧:

建议 说明
版本控制 API 规范 请考虑签入和版本控制 Swagger 文件,而不是指向实时 API 规范。 这样,AI 研究人员就可以测试 AI 代理使用的 API 规范(并更改),而不会影响实时 API,反之亦然。
限制终结点数 尝试限制 API 中的终结点数。 将类似的功能合并到具有可选参数的单个终结点中,以减少复杂性。
对终结点和参数使用描述性名称 确保终结点和参数的名称具有描述性和自我解释性。 这有助于 AI 了解其用途,而无需进行广泛的解释。
使用一致的命名约定 在整个 API 中保持一致的命名约定。 这样可以减少混淆,并帮助 AI 更轻松地学习和预测 API 的结构。
简化 API 规范 通常,OpenAPI 规范非常详细,并包含许多信息,这些信息对于 AI 代理来说并不需要帮助用户。 API 越简单,需要花费更少的令牌来描述 API,以及 AI 向其发送请求所需的令牌更少。
避免字符串参数 如果可能,请避免在 API 中使用字符串参数。 请改用更具体的类型,例如整数、布尔值或枚举。 这将有助于 AI 更好地了解 API。
提供说明中的示例 当人类使用 Swagger 文件时,他们通常能够使用 Swagger UI(包括示例请求和响应)测试 API。 由于 AI 代理无法执行此操作,因此请考虑在参数的说明中提供示例。
在说明中引用其他终结点 通常,AIS 会混淆类似的终结点。 为了帮助 AI 区分终结点,请考虑在说明中引用其他终结点。 例如,可以说“此终结点与 get_all_lights 终结点类似,但它只返回一盏灯。
提供有用的错误消息 虽然不在 OpenAPI 规范中,但请考虑提供有助于 AI 自我更正的错误消息。 例如,如果用户提供无效 ID,请考虑提供一条错误消息,建议 AI 代理从 get_all_lights 终结点获取正确的 ID。

后续步骤

了解如何创建插件后,现在可以了解如何将其与 AI 代理配合使用。 根据添加到插件的函数类型,应遵循不同的模式。 有关检索函数,请参阅 using 检索函数 一文。 有关任务自动化函数,请参阅 使用任务自动化函数 一文。