Claude Platform Docs
АдминистрированиеХуки инференса

Разработка интеграции Inference hooks

Создайте сервер безопасности ИИ, который принимает подписанные запросы Inference hooks, проверяет их и возвращает вердикты allow или deny.

Интеграция Inference hooks — это «AI security server» (сервер безопасности ИИ): HTTPS-сервис, который вызывает Anthropic. Для каждого контролируемого запроса ваш сервер получает подписанный POST, содержащий транскрипт разговора, и отвечает вердиктом allow (разрешить) или deny (отклонить). На этой странице описан протокол для создания такого сервера: схемы запроса и вердикта, проверка подписи и операционный контракт.

Чтобы включить Inference hooks и направить их на вашу конечную точку, см. Настройка Inference hooks. Чтобы узнать, что такое Inference hooks и когда их использовать, см. обзор Inference hooks.

Получите первый полный цикл вердикта

Минимальная работающая интеграция — это сервер, который читает каждый запрос и разрешает его. Запустите один из следующих серверов, опубликуйте его по общедоступному URL https:// (например, за обратным прокси с терминацией TLS на хосте, который вы контролируете, а не через сервис обратного туннелирования; см. Получение запроса), затем попросите вашего администратора указать его в качестве конечной точки и протестировать соединение: результат Test connection сообщает вердикт allow, который вернул ваш сервер.

# Запуск: python server.py
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer


class VerdictHandler(BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.1"  # keep the connection open between verdicts

    def do_POST(self):
        # Вычитываем тело полностью; транскрипты могут занимать мегабайты.
        self.rfile.read(int(self.headers.get("Content-Length", 0)))
        verdict = b'{"action": "allow"}'
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(verdict)))
        self.end_headers()
        self.wfile.write(verdict)


ThreadingHTTPServer(("", 8000), VerdictHandler).serve_forever()

Получение запроса

Anthropic отправляет HTTPS POST на URL, который настраивает ваш администратор. Весь настроенный URL является конечной точкой: фиксированного суффикса пути нет, поэтому выберите любой путь, подходящий вашему серверу.

Разместите ваш сервер безопасности ИИ там, где Anthropic сможет до него достучаться: URL https:// на порту 443, на публично маршрутизируемом хосте (частные диапазоны, loopback и диапазоны carrier-grade NAT отклоняются при подключении), с сертификатом, который проходит проверку по публичному хранилищу доверенных CA, и с ответом без перенаправлений. У хоста должен быть IPv4-адрес, который Anthropic использует, даже если у хоста есть и IPv6-адреса; URL, хостом которого является localhost или IPv6-адрес, отклоняется. Настроенный URL должен быть конечным адресом назначения. Хосты обратного туннелирования (ngrok и аналогичные сервисы туннелирования) не поддерживаются: сетевая политика Anthropic их блокирует. Размещайте сервер на домене, которым вы управляете. В разделе Настройка Inference hooks описано, как администратор задаёт и проверяет URL.

Каждый запрос содержит эти фиксированные заголовки, а также любые пользовательские заголовки запроса, настроенные вашим администратором, и — как только у вашей организации появится секрет подписи — заголовки подписи webhook-*, описанные в разделе Проверка подписи:

ЗаголовокЗначение
Content-Typeapplication/json
User-Agentanthropic-dlp/1
Accept-Encodingidentity

Существует два события хуков, которые различаются по полю верхнего уровня type. Кадр подсказки отправляется один раз для каждого контролируемого запроса инференса, до начала инференса. Кадр вызова инструментов отправляется, когда ответ модели содержит вызовы инструментов, до выполнения любого из них, в организациях, где включён параметр Validate tool calls. В обоих случаях Anthropic ждёт, пока ваш сервер безопасности ИИ не ответит или не истечёт тайм-аут вердикта.

Кадр подсказки

Тело запроса — это JSON-объект со следующими полями:

