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

Типы агентов
Прежде чем углубляться в конкретные стратегии оркестрации, давайте разберемся с различными типами агентов. Каждый тип воплощает особый подход к рассуждениям, планированию и действиям, влияя на то, как происходит декомпозиция и выполнение задач. Некоторые агенты реагируют мгновенно, действуя по заранее заданным правилам, в то время как другие итеративно рассуждают и строят логические умозаключения, чтобы справляться со сложными неформализованными целями. Выбор типа агента напрямую влияет на производительность вашей системы, ее стоимость и возможности. В этом разделе мы исследуем весь спектр: от рефлекторных агентов, мгновенно предоставляющих ответы, до агентов глубокого исследования, которые проводят многофазные исследования с адаптивными планами и синтезом результатов. Понимание этих архетипов поможет проектировать агентов, соответствующих потребностям и ограничениям вашего приложения; кроме того, вы начнете лучше понимать, как паттерны оркестрации, выбор инструментов и построение контекста сочетаются в каждом типе для достижения эффективных и надежных результатов.
Рефлекторный агент
Рефлекторный агент (reflex agent) реализует прямое соответствие между вводом и действием без каких-либо внутренних умозаключений. Простые рефлекторные агенты следуют правилам «если (условие), то (действие)», вызывая соответствующий инструмент сразу же после обнаружения предварительно заданных триггеров. Так как рефлекторные агенты обходят промежуточную логическую обработку, они выдают ответы с минимальной задержкой и прогнозируемой производительностью, вследствие чего они хорошо подходят для таких сценариев, как маршрутизация по ключевым словам, одношаговый поиск данных или базовые автоматизации (например, «Если X, вызвать инструмент Y»). Тем не менее их ограниченные возможности означают, что они не справляются с задачами, требующими многоэтапных рассуждений или контекста за пределами непосредственного ввода.
Агент ReAct
Агент ReAct чередует логическую обработку и действия в итеративном цикле: модель генерирует заключение, выбирает и вызывает инструмент, наблюдает за результатом и повторяет цикл по мере надобности. Этот паттерн позволяет разбивать сложные задачи на выполнимые этапы, обновляя план в зависимости от промежуточных итогов.
ZERO_SHOT_REACT_DESCRIPTION (LangChain) предоставляет инструменты и инструкции в одном промпте, полагаясь на то, что внутренние рассуждения LLM обеспечат выбор и вызов нужных инструментов без предоставленных примеров.
CHAT_ZERO_SHOT_REACT_DESCRIPTION расширяет эту модель внедрением истории диалога, позволяя агенту использовать прошлые взаимодействия для выбора следующего действия.
Агенты ReAct отлично проявляют себя в исследовательских сценариях (динамический анализ данных, агрегирование нескольких источников, диагностика), в которых возможность адаптации на промежуточных стадиях перевешивает дополнительную задержку и вычислительные затраты. Их циклическая структура также обеспечивает прозрачность («цепочку размышлений»), которая упрощает отладку и аудит, хотя и может повышать затраты API и время отклика.
Агент «планировщик-исполнитель»
Агент «планировщик-исполнитель» (planner-executor agent) разбивает задачу на две фазы: планирование, когда модель генерирует многошаговый план, и исполнение, когда каждый запланированный шаг выполняется вызовами инструментов. Это четкое разделение позволяет планировщику сосредоточиться на рассуждениях, направленных на будущее, тогда как исполнители активизируют только необходимые инструменты, сокращая избыточные вызовы LLM. Так как план выражен явно, отладка и мониторинг упрощаются — вы можете просмотреть сгенерированный план, отследить, какой шаг завершился сбоем, и при необходимости запланировать его заново. Такой подход обладает рядом преимуществ.
Четкая декомпозиция
Сложные задачи разбиваются на выполнимые подзадачи.
Удобство отладки
Явно выраженные планы показывают, где и почему возникают ошибки.
Эффективность по затратам
Выполнением управляют меньшие модели или меньшее количество вызовов LLM, тогда как большие модели резервируются для планирования.
Агент декомпозиции запросов
Агент декомпозиции запросов (query-decomposition agent) формирует ответ на сложный вопрос, итеративно разбивая его на подвопросы, вызывает поиск или другие инструменты для каждого из них, а затем синтезирует финальный ответ. Этот паттерн, часто называемый «самовопросами с поиском» (self-ask with search), действует по схеме: «Какой следующий вопрос мне нужен?» → вызов поиска → «каков следующий вопрос?» → … → «каков итоговый ответ?».
Пример: SELF_ASK_WITH_SEARCH
Вопрос: «Кто прожил дольше, X или Y?»
Самовопрос: «Какова продолжительность жизни X?» → инструмент поиска.
Самовопрос: «Какова продолжительность жизни Y?» → инструмент поиска.
Синтез: «X прожил 85 лет, Y прожил 90 лет, а значит, Y прожил дольше».
Этот подход хорошо проявляет себя там, где требуется извлечение внешней информации. Он проверяет, что каждый факт базируется на результатах инструмента, прежде чем строить итоговый ответ.
Агент с рефлексией и метарассуждениями
Агент с рефлексией и метарассуждениями (reflection and metareasoning agent) расширяет парадигму ReAct: он не только чередует рассуждения с действиями, но и анализирует прошлые шаги, идентифицируя и исправляя ошибки перед продолжением. При таком подходе (примером которого служит недавно предложенный фреймворк ReflAct) агент постоянно обосновывает свои рассуждения рефлексией относительного целевого состояния (goal-state reflections), сопоставляя свое текущее состояние с желаемым результатом и корректируя план при возникновении несоответствий. Рефлексия стимулирует модель к тому, чтобы критиковать собственную цепочку рассуждений, исправлять логические ошибки и подкреплять успешные стратегии, фактически моделируя человеческий процесс самооценки при решении сложных задач.
Паттерн хорошо работает в критических рабочих потоках, где ранние ошибки могут трансформироваться в дорогостоящие сбои: оркестрация финансовых транзакций, поддержка медицинской диагностики или реакция на критические инциденты. Сопоставляя каждое действие с шагом рефлексии, агент обнаруживает, когда результат инструмента отклоняется от ожиданий, и может перепланировать или выполнить возврат, прежде чем сохранять необратимые операции. Хотя метарассуждения приводят к задержкам и дополнительным вычислительным затратам, для задач, где правильность и надежность важнее скорости, рефлексивные агенты служат гарантией от накопления ошибок и обеспечивают соответствие общим целям.
Агент глубокого исследования
Агент глубокого исследования (deep research agent) специализируется на открытых, особо сложных исследованиях, которые требуют сбора обширных внешних знаний, проверки гипотез и синтеза: обзоры литературы, научные исследования или стратегический анализ рынка. Такие агенты объединяют несколько паттернов: фаза «планировщик-исполнитель» для планирования исследовательских рабочих потоков; декомпозиция запросов для разбиения больших запросов на целенаправленные поиски; циклы ReAct для итеративного уточнения гипотез на основании новых находок. В типичном цикле агент глубокого исследования:
Планирует общую стратегию поиска (например, идентифицирует ключевые подтемы или источники данных).
Проводит декомпозицию каждой подтемы на конкретные запросы (через SELF_ASK или другие аналогичные методы).
Вызывает инструменты (от академических поисковых API до предметно-специфических баз данных) и анализирует релевантность и надежность каждого результата.
Синтезирует полученные выводы в отчет или набор рекомендаций, используя LLM-управляемое реферирование и критику на каждом шаге.
Сильные стороны
Функциональность
Возможность проведения сложных многоэтапных исследований, опирающихся на специализированные базы данных и междисциплинарные источники знаний.
Адаптивность
Направление исследований корректируется при появлении новых фактов.
Прозрачность
Явные планы и этапы декомпозиции упрощают аудит.
Слабые стороны
Высокие затраты
Обширное использование фундаментальной модели и множественные вызовы API приводят к росту затрат на вычисления и токены.
Задержка
Каждый уровень планирования, декомпозиции и рефлексии добавляет дополнительную задержку.
Хрупкость
Зависят от качества и доступности внешних источников данных; необходимы тщательно продуманные стратегии обработки ошибок и резервных действий.
Агенты глубокого исследования лучше всего подходят для долгосрочных задач экспертного уровня — обзоров научной литературы, технической экспертизы, анализа деятельности конкурентов и т. п., где глубина и точность важнее скорости.
В табл. 5.1 приведена сводка самых частых архетипов агентов, у каждого из которых имеются свои компромиссы по скорости, гибкости и сложности. Тем не менее ситуация стремительно меняется. Постоянно появляются новые гибридные паттерны, фреймворки метарассуждений и стратегии планирования, поэтому классификация типов агентов будет становиться более разнообразной. Считайте этот список отправной точкой, а не единственно верной таксономией: с развитием данной области мы увидим новые подходы, базирующиеся на этих основах, так что проявляйте любознательность, чаще экспериментируйте и будьте готовы адаптировать свои стратегии оркестрации по мере развития исследований и инструментариев.
Таблица 5.1. Основные архетипы агентов
Тип агента | Сильные стороны | Слабые стороны | Оптимальное применение |
Рефлекторный | Ответы за миллисекунды | Отсутствие многошаговых рассуждений | Маршрутизация по ключевым словам, простой поиск |
ReAct | Гибкость, быстрая адаптация | Более высокая задержка и затраты | Исследовательские процессы, диагностика проблем |
Планировщик-исполнитель | Четкое разбиение задач | Затраты на планирование | Сложные многошаговые процессы |
Декомпозиция запросов | Получение проверенной информации | Множественные вызовы инструментов | Исследования, базирующиеся на фактах вопросы и ответы |
Рефлексия | Раннее обнаружение ошибок | Лишние вычисления и задержка | Ответственные, критические по безопасности задачи |
Глубокое исследование | Управление многошаговыми адаптивными исследованиями | Высокие вычислительные затраты и очень высокая задержка | Рецензирование литературы |
Выбор инструмента
Прежде чем переходить к оркестрации, поговорим о выборе инструментов, потому что он лежит в основе более продвинутого планирования. Разные подходы к выбору инструментов имеют свои уникальные достоинства и учитывают различные нюансы, что позволяет удовлетворять разные требования и адаптироваться к различным средам. Будем считать, что инструментарий уже был разработан (если вам понадобится вспомнить, о чем идет речь, вернитесь к главе 4).
Таблица 5.2. Стратегии выбора инструмента
Метод | Достоинства | Недостатки |
Стандартный выбор инструментов | Простота реализации | Плохо масштабируется для большого количества инструментов |
Семантический выбор инструментов | Хорошо масштабируется для большого количества инструментов Низкая задержка для реализации | Снижение точности выбора из-за семантических коллизий |
Иерархический выбор инструментов | Хорошо масштабируется для большого количества инструментов | Медленнее работает, потому что требует множества последовательных вызовов фундаментальной модели |
Стандартный выбор инструментов
Простейший способ — стандартный выбор инструментов. В этом случае фундаментальная модель получает инструменты, их определения и описания, и должна выбрать наиболее подходящий для заданного контекста. Вывод модели затем сравнивается с инструментарием, и выбирается наилучший вариант. Этот метод легко реализуется и не требует дополнительного обучения, внедрения или иерархии инструментов. Его главным недостатком является задержка, так как он требует дополнительного вызова фундаментальной модели, который может добавить несколько секунд к общему времени отклика. Он может выиграть от обучения в контексте, когда предоставляются примеры, повышающие прогностическую точность для задачи без затрат на обучение или тонкую настройку модели.
Эффективный выбор инструментов часто определяется тем, как вы описываете функциональность каждого из них. Для начала назначьте инструменту короткое содержательное имя (например, calculate_sum вместо process_numbers) и снабдите сводкой из одного предложения, которое описывает его основное предназначение (например, «Возвращает сумму двух чисел»). Включите в описание пример вызова с типичным вводом и выводом, чтобы понимание модели основывалось на конкретных условиях, а не на абстракциях. Наконец, установите ограничения ввода, указывая типы и диапазоны (например, «x и y должны быть целыми числами от 0 до 1000»), чтобы сократить неоднозначные совпадения и помочь фундаментальной модели исключить нерелевантные инструменты. Итеративное тестирование с типичными промптами и уточнение каждого описания для ясности и конкретности позволит значительно повысить точность выбора без дополнительного обучения или расширения инфраструктуры. Звучит достаточно просто, но с ростом количества инструментов, регистрируемых вашим агентом, перекрытия в их описаниях часто создают проблемы и становятся источником ошибок. Здесь мы определим другой инструмент, способный вычислять математические выражения и формулы, — у фундаментальных моделей с этим нередко возникают проблемы:
from langchain.tools import tool import requests @tool def query_wolfram_alpha(expression: str) -> str: """ Запрос к Wolfram Alpha для вычисления выражений или получения информации. Args: expression (str): Математическое выражение или запрос для вычисления. Returns: str: Результат вычисления или полученная информация. """ api_url = ( "https://api.wolframalpha.com/v1/result?" f"i={requests.utils.quote(expression)}&" "appid=YOUR_WOLFRAM_ALPHA_APP_ID" ) try: response = requests.get(api_url) if response.status_code == 200: return response.text else: raise ValueError( "Ошибка API Wolfram Alpha API: " f"{response.status_code} - {response.text}" ) except requests.exceptions.RequestException as e: raise ValueError(f" Не удалось выполнить запрос к Wolfram Alpha: {e}") @tool def trigger_zapier_webhook(zap_id: str, payload: dict) -> str: """ Запуск вебхука Zapier для выполнения предопределенного Zap-сценария. Args: zap_id (str): Уникальный идентификатор Zap-сценария для запуска. payload (dict): Данные для отправки вебхуку Zapier. Returns: str: Сообщение о подтверждении успешного запуска Zap-сценария. Raises: ValueError: В случае неудачного запроса к API или получения ошибки в ответе. """ zapier_webhook_url = f"https://hooks.zapier.com/hooks/catch/{zap_id}/" try: response = requests.post(zapier_webhook_url, json=payload) if response.status_code == 200: return f"Вебхук Zapier '{zap_id}' успешно запущен." else: raise ValueError( "Ошибка Zapier API: " f"{response.status_code} - {response.text}" ) except requests.exceptions.RequestException as e: raise ValueError(f"Не удалось запустить вебхук Zapier '{zap_id}': {e}")
Еще один пример инструмента, который вы можете зарегистрировать со своим агентом для оповещения конкретного канала о том, что ваша задача завершилась или требует внимания в паттерне с участием человека в цикле:
@tool def send_slack_message(channel: str, message: str) -> str: """ Отправка сообщения в указанный канал Slack. Args: channel (str): ID или название канала Slack, куда будет отправлено сообщение. message (str): Текст отправляемого сообщения. Returns: str: Сообщение о подтверждении успешной отправки. Raises: ValueError: Если запрос к API завершился ошибкой. """ api_url = "https://slack.com/api/chat.postMessage" headers = { "Authorization": "Bearer YOUR_SLACK_BOT_TOKEN", "Content-Type": "application/json" } payload = { "channel": channel, "text": message } try: response = requests.post(api_url, headers=headers, json=payload) response_data = response.json() if response.status_code == 200 and response_data.get("ok"): return f"Сообщение успешно отправлено в канал Slack '{channel}'." else: error_msg = response_data.get("error", "Unknown error") raise ValueError(f"Ошибка Slack API: {error_msg}") except requests.exceptions.RequestException as e: raise ValueError( 'Не удалось отправить сообщение в канал Slack ' f'"{channel}": {e}' )
После того как инструменты будут определены, мы связываем их с клиентской моделью и предоставляем ей возможность выбрать, какие из них лучше всего выбрать для ввода:
# Инициализация LLM моделью GPT-4o и привязка инструментов llm = ChatOpenAI(model_name="gpt-4o") llm_with_tools = llm.bind_tools([get_stock_price, send_slack_message, query_wolfram_alpha]) messages = [HumanMessage("какова биржевая цена акций Apple?")] ai_msg = llm_with_tools.invoke(messages) messages.append(ai_msg) for tool_call in ai_msg.tool_calls: tool_msg = get_stock_price.invoke(tool_call) messages.append(tool_msg) final_response = llm_with_tools.invoke(messages) print(final_response.content)
Итак, стандартный выбор инструментов предоставляет быстрый интуитивный способ интеграции инструментов в вашу агентную систему без дополнительной инфраструктуры или затрат на обучение. Хотя он хорошо масштабируется для малых инструментариев, тщательное конструирование описаний становится все более важным по мере роста вашей библиотеки инструментов, чтобы обеспечить точность и избежать ошибочного выбора. Этот простой, но мощный подход, объединяющий содержательные описания с итеративным тестированием промптов, позволяет обеспечить хорошую производительность.
Семантический выбор инструментов
Другой способ — семантический выбор инструментов — использует семантические представления для индексирования всех доступных инструментов и семантического поиска для выборки наиболее релевантных из них. Этот подход сокращает количество инструментов, из которых можно выбирать, и полагается на фундаментальную модель для выбора правильного инструмента и параметров из значительно сокращенного набора. Каждое определение и описание инструмента заранее преобразуется в векторное представление (эмбеддинг) с помощью модели типа «только энкодер» (encoder-only), такой как Ada (OpenAI), Titan (Amazon), Embed (Cohere), ModernBERT и т. д., представляющей название и описание в виде вектора чисел. Этот процесс проиллюстрирован на рис. 5.2. Каждый инструмент преобразуется в эмбеддинг для быстрого поиска на основе семантического сходства с запросом задачи.

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

