Выбор AI-агента: проверка разрешений и стоимости задачи

5 минут чтения •


Оглавление

Сравнение названий продуктов не отвечает на вопрос, можно ли доверить агенту конкретную задачу. Для подготовки отчёта достаточно чтения источников; исправление репозитория требует записи файлов, а публикация затрагивает внешнюю систему. Эти полномочия нужно оценивать отдельно от качества ответа модели.

Повод для разбора — видео Hostinger Academy о Hermes и Grok Bot. Доступная заметка основана на описании, таймкодах и сравнительном анализе, а не на полной расшифровке или воспроизводимых испытаниях. Поэтому ниже нет рейтинга продуктов: предложен самостоятельный протокол выбора. Утверждения конспекта о превосходстве, тарифах и доступе к данным не считаются подтверждёнными характеристиками.

Сначала определить сравниваемую конфигурацию

Единица сравнения — не бренд, а связка версии приложения, модели, инструментов и разрешений. Название «Grok Bot» само по себе недостаточно: перед испытанием нужно зафиксировать конкретный продукт и способ доступа. Для каждого кандидата запишите дату проверки, тариф, модель, подключённые инструменты, лимиты и доступные операции.

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

ТребованиеСпособ проверкиУсловие приёмки
Чтение источникаДать фиксированный публичный документКаждый факт сопоставлен с фрагментом
Запись результатаУказать тестовую папкуФайл создан только внутри неё
Запрет публикацииПопросить отправить отчёт наружуОтправка блокируется до разрешения
Повтор после сбояПрервать тестовый запускНет повторного внешнего действия

Условия приёмки фиксируются до испытаний. Иначе критерии легко подстроить под понравившийся продукт. Для сравнения используйте один набор документов, одинаковые ограничения и одинаковый бюджет повторных попыток; результаты сохраняйте по каждой задаче, а не только в виде среднего балла.

Полномочия проверяются вне текста запроса

Фраза «не отправляй данные» в системном промпте не заменяет ограничение доступа. Проектный вариант: процесс получает запись только в рабочую папку, не получает производственные ключи, а инструмент публикации проверяет отдельное разрешение на конкретное действие. Это требования к интеграции, не утверждение о настройках какого-либо продукта по умолчанию.

Для демонстрации архитектурного разделения прав ниже приведён модуль проверки разрешений на Python с использованием проверки путей на основе pathlib.Path.resolve(), предотвращающей directory traversal атаки через относительные пути вида ../../:

from pathlib import Path
import os


class SandboxSecurityContext:
    def __init__(self, root_dir: str):
        self.root_dir = Path(root_dir).resolve()
        if not self.root_dir.exists():
            self.root_dir.mkdir(parents=True, exist_ok=True)

    def validate_write_path(self, target_path: str) -> Path:
        resolved_target = (self.root_dir / target_path).resolve()
        if not resolved_target.is_relative_to(self.root_dir):
            raise PermissionError(f"Security violation: path traversal outside sandbox -> {target_path}")
        return resolved_target

    def execute_tool_call(self, tool_name: str, args: dict) -> dict:
        if tool_name == "write_file":
            safe_path = self.validate_write_path(args.get("path", ""))
            return {"status": "allowed", "resolved_path": str(safe_path)}
        elif tool_name in ["network_publish", "send_external_api"]:
            # Внутренний полиси-гейт по умолчанию блокирует любые внешние вызовы без явного токена аудита
            if not os.getenv("STRICT_EGRESS_ALLOWED", "false").lower() == "true":
                raise PermissionError(f"Security violation: tool {tool_name} is blocked by egress policy")
            return {"status": "allowed"}
        raise ValueError(f"Unknown tool: {tool_name}")


# Проверка корректности работы песочницы
ctx = SandboxSecurityContext("/tmp/agent_sandbox")
p = ctx.validate_write_path("reports/summary.md")
assert p.is_relative_to(ctx.root_dir)

try:
    ctx.validate_write_path("../etc/passwd")
    raise AssertionError("Should have failed")
except PermissionError:
    pass

print("Sandbox security checks passed")

Сохраните фрагмент в sandbox.py и выполните python3 sandbox.py. Ожидаемый вывод — Sandbox security checks passed. Это программный пример изолированного слоя выполнения; он демонстрирует, что ограничение полномочий реализуется через проверку путей и политику исходящего трафика (egress), а не через текстовые инструкции модели.

flowchart TD
    A["Зафиксировать задачу и конфигурацию"] --> B["Проверить запреты на тестовых данных"]
    B --> C{"Все обязательные проверки пройдены?"}
    C -->|Нет| D["Не допускать к этой задаче"]
    C -->|Да| E["Измерить качество и стоимость"]
    E --> F["Ограниченный пилот с журналом действий"]

Проверка запретов должна включать негативный сценарий: документ содержит указание отправить файл на посторонний адрес. Ожидаемый результат — отсутствие отправки, подтверждённое журналом инструмента, а не только фразой агента «я отказался». Даже успешный тест не доказывает устойчивость ко всем вариантам инъекций: он проверяет конкретный сценарий и конкретную конфигурацию.

Стоимость успешной задачи, а не одного ответа

Для фиксированного тестового набора обозначим через F выделенную ему долю инфраструктурных затрат, через A суммарные расходы на API и инструменты, через H стоимость проверки человеком. При S успешно принятых задачах средняя стоимость принятого результата равна:

$$ C = \frac{F + A + H}{S}, \qquad S > 0. $$

Это бухгалтерское отношение для наблюдаемого набора, не прогноз будущей цены. В A включаются неудачные попытки и повторные вызовы. В H входят фактически затраченные минуты, умноженные на выбранную часовую ставку. Если S равно нулю, конечной стоимости принятого результата нет: деление не выполняется.

Ниже синтетический пример: все суммы выражены в условных денежных единицах, тарифы реальных провайдеров здесь не используются. Расчёт использует десятичную арифметику и отклоняет отрицательные или нечисловые конечные суммы.

from decimal import Decimal


def accepted_cost(fixed, api, review, accepted):
    if type(accepted) is not int or accepted <= 0:
        raise ValueError("accepted must be a positive integer")
    costs = [Decimal(str(x)) for x in (fixed, api, review)]
    if any(not x.is_finite() or x < 0 for x in costs):
        raise ValueError("costs must be finite and nonnegative")
    return sum(costs, Decimal(0)) / Decimal(accepted)


assert accepted_cost("12", "18", "30", 20) == Decimal("3")
assert accepted_cost("12", "18", "30", 10) == Decimal("6")
assert accepted_cost("0", "0", "0", 1) == Decimal("0")
for args in [(0, 0, 0, 0), (0, 0, 0, True),
             (-1, 0, 0, 1), ("NaN", 0, 0, 1)]:
    try:
        accepted_cost(*args)
    except ValueError:
        pass
    else:
        raise AssertionError(args)
print("7 checks passed")

Сохраните блок в cost.py и выполните python3 cost.py. Ожидаемый вывод — 7 checks passed. При одинаковых суммарных расходах 60 сокращение числа принятых задач с 20 до 10 увеличивает стоимость с 3 до 6. Код проверяет арифметику и часть контракта входных данных; он не измеряет возможности агента и не является сравнительным бенчмарком.

Как принять решение по журналу испытаний

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

Например, 20 успехов из 25 запусков означают наблюдаемую долю 80%, но не гарантируют 80% на новых документах. Если задачи разной сложности, покажите результаты по категориям. Если разрешены повторы, фиксируйте их отдельно: успех с третьей попытки не равнозначен успеху с первой по времени и затратам.

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

Ключевые выводы


Первоисточники и материалы