🤔 Introducing APISIX AI Gateway – Built for LLMs and AI workloads. Learn More

ai-prompt-guard

描述

ai-prompt-guard 插件通过检查和验证传入的提示消息来保护你的 LLM 端点。它根据用户定义的允许和拒绝模式检查请求内容,确保只有经过批准的输入才会被转发到上游 LLM。根据其配置,该插件可以仅检查最新消息或整个对话历史,并且可以设置为检查所有角色的提示或仅检查最终用户的提示。

当同时配置了 allow_patternsdeny_patterns 时,插件首先确保至少匹配一个 allow_patterns。如果没有匹配,请求将被拒绝。如果匹配了允许的模式,它会继续检查是否存在任何拒绝模式的匹配。

插件属性

名称类型必选项默认值有效值描述
match_all_rolesbooleanfalse如果为 true,验证所有角色的消息。如果为 false,仅验证 user 角色的消息。
match_all_conversation_historybooleanfalse如果为 true,连接并检查对话历史中的所有消息。如果为 false,仅检查最后一条消息的内容。
allow_patternsarray[]消息应匹配的正则表达式模式数组。配置后,消息必须至少匹配一个模式才被视为有效。
deny_patternsarray[]消息不应匹配的正则表达式模式数组。如果消息匹配任何模式,请求将被拒绝。如果同时配置了 allow_patternsdeny_patterns,插件会首先确保至少匹配一个 allow_patterns

使用示例

以下示例将使用 OpenAI 作为上游服务提供商。在继续之前,请创建一个 OpenAI 账户和一个 API 密钥。你可以选择将密钥保存到环境变量中:

export OPENAI_API_KEY=<YOUR_OPENAI_API_KEY>

如果你使用其他 LLM 提供商,请参阅提供商的文档以获取 API 密钥。

实现允许和拒绝模式

以下示例演示了如何使用 ai-prompt-guard 插件通过定义允许和拒绝模式来验证用户提示,以及如何理解允许模式的优先级。

定义允许和拒绝模式。你可以选择将它们保存到环境变量中以便于转义:

# 允许美元金额
export ALLOW_PATTERN_1='\\$?\\(?\\d{1,3}(,\\d{3})*(\\.\\d{1,2})?\\)?'
# 拒绝美国电话号码格式
export DENY_PATTERN_1='(\\([0-9]{3}\\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}'

NOTE

你可以使用以下命令从 config.yaml 中获取 admin_key 并保存到环境变量中:

admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

Admin API

创建一个路由,使用 ai-proxy 代理到 OpenAI 并使用 ai-prompt-guard 检查输入提示:

curl "http://127.0.0.1:9180/apisix/admin/routes/1" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "uri": "/anything",
    "methods": ["POST"],
    "plugins": {
      "ai-proxy": {
        "provider": "openai",
        "auth": {
          "header": {
            "Authorization": "Bearer '"$OPENAI_API_KEY"'"
          }
        },
        "options":{
          "model": "gpt-4"
        }
      },
      "ai-prompt-guard": {
        "allow_patterns": [
          "'"$ALLOW_PATTERN_1"'"
        ],
        "deny_patterns": [
          "'"$DENY_PATTERN_1"'"
        ]
      }
    }
  }'

ADC

创建一个配置了 ai-prompt-guardai-proxy 插件的路由:

adc.yaml
services:
  - name: prompt-guard-service
    routes:
      - name: prompt-guard-route
        uris:
          - /anything
        methods:
          - POST
        plugins:
          ai-proxy:
            provider: openai
            auth:
              header:
                Authorization: "Bearer ${OPENAI_API_KEY}"
            options:
              model: gpt-4
          ai-prompt-guard:
            allow_patterns:
              - '\$?\(?\d{1,3}(,\d{3})*(\.\d{1,2})?\)?'
            deny_patterns:
              - '(\([0-9]{3}\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}'

将配置同步到网关:

adc sync -f adc.yaml

Ingress Controller

Gateway API

创建一个配置了 ai-prompt-guardai-proxy 插件的路由:

ai-prompt-guard-ic.yaml
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
  namespace: aic
  name: ai-prompt-guard-plugin-config
spec:
  plugins:
    - name: ai-prompt-guard
      config:
        allow_patterns:
          - '\$?\(?\d{1,3}(,\d{3})*(\.\d{1,2})?\)?'
        deny_patterns:
          - '(\([0-9]{3}\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}'
    - name: ai-proxy
      config:
        provider: openai
        auth:
          header:
            Authorization: "Bearer your-api-key"
        options:
          model: gpt-4
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  namespace: aic
  name: prompt-guard-route
