> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anyfast.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# x-safety-id

> 终端用户 Safety ID 接入指南：生成稳定标识、发送请求头并处理防蒸馏限制。

面向通过后端服务调用平台 API 的应用接入方。您可以在请求头中传入 x-safety-id，标识自己平台上的终端用户，协助平台识别可能违反使用政策的请求。在已启用防蒸馏限制的调用范围内，平台可以针对该终端用户累计拒绝和执行临时限制，减少对您其他用户的影响。

本文将您在本平台的账户称为“平台账户”，将使用您应用的用户称为“终端用户”。Safety ID 由您的后端生成和维护，无需向平台预先注册，也无需申请单独的子用户 ID。原有 API Key 鉴权方式保持不变。

接入前，请与平台确认使用的模型和接入线路已支持并启用该能力。仅添加请求头不会自动开启限制，也不代表所有模型、协议和接口均支持该检测。

## 快速接入

1. 为每位终端用户生成稳定、唯一的 Safety ID，并保留与您内部用户 ID 的对应关系。
2. 在后端向平台发出的每次相关请求中添加一个 x-safety-id 请求头，包括流式请求和重试请求。
3. 记录每次调用使用的 Safety ID，并按 HTTP 状态码、错误标识和 Retry-After 处理异常。

```http theme={null}
x-safety-id: 641218f96a549a57c1a3f997cda033a1ff43b28fa494b6cdd01dba105eb08d50

```

请完整覆盖相关调用入口。请求头缺失或为空时，防蒸馏检测会使用平台账户范围；该范围触发限制后，可能影响同一账户下的其他终端用户。

## 请求头定义

| 项目 | 约定 |
| - | - |
| 名称 | x-safety-id，请求头名称不区分大小写 |
| 类型 | 字符串 |
| 长度 | 去除首尾空白后，非空值为 1～64 个 ASCII 字符 |
| 允许字符 | 英文字母 A-Z、a-z，数字 0-9，以及 .、\_、:、@、- |
| 校验规则 | 非空值必须匹配 ^\[A-Za-z0-9.\_:@-]{1,64}\$ |
| 大小写 | 值区分大小写，Customer-A 与 customer-a 是不同标识 |
| 稳定性 | 同一终端用户始终使用同一值，不同终端用户使用不同值 |
| 缺失或空值 | 未传、空字符串、仅含空白均使用平台账户范围 |
| 多值 | 只允许一个值；重复请求头或以逗号拼接多个值均不接受 |
| 非法值 | 返回 HTTP 400，不发送到上游，也不会自动改用账户范围继续调用 |

平台会去除值的首尾空白，建议客户端直接发送无空白的规范值。中文、字符串内部空格、斜杠 /、加号 +、等号 = 和逗号 , 均不在允许范围内。

该标识用于平台内的防蒸馏识别，不会透传给上游模型服务商。请将它放在 HTTP 请求头中。

## 生成并维护标识

您无需向平台提供真实用户 ID、用户名、邮箱或租户编号等业务身份信息。推荐在自己的后端使用私有密钥，通过 HMAC-SHA256 生成稳定的脱敏标识，仅将结果作为 x-safety-id 传入。密钥、原始身份和用户映射由您自行保管，无需提供给平台。

HMAC-SHA256 是带密钥的哈希算法，输出的十六进制字符串为 64 个字符，符合请求头要求。建议自行生成 32 字节的安全随机密钥，作为此用途的专用密钥保存在后端密钥管理系统中。固定身份输入格式和 UTF-8 编码；不要为每次请求重新生成密钥，也不要把密钥放到浏览器或 App 中。

下面使用 Python 标准库 hmac，无需安装额外依赖。密钥和 tenant-a:user-10001 均为演示值；生产环境请使用自己生成并妥善保存的密钥，以及能唯一对应终端用户的身份输入。

```python theme={null}
import hashlib
import hmac

# 仅供演示；生产环境从后端密钥管理系统读取专用随机密钥。
secret_key = b"example-only-do-not-use-in-production"
identity = "tenant-a:user-10001"
safety_id = hmac.new(secret_key, identity.encode("utf-8"), hashlib.sha256).hexdigest()
print(safety_id)
```

输出：

```text theme={null}
641218f96a549a57c1a3f997cda033a1ff43b28fa494b6cdd01dba105eb08d50
```

如果您的应用包含多个租户，且用户 ID 只在租户内唯一，请将租户身份纳入生成规则，并确保组合方式无歧义，避免不同租户生成相同的 Safety ID。租户身份仅在您的后端参与计算，无需明文发送给平台。平台不要求不同平台账户之间的 Safety ID 全局唯一。

