在 Azure AI 搜索中创建技能组

索引器阶段

技能组定义从包含图像或非结构化文本的文档生成文本内容和结构的操作。 例如图像的 OCR、无差别文本的实体识别和文本翻译。 从外部数据源提取文本和图像以及处理字段映射后,将执行技能组。

本文介绍如何使用 REST API 创建技能组,但同样的概念和步骤也适用于其他编程语言。

技能组定义规则包括:

  • 技能组集合中的唯一名称。 技能组是任何索引器都可以使用的顶级资源。
  • 至少一项技能。 三到五项技能是典型技能。 最大值为 30。
  • 技能组可以重复相同类型的技能(例如,多个整形程序技能)。
  • 技能组支持链式操作、循环和分支。

索引器驱动技能组的执行。 你需要 索引器搜索索引 ,然后才能测试你的技能组合。

提示

启用扩充缓存来重复使用已处理的内容并降低开发成本。

添加技能组定义

从基本结构开始。 在创建技能组 REST API 中,请求正文以 JSON 编写,并包含以下部分:

{
   "name":"skillset-template",
   "description":"A description makes the skillset self-documenting (comments aren't allowed in JSON itself)",
   "skills":[

   ],
   "cognitiveServices":{
      "@odata.type":"#Microsoft.Azure.Search.CognitiveServicesByKey",
      "description":"An Azure AI services resource in the same region as Azure AI Search",
      "key":"<Your-Cognitive-Services-Multiservice-Key>"
   },
   "knowledgeStore":{
      "storageConnectionString":"<Your-Azure-Storage-Connection-String>",
      "projections":[
         {
            "tables":[ ],
            "objects":[ ],
            "files":[ ]
         }
      ]
    },
    "encryptionKey":{ }
}

在 name 和 description 之后,技能组具有四个主要属性:

  • skills 数组,一个无序的技能集合。 技能可以是实用性的(比如拆分文本)、变革性的(基于 Azure AI 服务的 AI)或者你提供的自定义技能。 下一部分提供了技能数组的示例。

  • cognitiveServices 用于调用 Azure AI 服务 API 的可计费技能。 如果未使用计费技能或自定义实体查找,请删除此部分。 否则,请附加资源

  • knowledgeStore(可选)指定 Azure 存储帐户以及用于将技能组输出投影到 Azure 存储中的表、Blob 和文件的设置。 如果不需要,请删除此部分;如果需要,指定一个知识存储

  • encryptionKey(可选)指定一个 Azure 密钥保管库和用于对技能组定义中的敏感内容(说明、连接字符串、密钥)进行加密的客户管理的密钥。 如果不使用客户管理的加密,请删除此属性。

添加技能

在技能组定义中,技能数组指定要执行的技能。 三到五项技能是常见的,你也可以根据需要添加任意数量的技能,但要遵守服务限制

扩充管道的最终结果是搜索索引或知识存储中的文本内容。 因此,大多数技能要么从图像创建文本(OCR 文本、标题、标记),要么分析现有文本,以创建新信息(实体、关键短语、情绪)。 独立运行的技能并行处理。 相互依赖的技能将一项技能(如关键短语)的输出指定为第二项技能(如文本翻译)的输入。 搜索服务确定技能执行的顺序和执行环境。

所有技能都有类型、上下文、输入和输出。 技能可以选择有一个名称和说明。 以下示例显示了两个不相关的内置技能,以便可以比较基本结构。

"skills":[
  {
    "@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill",
    "name": "#1",
    "description": "This skill detects organizations in the source content",
    "context": "/document",
    "categories": [ "Organization" ],
    "inputs": [
      {
        "name": "text",
        "source": "/document/content"
      }
    ],
    "outputs": [
      {
        "name": "organizations",
        "targetName": "orgs"
      }
    ]
  },
  {
      "name": "#2",
      "description": "This skill detects corporate logos in the source files",
      "@odata.type": "#Microsoft.Skills.Vision.ImageAnalysisSkill",
      "context": "/document/normalized_images/*",
      "visualFeatures": [
          "brands"
      ],
      "inputs": [
          {
              "name": "image",
              "source": "/document/normalized_images/*"
          }
      ],
      "outputs": [
          {
              "name": "brands"
          }
      ]
  }
]

