(已失效)Azure OpenAI 禁用内容过滤器以恢复流式输出

2024/03/22 更新:该方法已失效。

Microsoft Azure 提供了与 OpenAI 合作的服务,允许用户通过 Azure 访问 OpenAI 的各种人工智能模型,包括 GPT-3.5 以及 GPT-4 模型。但是,在通过 Azure API 调用这些 OpenAI 模型时,会发现默认情况下,模型的输出不是像 ChatGPT 那样逐字输出,而是一段一段地输出,有比较明显的卡顿感。

在先前,笔者道听途说地了解到 Azure 会默认开启内容过滤器,此时模型的输出会先进行过滤,然后才输出给调用方。由于内容过滤器不是完全流式的,所以 Azure 会每隔若干长度的输出进行一次内容过滤,在得到过滤结果前,输出会被阻塞。以及可以通过这个 表单 申请允许关闭 Content Filter 功能,但是笔者打开一看很长的问卷,懒得填——关闭。

后来也留意到 Azure OpenAI 控制台的 Content filters (Preview) 的功能入口,应该是对内容过滤器的一些自定义选项。由此进行了一些尝试,最终成功地在没有提交上述申请的情况下,禁用了 Azure OpenAI 的内容过滤器,得到正常的流式输出。

Azure OpenAI Chat Completions API
开启内容过滤器(默认) 禁用内容过滤器

如果想要在 Azure OpenAI 没有提交上述申请的情况下禁用内容过滤器,请阅读 免申请禁用内容过滤器。如果想要了解这样操作的原因,请阅读 了解 Azure OpenAI 的内容过滤器 以及 探索免申请禁用内容过滤器的途径

免申请禁用内容过滤器

2024/03/16 更新:有另外一种基于 Tampermonkey 与用户脚本的方法,比起本文描述的步骤更容易操作,如果您了解如何使用 Tampermonkey,建议您参考这篇文章中的步骤:一种更简单的关闭 Azure OpenAI 内容筛选器的方法

  1. 创建自定义内容过滤器

    1. 登录 Azure OpenAI Studio
    2. 选择左侧边栏 Management 下的 Content filters (Preview)
    3. Content filtering configuration 页面,点击 Create customized content filter
    4. 填写 Create custom configuration name,其他设置项不用修改,一直点 Next
    5. 在最后一步点击 Create content filter
  2. 录制修改自定义内容过滤器的 HTTP 请求(建议使用 Chrome 浏览器)

    1. 在内容过滤器列表中,选择刚刚创建的内容过滤器
    2. 点击 Edit content filter
    3. 打开 Chrome 浏览器的 DevTools(为了录制修改自定义内容过滤器的 HTTP 请求;可以按 F12 快捷键)
    4. 设置项不用修改,一直点 Next
    5. 在最后一步点击 Update content filter
    6. 在 DevTools 的 Network 标签页,找到一个形如以下 URL 的 PUT 请求(可以使用 raiPolicies method:PUT 这个过滤字符串来查找)

      https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<org-name>/providers/Microsoft.CognitiveServices/accounts/<resource>/raiPolicies/<content-filter-name>
    7. 右键,选择 Copy > Copy as cURL (bash),或者其他你用得顺手的 HTTP 请求工具
  3. 修改并重放请求

    1. 对复制出来的请求做修改:
      "blocking":true,"enabled":true
      替换成 "blocking":false,"enabled":false
    2. 发送修改后的请求
  4. 检查修改是否生效

    1. 在内容过滤器列表中,点击 Refresh 刷新
    2. 选择刚刚创建并修改的内容过滤器
    3. 点击 Edit content filter
    4. 观察是否显示 Filters are turned off
  5. 对 Deployment 启用我们修改过的内容过滤器

    1. 选择左侧边栏 Management 下的 Deployments
    2. 在模型部署列表中,选择一个模型部署
    3. 点击 Edit deployment
    4. 点击 Advanced options
    5. Content Filter 下拉框中选择我们修改过的内容过滤器
    6. 点击 Save and close

了解 Azure OpenAI 的内容过滤器

参考资料

Azure OpenAI 的内容过滤系统简述

Azure OpenAI 服务包括一个与核心模型协同工作的内容过滤系统。 该系统通过一系列分类模型来运行提示和补全,旨在检测和防止有害内容的输出。

可配置性功能在预览中可用,允许客户分别调整提示和完成设置,以便按不同的严重性级别过滤每个内容类别的内容。