ПолеТипОписание
typestringСобытие хука: "prompt" или "tool_call" (см. Кадр вызова инструментов). В будущем появятся другие типы событий, поэтому корректно обрабатывайте нераспознанное значение (см. Прямая совместимость).
request_idstringНепрозрачный идентификатор для корреляции, уникальный для каждого кадра. Совпадает с заголовком webhook-id.
tenant_idstring или nullНепрозрачный идентификатор организации, к которой относится запрос.
actorobjectСубъект, которому приписывается запрос, различаемый по type ("user" — единственное значение, отправляемое сегодня): id (тегированный идентификатор, стабильный между запросами для одной и той же учётной записи) и email_address (при наличии). И id, и email_address могут быть null.
sourceobjectИсходное приложение: application (см. Значения source).
messagesarrayТранскрипт разговора до момента инференса. См. Блоки содержимого.
session_idstring или nullНепрозрачный идентификатор разговора, если он существует. Не разбирайте его. Для Claude Code это идентификатор сессии, заявленный клиентом по принципу best-effort.
modelstring или nullПубличный идентификатор модели для этого запроса, при наличии.
metadataobjectЗарезервированная карта расширений со строковыми ключами и строковыми значениями, сегодня отправляется пустой. Ничего от неё не требуйте и допускайте её отсутствие, её наличие и любые появляющиеся ключи.

Пример тела запроса:

{
  "type": "prompt",
  "request_id": "req_abc123",
  "tenant_id": "11111111-1111-1111-1111-111111111111",
  "actor": {
    "type": "user",
    "id": "user_01AbCdEfGhIjKlMnOpQrStUv",
    "email_address": "alice@example.com"
  },
  "source": {
    "application": "claude-ai"
  },
  "session_id": "22222222-2222-2222-2222-222222222222",
  "model": "claude-sonnet-4-5",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Summarize the attached report."
        },
        {
          "type": "attachment",
          "file_name": "q2-report.pdf",
          "media_type": "application/pdf",
          "size_bytes": 48213,
          "text": "Q2 revenue grew 14% quarter over quarter..."
        }
      ]
    }
  ],
  "metadata": {}
}

Блоки содержимого

Каждая запись в messages имеет role со значением user или assistant (результаты инструментов появляются под ролью user, в соответствии с моделью содержимого публичного Messages API) и массив content из блоков, различаемых по type:

type блокаПоля
texttext: текстовое содержимое.
tool_useid: идентификатор, на который ссылается соответствующий результат инструмента. tool_name: имя инструмента. input: аргументы, которые модель передала инструменту. tool_info: только в кадре вызова инструментов (в остальных случаях опускается, никогда не null) — объект, указывающий, кто выполняет или предоставляет инструмент; см. Кадр вызова инструментов.
tool_resultcontent: вывод инструмента в виде текста, части соединены переводами строк; бинарные части, такие как изображения, заменяются маркерами-заполнителями, а сырые байты никогда не отправляются. is_error: завершился ли вызов инструмента ошибкой. tool_name: имя инструмента, чтобы политика могла учитывать идентичность инструмента без перекрёстных ссылок на более ранний блок. tool_use_id: id соответствующего блока tool_use.
attachmentfile_name: исходное имя файла или путь. media_type: медиатип вложения. size_bytes: размер исходного файла. text: текстовое содержимое вложения при наличии, например извлечённый текст документа, транскрипт аудио или метаданные ссылки. Сырые байты вложений никогда не отправляются.

За исключением type, поля text блока text, а также полей content и is_error блока tool_result, любое из этих полей может быть null, если значение неизвестно; например, изображение поступает как блок attachment, у которого file_name и text равны null.

Блок, type которого вы не распознаёте, является прямо совместимым дополнением. Единственное поле, которое он гарантирует, — это type; ваша политика может проверять любые другие присутствующие поля, но не должна отклонять запрос из-за нераспознанного типа.

Что содержит транскрипт

Транскрипт — это разговор в том виде, в каком его видит конечный пользователь, до момента инференса: текст транскрипта, вызовы инструментов и их результаты, извлечённый текст вложений и предыдущие ходы. Он никогда не включает системные подсказки, определения инструментов, внутренний контекст Anthropic, скрытые рассуждения Claude или сырые байты файлов.