每项技能在其输入值和所采用的参数方面都是唯一的。 技能参考文档描述了给定技能的所有参数和属性。 尽管存在差异,但大多数技能共享一个通用集,且具有相似的模式。

注意

可以使用条件技能来创建表达式,从而构建带循环和分支的复杂技能组。 语法基于 JSON 指针路径表示法,做了少量的修改来标识扩充树中的节点。 "/" 遍历树中的较低级别,"*" 充当上下文中的 for-each 运算符。 本文中的许多示例阐释了此语法

设置技能上下文

每项技能都有一个上下文属性,用于确定操作发生的级别。 如果未明确设置“上下文”属性,则默认为 "/document",上下文是整个文档(每个文档调用该技能一次)。

"skills":[
  {
    "@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill",
    "context": "/document",
    "inputs": [],
    "outputs": []
  },
  {
      "@odata.type": "#Microsoft.Skills.Vision.ImageAnalysisSkill",
      "context": "/document/normalized_images/*",
      "visualFeatures": [],
      "inputs": [],
      "outputs": []
  }
]

上下文通常设置为以下示例之一:

上下文示例 说明
"context": "/document" (默认)输入和输出位于文档级别。
"context": "/document/pages/*" 某些技能(如情绪分析)在较小文本块上的表现更佳。 如果要将大型内容字段拆分为页或句子,则上下文应基于每个组件部分。
"context": "/document/normalized_images/*" 对于图像内容,父文档中的每个图像有一对输入和输出。

上下文还决定了在扩充树中生成输出的位置。 例如,实体识别技能返回一个名为 "organizations" 的属性,捕获为 orgs。 如果上下文为 "/document",则会将“组织”节点添加为 "/document" 的子节点。 如果随后想要在下游技能中引用此节点,则路径将为 "/document/orgs"

定义输入

从扩充文档读取和写入的技能。 技能输入指定传入数据的源。 它通常是扩充文档的根节点。 对于 Blob,典型的技能输入是文档的内容属性。

有关每种技能的技能参考文档描述了它可以使用的输入。 每个输入都有一个标识特定输入的“名称”,以及一个指定扩充文档中数据位置的“源”。 以下示例来自实体识别技能:

"inputs": [
    {
        "name": "text", 
        "source": "/document/content"
    },
    {
        "name": "languageCode", 
        "source": "/document/language"
    }
]
  • 技能可以有多个输入。 “name”是特定输入。 对于实体识别,具体输入为“text”和“languageCode”。

  • “source”属性指定哪个字段或行提供要处理的内容。 对于基于文本的技能,源是提供文本的文档或行中的字段。 对于基于图像的技能,提供输入的节点是规范化图像。

    源示例 说明
    "source": "/document" 对于表格数据集,一个文档对应于一行。
    "source": "/document/content" 对于 Blob,源通常是 Blob 的内容属性。
    "source": "/document/some-named-field" 对于基于文本的技能(如实体识别或关键短语提取)来说,源应是诸如 "description" 或 "summary" 之类的字段,其中包含要分析的足够文本。
    "source": "/document/normalized_images/*" 对于图像内容,源是在文档破解期间已规范化的图像。

