Глава 5.4 — Агенты и использование инструментов
Содержание
- От восприятия — к действию
- Что инструменты дают языковой модели, чего не могут дать параметры
- Вызов функций: базовый механизм
- ReAct: чередование рассуждения и действия
- Toolformer: использование инструментов как цель обучения
- Честный разрыв между демонстрациями и надёжными агентами
- Взгляд с точки зрения интервью
- Вопросы для самопроверки
- Источники
1. От восприятия — к действию
Глава 5.3 расширила то, что языковая модель способна воспринимать, позволив ей обусловливать генерацию не только текстом, но и изображениями. Эта глава расширяет то, что модель способна делать: модель, которая хорошо рассуждает (глава 5.1) и умеет воспринимать богатый, привязанный к реальности контекст (главы 5.2 и 5.3), получает способ действовать в мире — выполнять код, обращаться к живой базе данных, вызывать API или искать информацию в интернете — вместо того чтобы ограничиваться порождением текста и ничем больше. Это и есть «агентная» парадигма, которая стала доминировать в значительной части прикладной инженерии LLM: языковая модель — это уже не просто генератор текста, стоящий в конце диалога, а контроллер цикла, который может совершать действия, наблюдать их результаты и решать, что делать дальше.
2. Что инструменты дают языковой модели, чего не могут дать параметры
Стоит точно определить, какую именно проблему решает использование инструментов, потому что от этой формулировки зависит, как рассуждать о том, когда агентная система — правильное решение, а когда — избыточное усложнение. Параметрическое знание и способность к рассуждению языковой модели, какими бы хорошими они ни были, обладают конкретными структурными слабостями, которые не устраняются ни масштабом, ни хитрым промптингом. Точная арифметика и точные вычисления — одна из них: модель порождает токены через выученное распределение вероятностей, а не через детерминированный вычислительный движок, поэтому надёжно перемножить два больших числа или выполнить точный алгоритм — это принципиально плохо подходящая задача для авторегрессивной генерации токенов, хотя модель и может научиться приближённо выполнять арифметику для небольших случаев. Живые или приватные данные — другая слабость: параметрическая память модели заморожена на момент обучения (снова формулировка из главы 5.2), поэтому она структурно не может знать сегодняшнюю цену акции, содержимое вашей приватной базы данных или что-либо, произошедшее после отсечки обучения, — как бы её ни просили об этом в промпте. И совершение реального действия — отправка письма, исполнение сделки, изменение файла, вызов production-API — вообще не относится к тому, что делает генерация текста; порождение текста «Я отправил письмо» не отправляет письмо. Внешние инструменты — калькуляторы, интерпретаторы кода, поисковые системы, базы данных, произвольные API — это как раз те механизмы, которые уже надёжно решают каждую из этих проблем, и инженерный вопрос, на который отвечает использование инструментов, состоит в том, как позволить языковой модели вызывать их уместно, а не пытаться заставить саму модель воспроизвести то, что калькулятор или база данных и так делают лучше.
3. Вызов функций: базовый механизм
Базовый механизм, лежащий в основе практически любой агентной системы, — это вызов функций (function calling): модель обучается или инструктируется распознавать, когда вызов внешней функции поможет ответить на текущий запрос, и порождать структурированный запрос, указывающий, какую функцию вызвать и с какими аргументами, вместо того чтобы сразу выдавать ответ на естественном языке. Этот структурированный запрос — как правило, имя функции и набор аргументов, сериализованных по фиксированной схеме, — перехватывается окружающей системой (он не генерируется как галлюцинированный «результат», а действительно исполняется относительно реальной функции), и фактическое возвращаемое значение функции вставляется обратно в контекст модели как наблюдение, после чего модель продолжает генерацию, теперь уже обусловленную этим реальным результатом. Это прямое расширение авторегрессивной формулировки из главы 1.1: моделируемая последовательность просто становится богаче, чередуя токены, порождаемые моделью, и токены, вставляемые извне собственного распределения модели, — результаты реального исполнения функций, — причём модель обусловливает своё последующее порождение и на тех, и на других точно так же, как и на любом другом предшествующем контексте. То, как добиться, чтобы модель действительно надёжно порождала такой запрос в валидной по схеме форме, а не просто обычно это делала, — отдельная инженерная задача, которой напрямую посвящена глава 5.6.
Инженерная ценность вызова функций в том, что он превращает открытую, ненадёжную задачу генерации («правильно вычислить это») в узкую, чётко специфицированную («решить, вызывать ли внешнюю функцию и как, а затем правильно интерпретировать её вывод»), что играет на сильные стороны языковых моделей — понимание намерения, выбор подходящего действия и синтез результатов в связный ответ, — при этом перекладывая структурно слабые для них части задачи на системы, специально построенные именно под эти части.
Вызов функций, описанный только что, ничего не говорит о том, как схема конкретного инструмента реально доходит до конкретной модели, а на практике это исторически означало специализированный, написанный под конкретное приложение и конкретный инструмент интеграционный код — каждый агентный фреймворк подключал схему и логику вызова каждого инструмента по-своему. Model Context Protocol (MCP), предложенный Anthropic, вместо этого стандартизирует эту проводку: он определяет общий протокол, посредством которого инструмент (или источник данных, или целая внешняя система) объявляет свои доступные функции, их схемы и способ их вызова, так что любая MCP-совместимая модель или агентный фреймворк может обнаружить и вызвать любой MCP-совместимый сервер инструментов без специального интеграционного кода, написанного именно под эту пару. Инженерная ценность — та же самая стандартизация, что сделала полезными HTTP или USB: она превращает проблему интеграции $M \times N$ (каждый агентный фреймворк отдельно подключает каждый инструмент) в проблему $M + N$ (каждый инструмент реализует MCP один раз, каждый фреймворк реализует MCP один раз, и любой инструмент по построению работает с любым фреймворком).
4. ReAct: чередование рассуждения и действия
Сам по себе вызов функций описывает единственный шаг «действие-наблюдение»; он ничего не говорит о том, как модель должна принимать решение о целой последовательности действий для выполнения многошаговой задачи или как ей учитывать результаты одного действия при выборе следующего. Yao и др. (2022) предложили ReAct (Reasoning and Acting, «рассуждение и действие») как влиятельный фреймворк именно для этого: вместо того чтобы модель либо рассуждала молча, а затем действовала, либо действовала многократно вообще без явного рассуждения, ReAct заставляет модель порождать явный, чередующийся след из «Мысли» (Thought — рассуждение о том, что делать дальше и почему), «Действия» (Action — вызов инструмента или функции) и «Наблюдения» (Observation — реальный результат, возвращённый этим действием), повторяющийся в цикле до тех пор, пока модель не решит, что у неё достаточно информации для финального ответа.
Эмпирическое обоснование именно такого чередования, а не рассуждения-без-действий (chain-of-thought) или действий-без-явного-рассуждения, состоит в том, что рассуждение и действие взаимно дополняют друг друга и каждое исправляет характерные для другого сбои. Рассуждение-без-действий (глава 5.1) может порождать беглые, правдоподобно звучащие выводы, которые попросту неверны, поскольку они не привязаны ни к какому реальному, проверяемому внешнему состоянию, — модель может галлюцинировать факт посреди цепочки рассуждений, и ничто не поймает эту ошибку. Действие без явного рассуждения, напротив, склонно порождать импульсивные, плохо спланированные вызовы инструментов, вызываемые без ясно сформулированной цели, почему именно это действие является правильным следующим шагом, из-за чего модели (или человеку, отлаживающему её поведение) труднее распознать, что выбранное действие на самом деле не поможет. Чередование этих двух режимов позволяет явному шагу «Мысль» спланировать и обосновать следующее действие до того, как оно будет совершено, а шагу «Наблюдение» — привязать последующее рассуждение к реальной, проверенной информации из внешнего мира, а не к возможно галлюцинированным внутренним убеждениям модели: каждая итерация цикла — это возможность для модели заметить, что план был неверен, и скорректировать его, а не идти по единой непроверяемой цепочке до самого конца. Именно этот цикл «Мысль-Действие-Наблюдение» структурно лежит в основе большинства последовавших агентных фреймворков и агентно-ориентированных функций продуктов.
5. Toolformer: использование инструментов как цель обучения
ReAct — это, по сути, фреймворк промптинга: он опирается на тщательно построенные промпты (и примеры в контексте), чтобы вызвать паттерн «Мысль-Действие-Наблюдение» у модели, которую никогда специально не обучали его порождать, — точно так же, как промптинг «цепочки рассуждений» из главы 5.1 вызывал рассуждение у модели, никогда явно не обученной рассуждать. Schick и др. (2023) задали естественный следующий вопрос, повторяя логику перехода главы 5.1 от промптинга к обучению: может ли модель научиться, через обучение, а не только через промптинг, самостоятельно определять, когда и как вызывать инструменты?
Ответ Toolformer — это самообучаемая (self-supervised) процедура бутстреппинга, не требующая никаких вручную размеченных примеров правильного использования инструментов. Начиная с базовой языковой модели и небольшого набора примеров форматов вызова инструментов, модель используется для генерации кандидатов на вставку вызовов инструментов во многих позициях по всему большому текстовому корпусу — по сути, модель предлагает: «вот место в этом отрывке, где вызов калькулятора, поисковой системы или API календаря может помочь точнее предсказать следующий текст». Каждая кандидатная вставка затем действительно исполняется относительно реального инструмента, и полученный вывод инструмента вставляется в текст в этой позиции. Ключевой этап фильтрации — самообучаемый: дополненный текст (со вставленным вызовом инструмента и его реальным результатом) оценивается по тому, насколько он улучшает собственную функцию потерь модели для предсказания следующего токена на последующем тексте по сравнению с исходным, недополненным текстом или версией с неинформативным вызовом инструмента. Только те вставки вызовов инструментов, которые действительно снижают потери модели на предсказании последующих токенов, сохраняются как положительные обучающие примеры, и модель затем дообучается на этом отфильтрованном наборе данных вида «вот текст, вот вызов инструмента, помогающий предсказать, что будет дальше, вот реальный вывод инструмента».
Это наглядная иллюстрация повторяющегося паттерна этой книги: способность (в данном случае — решение о том, когда вызов инструмента поможет) превращается в нечто, чему модель может научиться напрямую, используя собственную уже существующую целевую функцию модели (предсказание следующего токена) в качестве фильтра того, что считать хорошим обучающим примером, вместо того чтобы требовать от человека вручную размечать «да, здесь уместно вызвать калькулятор». Результатом становится модель, которая на этапе инференса самопроизвольно вставляет вызовы инструментов в собственную генерацию, когда это повышает точность того, что она собирается сказать, — без необходимости в промпт-каркасе в стиле ReAct для вызова такого поведения.
6. Честный разрыв между демонстрациями и надёжными агентами
Было бы ошибкой — и именно той ошибкой, которую явно избегает сильный ответ на собеседовании, — заключить из ReAct и Toolformer, что агентное использование инструментов является решённой проблемой. Обе работы демонстрируют работу механизма — модель может быть промптирована или обучена разумно вызывать инструменты — на задачах со сравнительно коротким горизонтом: несколько циклов «рассуждение-действие-наблюдение» или единичные, чётко определённые вставки вызова инструмента. Производственные же агентные системы, напротив, обычно должны выполнять длинные последовательности зависимых шагов — десятки и более последовательных действий, каждое из которых зависит от успеха предыдущих, — и этот сдвиг в длине горизонта обнажает проблемы, не проявляющиеся в коротких демонстрациях.
Наиболее фундаментальная из них — накопление ошибок: если каждый шаг в цепочке действий имеет даже скромную независимую вероятность пойти не так, вероятность того, что вся многошаговая последовательность завершится корректно, падает мультипликативно с числом шагов — цепочка из $n$ шагов, каждый из которых успешен независимо с вероятностью $p$, завершается успешно от начала до конца с вероятностью примерно $p^n$, что быстро деградирует даже при довольно надёжном $p$ для одного шага. Это чисто структурная проблема, а не то, что напрямую исправляется более удачным промптингом или чуть более способной базовой моделью, поскольку она является свойством сцепления множества вероятностных шагов, а не свойством качества какого-либо одного шага. С этим связана трудность долгосрочного планирования: заранее спланировать хорошую последовательность действий на много шагов вперёд, особенно когда более поздние шаги зависят от информации, доступной только после исполнения более ранних действий, — задача сложнее, чем выбор единственного наилучшего следующего действия, и современные агентные системы значительно лучше справляются со вторым, чем с первым. Не менее важно и восстановление после ошибок: способный агент должен замечать, когда действие не дало ожидаемого результата или когда общий план пошёл не так, и откатываться назад или перепланировать соответственно, а не продолжать наращивать уже сломанную траекторию, — а надёжное обнаружение «это не работает» посреди длинной последовательности действий остаётся по-настоящему сложной, открытой проблемой, а не тем, что современные системы делают уверенно.
Честная, уместная для собеседования формулировка состоит в том, что надёжное долгосрочное агентное поведение — это открытая инженерная проблема, над которой активно работает вся область, а не уже раскрытая способность, ожидающая лишь более широкого развёртывания. Умение чётко объяснить, почему мультипликативное накопление ошибок делает это сложным, вместо того чтобы повторять лозунг «агенты — это будущее», — именно та точность, которая отличает сильный ответ.
Стоит назвать два дальнейших направления, поскольку они усугубляют ту же самую лежащую в основе трудность, а не обходят её. Мультиагентные системы заменяют одного агента, работающего над задачей, несколькими агентами, часто с разными ролями или специализированными промптами (планировщик, кодер, критик, проверяющий работу остальных), координирующимися к общей цели. Это может по-настоящему помочь, дав задаче явные проверки, которых не хватает собственной самооценке одного агента, — выделенный агент-критик ловит ошибку, мимо которой единственный агент мог бы уговорить сам себя пройти, — но это не обходит проблему накапливающейся ошибки, а лишь перемещает её: теперь вероятность успеха от начала до конца зависит от индивидуальной надёжности каждого агента и от надёжности координации между ними, а это собственный дополнительный источник сбоя (недопонимание, агенты, работающие вразнобой, ошибка, внесённая одним агентом, которую остальные не ловят), наслаивающийся поверх проблемы одного агента, описанной в разделе выше. Агенты, управляющие компьютером (computer-use агенты), проталкивают долгосрочное действие в ещё менее структурированную среду: вместо вызова чётко специфицированных функций со схемой агент воспринимает экран (через скриншоты или дерево accessibility) и действует через те же самые интерфейсы, что и человек, — кликая, печатая, прокручивая, — на программном обеспечении, которое вообще не проектировалось для управления через вызов API. Это полностью убирает чистое, чётко специфицированное пространство действий вызова функций, заменяя его гораздо большим и гораздо менее прощающим пространством «всего, что мышь и клавиатура могут сделать с этим конкретным программным обеспечением», что делает упомянутые выше проблемы накапливающейся ошибки и восстановления после ошибок острее, а не мягче: единственный промах мимо кнопки может незаметно сорвать длинную задачу так, как некорректно сформированный вызов функции, по крайней мере, обычно не может.
Рассуждение, извлечение информации, мультимодальное восприятие и агентность с использованием инструментов — всё это по отдельности способности, расширяющие то, что может языковая модель. Ни одна из них сама по себе не говорит о том, действительно ли система, построенная из них, хороша — производит ли она корректный, полезный, безопасный вывод чаще, чем нет, причём измеримым и заслуживающим доверия образом. Именно к этому вопросу — оценке — обращается следующая глава, и это в определённом смысле наименее зрелая часть всего рассмотренного до сих пор конвейера.
7. Взгляд с точки зрения интервью
Вопрос: Когда стоит выбирать агентную архитектуру с использованием инструментов вместо простого RAG-конвейера или обычной однократной подсказки модели? Сильный ответ различает варианты по структуре задачи: однократного промптинга достаточно, когда параметрического знания модели и однопроходного рассуждения хватает; RAG уместен, когда узкое место — отсутствующее или устаревшее знание, которое можно напрямую восполнить шагом извлечения; агентный цикл с инструментами оправдан, когда задача требует действий с побочными эффектами (обращение к живой системе, исполнение кода, вызов API) или многошагового процесса, где поздние шаги зависят от результатов более ранних, — и стоит отметить, что агентные архитектуры вносят издержки накопления ошибок и надёжности, которые не бесплатны, поэтому к ним не стоит прибегать по умолчанию.
Вопрос: Почему ReAct чередует рассуждение и действие, а не заставляет модель сначала породить рассуждение, а затем один вызов инструмента? Сильный ответ объясняет, что цепочки-рассуждения-без-действий могут быть беглыми, но не привязанными к реальности, склонными к галлюцинированным промежуточным «фактам», которые нечем проверить, тогда как действие без явного рассуждения склонно порождать плохо обоснованные, импульсивные вызовы инструментов; чередование позволяет спланировать каждое действие явным шагом мысли, а затем скорректировать его реальным наблюдением перед следующей мыслью, так что ошибки перехватываются внутри цикла, а не накапливаются молча по всему непроверенному многошаговому плану.
Вопрос: Как Toolformer определяет, какие вызовы инструментов действительно полезны, если у него нет размеченных человеком примеров правильного использования инструментов? Сильный ответ точно описывает процедуру самообучаемой фильтрации: кандидатные вставки вызовов инструментов генерируются, исполняются относительно реальных инструментов и сохраняются как обучающие примеры только в том случае, если вставка реального вывода инструмента измеримо снижает собственные потери модели на предсказании следующего токена для последующего текста по сравнению с отсутствием вставки, — фильтром служит собственная обучающая цель модели, а не человек-оценщик.
Вопрос: Почему сцепление множества агентных шагов ухудшает надёжность, даже если каждый отдельный шаг довольно хорош? Сильный ответ напрямую приводит мультипликативный вероятностный аргумент: если каждый из $n$ последовательных шагов успешен независимо с вероятностью $p$, вероятность успеха всей цепочки составляет примерно $p^n$, что быстро падает с ростом $n$ даже при высоком $p$ для одного шага, — и стоит отметить, что это структурное свойство сцепления, а не то, что само по себе исправляется чуть более удачной моделью.
Вопрос: В чём разница между «модель может вызвать калькулятор» и «модель научилась, когда вызывать калькулятор», и почему это различие важно? Сильный ответ связывает это с различием ReAct и Toolformer: вызов функций — это просто механизм (структурированный запрос, который исполняет окружающая система); ReAct вызывает разумное поведение использования инструментов через промптинг; Toolformer обучает решение о том, когда и как вызывать инструмент, непосредственно в весах модели через самообучаемую цель, так что модели не нужны промпт-каркасы, чтобы вести себя хорошо, — это отражает общий сдвиг от промптинга к обучению, обсуждавшийся в главе 5.1.
8. Вопросы для самопроверки
- Назовите три структурные слабости чисто параметрических языковых моделей, мотивирующие использование инструментов, и приведите конкретный пример для каждой.
- Пройдитесь по базовому циклу вызова функций: что порождает модель, что окружающая система делает с этим, и как результат вновь попадает в контекст модели?
- Каковы три компонента цикла ReAct и какой конкретный сбой промптинга «только рассуждение» исправляет шаг «Действие»/«Наблюдение»?
- Опишите своими словами шаг самообучаемой фильтрации Toolformer: что делает так, что кандидатная вставка вызова инструмента сохраняется как обучающий пример?
- Почему Toolformer описывается как обучающий аналог того, чего ReAct достигает через промптинг?
- Выведите, используя аргумент независимых вероятностей шагов, почему у 10-шаговой агентной задачи с 95%-й надёжностью на шаг итоговая вероятность успеха заметно ниже, чем можно было бы предположить, глядя на цифру 95%.
- Почему «надёжные долгосрочные агенты» описываются как открытая, а не решённая проблема, и на какие две конкретные подпроблемы (помимо накопления ошибок) указывает эта формулировка?
9. Источники
- Yao, S., Zhao, J., Yu, D., et al. (2022). ReAct: Synergizing Reasoning and Acting in Language Models. ICLR 2023. arXiv:2210.03629. https://arxiv.org/abs/2210.03629
- Schick, T., Dwivedi-Yu, J., Dessì, R., et al. (2023). Toolformer: Language Models Can Teach Themselves to Use Tools. NeurIPS 2023. arXiv:2302.04761. https://arxiv.org/abs/2302.04761
- Anthropic (2024). Model Context Protocol Specification. https://modelcontextprotocol.io