Ход, каждый блок которого исключён, опускается полностью, поэтому не предполагайте строгого чередования user и assistant.

Транскрипты отправляются без усечения, поэтому длинный разговор с большими вложениями порождает большое тело запроса. На практике контекстное окно модели удерживает размер тела в пределах примерно 10 МБ, но протокол допускает до 64 МиБ. Некоторые распространённые значения по умолчанию гораздо меньше, в том числе client_max_body_size в nginx (1 МБ) и express.json() в Express (100 кБ), а отклонённое тело считается сбоем вебхука, поэтому при обработке сбоев Allow the request слишком большая подсказка дойдёт до модели без проверки.

Значения source

source.application — это открытая строка, а не закрытое перечисление. Распространённые значения: claude-ai, claude-code и cowork; проверки подключения и автоматические проверки восстановления автоматического выключателя используют config-test. Могут появляться новые значения, и ваш сервер не должен отклонять запрос из-за значения, которое он не распознаёт.

Рассматривайте source.application как рекомендательные метаданные маршрутизации, а не как границу доверия: не основывайте критичное для безопасности решение политики только на нём.

Кадр вызова инструментов

Когда Claude создаёт вызовы инструментов, Anthropic отправляет один кадр вызова инструментов, в котором они перечислены. Вызовы некоторых собственных инструментов claude.ai могут быть опущены, а ответ, все вызовы инструментов которого опущены, не порождает кадр вызова инструментов; см. Доступность. Один вердикт охватывает весь кадр: нельзя разрешить одни вызовы инструментов и отклонить другие. Кадр отправляется на ту же конечную точку, что и кадр подсказки, с теми же заголовками, подписью и полями верхнего уровня. Вызовы инструментов, выполняемые кодом, который Claude запускает в инструменте выполнения кода, отправляются так же, в отдельных кадрах вызова инструментов, до их выполнения.

От кадра подсказки он отличается тремя особенностями:

  • type равен "tool_call".
  • messages содержит только последнее сообщение — сообщение assistant, которое Claude только что создал: все блоки text и по одному блоку tool_use на каждый вызов инструмента, перечисленный в кадре, в том порядке, в котором их создала модель. Более ранняя часть разговора опускается, поскольку её содержал кадр подсказки, отправленный перед этим вызовом модели. Читайте последнюю запись messages, поскольку в будущем протокол может добавлять перед ней более ранние сообщения.
  • Каждый блок tool_use содержит объект tool_info, указывающий, кто выполняет или предоставляет инструмент.

Если session_id задан, он одинаков в обоих кадрах. У кадра вызова инструментов есть собственный request_id, такой же непрозрачный, как у кадра подсказки.

tool_info указывает, кто выполняет или предоставляет инструмент, а не к чему инструмент имеет доступ. Он относится к одному из четырёх видов, различаемых по полю type, и каждый вид содержит собственные поля. Anthropic отправляет первый из следующих видов, который подходит инструменту. Могут появиться новые виды: принимайте type, который вы не распознаёте, и для такого вида полагайтесь только на type.

Неприменимое необязательное поле опускается, а не передаётся как null, поэтому tool_info может быть просто {"type": "client"}. tool_name выбирает тот, кто определил инструмент, а toolset_name сервера — тот, кто написал запрос, поэтому не рассматривайте ни одно из них как границу доверия.

Инструменты платформы

Инструмент платформы — это инструмент, который сам Claude API выполняет при обслуживании запроса, например веб-поиск или выполнение кода.

ПолеНаличиеОписание
typeВсегда"platform"
tool_typeВсегдаВерсионированный тип инструмента, например web_search_20250305. Сопоставляйте его точно; не извлекайте из него имя или дату.
toolset_nameНеобязательноГруппа инструментов, к которой он относится.

Инструменты приложения

Инструмент приложения — это инструмент, который предоставляет само приложение Anthropic, выполняющее запрос, например собственные инструменты claude.ai.

ПолеНаличиеОписание
typeВсегда"application"
toolset_nameНеобязательноГруппа инструментов, к которой он относится.

