在 Azure AI 搜索扩充管道中自定义 Web API 技能

注意

Azure AI 搜索可通过Azure门户REST APIAzure SDK获取。

使用 自定义 Web API 技能通过调用提供自定义操作的 Web API 终结点来扩展 AI 扩充。 与内置技能一样, 自定义 Web API 技能具有输入和输出。 根据输入,Web API 在索引器运行时接收 JSON 有效负载,并返回 JSON 有效负载作为响应,以及成功状态代码。 响应必须包含自定义技能指定的输出。 其他任何响应都被视为错误,并且不会执行任何扩充。 本文档稍后将介绍 JSON 有效负载的结构。

本文档进一步详细介绍了 JSON 有效负载的结构。

注意

索引器会对 Web API 返回的某些标准 HTTP 状态代码重试两次。 这些 HTTP 状态代码为:

  • 502 Bad Gateway
  • 503 Service Unavailable
  • 429 Too Many Requests

@odata.type

Microsoft.Skills.Custom.WebApiSkill

技能参数

参数区分大小写。

参数名称 说明
uri JSON 有效负载发送到的 Web API 的 URI。 仅支持 https URI 方案。
authResourceId (可选)一个字符串,如果设置了该字符串,则它指示此技能在连接到托管代码的函数或应用时应使用系统托管标识。 此属性采用应用程序(客户端)ID 或应用在 Microsoft Entra ID 中的注册,并采用以下任何格式:api://<appId><appId>/.defaultapi://<appId>/.default。 此值用于确定索引器检索到的身份验证令牌的作用域,并随自定义 Web 技能 API 请求一起发送到函数或应用。 设置此属性要求搜索服务配置为托管标识,并且 Azure 函数应用配置为 Microsoft Entra 登录。 要使用此参数,请使用 api-version=2023-10-01-Preview 调用 API。
authIdentity (可选)搜索服务用于连接托管代码的函数或应用的用户托管标识。 可以使用系统托管标识或用户托管标识。 若要使用系统托管标识,请留 authIdentity 空。
httpMethod 发送有效负载时使用的方法。 允许使用的方法为 PUTPOST
httpHeaders 键值对集合,其中键表示头名称,值表示发送到 Web API 的头值以及有效负载。 此集合中禁止使用以下标头:AcceptAccept-CharsetAccept-EncodingContent-LengthContent-TypeCookieHostTEUpgradeVia
timeout (可选)如果指定,表明执行 API 调用的 http 客户端的超时值。 必须将其格式化为 XSD“dayTimeDuration”值(ISO 8601 持续时间值的受限子集)。 例如,PT60S 表示 60 秒。 如果未设置,选择的是默认值 30 秒。 超时可以设置为最大 230 秒和最小 1 秒。
batchSize (可选)表示每 API 调用发送多少个“数据记录”(请参阅下面的 JSON 有效负载结构)。 如果未设置,选择的是默认值 1000。 使用此参数在 API 上的索引吞吐量和负载之间实现适当的权衡。
degreeOfParallelism (可选)在已指定的情况下指示索引器对你提供的终结点进行的并行调用数。 如果终结点在压力下失败,可以减小此值,如果终结点可以处理负载,则可以提高此值。 如果未设置,则将使用默认值 5。 可以为 degreeOfParallelism 设置的最大值为 10,最小值为 1。

authResourceId了解值

当自定义 Web API 技能使用托管标识身份验证时,Azure AI 搜索获取Microsoft Entra访问令牌并将其发送到自定义技能终结点。 该 authResourceId 属性指定请求令牌的资源标识符,也称为访问群体或应用程序 ID URI。 该值必须与目标应用程序在令牌验证期间期望的值匹配。 否则,身份验证失败并出现 401 Unauthorized 响应。

该值 authResourceId 标识托管自定义技能的应用程序。 它不是搜索服务或索引器的 URL。

下表显示了常见格式:

目标应用程序 authResourceId
Microsoft Entra受保护的 Web 应用程序 api://<application-client-id>
使用自定义应用程序 ID URI 配置的应用程序 自定义应用程序 ID URI,例如 api://contoso-customskill
受Microsoft Entra ID保护的Azure函数 为函数应用的应用注册配置的应用程序 ID URI,例如 api://contoso-funcapp

