Главная / Статьи

Проектирование среды для агента: политики, изоляция в песочнице, память и верификация

Узнайте, какие слои выполнения превращают ЯИИ, выполняющий вызовы инструментов, в надежного агента: политика выполнения, сандбокс операционной системы, постоянное состояние, верификация, контроль контекста и затраты.

Издатель: REACTAPP.TOP19 мин чтения4372 слов

Источники: Agent Harness Engineering: The Missing Layer Between an LLM and a Real AI Agent

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

Модель, способная вызывать инструменты, ещё не является агентом

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

search()
read_file()
write_file()
run_command()

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

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

Цикл в центре и связанные с ним вопросы

Если свести всё к сути, агент — это цикл: задаётся модели вопрос о действии, выполняется запрошенный инструмент, результат добавляется в контекст, и процесс повторяется до тех пор, пока модель не сообщит о завершении.

while True:
    response = model(context)

    if response.is_final:
        break

    result = execute_tool(response.tool_call)

    context.append(result)

У многих реальных агентов в основе лежит нечто очень похожее на это. Модель принимает решение, движок выполняет его, возвращаются результаты наблюдений, и модель выбирает следующий шаг. Сам цикл прост; основные усилия приходится приложить к всему, что его окружает. Полезный инструментарий должен отвечать на длинный список операционных вопросов при каждом шаге.

Can the agent execute this command?

Can it access this directory?

Does it need human approval?

What happens if the command fails?

What information should return to the model?

What should survive the session?

Should another agent review the result?

How much context should we send?

How much will this turn cost?

What happens if the model loops forever?

В совокупности все эти компоненты образуют так называемый «харнес». В одной из недавних концептуальных статей он описывается как среда выполнения, соединяющая языковую модель с внешним миром с помощью инструментов, механизмов управления контекстом, средств безопасности, функций оркестрации и точек расширения. Удобным способом для понимания является разделение агента на две части.

                  AI Agent
                       │
              ┌────────┴────────┐
              │                 │
           Model             Harness
              │                 │
        reasoning        ┌──────┼───────┐
        planning         │      │       │
        generation     Tools  Memory  Safety
                        │      │       │
                     Sandbox Context Verification

С одной стороны модель обеспечивает рассуждения, планирование и генерацию текста. С другой стороны «харнес» предоставляет инструменты, память и механизмы безопасности, подкрепляемые песочницей, обработкой контекста и проверками. Модель приносит интеллектуальные возможности; «харнес» определяет, как этот интеллект взаимодействует с реальными системами.

Почему промпт не может служить механизмом безопасности

Предположим, что системный промпт содержит четкое правило:

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

В этом предложении нет ничего двусмысленного, однако оно по-прежнему является просьбой. Модель может неправильно его понять, потерять из виду в ходе длительной сессии, сопоставить его с противоречащими указаниями в других частях контекста, убедить себя в том, что текущий случай — исключение, или добиться такого же разрушительного результата с помощью другого инструмента, который не был явно предусмотрен правилом. Просьба к агенту избегать чего-либо существенно отличается от делания этого невозможным без разрешения. Пrompt выражает желание:

Please don't do X.

Харнес может содержать правило, которое оценивается в коде:

if dangerous_action and not approved:
    deny()

Вторая версия работает независимо от того, помнит ли модель инструкцию. Это иллюстрирует первый принцип инженерии управления: когда правило детерминировано, его следует реализовать в детерминированном коде. Claude Code придерживается того же подхода в своей архитектуре. Хуки выполняются при событиях жизненного цикла и вызовах инструментов и могут, например, отклонять вызов инструмента до его выполнения, в то время как такие файлы, как CLAUDE.md, предоставляют руководство, которое модель читает в качестве контекста. Если вы пишете такой файл, храните его в качестве руководства и перенесите механизмы контроля в хуки; наш пособие по созданию эффективного файла CLAUDE.md описывает, что туда следует включать.

