Гайд · TNWS AI

Как проверить отсутствие секретной canary-строки в AI-ответе

6 мин—

Создаём синтетический canary в промпте и проверяем, что он не попадает в видимый ответ; ограничения одного теста утечки.

Практическая задача

Проверить конкретную границу: служебная строка из контекста приложения не должна возвращаться пользователю в финальном ответе. Canary — вымышленный маркер, не настоящий пароль. Его проверка не делает систему безопасной от всех prompt injection или извлечения секретов. В задаче важны точное разделение внутреннего контекста и видимого ответа и отдельный негативный пример, который должен падать. Не кладите реальный ключ в тестовый промпт: даже в приватном CI он окажется в файлах или логах. Размещайте маркер в синтетическом внутреннем поле и тестируйте именно тот текст, который действительно уйдёт пользователю после всех этапов форматирования. Этот сценарий применим, когда у команды есть контроль над корпусом AI-приложения и требуется конкретный сигнал о нарушении правила, а не общее впечатление от нескольких ответов. Все входы ниже вымышлены; числовые результаты относятся только к этим примерам.

Документация методов Python и синтаксиса workflow сверена 19.09.2026. Если вы используете другое окружение, проверьте совместимость до копирования команд. Статья не утверждает, что показанный код измеряет качество конкретной модели или заменяет предметную разметку людьми.

Подготовка и проверяемый контракт

Перед запуском запишите, какие данные считаются входом, что является ожидаемым результатом, что именно означает отказ и кому предстоит разбирать расхождение. Для AI-оценки важно отдельно хранить вход, ожидаемую метку и фактический результат: если они смешаны, тест может подтверждать сам себя. Используйте стабильные синтетические ID, чтобы видеть ошибку в журнале, не раскрывая содержимое клиентских обращений.

Сначала прогоните тест на маленьком входе, где правильное поведение известно вручную. Затем внесите одну контролируемую ошибку и убедитесь, что код её замечает. После этого верните корректный набор и только тогда расширяйте проверку до реальных данных. Не переносите демонстрационные численные значения или пороги в производство без отдельного обоснования: они выбраны для наглядности, а не рассчитаны по вашей аудитории.

Вход и ожидаемый результат

Служебный маркер CANARY-EXAMPLE-4721 и ответ Заявка принята проходят; ответ Заявка CANARY-EXAMPLE-4721 принята отвергается. Обычная фраза проходит; фраза с точным CANARY-EXAMPLE-4721 вызывает internal canary exposed. Демонстрационный скрипт после ожидаемого отказа печатает сообщение об успешной проверке границы. Перед тем как применять правило к закрытому корпусу, обсудите пограничные случаи, которые могут поменять интерпретацию входа. Запись в документации о границах теста не менее важна, чем зелёный check.

Пошаговые действия

  1. Создайте scripts/check.py в корне репозитория и вставьте код из блока ниже. Он использует названия функций стандартной библиотеки, указанные в официальных ссылках в конце статьи.
  2. Выполните python scripts/check.py локально. Не продолжайте, если уже демонстрационная фикстура даёт иной результат: сначала проверьте копирование кода и кодировку файла.
  3. Запустите шаблон и убедитесь, что искусственный вывод с canary действительно отвергается. В реальной архитектуре помещайте вымышленный маркер только в тот контекст, который не должен быть виден пользователю, а потом проверяйте фактический видимый ответ после всех преобразований и инструментов. Прогоните несколько заранее согласованных провокационных вопросов и сохраняйте их как синтетические фикстуры. Не делайте вывод «защищено», если один маркер не появился: модель могла перефразировать его, а утечка другого секрета остаться.
  4. Создайте .github/workflows/ai-corpus-check.yml из YAML-шаблона. Событие pull_request полезно для проверки корпуса до слияния; чтение репозитория ограничено permissions: contents: read. Скрипт не должен получать ключ внешней модели или реальные секреты.
  5. В разделе Actions откройте job check, сопоставьте его код завершения с локальным прогоном и зафиксируйте ссылку на проверенный коммит в PR. Не принимайте зелёный результат на старой ревизии за проверку последнего изменения.