该属性接受带和不使用 .default 范围后缀的格式。 用于 api://<appId> 直接匹配应用程序 ID URI。 如果包含 .default 后缀,例如 api://<appId>/.default,访问令牌的 aud 声明包含没有后缀的基本应用程序 ID URI。

有关为 Azure 函数配置Microsoft Entra身份验证并设置authResourceId的步骤,请参阅使用搜索服务托管标识连接到 Azure 函数应用

示例:受Microsoft Entra ID保护的Azure函数

在此示例中,Azure AI 搜索获取访问authResourceId群体的访问令牌,并在调用自定义技能终结点时包含令牌。

{
  "@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
  "uri": "https://contoso-function.chinacloudsites.cn/api/enrich",
  "authResourceId": "api://contoso-customskill"
}

技能输入

此技能没有预定义的输入。 输入是要传递给自定义技能的任何现有字段或扩充树中的任何节点

技能输出

此技能没有预定义的输出。 如果技能的输出应发送到搜索索引中的字段,请确保在索引器中定义输出字段映射

示例定义

{
  "@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
  "description": "A custom skill that can identify positions of different phrases in the source text",
  "uri": "https://contoso.count-things.com",
  "batchSize": 4,
  "context": "/document",
  "inputs": [
    {
      "name": "text",
      "source": "/document/content"
    },
    {
      "name": "language",
      "source": "/document/languageCode"
    },
    {
      "name": "phraseList",
      "source": "/document/keyphrases"
    }
  ],
  "outputs": [
    {
      "name": "hitPositions"
    }
  ]
}

注意

使用 GET 检索技能集时,服务将返回<redacted>所有httpHeaders值以及?code=<redacted>?code=任何查询参数。uri 这两个值都阻止向持有搜索服务参与者角色但外部服务上没有角色的调用方公开凭据。 若要在不更改这些存储值的情况下更新技能,请为每个受影响的字段传递 <unchanged>

以下示例显示了使用基于标头的身份验证和Azure函数 URI 的技能的 GET 响应:

{
  "@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
  "uri": "https://contoso.example.org/api?code=<redacted>",
  "httpMethod": "POST",
  "name": "myCustomSkill",
  "httpHeaders": {
    "Authorization": "<redacted>",
    "Ocp-Apim-Subscription-Key": "<redacted>"
  }
}

若要在不更改现有值的情况下更新此技能,请使用 <unchanged>

{
  "uri": "<unchanged>",
  "httpHeaders": {
    "Authorization": "<unchanged>",
    "Ocp-Apim-Subscription-Key": "<unchanged>"
  }
}

示例输入 JSON 结构

此 JSON 结构表示发送到 Web API 的有效负载。 它始终遵循以下约束:

  • 顶级实体名为values,并且是对象数组。 这些对象的数量最多 batchSize

  • values数组中的每个对象都有:

    • recordId 一字符串的属性,用于标识该记录。

    • data 个 JSON 对象的属性。 data 属性的字段对应于技能定义的 inputs 部分中指定的“names”。 这些字段的值来自 source 这些字段(可能来自文档中的某个字段,也可能来自其他技能)。

{
    "values": [
      {
        "recordId": "0",
        "data":
           {
             "text": "Este es un contrato en Inglés",
             "language": "es",
             "phraseList": ["Este", "Inglés"]
           }
      },
      {
        "recordId": "1",
        "data":
           {
             "text": "Hello world",
             "language": "en",
             "phraseList": ["Hi"]
           }
      },
      {
        "recordId": "2",
        "data":
           {
             "text": "Hello world, Hi world",
             "language": "en",
             "phraseList": ["world"]
           }
      },
      {
        "recordId": "3",
        "data":
           {
             "text": "Test",
             "language": "es",
             "phraseList": []
           }
      }
    ]
}

示例输出 JSON 结构

“输出”对应于 Web API 返回的响应。 Web API 应仅返回 JSON 有效负载(通过查看 Content-Type 响应头进行验证),并且应遵循以下约束:

  • 应有名为values且是对象数组的顶级实体。

  • 数组中的对象数量应与发送到 Web API 的对象数量相同。

  • 每个对象都应有:

    • recordId 属性。

    • data 属性,这个对象中的字段是与 output 中“名称”匹配的扩充,且值被视为扩充。

    • errors属性,列出添加到索引器执行历史记录的任何错误的数组。 此属性是必需的,但可以有 null 值。

    • warnings属性,列出添加到索引器执行历史记录的任何警告的数组。 此属性是必需的,但可以有 null 值。

  • 在请求或响应中,values 中的对象的排序并不重要。 不过,由于recordId用于关联,因此响应中任何包含recordId(不属于向 Web API 发送的原始请求)的记录都会遭放弃。