spec:
  parentRefs:
    - name: apisix
  rules:
    - matches:
        - path:
            type: Exact
            value: /anything
          method: POST
      filters:
        - type: ExtensionRef
          extensionRef:
            group: apisix.apache.org
            kind: PluginConfig
            name: ai-prompt-guard-plugin-config

APISIX Ingress Controller

创建一个配置了 ai-prompt-guardai-proxy 插件的路由:

ai-prompt-guard-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  namespace: aic
  name: prompt-guard-route
spec:
  ingressClassName: apisix
  http:
    - name: prompt-guard-route
      match:
        paths:
          - /anything
        methods:
          - POST
      plugins:
        - name: ai-prompt-guard
          enable: true
          config:
            allow_patterns:
              - '\$?\(?\d{1,3}(,\d{3})*(\.\d{1,2})?\)?'
            deny_patterns:
              - '(\([0-9]{3}\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}'
        - name: ai-proxy
          enable: true
          config:
            provider: openai
            auth:
              header:
                Authorization: "Bearer your-api-key"
            options:
              model: gpt-4

将配置应用到集群:

kubectl apply -f ai-prompt-guard-ic.yaml

向路由发送一个请求,评估购买的公平性:

curl -i "http://127.0.0.1:9080/anything" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "system", "content": "Rate if the purchase is at a decent price in USD." },
      { "role": "user", "content": "John paid $12.5 for a hot brewed coffee in El Paso." }
    ]
  }'

你应该收到一个 HTTP/1.1 200 OK 响应,类似如下:

{
  ...
  "model": "gpt-4-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "The purchase is not at a decent price. Typically, a hot brewed coffee costs anywhere from $1 to $3 in most places in the US, so $12.5 is quite expensive.",
        "refusal": null
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  ...
}

发送另一个不包含任何价格的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "system", "content": "Rate if the purchase is at a decent price in USD." },
      { "role": "user", "content": "John paid a bit for a hot brewed coffee in El Paso." }
    ]
  }'

你应该收到一个 HTTP/1.1 400 Bad Request 响应,并看到以下消息:

{"message":"Request doesn't match allow patterns"}

发送第三个包含电话号码的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "system", "content": "Rate if the purchase is at a decent price in USD." },
      { "role": "user", "content": "John (647-200-9393) paid $12.5 for a hot brewed coffee in El Paso." }
    ]
  }'

你应该收到一个 HTTP/1.1 400 Bad Request 响应,并看到以下消息:

{"message":"Request contains prohibited content"}

默认情况下,插件仅检查 user 角色的输入和最后一条消息。例如,如果你发送一个在 system 提示中包含禁止内容的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "system", "content": "Rate if the purchase from 647-200-9393 is at a decent price in USD." },
      { "role": "user", "content": "John paid $12.5 for a hot brewed coffee in El Paso." }
    ]
  }'

你将收到一个 HTTP/1.1 200 OK 响应。

如果你发送一个在倒数第二条消息中包含禁止内容的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "system", "content": "Rate if the purchase is at a decent price in USD." },
      { "role": "user", "content": "Customer John contact: 647-200-9393" },
      { "role": "user", "content": "John paid $12.5 for a hot brewed coffee in El Paso." }
    ]
  }'

你也将收到一个 HTTP/1.1 200 OK 响应。

参阅下一个示例了解如何检查所有角色和所有消息。

验证所有角色的消息和对话历史

以下示例演示了如何使用 ai-prompt-guard 插件验证所有角色(如 systemuser)的提示,以及验证整个对话历史而不是仅验证最后一条消息。

定义允许和拒绝模式。你可以选择将它们保存到环境变量中以便于转义:

export ALLOW_PATTERN_1='\\$?\\(?\\d{1,3}(,\\d{3})*(\\.\\d{1,2})?\\)?'
export DENY_PATTERN_1='(\\([0-9]{3}\\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}'

Admin API

创建一个路由,使用 ai-proxy 代理到 OpenAI 并使用 ai-prompt-guard 检查输入提示。将 match_all_rolesmatch_all_conversation_history 设置为 true 以验证所有角色的消息和整个对话:

curl "http://127.0.0.1:9180/apisix/admin/routes/1" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "uri": "/anything",
    "methods": ["POST"],
    "plugins": {
      "ai-proxy": {
        "provider": "openai",
        "auth": {
          "header": {
            "Authorization": "Bearer '"$OPENAI_API_KEY"'"
          }
        },
        "options":{
          "model": "gpt-4"
        }
      },
      "ai-prompt-guard": {
        "match_all_roles": true,
        "match_all_conversation_history": true,
        "allow_patterns": [
          "'"$ALLOW_PATTERN_1"'"
        ],
        "deny_patterns": [
          "'"$DENY_PATTERN_1"'"
        ]
      }
    }
  }'