Это самый распространенный паттерн, который рекомендуется для большинства сценариев использования. Обычно он работает быстрее стандартного выбора инструмента, обладает хорошей производительностью и разумной масштабируемостью. Сначала база данных инструментов инициализируется эмбеддингами описаний инструментов:
from langchain.tools import tool from langchain_openai import ChatOpenAI, OpenAIEmbeddings from langchain_core.messages import HumanMessage, AIMessage, ToolMessage import faiss import numpy as np # Инициализация эмбеддингов OpenAI embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) # Описания инструментов tool_descriptions = { "query_wolfram_alpha": "Использование Wolfram Alpha для вычисления " "математических выражений или получения информации.", "trigger_zapier_webhook": "Запуск вебхука Zapier для выполнения " "предварительно настроенных автоматизированных рабочих процессов.", "send_slack_message": "Отправка сообщения в определенные каналы Slack " "для обсуждения с командой." } # Создание векторных форм для описаний всех инструментов tool_embeddings = [] tool_names = [] for tool_name, description in tool_descriptions.items(): embedding = embeddings.embed_query(description) tool_embeddings.append(embedding) tool_names.append(tool_name) # Инициализация векторного хранилища FAISS dimension = len(tool_embeddings[0]) index = faiss.IndexFlatL2(dimension) # Нормализация эмбеддингов для косинусной метрики сходства tool_embeddings_np = np.array(tool_embeddings).astype('float32') faiss.normalize_L2(tool_embeddings_np) # Преобразование списка в FAISS-совместимый формат index.add(tool_embeddings_np) # Сопоставление индекса с функциями инструментов index_to_tool = { 0: query_wolfram_alpha, 1: trigger_zapier_webhook, 2: send_slack_message }
Эти векторные формы для вашего инструмента каталогов достаточно вычислить всего один раз, после чего они будут готовы для быстрого поиска. Чтобы выбрать инструмент, обработайте свой запрос той же моделью эмбеддингов, проведите поиск по базе данных, выберите параметры и вызовите инструмент:
llm = ChatOpenAI(model_name="gpt-4o", temperature=0) def select_tool(query: str, top_k: int = 1) -> list: """ Выбор наиболее релевантного инструмента(-ов) на основе запроса с помощью векторного поиска. Args: query (str): Входной запрос пользователя. top_k (int): Количество наиболее подходящих инструментов для извлечения. Returns: list: Список выбранных функций-инструментов. """ query_embedding = np.array( embeddings.embed_query(query) ).astype('float32') query_embedding = query_embedding.reshape(1, -1) faiss.normalize_L2(query_embedding) D, I = index.search(query_embedding, top_k) selected_tools = [index_to_tool[idx] for idx in I[0] if idx in index_to_tool] return selected_tools def determine_parameters(query: str, tool_name: str) -> dict: """ Использование языковой модели (LLM) для анализа запроса и определения параметров вызова инструмента. Args: query (str): Входной запрос пользователя. tool_name (str): Название выбранного инструмента. Returns: dict: Параметры для вызова инструмента. """ messages = [ HumanMessage( f"Основываясь на запросе пользователя: '{query}', какие" f"параметры надо применить для инструмента '{tool_name}'?" ) ] # Вызов LLM для извлечения параметров response = llm.invoke(messages) # Пример логики для разбора ответов от LLM parameters = {} if tool_name == "query_wolfram_alpha": parameters["expression"] = response['expression'] # Извлечение математического выражения elif tool_name == "trigger_zapier_webhook": parameters["zap_id"] = response.get('zap_id', "123456") parameters["payload"] = response.get('payload', {"data": query}) elif tool_name == "send_slack_message": parameters["channel"] = response.get('channel', "#general") parameters["message"] = response.get('message', query) return parameters # Пример пользовательского запроса user_query = "Реши уравнение: 2x + 3 = 7" # Выбор наиболее подходящего инструмента selected_tools = select_tool(user_query, top_k=1) tool_name = selected_tools[0] if selected_tools else None if tool_name: # Использование LLM для определения параметров на основании запроса # и выбранного инструмента args = determine_parameters(user_query, tool_name) # Вызов выбранного инструмента try: # Предполагается, что каждый инструмент содержит метод `invoke` tool_result = globals()[tool_name].invoke(args) print(f"Инструмент '{tool_name}' Результат: {tool_result}") except ValueError as e: print(f"Ошибка вызова инструмента '{tool_name}': {e}") else: print("Инструмент не выбран.")
Иерархический выбор инструментов
Если ваш сценарий предполагает использование большого количества инструментов, рассмотрите возможность их иерархического выбора. Это особенно уместно, если многие из них семантически сходны и вы хотите повысить точность выбора за счет более высокой задержки и сложности. В этом паттерне инструменты делятся на группы, и каждой дается описание. Механизм выбора инструмента (стандартный или семантический) сначала выбирает группу, а затем проводит вторичный поиск только среди инструментов этой группы. На рис. 5.4 наглядно изображен этот двухэтапный процесс. Запрос сначала маршрутизируется соответствующей группе инструментов, а затем уточняется для выбора одного инструмента в этой группе.