Блок tool_use для инструмента веб-поиска, который предоставляет сам claude.ai:

{
  "type": "tool_use",
  "id": "toolu_01LmNoPqRsTuVwXyZaBcDeFg",
  "tool_name": "web_search",
  "input": {
    "query": "comparable deals for unannounced 4.2B USD Acme Corp acquisition"
  },
  "tool_info": {
    "type": "application"
  }
}

claude.ai не всегда называет этот инструмент web_search, поэтому не сопоставляйте только по имени. input всегда включает поисковый запрос и может содержать другие поля.

Сторонние инструменты

Сторонний инструмент — это инструмент на сервере, о котором Anthropic известно, например коннектор claude.ai или MCP-сервер, который запрос указывает в mcp_servers. Это не означает, что Anthropic проверила сервер.

ПолеНаличиеОписание
typeВсегда"third_party"
toolset_nameНеобязательноИмя, которое запрос даёт серверу.
originНеобязательноСхема, хост и нестандартный порт URL сервера. Это может быть частный или локальный адрес, включая localhost. Отсутствие origin означает «неизвестно», а не «безопасно».
verified_originВсегда, когда есть origintrue только тогда, когда серверы Anthropic сами подключаются к серверу. Рассматривайте false как источник, который Anthropic не подтвердила.

Блок tool_use для инструмента на MCP-сервере, который запрос называет crm в mcp_servers:

{
  "type": "tool_use",
  "id": "toolu_01GhIjKlMnOpQrStUvWxYzAb",
  "tool_name": "crm_search",
  "input": {
    "query": "accounts renewing in Q4"
  },
  "tool_info": {
    "type": "third_party",
    "toolset_name": "crm",
    "origin": "https://mcp.crm.example.com",
    "verified_origin": true
  }
}

Клиентские инструменты

Клиентский инструмент — это любой другой инструмент, обычно выполняемый приложением, которое вызывает Claude. Инструмент, который определяет Anthropic, но выполняет вызывающее приложение, например bash или инструмент использования компьютера, тоже является клиентским и содержит свой версионированный тип в tool_type. Вызов инструмента, который запрос не объявляет, также имеет тип "client".

Инструмент на MCP-сервере, к которому Claude Code подключается напрямую с компьютера пользователя, например на локальном MCP-сервере, является клиентским инструментом. Его tool_info равен {"type": "client"}, а его tool_name — это имя, которое ему даёт Claude Code, в формате mcp__<server>__<tool>.

Вердикт deny останавливает вызов до того, как Claude Code его выполнит. Обмен данными между Claude Code и локальным сервером не проходит через Anthropic, поэтому ваш сервер безопасности ИИ видит результат инструмента, только когда Claude Code отправляет его обратно. Тогда его текст находится в блоке tool_result в следующем кадре подсказки.

ПолеНаличиеОписание
typeВсегда"client"
tool_typeНеобязательноВерсионированный тип инструмента, например bash_20250124, если инструмент определяет Anthropic. Сопоставляйте его точно; не извлекайте из него имя или дату.
toolset_nameНеобязательноГруппа инструментов, к которой он относится, например browser.

Блок tool_use для инструмента, который объявляет вызывающее приложение:

{
  "type": "tool_use",
  "id": "toolu_01AbCdEfGhIjKlMnOpQrStUv",
  "tool_name": "read_file",
  "input": {
    "path": "reports/q3.txt"
  },
  "tool_info": {
    "type": "client"
  }
}

Блок tool_use для bash, который определяет Anthropic и выполняет вызывающее приложение:

{
  "type": "tool_use",
  "id": "toolu_01HiJkLmNoPqRsTuVwXyZaBc",
  "tool_name": "bash",
  "input": {
    "command": "ls -la reports/"
  },
  "tool_info": {
    "type": "client",
    "tool_type": "bash_20250124"
  }
}

Возврат вердикта

Отвечайте HTTP 200 и JSON-телом вердикта для обоих исходов; различает их поле action. Чтобы разрешить запрос:

{
  "action": "allow"
}

Чтобы отклонить его:

{
  "action": "deny",
  "deny_reason": "This prompt appears to contain customer payment card data, which your organization's policy does not allow.",
  "reference_id": "scan_01HXPT4R9V"
}
ПолеОграниченияСемантика
action"allow" или "deny"; обязательноеallow позволяет инференсу продолжиться; deny отклоняет его.
deny_reasonstring или null; не более 500 символов, более длинные значения усекаютсяПоказывается конечному пользователю, когда action равно deny; игнорируется при allow.
reference_idstring или null; не более 50 символов из [A-Za-z0-9._:/-]Ваш собственный идентификатор для этой оценки. Он записывается в активность соответствия inference_hooks_request_denied для отклонения и никогда не показывается конечному пользователю. Держите его непрозрачным: никакого содержимого запроса и никаких персональных данных.

Deny никогда не отбрасывается из-за проблемы форматирования: deny_reason чрезмерного размера усекается, некорректный reference_id молча отбрасывается, а action по-прежнему соблюдается.

Обратное неверно. Всё, кроме HTTP 200 с разбираемым вердиктом, является сбоем вебхука, и вместо вердикта применяется обработка сбоев вашей организации. В частности:

  • Не сигнализируйте deny статусом ошибки. Ответ, отличный от 200, — это сбой, а не deny.
  • Любое значение action, отличное от allow или deny, рассматривается как сбой вебхука.

Anthropic читает не более 64 КиБ тела ответа, и тело должно быть несжатым. Перенаправления не выполняются, а cookie игнорируются. Неизвестные поля в теле вердикта игнорируются, поэтому вы можете возвращать более богатый объект наряду с полями, задокументированными здесь.

Кадр вызова инструментов принимает то же тело вердикта, и каждое правило этого раздела применяется к нему без изменений. allow позволяет выполнить вызовы инструментов, и ответ продолжается; deny останавливает их все и завершает ответ той же ошибкой, что и отклонённая подсказка, включая ваш deny_reason. Текст, доставленный до первого вызова инструмента, не отзывается.

Проверка подписи

Запросы подписываются согласно спецификации Standard Webhooks с использованием трёх заголовков. Anthropic отправляет имена заголовков в нижнем регистре, а прокси могут свободно менять их регистр, поэтому ищите их без учёта регистра.

ЗаголовокСодержимое
webhook-idУникальный идентификатор этой доставки. Равен request_id в теле. Используйте его как ключ идемпотентности и как первый компонент подписываемой полезной нагрузки.
webhook-timestampВремя Unix в секундах в виде десятичной строки, когда запрос был подписан. Отклоняйте метку времени, отличающуюся от часов вашего сервера более чем на пять минут в любую сторону.
webhook-signatureОдно или несколько разделённых пробелами значений v1,<base64>, каждое — HMAC-SHA256 от {webhook-id}.{webhook-timestamp}.{raw body bytes}. Принимайте запрос, если любое значение совпадает с вашим, используя сравнение за постоянное время.

Две детали вызывают большинство ошибок проверки:

  • Проверяйте сырые байты. Вычисляйте HMAC по телу точно в том виде, в каком оно получено, до любого разбора JSON или перекодирования.
  • Декодируйте секрет стандартным декодером base64. Секрет подписи — это значение после префикса whsec_, закодированное стандартным алфавитом base64 (+ и /), как и подпись в заголовке. URL-безопасный декодер выводит неверные байты ключа всякий раз, когда секрет содержит + или /, что происходит в большинстве случаев.

Как только у вашей организации появляется секрет подписи, каждый запрос, отправляемый Anthropic, подписывается, включая проверку подключения, поскольку процесс настройки генерирует секрет до первой проверки. Для включения Inference hooks требуется секрет, поэтому отклоняйте любой запрос, поступивший без подписи. Одно исключение: организация, включившая Inference hooks до того, как секрет стал обязательным, продолжает отправлять неподписанные запросы, пока её администратор не сгенерирует секрет. Принимайте неподписанные запросы только до тех пор, пока администратор не подтвердит наличие секрета, а затем отклоняйте их.