请在后端根据已登录用户生成或读取该标识，覆盖来自浏览器或 App 的同名请求头，避免终端用户自行修改或删除。Safety ID 不是身份认证凭证，API Key 仍需妥善保存在后端。

同一终端用户更换会话、设备、API Key 或重试请求时，均应保持 Safety ID 不变。不要使用随机数、时间戳或请求 ID。修改生成规则或轮换密钥时，既有用户应继续使用已保存的 Safety ID；直接用新规则或新密钥重新计算会改变标识，使平台将其识别为另一位终端用户。

请保存内部用户与 Safety ID 的对应关系，或提供内部查询方式。平台反馈的是收到的 Safety ID，不会还原其哈希输入；哈希结果也应按用户关联数据管理。

## 请求示例

以下命令适用于 Bash。示例使用国际站 API 地址 `https://www.anyfast.ai`；将 `YOUR_API_KEY` 和 `YOUR_ENABLED_MODEL` 替换为您的 API Key 及已开通且支持该能力的模型。示例 Safety ID 对应上一节的演示用户，实际调用时应按当前终端用户替换。

### Claude Messages 格式

```bash theme={null}
curl --include 'https://www.anyfast.ai/v1/messages' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'anthropic-version: 2023-06-01' \
  --header 'x-safety-id: 641218f96a549a57c1a3f997cda033a1ff43b28fa494b6cdd01dba105eb08d50' \
  --data '{
    "model": "YOUR_ENABLED_MODEL",
    "max_tokens": 128,
    "stream": false,
    "messages": [{"role": "user", "content": "请用一句话介绍你能提供的帮助。"}]
  }'
```

### OpenAI Chat Completions 兼容格式

支持该接入格式且已启用防蒸馏检测的模型，同样通过请求头传入 Safety ID：

```bash theme={null}
curl --include 'https://www.anyfast.ai/v1/chat/completions' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'x-safety-id: 641218f96a549a57c1a3f997cda033a1ff43b28fa494b6cdd01dba105eb08d50' \
  --data '{
    "model": "YOUR_ENABLED_MODEL",
    "max_tokens": 128,
    "stream": false,
    "messages": [{"role": "user", "content": "请用一句话介绍你能提供的帮助。"}]
  }'
```

流式调用将 stream 设为 true，请求头保持一致。客户端应先判断 HTTP 状态码和 Content-Type；在开始输出流之前被平台拦截时，响应可能是错误 JSON，不能直接按 SSE 数据流解析。

如果使用 SDK，请通过其自定义请求头能力传入 x-safety-id。同一 SDK 客户端服务多位终端用户时，应为每次调用设置对应的标识，避免把某位用户的标识固定在共享客户端上，或并发修改共享请求头造成串用。

## 限制的影响范围

平台按“平台账户 + Safety ID”关联终端用户，具体防蒸馏限制还按接入通道和实际调用的上游模型区分。账户范围限制表示对应通道、模型下的全部终端用户受影响，并非账户的所有接口和所有模型一律停用。

| 场景 | 处理方式 |
| - | - |
| 携带有效 Safety ID 的请求触发限制 | 限制对应终端用户在该通道、实际模型下的调用 |
| 未携带或传入空 Safety ID 的请求触发限制 | 限制对应平台账户在该通道、实际模型下的调用，涵盖该账户的全部终端用户 |
| 同一账户的多个 Safety ID 达到账户升级条件 | 当前通道和实际模型下的全部终端用户共同进入账户范围限制 |
| 同一账户、相同 Safety ID、不同 API Key | 共享该终端用户的拒绝计数和限制 |
| 同一账户、不同 Safety ID | 终端用户范围分别记录；仍受共同的账户范围限制约束 |
| 不同账户、相同 Safety ID | 分别关联各自账户，互不混用 |
| 已存在账户范围限制，再补传有效 Safety ID | 账户范围限制继续生效，不会因补传标识而解除 |

例如，您的平台账户下有终端用户 A 和 B。若 A 的有效 Safety ID 触发了终端用户范围限制，B 不会因此被计入 A 的限制。在没有账户范围限制或其他调用限制的前提下，B 可以继续正常调用。

## 多位终端用户触发时的账户限制

平台可配置两条账户升级条件：在滚动时间窗口内，达到指定数量的不同 Safety ID 出现匹配的防蒸馏拒绝，或达到指定数量的不同 Safety ID 因匹配拒绝触发终端用户限制。两条条件分别统计，任一达到阈值，都会使同一平台账户在当前通道和实际模型下的全部终端用户进入冷却。

新策略的默认值为滚动 600 秒内，20 个不同 Safety ID 出现匹配拒绝，或 5 个不同 Safety ID 触发终端用户限制。实际是否启用及阈值请以平台确认的生效策略为准。每条条件内，同一个 Safety ID 重复出现只计一个；成功响应不会清空窗口内已有记录，记录随时间移出窗口。同一账户的不同 API Key 共用这些统计。