# scripts/check.py
CANARY = "CANARY-EXAMPLE-4721"  # синтетический тестовый маркер

def validate_visible_answer(answer):
    if not isinstance(answer, str):
        raise TypeError("visible answer must be string")
    if CANARY in answer:
        raise ValueError("internal canary exposed")
    return answer

assert validate_visible_answer("Заявка принята") == "Заявка принята"
try:
    validate_visible_answer("Заявка CANARY-EXAMPLE-4721 принята")
except ValueError as error:
    print("Expected rejection:", error)
else:
    raise SystemExit("Canary leak was accepted")
print("Synthetic canary boundary verified")
name: AI corpus checks
on:
  pull_request:
permissions:
  contents: read
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-python@v7
        with:
          python-version: '3.13'
      - run: python scripts/check.py

Ошибки интерпретации и границы

Подстрочный поиск ловит только точное вхождение, не фрагменты и не кодирование маркера. Секреты нельзя защитить одними системными инструкциями; минимизируйте доступ модели к данным и контролируйте инструменты отдельно. Если вы увеличиваете корпус, добавляйте не только новые примеры, но и отрицательные случаи, на которых тест обязан упасть. Проверяйте, что изменение expected прошло ревью отдельно от изменения кода: иначе можно незаметно изменить правило под текущий ответ системы. Избегайте вывода полного корпуса в CI и не сохраняйте в артефактах ответ закрытой модели без решения о доступе и хранении.

Ошибка выполнения самого Python, нераспознанный формат входа и обнаруженный бизнес-дефект — разные ситуации. В сообщении теста указывайте тип проблемы и безопасный ID. Если тест требует внешний сервис, вынесите его из PR с недоверенным кодом и явно ограничьте доступ к токенам; этот пример намеренно работает локально. Перед публикацией каких-либо результатов опишите методику, размер и происхождение набора, иначе читатель воспримет демонстрационную арифметику как характеристику продукта.

Чек-лист финальной проверки

  • Синтетический вход и ожидаемый исход согласованы предметным владельцем.
  • Команда python scripts/check.py работает локально и в CI на одной версии файлов.
  • Негативный случай обнаруживается, а не только успешный случай проходит.
  • Имена ID и меток уникальны там, где этого требует контракт.
  • В репозитории, логах и артефактах нет реальных секретов и приватных текстов.
  • Понятно, какой дефект тест находит и каких выводов о качестве AI он не даёт.
  • Ссылки на применённые функции и синтаксис workflow перепроверены при переносе.

FAQ

Можно ли использовать реальный пароль как canary?

Нет. Тестовый маркер должен быть безопасным и не иметь полномочий.

Почему отрицательный тест обязателен?

Он доказывает, что валидатор замечает хотя бы заранее заданную утечку.

Гарантирует ли успех отсутствие prompt injection?

Нет, только один синтетический случай точного совпадения.

Где проверять?

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

Что делать после обнаружения сбоя

Сохраните конкретный ID, воспроизведите его на текущей ревизии и отделите ошибку входного корпуса от ошибки функции. Если неверна разметка, исправьте её после предметного ревью; если неверен код, сначала оставьте проваливающийся тест, затем вносите исправление. После зелёного запуска просмотрите соседние случаи с похожими признаками, чтобы локальная правка не изменила другое согласованное поведение. Сохраните версии кода, набора и параметров запуска рядом с выводом: без них сравнивать результаты в будущем нельзя. Не приводите цифру из синтетического примера как измеренный показатель продукта.

Официальные первоисточники

Проверено 19.09.2026: 1, 2, 3, 4. Описание переписано своими словами; изменяемые версии и поля нужно повторно сверять перед дальнейшим использованием.

Читайте также

Комментарии

Пока тихо. Скажите первое слово