{
    "values": [
        {
            "recordId": "3",
            "data": {
            },
            "errors": [
              {
                "message" : "'phraseList' should not be null or empty"
              }
            ],
            "warnings": null
        },
        {
            "recordId": "2",
            "data": {
                "hitPositions": [6, 16]
            },
            "errors": null,
            "warnings": null
        },
        {
            "recordId": "0",
            "data": {
                "hitPositions": [0, 23]
            },
            "errors": null,
            "warnings": null
        },
        {
            "recordId": "1",
            "data": {
                "hitPositions": []
            },
            "errors": null,
            "warnings": [
              {
                "message": "No occurrences of 'Hi' were found in the input text"
              }
            ]
        },
    ]
}

错误案例

除了 Web API 不可用或发送非成功状态代码之外,请考虑以下情况作为错误:

  • 如果 Web API 返回成功状态代码,但响应指示它不是 application/json,则响应无效,并且不会执行扩充。

  • 如果响应 values 数组包含无效记录(例如缺失或重复 recordId),则不会扩充无效记录。 开发自定义技能时,请遵循 Web API 技能协定。 可以参考遵循此预期协定的 Power Skill 存储库中提供的此示例

对于 Web API 不可用或返回 HTTP 错误的情况,索引器执行历史记录包含友好错误,其中包含有关 HTTP 错误的任何可用详细信息。

托管标识身份验证的安全注意事项

将托管标识身份验证与自定义 Web API 技能结合使用时,Azure AI 搜索获取由authResourceId标识的应用程序的Microsoft Entra访问令牌,并在发送到终结点的请求uri中包含该令牌。 引用的uri终结点通常是Azure函数、Azure 应用服务、Azure API 管理终结点或其他受Microsoft Entra保护的应用程序。 你负责配置和维护终结点与标识的应用程序 authResourceId之间的关系。

无论身份验证方法如何,自定义技能输入都可以包含客户提供的文档或派生自这些文档的值。 将所有自定义技能输入视为不受信任。 Azure AI 搜索将技能集中配置的输入转发到终结点,而无需解释、验证或限制自定义实现的内容。

在出站请求或其他安全敏感操作中使用文档派生值之前,先验证和约束自定义技能中的文档派生值。 使用输入验证、目标允许列表、URL 和主机名验证、协议限制和最小特权网络访问,仅允许技能所需的目标和端口。 有关详细信息,请参阅 网络和连接的体系结构策略

若要帮助维护安全部署,请遵循以下做法:

  • uri属性配置为仅指向用于接收来自Azure AI 搜索请求的受信任终结点。
  • 配置authResourceId以标识预期接收和验证访问令牌的Microsoft Entra应用程序。
  • 在处理请求之前,请确保接收请求的应用程序验证标准令牌声明,包括访问群体()、颁发者(audiss)、租户(tid)和任何必需的应用程序角色或权限。
  • 向Azure AI 搜索托管标识授予权限时,应用最低特权原则。
  • 定期查看自定义 Web API 技能定义、Microsoft Entra应用程序注册以及授予Azure AI 搜索托管标识的应用角色分配和权限。 通过建立的变更管理和安全评审流程查看配置更改。
  • 定期查看Azure Functions、应用服务、API 和 API 网关的终结点配置。
  • 监视应用程序登录日志、身份验证事件和 API 访问日志,以获取意外或未经授权的活动。
  • 删除不再需要的未使用的终结点、权限、应用程序注册和角色分配。

限制对技能集配置的访问

可以创建、修改或运行技能集的用户可以控制自定义 Web API 技能使用的目标终结点和身份验证配置。 将这些权限限制为受信任的管理员,并在配置已启用托管标识的自定义技能时遵循标准变更管理和安全评审过程。

Important

该值 authResourceId 标识访问令牌的预期收件人应用程序。 确保指定的 uri 终结点是应接收和验证该应用程序的令牌的终结点。 配置不正确可能会导致身份验证失败或请求发送到意外终结点。

另请参阅