因此，稳定传入 Safety ID 有助于细分单个用户的限制，但不保证其他终端用户始终不受影响。账户范围限制一旦生效，切换到新的 Safety ID、移除请求头或更换同账户 API Key 都不能绕过它；其他通道和实际模型仍分别处理。

## 错误处理和恢复

平台可能返回以下参数校验或防蒸馏相关错误。OpenAI 兼容格式读取 error.code，Claude Messages 格式读取 error.type；不要依赖 message 的具体文案判断错误类型。

| HTTP 状态码 | 错误标识或情况 | 客户端处理 |
| - | - | - |
| 400 | Safety ID 格式非法、超长或重复传入 | 修正请求头后重新调用；不要通过删除请求头自动降级重试 |
| 503 | user\_model\_circuit\_open | 当前适用范围仍在冷却，按响应中的 Retry-After 等待后再尝试 |
| 503 | user\_model\_probe\_busy | 当前范围已有恢复试探正在进行，等待 Retry-After 指定的时间后再尝试，避免并发重试 |
| 503 | user\_model\_circuit\_state\_unavailable | 平台暂时无法确认当前请求能否放行；采用有限次数的退避重试，持续发生时联系平台 |

Safety ID 校验失败时，OpenAI 兼容格式返回 error.code: "invalid\_request"、error.type: "anyfast\_api\_error"；Claude Messages 格式返回 error.type: "anyfast\_api\_error"，没有 error.code。这些值也可能用于其他参数错误，请结合 HTTP 400 和 message 定位需要修正的输入。上表中的三个 503 标识则分别通过两种协议对应的错误字段返回。

Retry-After 表示建议等待的秒数。例如 Retry-After: 120 表示至少等待 120 秒后再尝试，不表示届时一定恢复全部调用。未返回该响应头时，采用有限次数的退避重试，避免持续高频请求。

冷却结束后，平台会先允许受控试探，再根据完整调用结果逐步恢复。若平台账户和该终端用户都处于限制状态，两层限制需要依次恢复，不能只按其中一层的冷却时间判断。具体触发阈值、冷却时长和恢复条件以平台生效策略为准。

请求重试应沿用原 Safety ID。收到 503 后，不要立刻停用整个账户的全部用户，也不要轮换 Safety ID、切换 API Key 或移除请求头尝试绕过限制。应结合平台反馈确认影响范围，控制对应调用的重试频率。

达到触发条件的那次上游调用可能仍以 HTTP 200 返回拒绝内容；后续调用才受到限制。客户端还需按接口协议处理模型的拒绝结果，不能将 HTTP 200 一律视为业务成功。user\_model\_circuit\_state\_unavailable 也不等同于已判定某位终端用户违规。

## 根据平台反馈定位终端用户

当您从平台获得限制记录或通知时，可使用其中的平台账户及客户平台 Safety ID 定位终端用户。通知方式需另行与平台确认，添加请求头不会自动订阅通知。您可以用原样的 Safety ID 查询内部映射，找到对应终端用户及其请求记录。账户范围记录以“所有终端客户”表示；不要将它理解为某个终端用户的 Safety ID。若因多位终端用户触发账户升级，反馈中的窗口、去重标识数量和阈值用于说明触发条件，不表示连续拒绝次数。

建议在自己的调用日志中记录 Safety ID、请求时间、模型、HTTP 状态码、错误标识，以及响应提供的请求 ID（如有）。标准错误响应不会额外回显 Safety ID，请保留请求侧的关联信息。

联系平台协助排查时，请提供：

* 您的平台账户 ID。
* 原样的 Safety ID，保留大小写；若当次请求未传或为空，请明确说明。
* 请求时间及所在时区、请求模型。
* HTTP 状态码、错误标识和 Retry-After（如有）。
* 请求 ID，以及平台已经提供的限制记录或事件编号（如有）。
  请勿提供 API Key、密码等认证信息。需要协助解除限制时，请同时提供对应的范围信息，由平台核查处理。

## 上线自查

* 同一终端用户在普通调用、流式调用、重试和不同 API Key 下使用同一个 Safety ID。
* 不同终端用户及不同租户不会意外复用同一标识。
* 后端和中间代理只发送一个请求头，既不会丢失，也不会追加成多个值。
* SDK 并发调用不会串用其他终端用户的标识。
* 客户端能处理 400、503、Retry-After 及流式调用前返回的错误 JSON。
* 能根据平台反馈的 Safety ID 查到内部终端用户及相关请求。

<script src="/public/feedback.js" />


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.