Инженерное ИИ-агенты Control Plane ~15 мин чтения

TL-Agent: control plane для ИИ-агентов на нотариальных квитанциях

Инженерная записка — что такое TL-Agent, как он работает и два способа его развернуть: стандартный локальный bundle и air-gapped режим с USB-носителем. Написано так, чтобы любой разработчик ИИ-агентов понял суть и мог применить.

1. Что такое TL-Agent — и чем он не является

TL-Agent — это control plane и неподделываемая история действий для ИИ-агентов, построенные на нотариальных квитанциях сети TimeLayer. Простыми словами: прежде чем агент что-то сделает — прочитает файл, вызовет API, отправит сообщение — у него должна быть квитанция, которую он не мог выписать себе сам. Нет валидной квитанции — действие не выполняется. Точка.

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

TL-Agent имеет два слоя, которые всегда строго разделены:

  • cert.tlcert + bundle.tlbundle — сама нотариальная квитанция, пара файлов, выданная сетью: подписанный сертификат и bundle для гейта, которые верификатор проверяет вместе. Никогда не изменяется, никогда не переписывается. Это источник истины.
  • envelope.json — агентская обёртка: action_id, scope, допустимые следующие действия, ссылка на топологию. Указывает на файлы квитанции. Не заменяет их.

Вместе они образуют Receipt Action Unit — одно разрешённое действие, криптографически зафиксированное.

Чем TL-Agent НЕ является

Не система памяти — квитанции не хранят содержимое и не делают смысловой поиск (это провенанс, а не знание). Не песочница, физически останавливающая злонамеренный код — гейт работает для кооперативного агента, честно использующего SDK. Не замена debug-логам — они остаются эфемерным инструментом разработчика; TL-Agent покрывает значимые действия, а не каждый вызов функции.

2. Какую проблему решает

Вы строите ИИ-агента, который делает настоящие вещи в реальном мире: читает файлы, вызывает API, публикует данные, принимает решения. Три проблемы, которые не исчезают сами по себе, как бы аккуратно вы ни писали код:

Без TL-Agent

Агент может «разрешить» себе действие — установив флаг, который сам и проверяет. Тот же код, что решает что делать, решает и разрешено ли это.

История действий живёт в логе вашего сервера. Вы контролируете лог. Третья сторона не может независимо его проверить — придётся верить вам на слово.

Нет машинно-проверяемой границы между «что агенту позволено» и «что он заявляет, что сделал».

С TL-Agent

Разрешения — нотариальные квитанции. Агент их не выдавал — их выдала сеть до начала сессии. Агент не может разрешить себе что-либо (INV-01).

История — квитанции. Ни агент, ни вы не можете их переписать. Третья сторона с открытым верификатором может проверить любую квитанцию офлайн без обращения к вашим серверам.

Гейт — 6-шаговый алгоритм fail-closed. Любой пробел — нет квитанции, невалидная подпись, неверный переход — останавливает агента и требует участия человека.

3. Главный принцип

НЕТ КВИТАНЦИИ — НЕТ ДЕЙСТВИЯ

Каждое действие в топологии агента должно иметь квитанцию, прежде чем может быть выполнено. Не флаг. Не запись в логе. Квитанцию от сети, которую агент не мог сфабриковать. Одно это правило, применяемое без исключений, и отделяет TL-Agent от любого самоконтролируемого подхода.

4. Два режима работы

TL-Agent имеет режим по умолчанию, работающий на любой машине, и опциональный air-gapped режим для сред, где важна физическая изоляция разрешений.

По умолчанию

Режим 1 — Локальный bundle

Bundle (разрешения + топология + квитанции) лежит как папка на хост-машине. Агент загружает его при старте, все проверки гейта выполняются локально, никаких сетевых вызовов во время работы.

  • Работает на любой машине с бинарником tl-agent
  • Вся верификация — офлайн (интернет не нужен во время гейт-проверок)
  • Bundle создаётся один раз через Конструктор агента в кабинете
  • Вы храните копию bundle вне среды агента (INV-08)
Опция

Режим 2 — Air-gapped USB

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

  • Read-only съёмный носитель — хранит bundle разрешений (cert.tlcert + bundle.tlbundle, топологию, политики). Агент монтирует, читает, проверяет, действует. Сюда никогда не пишет.
  • Отдельный append-only носитель — принимает сырые результаты (что сделано + хеш). Заверение результатов происходит вне среды агента, чтобы агент не мог сфабриковать result-квитанцию.