Ротация секрета — это немедленное переключение, но запросы, подписанные предыдущим секретом, всё ещё могут приходить примерно в течение минуты после этого, плюс всё, что уже находится в пути. Пусть ваш сервер безопасности ИИ принимает подписи от обоих секретов во время переключения, чтобы эти опоздавшие запросы не отклонялись.

Следующие примеры являются серверными реализациями, поэтому вкладки shell нет: сервер безопасности ИИ — это долго работающий HTTPS-сервис, а не одноразовый запрос. Каждый пример использует только стандартную библиотеку языка; проект Standard Webhooks также публикует библиотеки проверки для большинства языков.

import base64
import hashlib
import hmac
import time

TOLERANCE_SECONDS = 300


def verify(secret: str, headers: dict[str, str], body: bytes) -> bool:
    """Return True if the body was signed by Anthropic for this organization.

    Anthropic sends header names in lowercase, but proxies are free to
    re-case them, so normalize the lookup to lowercase.
    """
    lowercased = {name.lower(): value for name, value in headers.items()}
    try:
        message_id = lowercased["webhook-id"]
        timestamp = lowercased["webhook-timestamp"]
        signatures = lowercased["webhook-signature"]
    except KeyError:
        return False  # unsigned request: not from Anthropic

    try:
        signed_at = int(timestamp)
    except ValueError:
        return False
    if abs(time.time() - signed_at) > TOLERANCE_SECONDS:
        return False  # replayed, or the clocks disagree

    try:
        key = base64.b64decode(secret.removeprefix("whsec_"), validate=True)
    except ValueError:
        return False  # misconfigured secret: reject rather than crash

    payload = f"{message_id}.{timestamp}.".encode() + body
    expected = b"v1," + base64.b64encode(
        hmac.new(key, payload, hashlib.sha256).digest()
    )

    # Сравниваем байты: compare_digest для str выбрасывает исключение при не-ASCII вводе.
    return any(
        hmac.compare_digest(expected, candidate.encode())
        for candidate in signatures.split()
    )

Операционная семантика

Тайм-аут и повтор

Ваш администратор задаёт тайм-аут вердикта от 1 до 10 000 мс (по умолчанию 5 000 мс). Этот бюджет охватывает весь обмен: подключение, TLS-рукопожатие, запрос и ответ. Тот же тайм-аут применяется к кадрам вызова инструментов.

Anthropic повторяет попытку ровно один раз, после задержки в 100 мс, и только когда попытка подключения завершается неудачей. Повтор использует тот же бюджет тайм-аута и несёт тот же webhook-id и ту же подпись. Как только ваш сервер безопасности ИИ ответил, обмен никогда не повторяется.

Сбои вебхука

Тайм-ауты, статусы, отличные от 200 (включая перенаправления), неразбираемые или чрезмерно большие тела ответов и недоступные конечные точки — всё это сбои вебхука. Сбой вебхука никогда не превращается в deny; вместо этого настройка обработки сбоев вашей организации решает, будет ли затронутый запрос заблокирован или продолжится без проверки.

Автоматический предохранитель

Устойчивые сбои вебхука, относимые к вашему серверу безопасности ИИ, приводят к срабатыванию «circuit breaker» (автоматического предохранителя), который останавливает принудительное применение: Anthropic прекращает обращаться к вашему серверу, и обработка сбоев применяется к каждому запросу.

Начиная через 10 минут после срабатывания, Anthropic проверяет, восстановился ли ваш сервер: не чаще примерно одного раза в минуту он отправляет вашему серверу тот же синтетический тестовый запрос, что и Test connection (source.application равно config-test), подписанный как любой другой запрос и не содержащий пользовательского содержимого. Отвечайте на него как обычно. Корректный вердикт, allow или deny, сбрасывает выключатель, и принудительное применение возобновляется; сбой вебхука оставляет выключатель в сработавшем состоянии, и проверки продолжаются. Администратор также может сбросить выключатель в любой момент, а изменения конфигурации администратором останавливают автоматические проверки; см. Автоматический выключатель.

