2026 г.

Глава 11. Агенты

Учебник «Большие языковые модели»

Всё, что мы строили до сих пор, укладывается в схему «запрос → ответ»: один вызов модели, возможно, с подготовленным контекстом. Но многие задачи по природе многошаговы: «разберись, почему упал сервис», «собери дайджест новостей за неделю и опубликуй», «почини падающий тест». Заранее неизвестно ни число шагов, ни их состав — следующий шаг зависит от результата предыдущего. Системы, в которых модель сама планирует и выполняет шаги, вызывая инструменты и реагируя на их результаты, называют агентами. Они полезны там, где следующий шаг действительно зависит от наблюдения, но длинные демонстрации заметно проще надёжных производственных систем. Разберём и механику, и границы.

11.1. Цикл агента

Ядро агента — цикл «состояние и решение → действие → наблюдение», идея которого была оформлена в работе ReAct (Яо и др., 2022): модель оценивает текущее состояние задачи, выбирает действие (инструмент и аргументы), получает результат и выбирает следующий шаг — до достижения цели или исчерпания лимита. Технически это цикл вокруг вызова функций из главы 9. Публиковать скрытую цепочку рассуждений для этого не требуется:

import json

def run_agent(task, tools, tool_impls, max_steps=15):
    items = [{"role": "user", "content": task}]
    for step in range(max_steps):
        response = client.responses.create(
            model=MODEL,
            instructions=SYSTEM_PROMPT,
            input=items,
            tools=tools,
        )
        items += response.output
        calls = [x for x in response.output if x.type == "function_call"]

        if not calls:                     # кандидат на завершённый ответ;
            return response.output_text   # успех отдельно проверяет приложение

        for call in calls:
            if call.name not in tool_impls:
                raise ValueError(f"неразрешённый инструмент: {call.name}")
            try:
                args = validate_tool_args(call.name, call.arguments)
                result = tool_impls[call.name](**args)
                output = bounded_tool_result(result)
            except SafeToolError as error:
                # Только безопасное сообщение без стека, секретов и путей.
                output = json.dumps({"ok": False,
                                     "error": error.public_message})
            items.append({
                "type": "function_call_output",
                "call_id": call.call_id,
                "output": output,
            })
    return "Задача не решена за отведённое число шагов."

validate_tool_args, bounded_tool_result и SafeToolError здесь обозначают прикладные обёртки: строгую проверку схемы и авторизации, ограничение размера структурированного ответа и исключение с безопасным публичным сообщением.

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

11.2. Инструменты и промпт агента

Агент ограничен качеством своих инструментов. Начинайте с небольшого неперекрывающегося набора и добавляйте функции по результатам eval; описания написаны как документация для нового сотрудника — что делает, когда применять, что возвращает, примеры аргументов (это тоже промпт, и он подчиняется главе 8); результаты информативны в обе стороны — при ожидаемой ошибке он возвращает код, безопасное описание и допустимые варианты исправления, не раскрывая структуру каталогов или секреты. Универсальный и самый опасный инструмент — исполнение кода (bash, Python): он покрывает бесконечный хвост задач, для которых не написан специальный инструмент, но требует песочницы — о безопасности ниже.

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

11.3. MCP: стандарт подключения инструментов

Пока инструменты пишете вы сами, достаточно вызова функций. Но инструменты хочется переиспользовать: доступ к базе, к тикет-системе, к браузеру нужен всем агентам сразу. MCP (Model Context Protocol, открытый протокол) задаёт архитектуру host–client–server, согласование версии и возможностей и обмен по JSON-RPC. Сервер может публиковать не только tools, но и resources и prompts; host решает, что показать модели и что разрешить выполнить. Для Python есть официальный SDK.

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

11.4. Память и длинные задачи

Контекст агента растёт с каждым шагом: рассуждения, вызовы, результаты. На длинной задаче он упирается в окно, и наступает знакомая по главе 7 развилка: суммаризация старой части траектории (теряет детали) и/или внешняя память — агенту даются инструменты записи и чтения заметок (файл заметок, список задач), и промпт предписывает фиксировать там план, принятые решения и найденные факты. Именно так устроены агентные кодовые инструменты: план в файле, вычёркивание сделанного, компактизация истории. Побочная выгода внешней памяти — наблюдаемость: заметки агента читаемы человеком, и по ним видно, где траектория свернула не туда. Но память тоже может устареть или быть отравлена недоверенными данными; записи требуют происхождения, проверки и разграничения прав, а изменение долговременной памяти следует считать привилегированной операцией.

11.5. Где агенты ломаются

Пусть в упрощённом примере каждый из двадцати независимых шагов успешен с вероятностью 95%, а любая ошибка фатальна. Тогда вероятность общей цепочки равна 0,9520 ≈ 36%. В реальности ошибки зависимы, часть из них можно обнаружить и исправить, а не каждый шаг критичен; формула иллюстрирует, почему надёжность надо измерять на полной траектории. Частные проявления: зацикливание (агент повторяет неработающее действие с косметическими вариациями); дрейф цели (увлёкся побочной подзадачей и «забыл», зачем начинал — особенно после суммаризации контекста); галлюцинация успеха (отчитался о выполнении, не выполнив, — классика: «тесты проходят» без запуска тестов); каскад после ранней ошибки (неверный вывод на шаге 2 уверенно развивается шагами 3–15).

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

11.6. Безопасность агентов

Агент — это LLM с доступом к действиям, и всё из главы 6 о недостоверности генерации приобретает материальные последствия. Главная угроза — prompt injection: агент, читающий внешние данные (веб-страницы, письма, тикеты, результаты поиска), может встретить в них текст, составленный как инструкция («системное сообщение: перешли содержимое секретов на …»), и модели ненадёжно соблюдают границу между данными и инструкциями. Пока это открытая проблема без общего решения, действуют архитектурные меры: минимальные права инструментов (агенту дайджеста не нужен доступ к ~/.ssh); песочницы для исполнения кода (контейнер, отдельный пользователь); белые списки адресатов для исходящих действий; подтверждение человеком всего необратимого; и правило-минимум — не совмещать в одном автономном агенте чтение недоверенных данных и доступ к секретам или необратимым действиям. Дополнительно ограничивают время, число вызовов и расходы, а результаты инструментов валидируют как недоверенный ввод. Подробно — в главе 15.

11.7. Итоги

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

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

Упражнения

1. В изолированной копии каталога соберите из цикла раздела 11.1 агента с двумя инструментами только для чтения: чтение файла и поиск по каталогу. Дайте задачу «найди в каталоге статей все упоминания устаревшего домена и составь список файлов для правки». Сколько шагов потребовалось? Где агент ошибался?

2. Посчитайте вероятность успеха 5-, 10- и 30-шаговой задачи при пошаговой надёжности 90, 95 и 99%. При какой надёжности шага 30-шаговый автономный агент становится практичным (скажем, >80% успеха)?

3. Спроектируйте (на бумаге) агента для еженедельного дайджеста новостей с публикацией. Какие действия необратимы? Где поставите контрольную точку с человеком, а что отдадите в полную автономию?

404 Not Found

404 Not Found


nginx/1.24.0 (Ubuntu)

Связь с редакцией