惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

美团技术团队
W
WeLiveSecurity
Stack Overflow Blog
Stack Overflow Blog
L
LangChain Blog
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
Google DeepMind News
Google DeepMind News
F
Full Disclosure
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Register - Security
The Register - Security
G
Google Developers Blog
C
Check Point Blog
GbyAI
GbyAI
A
About on SuperTechFans
V
Vulnerabilities – Threatpost
T
The Blog of Author Tim Ferriss
T
Tor Project blog
AWS News Blog
AWS News Blog
Cyberwarzone
Cyberwarzone
C
CERT Recently Published Vulnerability Notes
MongoDB | Blog
MongoDB | Blog
Latest news
Latest news
aimingoo的专栏
aimingoo的专栏
U
Unit 42
Y
Y Combinator Blog
P
Privacy International News Feed
Cisco Talos Blog
Cisco Talos Blog
S
Securelist
S
Schneier on Security
雷峰网
雷峰网
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Attack and Defense Labs
Attack and Defense Labs
P
Proofpoint News Feed
C
Cisco Blogs
Webroot Blog
Webroot Blog
T
Troy Hunt's Blog
Google Online Security Blog
Google Online Security Blog
月光博客
月光博客
P
Privacy & Cybersecurity Law Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
罗磊的独立博客
Cloudbric
Cloudbric
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Hacker News: Ask HN
Hacker News: Ask HN
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Microsoft Security Blog
Microsoft Security Blog

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Та самая Оркестрация
ph_piter · 2026-06-25 · via Все публикации подряд на Хабре

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

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

Рис. 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 для итеративного уточнения гипотез на основании новых находок. В типичном цикле агент глубокого исследования:

  1. Планирует общую стратегию поиска (например, идентифицирует ключевые подтемы или источники данных).

  2. Проводит декомпозицию каждой подтемы на конкретные запросы (через SELF_ASK или другие аналогичные методы).

  3. Вызывает инструменты (от академических поисковых API до предметно-специфических баз данных) и анализирует релевантность и надежность каждого результата.

  4. Синтезирует полученные выводы в отчет или набор рекомендаций, используя 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.2. Каждый инструмент или навык кодируется в плотное векторное представление при помощи модели эмбеддингов. Затем эти векторы сохраняются для эффективного семантического поиска, что позволяет системе найти наиболее релевантные инструменты на основании запроса задачи

Рис. 5.2. Каждый инструмент или навык кодируется в плотное векторное представление при помощи модели эмбеддингов. Затем эти векторы сохраняются для эффективного семантического поиска, что позволяет системе найти наиболее релевантные инструменты на основании запроса задачи

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

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

Рис. 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 наглядно изображен этот двухэтапный процесс. Запрос сначала маршрутизируется соответствующей группе инструментов, а затем уточняется для выбора одного инструмента в этой группе.

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

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

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

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% по промокоду — Предзаказ