Кадры подсказки и кадры вызова инструментов используют один общий автоматический выключатель, и сбои любого из них учитываются в нём.

Каждое срабатывание записывается как активность inference_hooks_circuit_breaker_tripped в Activity Feed (ленте активности), по одной активности на срабатывание. Пока предохранитель сработал, никакие активности Inference hooks по отдельным запросам не записываются, поэтому активность срабатывания — единственная запись в ленте о периоде срабатывания.

Задержка

Принудительное применение добавляет время полного цикла обмена с вашим сервером безопасности ИИ к задержке каждого контролируемого запроса в вашей организации. При включённом Validate tool calls ответ, порождающий кадр вызова инструментов, также ожидает его вердикта, в том числе в теневом режиме. Обеспечьте быстрый вердикт и проведите нагрузочное тестирование сервера перед развёртыванием в крупной организации.

Исходные IP-адреса

Запросы к вашему серверу безопасности ИИ исходят из 160.79.106.0/24, части опубликованных Anthropic исходящих диапазонов IP. Добавьте в список разрешённых этот блок, а не входящие диапазоны на той же странице, которые его не покрывают. Список разрешённых сужает поверхность атаки вашего сервера, но не заменяет проверку подписи: этот блок несёт исходящий трафик Anthropic не только для Inference hooks.

Прямая совместимость

Протокол развивается, не ломая корректно написанные серверы. Ваш сервер должен игнорировать:

  • Неизвестные поля верхнего уровня в любом из кадров.
  • Неизвестные ключи в metadata.
  • Новые значения source.application.
  • Новые значения actor.type. actor — это объединение, различаемое по type, и "user" — единственный вид, отправляемый сегодня; будущий вид гарантирует только наличие type.
  • Блоки содержимого с нераспознанным type.
  • Сообщения с role, отличной от user или assistant, которые может добавить более поздняя редакция.

Никогда не отклоняйте запрос из-за нераспознанного типа блока или поля; читайте поля, которые вы знаете, и пропускайте остальные.

В будущем будут введены другие типы событий хука. Новый тип события — это дополнение, которое ваш сервер не может обработать пропуском поля: запросу всё равно нужен вердикт. Когда type верхнего уровня имеет значение, которое вы не распознаёте, возвращайте вердикт allow, а не статус ошибки; ответ с ошибкой — это сбой вебхука, а устойчивые сбои приводят к срабатыванию автоматического предохранителя.

Проектирование вашей интеграции

Продакшн-сервер безопасности ИИ принимает несколько проектных решений помимо протокола передачи.

Дедуплицируйте по webhook-id. Заголовок webhook-id уникален для каждой доставки и равен request_id в теле, а повтор при сбое подключения использует его повторно, поэтому он работает как ключ идемпотентности. Если вы записываете вердикты, используйте его в качестве ключа записей.

Записывайте вердикты и сопоставляйте отклонения. Сохраняйте каждый возвращаемый вердикт вместе с его reference_id. Каждое отклонение записывается как активность соответствия inference_hooks_request_denied, содержащая reference_id, который вернул ваш сервер, поэтому вы можете сопоставлять отклонения в Activity Feed с соответствующими записями в вашей собственной системе.

Архивируйте с помощью всегда разрешающего сервера. Чтобы захватывать транскрипты в реальном времени, не контролируя их, безусловно возвращайте {"action": "allow"} и сохраняйте кадр после ответа. Это push-альтернатива опросу Compliance API, а ответ до сохранения убирает ваш полный цикл из критического пути пользователя.

Пишите deny_reason для конечного пользователя. Возвращаемый вами текст — это то, что видит пользователь, когда его запрос заблокирован, усечённый до 500 символов. Скажите ему, что изменить, например какой вид содержимого удалить, вместо того чтобы выдавать код сканера, который может интерпретировать только ваша команда.

Следующие шаги

Включите Inference hooks, подключите и протестируйте вашу конечную точку и управляйте принудительным применением, обработкой сбоев и развёртыванием.

Что такое Inference hooks, как работает полный цикл вердикта и когда их использовать.

Was this page helpful?