Слой 1: граница выполнения между запросом и действием

Первый вопрос, который необходимо решить, — это определение тех действий, которые агент вообще может выполнять. Рассмотрим инструмент для удаления файла.

def delete_file(path):
    os.remove(path)

Модель может вызвать его с любыми аргументами, которые пожелает.

delete_file("important.md")

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

def execute(call):

    if call.name == "delete_file":
        if not call.args.get("human_approved"):
            return "DENIED: human approval required"

    return dispatch(call)

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

Model decision
      ↓
Policy check
      ↓
Permission?
   ↙       ↘
 No         Yes
 ↓           ↓
Deny       Execute

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

Почему проверки на уровне инструментов неэффективны

Политики инструментов необходимы, но недостаточны. Представьте, что такой инструмент отклоняет данный вызов:

delete_file("secrets/api_key")

Это кажется защитой, пока агент не выполняет вместо этого соответствующую команду оболочки:

rm secrets/api_key

Политика delete_file никогда не фиксирует такую операцию. Или же инструмент блокирует чтение секретного пути:

read("secrets/api_key")

Но относительный путь может проникнуть, поскольку никто его не нормализовал:

read("../secrets/api_key")

Симлинки, вспомогательные программы, открывающие файлы от имени агента, и интерпретаторы, принимающие произвольный код, все они создают подобные «боковые двери». Политика, сформулированная с использованием названий инструментов и строковых аргументов, не может перечислить все пути к ресурсам, поэтому она не является полным защитным барьером. Рекомендации OpenAI по работе с кодирующими агентами предусматривают использование сандбоксинга, политик утверждения, ограниченной экспекуции, сетевого контроля и телеметрии вместо зависимости от промптов. Основной принцип: среда выполнения обеспечивает соблюдение политики, а операционная система — окончательный защитный барьер.

Уровень 2: сандбоксинг того, до чего физически может дотянуться агент

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

Don't access:
- /etc
- ~/.ssh
- secrets/
- production/
- credentials/
- ...

Такие списки никогда не бывают полными. Более эффективный подход заключается в обратном: сначала не разрешать почти ничего, а затем добавлять именно то, что необходимо для выполнения задачи, например, рабочее пространство одного проекта.

Agent workspace:

/workspace
    ├── src/
    ├── tests/
    ├── pyproject.toml
    └── README.md

Агент получает только /workspace, и ничего больше на хосте. В формате политики это выглядит как список разрешений.

Allowed:
    /workspace

Everything else:
    unavailable

Поскольку с точки зрения агента остальная часть файловой системы просто не существует, трюки с путями, символические ссылки и вспомогательные процессы теряют большую часть своей эффективности. Контейнеры, специализированные виртуальные машины и ограниченные учетные записи пользователей — это распространенные способы реализации этого подхода. SDK Agents от OpenAI добавило встроенную среду исполнения в песочнице именно для этой цели, чтобы агенты могли устанавливать зависимости, редактировать файлы и выполнять команды в контролируемой среде.

Ограничения сети и ресурсов должны находиться в песочнице

Изоляция файловой системы — это еще не все. Агент, способный выполнять даже такие простые операции, представляет совершенно иной уровень угрозы:

curl https://example.com