过滤器可选配置:无过滤器(需要获得批准)、低严重性、中严重性、高严重性

内容过滤器的三种开启状态

  1. 过滤(filtering,默认)
  2. 仅标注(annotating)
  3. 完全禁用

Azure OpenAI 的内容过滤器有标注(annotate)和过滤(filter)两种行为。在过滤行为下,有害内容会被过滤而不会返回给调用方;在标注行为下,调用方除了可以拿到模型的原始输出外,还会在 prompt_filter_resultscontent_filter_results 字段得到提示词和补全的标注结果(包括有害内容分类、严重程度等信息)。

内容过滤器会阻塞流式输出吗?

For streaming completions calls, segments will be returned back to the user as they're completed. The service will continue streaming until either reaching a stop token, length, or when content that is classified at a filtered category and severity level is detected.

翻译:在进行流式 Completions API 调用时,一旦(?)完成,片段将会返回给用户。服务将继续进行流式传输,直到遇到停止标记、达到长度限制,或者检测到被归类为过滤类别和严重性等级的内容为止。

Azure 文档里面含糊其辞,as they're completed 到底是指补全完成还是内容过滤完成?segment 是指模型的原始输出,还是说有一定长度的 buffer?至少从结果上看内容过滤器确实是对流式输出的性能有着明显的影响:

Azure OpenAI Chat Completions API
开启内容过滤器(默认) 禁用内容过滤器

探索免申请禁用内容过滤器的途径

尝试从控制台禁用内容过滤器

笔者在 Azure OpenAI 控制台的 Content filters (Preview) 页面看到,默认情况下,用户只能修改内容过滤器的严重程度,不能取消内容过滤器的开启状态(滑动条可以滑动,但勾选框是禁用状态,无法取消勾选)。

阅读 Azure 的 文档 有相关的描述。如上文所述,想要在这里禁用内容过滤器,需要向 Azure 提交申请。

无过滤器:只有已批准修改内容过滤的客户才具有完整的内容过滤控制,并且可以部分或完全关闭内容过滤器。使用此 表格 申请修改的内容过滤器。

但笔者发现,只要在网页上将勾选框的禁用状态去掉,即可修改内容过滤器为 annotated but not filtered 的状态,并且可以正常保存生效。也就是说实际上后端接口没有对用户修改这个设置的权限做校验,这个设置项的可用性只有前端进行控制。

开启的内容过滤器 禁用的内容过滤器

在浏览器 DevTools Console 中执行以下代码可以将这些勾选框的禁用状态去掉:

document.querySelectorAll('.ms-Modal input[type="checkbox"][disabled]')
  .forEach(el => el.removeAttribute('disabled'));

但如此修改之后,模型的输出仍然是一段一段的,但不会拦截不合适的输入输出了。看起来以上修改只是将内容过滤器修改成了仅标注的状态,虽然不再过滤有害内容,但由于仍然有标注的需求,模型的输出仍被内容过滤器阻塞。

尝试通过 API 禁用内容过滤器

从浏览器的 DevTools 观察,当保存内容过滤器的修改时,Azure 控制台向以下接口发起了一个 PUT 请求:

https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<org-name>/providers/Microsoft.CognitiveServices/accounts/<resource>/raiPolicies/<content-filter-name>?api-version=2023-10-01-preview

在请求 body 中,properties.contentFilters[*] 里面的以下字段引起了笔者的注意:

  • allowedContentLevel:与控制台上过滤器的严重等级(滑动条)对应
  • blocking:与控制台上过滤器的开启状态(勾选框)对应
  • enabled:始终为 true

考虑到 blocking 可以自由修改,尝试将 enabled 都改为 false 然后重放这个请求……

{
  // ...
  "properties": {
    "type": "UserManaged",
    "mode": "Default",
    "basePolicyName": "Microsoft.Default",
    "contentFilters": [
      {
        "name": "hate",
        "allowedContentLevel": "Medium",
        "blocking": false,
        "enabled": true,
        "source": "Prompt"
      },
      // ...
    ]
  }
}

Bingo!另外看到文案是 Turn on the switch above to enable or modify the filters,也就是说前面提到的表单申请通过后,应该是可以彻底禁用内容过滤器的,只是我们没有通过这个申请,所以没有看到对应的开关?

这样修改之后,再调用 Azure OpenAI 的 GPT 模型,可以得到预期的流式输出。