Хотя этот способ медленнее, а в случае его параллелизации потребуются дополнительные затраты, он разбивает сложную задачу выбора инструмента на две более простые подзадачи, что часто приводит к более высокой точности выбора. Создание и сопровождение таких групп требует времени и усилий, и применять этот подход рекомендуется только при наличии действительно большого количества инструментов:
import requests from langchain.tools import tool from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, AIMessage, ToolMessage # Инициализация LLM llm = ChatOpenAI(model_name="gpt-4", temperature=0) # Определение групп инструментов с описаниями tool_groups = { "Computation": { "description": ( "Инструменты для математических вычислений " "и анализа данных." ), "tools": [] }, "Automation": { "description": ( "Инструменты для автоматизации рабочих процессов " "и интеграции различных сервисов" ), "tools": [] }, "Communication": { "description": ( "Инструменты для организации коммуникации " "и обмена сообщениями." ), "tools": [] } } # Определение инструментов @tool def query_wolfram_alpha(expression: str) -> str: api_url = ( "https://api.wolframalpha.com/v1/result?" f"i={requests.utils.quote(expression)}&" "appid=YOUR_WOLFRAM_ALPHA_APP_ID" ) try: response = requests.get(api_url) if response.status_code == 200: return response.text else: raise ValueError( "Ошибка Wolfram Alpha API: " f"{response.status_code} - {response.text}" ) except requests.exceptions.RequestException as e: raise ValueError(f"Не удалось выполнить запрос к Wolfram Alpha: {e}") @tool def trigger_zapier_webhook(zap_id: str, payload: dict) -> str: zapier_webhook_url = f"https://hooks.zapier.com/hooks/catch/{zap_id}/" try: response = requests.post(zapier_webhook_url, json=payload) if response.status_code == 200: return f"Вебхук Zapier '{zap_id}' успешно запущен." else: raise ValueError( "Ошибка Zapier API: " f"{response.status_code} - {response.text}" ) except requests.exceptions.RequestException as e: raise ValueError(f"Не удалось запустить вебхук Zapier '{zap_id}': {e}") @tool def send_slack_message(channel: str, message: str) -> str: api_url = "https://slack.com/api/chat.postMessage" headers = { "Authorization": f"Bearer {SLACK_BOT_TOKEN}", "Content-Type": "application/json" } payload = { "channel": channel, "text": message } try: response = requests.post(api_url, headers=headers, json=payload) response_data = response.json() if response.status_code == 200 and response_data.get("ok"): return f"Сообщение успешно отправлено в канал Slack '{channel}'." else: error_msg = response_data.get("error", "Unknown error") raise ValueError(f"Ошибка Slack API: {error_msg}") except requests.exceptions.RequestException as e: raise ValueError( 'Не удалось отправить сообщение в канал Slack ' f'"{channel}": {e}' ) # Распределение инструментов по группам tool_groups["Computation"]["tools"].append(query_wolfram_alpha) tool_groups["Automation"]["tools"].append(trigger_zapier_webhook) tool_groups["Communication"]["tools"].append(send_slack_message) # -------------------------------------------- # Иерархический выбор инструментов на базе LLM # -------------------------------------------- def select_group_llm(query: str) -> str: """ Использование LLM для определения наиболее подходящей группы инструментов на основе запроса пользователя. Args: query (str): Входной запрос пользователя. Returns: str: Название выбранной группы. """ prompt = f'''Выбор самой подходящей группы инструментов для запроса: '{query}'.\nВозможные группы: Computation, Automation, Communication.''' response = llm.invoke([HumanMessage(content=prompt)]) return response.content.strip() def select_tool_llm(query: str, group_name: str) -> str: """ Использование LLM для определения наиболее подходящего инструмента внутри группы на основе запроса пользователя. Args: query (str): Входной запрос пользователя. group_name (str): Название выбранной группы инструментов. Returns: str: Название выбранной функции-инструмента. """ prompt = f'''Основано на запросе: '{query}', выбрать наиболее подходящий инструмент из группы '{group_name}'.''' response = llm([HumanMessage(content=prompt)]) return response.content.strip() # Пример пользовательского запроса user_query = "Реши это уравнение: 2x + 3 = 7" # Шаг 1: Выбор самой релевантной группы с использованием LLM selected_group_name = select_group_llm(user_query) if not selected_group_name: print("Не найдено релевантной группы инструментов для вашего запроса.") else: print(f"Выбранная группа инструментов: {selected_group_name}") # шаг 2: Выбор самого релевантного инструмента в группе с применением LLM selected_tool_name = select_tool_llm(user_query, selected_group_name) selected_tool = globals().get(selected_tool_name, None) if not selected_tool: print("Не найдено релевантного инструмента в выбранной группе.") else: print(f"Selected Tool: {selected_tool.__name__}") # Подготовка аргументов в зависимости от инструмента args = {} if selected_tool == query_wolfram_alpha: # Предполагается, что весь запрос является выражением args["expression"] = user_query elif selected_tool == trigger_zapier_webhook: # Заполнители для примера args["zap_id"] = "123456" args["payload"] = {"message": user_query} elif selected_tool == send_slack_message: # Заполнители для примера args["channel"] = "#general" args["message"] = user_query else: print("Выбранный инструмент не найден.") # Вызов выбранного инструмента try: tool_result = selected_tool.invoke(args) print( f"Инструмент '{selected_tool.__name__}' " f"Результат: {tool_result}" ) except ValueError as e: print(f"Ошибка: {e}")
Выполнение инструментов
Параметризацией называется процесс определения и задания параметров, управляющих выполнением инструмента в языковой модели. Этот процесс очень важен: именно он определяет, как модель интерпретирует задачу, и настраивает ее ответ для удовлетворения конкретных требований. Параметры задаются в определении инструмента, как более подробно показано в главе 4. Текущее состояние агента, включая прогресс выполнения задачи, добавляется как дополнительный контекст в окно промпта, а фундаментальной модели предлагается заполнить параметры нужными типами данных в соответствии с ожидаемыми входными данными для вызова функции. В окно контекста может включаться дополнительная информация (например, текущее время или местоположение пользователя), что служит ориентиром для функций, зависящих от подобных данных. Рекомендуется пользоваться базовым парсером для проверки того, что ввод отвечает основным критериям типов данных, и предлагать фундаментальной модели исправить передаваемые входные данные, если они не проходят проверку.
После того как параметры будут заданы, начинается фаза выполнения инструментов. Некоторые из них легко выполняются локально, тогда как другие требуют вызова удаленного API. В процессе работы модель может взаимодействовать с разными API, базами данных или другими инструментами для получения информации, вычислений или других действий, необходимых для завершения задачи. Интеграция внешних источников данных и инструментов может значительно улучшить полезность и точность результатов агентов. Логику тайм-аута и повторных попыток необходимо будет скорректировать в соответствии с требованиями по задержке и производительности конкретного сценария использования.
Топологии инструментов
В наше время большинство чат-ботов выполняют одну запрошенную операцию, не умея планировать последовательность действий. Это вполне логично: такой подход проще реализуется и обладает более низкой задержкой. Если ваша команда разрабатывает свою первую систему на базе агентов или если этого достаточно для потребностей вашего первого сценария, вы можете остановиться на этом после прочтения следующего раздела «Выполнение одного инструмента». Однако во многих случаях бывает нужно, чтобы системы могли выполнять сложные задачи, требующие нескольких инструментов. Наделяя агента достаточным набором инструментов, вы даете ему возможность применять их в оптимальном порядке для решения широкого спектра задач. В традиционной разработке ПО проектировщику приходится реализовать программную логику и порядок, в котором должны выполняться действия. Затем можно перейти к реализации инструментов и определить топологию, в которой может работать агент, после чего предоставить возможность динамически конструировать точную композицию в соответствии с контекстом и имеющейся задачей. В этом разделе рассматриваются разные топологии инструментов и обсуждаются присущие им компромиссы.
Оформить предзаказ на книгу «Создание приложений с ИИ-агентами. Проектирование и внедрение мультиагентных систем» можно на нашем сайте.
Для Хаброжителей действует скидка 35% по промокоду — Предзаказ