Почему два отдельных носителя в air-gapped режиме

Если разрешения и результаты находятся в одном месте с возможностью записи, агент может перезаписать свои разрешения или подсунуть фальшивый результат. Разделение на read-only разрешения и append-only результаты исключает это — принуждает к соблюдению INV-01 (агент не выдаёт квитанции) и INV-02 (агент не изменяет bundle) на аппаратном уровне.

Честные ограничения air-gapped режима

Air-gap защищает от агента, но не от взломанной ОС хоста. Скомпрометированная операционная система может перехватить чтение с носителя в момент чтения. Аппаратная защита от записи на USB — настоящая защита; программное «только чтение» агент с правами обойдёт. И ещё: проверять квитанции и читать разрешения можно офлайн, но выдать новую нотариальную квитанцию (подпись сети) всё равно требует момента связи с кворумом.

5. Алгоритм гейта — 6 шагов, fail-closed

Каждый раз, когда агент хочет выполнить действие, он вызывает bundle.check_action(action_id). SDK выполняет эту последовательность — fail-closed на каждом шаге:

1. Квитанция есть?
2. Статус активен?
3. В топологии?
4. Квитанция валидна?
5. Переход разрешён?
ALLOW

Любая проверка, которая не прошла → немедленный STOP. Причина останова возвращается вызывающей стороне. Политика остановки требует участия человека перед продолжением. Нет «мягкого отказа» или «предупреди и продолжи».

match bundle.check_action("action_read_files") {
    CheckResult::Allow(receipt) => {
        // receipt — нотариальное доказательство — выполняем действие
    }
    CheckResult::Stop { reason, message, .. } => {
        // reason: NO_RECEIPT | REVOKED | TOPOLOGY_DENIED
        //       | TLSIG_INVALID | TRANSITION_DENIED
        // остановиться и сообщить человеку — не продолжать молча
    }
}

Exit-коды для CLI: 0 = ALLOW, 1 = STOP. Это позволяет легко встроить в любой shell-скрипт или CI-пайплайн.

6. Структура bundle

Bundle — это папка. Вы создаёте её один раз через Конструктор агента и передаёте агенту. Агент читает её; никогда в неё не пишет.

agent-bundle/
  manifest.json          ← ID bundle, владелец, кол-во квитанций, флаги
  topology.json          ← граф допустимых переходов между действиями
  policies/
    agent_policy.json    ← что агенту запрещено делать
    tool_policy.json     ← какие инструменты разрешены
    stop_policy.json     ← когда агент обязан остановиться
  receipts/
    <action_id>/
      envelope.json      ← метаданные действия + allowed_next_actions
      cert.tlcert        ← нотариальный сертификат — НИКОГДА не изменяется
      bundle.tlbundle    ← bundle для гейта, проверяется вместе с cert — НИКОГДА не изменяется

Ключевое правило: cert.tlcert и bundle.tlbundle не трогаются после того, как помещены сюда. envelope.json только ссылается на них — не заменяет их. Эти два файла проверяются вместе офлайн, без реестра и внешних обращений. В manifest.json явно прописано "agent_can_write": false и "agent_can_issue_receipts": false.

Что определяет topology.json

Топология — это граф: какие действия разрешены и в каком порядке они могут следовать друг за другом. Если агент попытается перейти с action_read_files на action_send_email, а топология допускает только action_summarize — это STOP. Агент не может менять порядок своего собственного рабочего процесса.

7. Типы квитанций

У каждого действия в bundle есть квитанция с типом, описывающим её роль в рабочем процессе:

ТипНазначение
permission_receiptРазрешение на выполнение действия — обязательно для каждого действия (INV-03)
identity_receiptКто создал задачу (устанавливает принципала-человека)
task_receiptФиксирует определение задачи — что делает агент и зачем
scope_receiptОпределяет границы: какие пути, read-only или read-write, доступ к сети
tool_receiptАвторизует конкретный инструмент для использования
execution_receiptФиксирует факт выполнения действия (с хешем результата)
result_receiptУдостоверяет результат действия
validation_receiptПодтверждает, что результат прошёл валидацию (требуется, если задано в stop_policy)
stop_receiptАвторизует команду остановки
revoke_receiptОтзывает ранее выданное разрешение
final_receiptОтмечает конечное состояние рабочего процесса

