Вашему агенту нужна не умнее модель, а меньше инструментов
Почти все поломки агентов, которые я разбираю, это ошибки выбора инструмента, а не ошибки рассуждения. Разбираю, как проектировать tool surface: имена по интенту, крупные инструменты, схемы, блокирующие плохие вызовы, progressive disclosure и eval на выбор инструмента в CI.
Pavel Duglas
AI Automation & MVP Architect
В прошлом месяце мне написал клиент с до боли знакомой формулировкой: «агент стал тупее после того, как мы подключили новую интеграцию». Промпт не меняли. Модель не меняли. Изменилось одно: они подключили третий MCP-сервер, и количество инструментов выросло с 12 до 31. Теперь агент тратил внимание на выбор между update_record, patch_row, set_field и write_cell, причём три из них писали в одну и ту же базу, просто через разные сервисы.
Это не проблема модели. Это проблема UX, и пользователь здесь - модель. Я разобрал достаточно таких кейсов, чтобы сказать прямо: в продакшн-агентах неверный выбор инструмента встречается чаще, чем плохое рассуждение. И почти никто это не измеряет.
Поломка, которую никто не логирует
Когда агент ошибается, команда смотрит на финальный ответ и пишет в тикете «галлюцинация» или «нужен промпт получше». Дальше в system prompt дописывают 400 слов инструкций о том, какой инструмент когда применять. Это заплатка поверх плохо спроектированного интерфейса.
Откройте сырые логи tool calls за неделю. Вы найдёте четыре устойчивых паттерна:
- Верный интент, неверный инструмент. Агент хотел найти клиента и вызвал
search_documentsвместоfind_customer, потому что в обоих описаниях есть слово «search». - Верный инструмент, мусорные аргументы. Передал
project: "Acme Corp", где схема ждала slug видаacme-corp, получил пустой результат и уверенно доложил, что такого проекта не существует. - Метание между инструментами. Четыре вызова list-эндпоинтов подряд, потому что ни один инструмент не отвечал на исходный вопрос. Агент пытался собрать ответ руками и выжрал контекст.
- Тихий no-op. Инструмент вернул
{"ok": true}на запись, которая задела ноль строк. Агент отрапортовал об успехе. Никто не замечал три дня.
Всё это лечится на уровне интерфейса. И ничего из этого не лечится более крупной моделью.
Определения инструментов не бесплатны
Есть второй счёт, про который легко забыть. Те самые 31 инструмент занимают примерно 8 400 токенов JSON-схем в каждом запросе цикла. На задаче из 20 шагов это 168 000 токенов чистого меню до начала полезной работы. Вы платите деньгами, latency и вниманием: чем больше инструментов вы показываете, тем ровнее становятся предпочтения модели между ними.
Правило 1: имя по интенту, а не по эндпоинту
Большинство наборов инструментов сгенерированы из API. Поэтому они и выглядят как get_v2_customers_by_id и post_orders_bulk. Модели глубоко безразлична ваша REST-разметка. Она сопоставляет интент пользователя с именем и описанием инструмента.
Называйте по задаче, которую инструмент решает:
find_customer_by_emailвместоget_v2_customersrefund_orderвместоpost_transaction_reversaldraft_reply_for_reviewвместоcreate_message
И пусть описание реально работает. Мой шаблон из трёх строк: что делает, когда использовать и когда использовать не надо. Отрицательная часть - самое полезное предложение, которое вы вообще можете написать.
{
"name": "find_customer_by_email",
"description": "Находит ровно одного клиента по email. Используй это в первую очередь, если пользователь упомянул email. НЕ используй для имён, названий компаний и частичных совпадений - для этого есть search_customers.",
"input_schema": {
"type": "object",
"required": ["email"],
"properties": {
"email": { "type": "string", "format": "email" }
}
}
}
Если два инструмента могут одинаково правдоподобно ответить на одну и ту же фразу пользователя, их надо либо слить, либо прописать явную развязку в оба описания. Неоднозначность между инструментами - это баг, который правится в текстовом редакторе.
Правило 2: один инструмент на одно решение, а не на один вызов API
Самый большой прирост качества я получаю, делая инструменты крупнее. Агент плохо тянет многошаговую обвязку и хорошо принимает одно решение за раз. Значит, обвязку надо убрать внутрь инструмента.
Реальный пример. У саппорт-агента было пять инструментов:
list_projects, get_project, list_subscriptions, get_invoice, get_payment_status
Чтобы ответить на «у этого клиента всё оплачено?», нужно было четыре сцепленных вызова, и в каждом протаскивать ID из предыдущего. Ошибки выбора и ошибки аргументов множились. Я заменил все пять на один:
get_account_billing_summary(email_or_slug), который возвращает плоский объект: тариф, статус, последний инвойс, сумма к оплате, дней просрочки, валидность способа оплаты.
Один вызов, одно решение, никакой жонглёрки с ID. Правило, которым я пользуюсь: если агент почти всегда вызывает B сразу после A, сделайте A+B одним инструментом. Детерминированная оркестрация живёт в вашем коде, а не в вероятностном цикле. Это ещё и дешевле: вы не оплачиваете круг рассуждений между каждым хопом.
Правило 3: схема должна делать плохой вызов невозможным
Относитесь к схеме инструмента как к публичной форме. Поля со свободным текстом - это место, где агенты умирают.
enumдля всего, где значений конечный набор.status: "open" | "pending" | "closed"всегда лучше, чемstatus: string.- Никогда не принимайте человекочитаемую подпись там, где нужен ID. Если очень нужно - принимайте оба варианта и резолвите на сервере.
- Ставьте
"additionalProperties": false. Выдуманные параметры должны падать громко, а не молча отбрасываться. - Держите обязательных параметров не больше трёх. Если их семь, у вас на руках workflow, а не инструмент.
- Опасный флаг выносите в отдельный инструмент. В
delete_records(confirm: true)рано или поздно прилетитconfirm: true. В отдельныйdelete_recordsза approval-гейтом - нет.
И валидируйте до исполнения той же схемой, которую вы объявили. Ошибки валидации я возвращаю в цикл текстом, а не бросаю исключение, и это ведёт прямо к следующему правилу.
Правило 4: сообщения об ошибках - это тоже промпт
Всё, что инструмент возвращает при сбое, становится частью контекста и формирует следующий вызов. {"error": "not found"} не учит ни о чём: агент либо ретраит то же самое, либо сдаётся и придумывает ответ.
Пишите ошибки, в которых лежит решение:
{
"error": "unknown_project",
"message": "Проекта со slug 'Acme Corp' нет. Slug - в нижнем регистре через дефис. Ближайшие совпадения: acme-corp, acme-corp-eu. Если нужен полный список - вызови list_projects.",
"retryable": true
}
То же и с пустым результатом на записи. Запись, задевшая ноль строк, это не успех. Возвращайте {"updated": 0, "warning": "ни одна строка не подошла под фильтр, проверь id"}, и целый класс тихих no-op багов почти исчезает.
Правило 5: progressive disclosure вместо одного гигантского меню
Не нужно показывать все 31 инструмент на каждом шаге. Работают два подхода.
Наборы инструментов по фазам. Реальные процессы почти всегда небольшой конечный автомат: разбор, сбор данных, действие, отчёт. Показывайте только те инструменты, которые легальны в текущей фазе. На разборе - только read-only-запросы. На действии - записи, и только после прохождения гардрейлов. Это срезает токены и убирает целые категории неверных вызовов структурно, а не убеждением.
Поиск инструментов как мета-инструмент. Для больших наборов оставьте 5-8 ядровых инструментов плюс find_tool(intent: string), который возвращает 3 наиболее подходящих определения из реестра. Агент просит возможность, вы подкладываете схемы just-in-time. Стоит один лишний хоп, зато масштабируется на сотни интеграций без размывания предпочтений модели.
По умолчанию беру фазы для всего до ~20 инструментов и поиск инструментов выше этого порога.
Правило 6: измеряйте точность выбора инструмента в CI
Эту часть пропускают почти все. Нельзя улучшить то, что вы не оцениваете.
Соберите небольшой разметочный набор: 50-80 реалистичных первых сообщений пользователя, для каждого - ожидаемое имя инструмента и ожидаемые ключевые аргументы. Прогоните через модель с вашими настоящими определениями инструментов, исполнять первый вызов не обязательно. Считайте три числа:
- Top-1 accuracy - выбран ли правильный инструмент.
- Валидность аргументов - проходит ли payload по схеме.
- Пары путаницы - какой инструмент выбрали вместо нужного. Это и есть ваш бэклог на редизайн.
На той системе с 31 инструментом базовая точность была 71%. После склейки цепочек в четыре крупных инструмента, добавления отрицательных формулировок в девять описаний и разделения записей по фазам вышло 96% на 12 инструментах. Модель не менялась, system prompt не переписывался. Теперь этот eval крутится на каждом PR, который трогает определения инструментов, а падение ниже 92% валит билд.
Самое ценное - матрица путаницы. Если search_documents отъедает 8 вызовов у find_customer_by_email, вы точно знаете, какое предложение переписать.
Чеклист, который я прогоняю перед релизом агента
- Посчитать инструменты. Если их больше 15 и нет progressive disclosure, сначала лечим это.
- Каждое имя описывает интент, а не эндпоинт.
- В каждом описании есть строка «НЕ используй для…».
- Нет двух инструментов, одинаково хорошо отвечающих на одну фразу пользователя.
- Никакого свободного текста там, где нужен enum или ID, и
additionalProperties: falseвезде. - Цепочки, которые агент всегда проходит целиком, склеены в один инструмент.
- Деструктивные действия - отдельные инструменты за гейтом, без булевой лазейки.
- Ошибки называют способ исправления и говорят, имеет ли смысл ретрай.
- Запись с нулём строк рапортует ноль строк, а не успех.
- Eval на выбор инструмента существует и блокирует мерж.
Ничего героического тут нет. Это обычное проектирование API под очень буквального, очень быстрого и слегка самоуверенного потребителя. Но каждый час, вложенный в чистку набора инструментов, приносил мне больше надёжности, чем любой час переписывания system prompt.
Прежде чем апгрейдить модель, прочитайте свои определения инструментов так, как их читает модель. Если вы сами замешкались на выборе - она уже замешкалась до вас.
Вопросы и ответы
Сколько инструментов можно дать агенту без потери качества?
По моему опыту до 10-15 инструментов большинство моделей держат уверенно, если имена и описания не пересекаются. Выше этого числа начинает расти доля неверных выборов и заметно растут расходы: схемы улетают в каждый запрос цикла. Если вам реально нужно больше, не увеличивайте плоский список, а включайте progressive disclosure: наборы по фазам процесса или мета-инструмент поиска, который подкладывает нужные 3 схемы по запросу.
Как быстро понять, что проблема в инструментах, а не в промпте?
Соберите 50-80 типичных первых сообщений пользователя, разметьте ожидаемый инструмент и ключевые аргументы, прогоните через модель с реальными определениями и посчитайте top-1 accuracy. Если она ниже 90%, никакой рерайт промпта вас не спасёт: сначала правьте tool surface. Дополнительно смотрите матрицу путаницы. Если два конкретных инструмента постоянно подменяют друг друга, значит их описания неотличимы для модели, и это правится текстом, а не более крупной моделью.
Не превратятся ли крупные инструменты в негибкий монолит?
Риск есть, поэтому я склеиваю только те цепочки, которые агент проходит целиком практически всегда: вызов B почти никогда не имеет смысла без A. Такие цепочки уже являются детерминированной логикой, и их место в коде, а не в вероятностном цикле. Если же шаг реально ветвится и у агента есть осмысленный выбор на середине пути, оставляйте инструменты раздельными. Практический тест: посмотрите в логах, в каком процентe случаев за A следует B. Выше 90% - склеивайте.
Похожие статьи
Сделаю под ключ
Соберу ИИ-агента под реальную задачу
С инструментами, памятью и логами, чтобы он работал в проде, а не только в демо.
от 1 500 $ · 1-2 недели