如果技能对数组进行循环访问,则上下文和输入源都应将 /* 包含在正确的位置。

定义输出

每项技能旨在发出特定类型的输出,在技能组中按名称引用这些输出。 技能输出具有“name”和可选的“targetName”。

有关每项技能的技能参考文档描述了它可以生成的输出。 以下示例来自实体识别技能:

"outputs": [
    {
        "name": "persons", 
        "targetName": "people"
    },
    {
        "name": "organizations", 
        "targetName": "orgs"
    },
    {
        "name": "locations", 
        "targetName": "places"
    }
]
  • 技能可以有多个输出。 “name”标识特定输出。 例如,对于实体识别,输出可以是“persons”、“locations”、“organizations”等。

  • “targetName”指定希望此节点在扩充文档中的名称。 如果技能输出具有相同的名称,这将非常有用。 如果有多项技能返回相同的输出,请使用 "targetName" 在扩充节点路径中进行名称消歧。 如果未指定目标名称,则将对二者使用名称属性。

在某些情况下,需要单独引用数组的每个元素。 例如,假设你想要将 "/document/orgs" 的每个元素单独传递到另一个技能。 为此,请向此路径添加星号:"/document/orgs/*"

技能输出将作为扩充树中的新节点写入扩充文档。 它可能是一个简单的值,例如情绪分数或语言代码。 它也可以是一个集合,例如组织、人员或位置的列表。 技能输出还可以是一个复杂的结构,就像整形器技能一样。 技能的输入决定了形状的构成,但输出是命名对象,可以在搜索索引、知识存储投影或其他技能中按名称进行引用。

添加自定义技能

本部分包含自定义技能的示例。 URI 指向一个 Azure 函数,该函数反过来调用你提供的模型或转换。 有关详细信息,请参阅定义自定义接口

尽管自定义技能正在执行管道外部的代码,但在技能数组中,这只是另一种技能。 与内置技能类似,它具有一个 type、context、inputs 和 outputs。 像内置技能一样,它也在扩充树中进行读取和写入。 请注意,“上下文”字段设置为包含星号的 "/document/orgs/*",这意味着,将对 "/document/orgs" 下的每个组织调用扩充步骤。

输出(例如本示例中的公司说明)是针对已识别的每个组织生成的。 引用下游步骤中的节点时(例如,在关键短语提取中),应该使用路径 "/document/orgs/*/companyDescription" 执行此操作。

{
  "@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
  "description": "This skill calls an Azure function, which in turn calls custom code",
  "uri": "https://indexer-e2e-webskill.chinacloudsites.cn/api/InvokeCode?code=foo",
  "httpHeaders": {
      "Ocp-Apim-Subscription-Key": "foobar"
  },
  "context": "/document/orgs/*",
  "inputs": [
    {
      "name": "query",
      "source": "/document/orgs/*"
    }
  ],
  "outputs": [
    {
      "name": "description",
      "targetName": "companyDescription"
    }
  ]
}

将输出发送到目标

尽管可选择性地缓存技能输出以重复使用,但这通常是临时的,仅在技能执行过程中存在。

  • 若要将输出发送到搜索索引中的字段,请在索引器中创建一个输出字段映射

  • 若要将输出发送到知识库,请创建投影

  • 若要将输出发送到下游技能,请在下游技能的输入源属性中通过其节点名称引用输出,例如 "/document/organization"。 有关示例,请参阅引用注释

有关第一个技能组的技巧

  • 运行“导入数据”向导。

    该向导会自动执行几个步骤,在首次执行时可能会有困难。 它定义技能组、索引和索引器,包括字段映射和输出字段映射。 如果使用的是投影,它还会在知识存储中定义投影。 对于某些技能(例如 OCR 或图像分析),向导将添加实用工具技能,用于合并在文档破解期间分隔的图像和文本内容。

    向导运行后,可以在 Azure 门户中打开每个对象以查看其 JSON 定义。

  • 尝试调试会话以调用目标文档的技能组执行,并检查技能组创建的扩充文档。 可以查看和修改输入与输出设置及值。 此教程是一个很好的起点:教程:使用调试会话调试技能组

后续步骤

上下文和输入源字段是扩充树中节点的路径。 下一步,请详细了解扩充树中的节点的路径语法。