Благодаря возможности выхода в сеть агент может:

  • скачивать и запускать произвольное программное обеспечение
  • выносить данные на внешний хост
  • обращаться к API сторонних сервисов
  • доступ к внутренним сервисам, которые доверяют локальной сети
  • получение контента с ненадежных веб-сайтов, что также является классическим путем для внедрения кода
  • Поэтому настоящая песочница охватывает несколько аспектов, а не только файлы.

    Filesystem
    Network
    Processes
    Environment variables
    Secrets
    CPU
    Memory
    Time
    

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

    Уровень 3: постоянное состояние, сохраняющееся после окончания сессии

    При длительных задачах возникают другие проблемы. Агент тратит час на изучение репозитория и усваивает важное архитектурное правило.

    The authentication service must never directly access the database.
    All database operations go through Repository classes.
    

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

    Conversation state
        ↓
    temporary
    
    Project state
        ↓
    persistent
    
    Harness configuration
        ↓
    persistent + globally enforced
    

    Конкретные примеры каждой категории:

    Conversation:
    "Let's investigate the login bug."
    
    Project:
    "Authentication uses OAuth."
    
    Harness:
    "Never modify generated migrations."
    

    Элемент разговора может безопасно исчезнуть по окончании задачи. Информация о проекте должна сохраняться между сессиями, например в файле заметок с версионированием или в хранилище памяти. Правило обработки должно применяться при каждой запускной процедуре, независимо от того, что в настоящее время помнит модель, что обычно означает его нахождение в коде конфигурации и контроля, а не в текстовом формате. По мере увеличения продолжительности сессий такое разделение становится ещё более важным. API Agents от OpenAI, например, включает функции управления контекстом, предназначенные для агентов с длительной работой, в том числе автоматическую компактацию при приближении сессии к её лимиту контекста. Именно в момент компактации теряется информация о проекте, которая не была зарегистрирована, поэтому целесообразно преднамеренно сохранять её до этого момента. Для более подробного рассмотрения уровней памяти см. модель памяти агента с четырьмя уровнями с использованием LangGraph и Amazon Bedrock.

    LangGraph и Bedrock.

    Слой 4: проверка того, что агент не владеет данными

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

    def calculate_total(items):
        return sum(item.price for item in items) + 1
    

    Непреднамеренный символ + 1 может показаться намеренным для модели, которая его написала. Независимый шаг проверки позволяет оценить изменения на основе нескольких критериев.

    Code
    Tests
    Type checking
    Linting
    Security rules
    Expected behavior
    

    Ценность этого подхода заключается в разделении процессов создания изменений и их оценки.

                     Agent
                       │
                       ↓
                    Changes
                       │
                       ↓
                  Verification
                   ↙        ↘
                PASS         FAIL
                 ↓             ↓
              Continue      Investigate
    

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

    Тестовый запуск в качестве стандартного режима для рискованных изменений

    Для операций с высоким уровнем риска стандартным является просмотр поведения по умолчанию. Вместо функции применения, действующей немедленно:

    apply_change()
    

    используется вариант с безопасным стандартным режимом — тестовым запуском:

    apply_change(dry_run=True)
    

    Сначала агент получает описание возможного эффекта.

    Would modify:
        src/auth.py
        tests/test_auth.py
    

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

    Уровень 5: инжиниринг контекста

    Каждый токен, помещаемый в контекст, стоит денег, конкурирует за внимание модели и при выполнении длительных задач склонен накапливаться быстрее, чем удаляется. Предположим, агенту нужна одна функция из файла длиной 5 000 строк. Примитивный механизм передачи данных отправляет весь файл, затем полный результат следующего поиска, затем результат следующего инструмента и так далее. Вскоре контекст заполняется всем этим:

    Task
    + entire repository
    + previous searches
    + tool output
    + logs
    + previous reasoning
    + repeated instructions
    

    Технически модель может видеть каждый токен, но наличие информации не означает её понимание. Более эффективный подход предусматривает использование контекста как конвейера, который сжимает информацию перед тем, как она попадёт к основному агенту.

    Main Agent
         │
         ├── Search Agent
         │      │
         │      └── 50,000 tokens
         │
         │      ↓
         │
         └── 1,000-token summary
    

    Здесь агент-поисковик может потратить 50 000 токенов на исследование, но основная сессия получает лишь краткое описание длиной 1 000 токенов с самым важным содержанием. Это убедительный аргумент в пользу сабагентов. Например, Claude Code описывает сабагентов как элементы, работающие в своих изолированных окнах контекста и возвращающие в основной диалог только свой окончательный результат, что предотвращает перегрузку основного контекста обширными вспомогательными исследованиями. Однако такой подход имеет недостаток: в кратком описании могут пропасть детали, которые позже понадобятся основному агенту, поэтому краткие сводки должны содержать указатели (пути к файлам, диапазоны строк), позволяющие агенту получать необходимую информацию по запросу.

    Экономика: цена за токен — это не стоимость задачи

    Управление контекстом также связано с вопросами бюджета. Вспомните исследование, показавшее разницу в количестве токенов за решённую задачу до 40 раз между разными инструментальными пакетами, при этом разница в проценте успешных выполнений была гораздо меньше. Это меняет вопрос, который стоит задать. Вместо «какая модель самая дешёвая?» спросите, сколько токенов требуется всей системе агентов для выполнения задачи. Сравните два варианта настройки.

    Агент А: дешёвая модель, неэффективный инструментальный пакет

    Model:
    $X / million tokens
    
    Task:
    500k tokens
    

    Агент Б: дороже модель, оптимизированный инструментальный пакет

    Model:
    2X / million tokens
    
    Task:
    100k tokens
    

    Агент B платит в два раза больше за токен, но использует лишь пятую часть токенов, поэтому стоимость каждой выполненной задачи составляет примерно 40 процентов от затрат агента A, ещё до учёта различий в проценте успехов. Ценообразование модели является входным параметром; экономика агентов определяется объёмом работы, который механизм заставляет модель выполнять. Наша модель затрат, основанная на архитектуре, для агентных ИИ более подробно рассматривает этот вопрос.

    Бесполезные ходы и политики завершения

    Часть ресурсов тратится бессмысленно, и это не отражается в показателях за отдельный запрос. Представьте агента, который постоянно объявляет о своих намерениях, не предпринимая никаких действий:

    I should inspect the repository.
    

    и снова на следующем ходу:

    I should inspect the repository.
    

    и ещё раз:

    I should inspect the repository.
    

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

    MAX_TURNS = 30
    
    if agent.turns >= MAX_TURNS:
        stop()
    

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

    No progress
    Repeated tool calls
    Repeated identical observations
    No state change
    Test suite unchanged
    Agent oscillation
    Budget exhausted
    

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

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

    LLM + tools
    

    Современные системы напоминают стек.

    LLM
     ↓
    Agent loop
     ↓
    Tool router
     ↓
    Policy engine
     ↓
    Sandbox
     ↓
    Context manager
     ↓
    Memory
     ↓
    Verification
     ↓
    Observability
     ↓
    Orchestration
    

    Модель по-прежнему остается ядром, но среда выполнения вокруг неё — от маршрутизатора инструментов и движка политик до среды безопасности, менеджера контекста, памяти, механизмов проверки, инструментов отслеживания и оркестрации — стала самостоятельным продуктом.

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

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

                        ┌──────────────┐
                        │    Model     │
                        └──────┬───────┘
                               │
                               ↓
                      ┌─────────────────┐
                      │   Agent Loop    │
                      └────────┬────────┘
                               │
                 ┌─────────────┼─────────────┐
                 ↓             ↓             ↓
            Tool Router     Context       Memory
                 │          Manager          │
                 ↓             │             ↓
           Policy Engine       │        Persistent State
                 │             │
                 ↓             ↓
              Sandbox ←────── Tools
                 │
                 ↓
            Verification
                 │
                 ↓
           Observability
    

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

    Развивайте инфраструктуру на основе ошибок, а не фреймворка

    Чтобы получить эти преимущества, вам не нужен огромный фреймворк для агентов. Центральный цикл может оставаться небольшим даже после добавления функций движка политик, сандбоксинга и проверки.

    while turns < MAX_TURNS:
    
        action = model.next_action(context)
    
        if action.is_final:
            return action.answer
    
        if not policy.allows(action):
            context.append("Action denied")
            continue
    
        result = sandbox.execute(action)
    
        verification = verifier.check(result)
    
        context.append(
            summarize(result, verification)
        )
    

    Обратите внимание на порядок действий: проверка политики происходит до выполнения кода, отклонённая операция возвращается модели вместо того, чтобы прервать цикл; выполнение всегда происходит внутри «песочницы», а то, что возвращается в контекст, — это краткое описание результата и его проверки, а не сырой вывод. Дополнительная сложность добавляется только в случае обнаружения сбоя.

    Agent deleted something?
        → add execution policy
    
    Agent accessed the wrong file?
        → strengthen sandbox
    
    Agent forgets architecture?
        → add persistent project memory
    
    Agent produces bad code?
        → add verification
    
    Agent becomes expensive?
        → optimize context
    
    Agent loops?
        → add termination detection
    

    Каждый симптом соответствует ровно одному уровню. Это гораздо лучше, чем вводить пятьдесят абстракций до того, как вы поймёте, в чём заключается проблема. Для более подробного обсуждения вопроса о том, стоит ли создавать такой цикл самостоятельно или использовать готовый, см. runtime harnesses vs composed frameworks.

    Репозиторий как база знаний агента

    В разработке с участием агентов репозиторий — это не просто исходный код. Он может хранить всё, что необходимо агенту для работы над проектом: решения по архитектуре, команды для разработки и тестирования, словарь терминов домена, схемы, планы, руководства по эксплуатации и инструкции, специфичные для агента; всё это версионируется вместе с кодом, который они описывают. Собственные материалы OpenAI по инженерии агентов подчёркивают этот момент, рассматривая версионированные объекты внутри репозитория как основную систему хранения информации, необходимой агенту для понимания и изменения проекта, и рекомендуя использовать карту, указывающую на конкретные документы, а не один огромный файл с инструкциями. Вытекающий из этого вывод прост: решение по дизайну, существующее только в голове человека или в чате, для агента не существует. Способность делать знания доступными стала частью архитектуры программного обеспечения.

    Hooks: поведение, которое модели не нужно запоминать

    Хуки являются одними из самых полезных примитивов харнеса. Хук позволяет системе выполнения реагировать на события жизненного цикла с помощью детерминированного кода. Самым очевидным примером является контроль вызовов инструментов.

    Before tool call
            ↓
    Check policy
            ↓
    Allow / deny
    

    Другой тип хуков обеспечивает стабильность качества кода после каждой правки.

    After file edit
            ↓
    Run formatter
            ↓
    Run type checker
    

    Третий тип защищает информацию до сжатия контекста.

    Before context compaction
            ↓
    Persist important state
    

    Четвертый тип создает лог аудита.

    After task completion
            ↓
    Generate audit record
    

    В документации Claude Code хуки описываются как команды, запускаемые в ответ на события жизненного цикла детерминированным образом, которые могут, среди прочего, блокировать вызов инструмента до его выполнения. Их сила заключается в том, что они полностью выносят поведение за рамки логики модели. Вместо того чтобы писать в запросе «пожалуйста, не забудьте запустить форматтер» и надеяться, система выполнения просто запускает форматтер каждый раз.

    Никогда не позволяйте модели контролировать границы

    Модели являются вероятностными; границы безопасности — нет. Этот антипаттерн передаёт принятие решений модели:

    if model_says_safe:
        execute()
    

    Этот паттерн передаёт его инфраструктуре, от которой невозможно добиться изменения ответа:

    if operating_system_allows:
        execute()
    

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

    Model:
    Should I modify this file?
    
    Harness:
    Is this file inside the workspace?
    
    OS:
    Can this process write to the file?
    
    Human:
    Should this high-risk action proceed?
    

    Модель решает, является ли изменение хорошей идеей, инструмент проверяет, находится ли цель в рабочей зоне, операционная система решает, может ли процесс записать файл, а человек решает, следует ли приступать к действию с высоким риском. Такие слойные решения гораздо надёжнее, чем ожидание того, что какой-то один компонент сделает всё правильно.

    Инструменты усиливают модели; они не заменяют их

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

    Model capability
        =
    What the agent can reason about
    
    Harness quality
        =
    How effectively that capability is deployed
    

    Блестящая модель внутри плохой среды выполнения тратит огромное количество ресурсов и денег. Тщательно спроектированная среда выполнения вокруг слабой модели все равно приводит к неэффективным решениям, только более безопасно и эффективно. Для работы необходимы оба элемента.

    Пять вопросов, которые следует задать перед развертыванием любого агента

    1. Что он может делать?

    Перечислите все инструменты и отметьте каждую опасную операцию.

    read
    write
    delete
    execute
    network
    deploy
    send_message
    

    2. До чего он может дотянуться?

    Определения инструментов раскрывают лишь часть информации. Проверьте, к чему на самом деле может получить доступ процесс:

    filesystem
    network
    environment
    secrets
    processes
    credentials
    

    3. Что сохраняется после перезагрузки?

    Перезагрузите агента и выясните:

    What does it remember?
    
    What does it forget?
    
    Where is important state stored?
    

    4. Кто проверяет результат?

    Для операций с последствиями недостаточно двухэтапного процесса:

    generate → approve
    

    Вставьте независимые проверки между генерацией и утверждением:

    generate
       ↓
    test
       ↓
    review
       ↓
    approve
    

    5. Сколько на самом деле стоит каждая задача?

    Количество токенов на запрос само по себе вводит в заблуждение:

    tokens per request
    

    Лучше измеряйте итоговые результаты:

    tokens per successful task
    latency per successful task
    tool calls per task
    retries per task
    human interventions
    

    Количество токенов, задержек, вызовов инструментов, попыток повтора и вмешательства человека на одну успешную задачу — вот показатели, которые показывают, стоит ли запускать систему.

    Рабочее определение производственного агента

    Сочетание всех компонентов позволяет получить более точное определение.

    Agent =
        Model
      + Tools
      + Execution Environment
      + Policy
      + Memory
      + Context Management
      + Verification
      + Observability
    

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

    Заключение

    Обсуждения в отрасли смещаются от того, какая модель показывает лучшие результаты в тестах, к тому, какая среда выполнения позволяет модели надежно выполнять полезную работу. Поставщики сходятся к одинаковым основным компонентам: OpenAI теперь продает инфраструктуру управляемых агентов, включающую песочницы, обработку контекста, поиск инструментов, вызовы инструментов из кода и длительное выполнение, в то время как Anthropic предоставляет постоянные инструкции, навыки, субагентов и детерминистические механизмы. Исследования начинают рассматривать эти компоненты как экспериментальные переменные, а не модель в целом как единую систему. Эти функции быстро развиваются, поэтому обращайтесь к актуальной документации.

    Простой способ создания агента выглядит следующим образом:

    Pick LLM
    +
    Add tools
    =
    Agent
    

    Реалистичный вариант выглядит так:

                  Model
                    ↓
              Agent Runtime
                    ↓
          ┌─────────┼─────────┐
          ↓         ↓         ↓
       Policy    Context    Memory
          ↓         ↓         ↓
       Sandbox   Tools    Persistence
          └─────────┼─────────┘
                    ↓
              Verification
                    ↓
              Observability
    

    Модель принимает решения; фреймворк определяет условия, при которых эти решения превращаются в действия. Прежде чем выбирать фреймворк, узнайте, что произойдет, если модель даст неверный ответ, и построите фреймворк на основе этого ответа.

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

    Цель не в создании агента, который никогда не ошибается, а в построении системы, в которой ошибка модели автоматически не превращается в инцидент в производственной среде.