ADC

创建一个配置了 ai-prompt-guardai-proxy 插件的路由。将 match_all_rolesmatch_all_conversation_history 设置为 true 以验证所有角色的消息和整个对话:

adc.yaml
services:
  - name: prompt-guard-service
    routes:
      - name: prompt-guard-route
        uris:
          - /anything
        methods:
          - POST
        plugins:
          ai-proxy:
            provider: openai
            auth:
              header:
                Authorization: "Bearer ${OPENAI_API_KEY}"
            options:
              model: gpt-4
          ai-prompt-guard:
            match_all_roles: true
            match_all_conversation_history: true
            allow_patterns:
              - '\$?\(?\d{1,3}(,\d{3})*(\.\d{1,2})?\)?'
            deny_patterns:
              - '(\([0-9]{3}\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}'

将配置同步到网关:

adc sync -f adc.yaml

Ingress Controller

Gateway API

创建一个配置了 ai-prompt-guardai-proxy 插件的路由。将 match_all_rolesmatch_all_conversation_history 设置为 true 以验证所有角色的消息和整个对话:

ai-prompt-guard-history-ic.yaml
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
  namespace: aic
  name: ai-prompt-guard-plugin-config
spec:
  plugins:
    - name: ai-prompt-guard
      config:
        match_all_roles: true
        match_all_conversation_history: true
        allow_patterns:
          - '\$?\(?\d{1,3}(,\d{3})*(\.\d{1,2})?\)?'
        deny_patterns:
          - '(\([0-9]{3}\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}'
    - name: ai-proxy
      config:
        provider: openai
        auth:
          header:
            Authorization: "Bearer your-api-key"
        options:
          model: gpt-4
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  namespace: aic
  name: prompt-guard-route
spec:
  parentRefs:
    - name: apisix
  rules:
    - matches:
        - path:
            type: Exact
            value: /anything
          method: POST
      filters:
        - type: ExtensionRef
          extensionRef:
            group: apisix.apache.org
            kind: PluginConfig
            name: ai-prompt-guard-plugin-config

APISIX Ingress Controller

创建一个配置了 ai-prompt-guardai-proxy 插件的路由。将 match_all_rolesmatch_all_conversation_history 设置为 true 以验证所有角色的消息和整个对话:

ai-prompt-guard-history-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  namespace: aic
  name: prompt-guard-route
spec:
  ingressClassName: apisix
  http:
    - name: prompt-guard-route
      match:
        paths:
          - /anything
        methods:
          - POST
      plugins:
        - name: ai-prompt-guard
          enable: true
          config:
            match_all_roles: true
            match_all_conversation_history: true
            allow_patterns:
              - '\$?\(?\d{1,3}(,\d{3})*(\.\d{1,2})?\)?'
            deny_patterns:
              - '(\([0-9]{3}\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}'
        - name: ai-proxy
          enable: true
          config:
            provider: openai
            auth:
              header:
                Authorization: "Bearer your-api-key"
            options:
              model: gpt-4

将配置应用到集群:

kubectl apply -f ai-prompt-guard-history-ic.yaml

发送一个在 system 提示中包含禁止内容的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "system", "content": "Rate if the purchase from 647-200-9393 is at a decent price in USD." },
      { "role": "user", "content": "John paid $12.5 for a hot brewed coffee in El Paso." }
    ]
  }'

你应该收到一个 HTTP/1.1 400 Bad Request 响应,并看到以下消息:

{"message":"Request contains prohibited content"}

发送一个来自同一角色的多条包含禁止内容的消息的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "system", "content": "Rate if the purchase is at a decent price in USD." },
      { "role": "user", "content": "Customer John contact: 647-200-9393" },
      { "role": "user", "content": "John paid $12.5 for a hot brewed coffee in El Paso." }
    ]
  }'

你应该收到一个 HTTP/1.1 400 Bad Request 响应,并看到以下消息:

{"message":"Request contains prohibited content"}

发送一个符合模式的请求:

curl -i "http://127.0.0.1:9080/anything" -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "system", "content": "Rate if the purchase is at a decent price in USD." },
      { "role": "system", "content": "The purchase is made in El Paso." },
      { "role": "user", "content": "Customer John contact: xxx-xxx-xxxx" },
      { "role": "user", "content": "John paid $12.5 for a hot brewed coffee." }
    ]
  }'

你应该收到一个 HTTP/1.1 200 OK 响应,类似如下:

{
  ...,
  "model": "gpt-4-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "$12.5 is generally considered quite expensive for a cup of brew coffee.",
        "refusal": null
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  ...
}