8. 10 инвариантов

Это правила, которые нельзя нарушать. Если какая-то фича нарушает любой из них — фича неправильная, а не инвариант. Инварианты — это и есть продукт.

IDПравило
INV-01Агент не выпускает валидные квитанции сам — их выдаёт сеть
INV-02Агент не изменяет bundle пользователя
INV-03Каждое действие требует permission_receipt
INV-04Каждый переход проверяется по topology.json
INV-05Любой конфликт → STOP (не soft-fail, не «предупреди и продолжи»)
INV-06Текст модели не является доказательством чего-либо
INV-07PASS невозможен без validation_receipt, если это требует политика
INV-08Пользователь хранит bundle вне среды агента (офлайн-копия)
INV-09Квитанция (cert.tlcert + bundle.tlbundle) не изменяется никогда после выдачи
INV-10envelope.json только ссылается на файлы квитанции — не заменяет их

9. Как пользоваться: от bundle до работающего агента

Шаг 1 — Собрать bundle в Конструкторе агента

Зайдите на cabinet.timelayer-os.com/agent. Задайте действия и топологию визуально. Каждое действие получает квитанцию, нотаризованную сетью. Скачайте ZIP. Распакуйте — это ваш bundle.

Шаг 2 — Гейт-проверка перед каждым действием

# В shell-скрипте или CI-пайплайне:
tl-agent check ./agent-bundle action_read_files
# exit 0 = ALLOW, exit 1 = STOP

# Посмотреть, какие действия разрешены следующими:
tl-agent next ./agent-bundle action_read_files

# Аудит всего bundle:
tl-agent audit ./agent-bundle

Шаг 3 — В Rust-агенте

let bundle = AgentBundle::load("./agent-bundle")?;

loop {
    let action = agent.decide_next_action();

    match bundle.check_action(&action) {
        CheckResult::Allow(receipt) => {
            agent.run_action(&action, &receipt);
            bundle.record_execution(&action, &result_hash)?;
        }
        CheckResult::Stop { reason, .. } => {
            // сообщить причину человеку — не продолжать цикл
            break;
        }
    }
}

Шаг 4 (air-gapped) — USB-носитель вместо локальной папки

Смонтируйте read-only USB-носитель при старте. Передайте точку монтирования как путь к bundle. Результаты направьте на отдельный append-only носитель. Всё остальное — идентично. SDK не знает и не требует, чтобы bundle был папкой на диске или смонтированным носителем.

# Монтируем read-only носитель с разрешениями
mount -o ro /dev/sdb1 /mnt/permits

# Запускаем агента с bundle на носителе
tl-agent check /mnt/permits/agent-bundle action_read_files

10. Честная рамка: что TL-Agent не делает

  • Не память. Квитанции не хранят содержимое. Они не запоминают, что агент сказал или нашёл. Они фиксируют, что было разрешено и что было выполнено (провенанс), а не то, что агент знает (recall).
  • Не песочница против взломанного хоста. Если операционная система скомпрометирована, достаточно привилегированный процесс может перехватить или подменить чтения из bundle. TL-Agent является гейтом для кооперативного агента. Air-gapped режим сужает, но не устраняет эту поверхность.
  • Не замена наблюдаемости. Debug-логи, трейсы и метрики остаются вашими инструментами разработчика. TL-Agent покрывает значимые внешне-верифицируемые действия — не каждый внутренний вызов функции.
  • Заверение требует связи. Проверять существующие квитанции — полностью офлайн. Выдать новую квитанцию — получить кворумную подпись сети — требует момента связи. Планируйте рабочий процесс соответственно.
  • Не гарантия правильности агента. Агент с валидной квитанцией всё равно может выдать неправильный результат. TL-Agent доказывает, что было разрешено и что было предпринято — человек, читающий аудиторский след, по-прежнему оценивает, был ли результат хорошим.

Суть в одной строке

TL-Agent даёт агенту разрешения, которые он не мог выдать себе сам, и историю, которую он не может переписать — под правилом НЕТ КВИТАНЦИИ → НЕТ ДЕЙСТВИЯ. Не память, не песочница от хоста, не наблюдаемость. Это неподделываемый control plane для кооперативного агента.