Engineering the Agentic Stack · Часть 3

Tool use ИИ-агентами: MCP, CLI, Skills и выполнение кода

Автоматический перевод Эта статья была автоматически переведена с оригинальной английской версии.

В части 1 мы рассмотрели циклы ризонинга, а в части 2 — память. Эта статья посвящена слою действий: тому, как агент предоставляет, выбирает и запускает инструменты. Память определяет, что агент знает перед началом шага; этот слой — что он может с этим сделать. В части 4 рассматривается проверка, которая решает, будет ли именованный вызов вообще выполнен, а в части 6 — харнесс, запускающий и вызов, и проверку. В этой статье харнесс — это управляющая программа, которая собирает каждый промпт, отправляет принятые вызовы инструментов и определяет момент завершения задачи, то есть весь обычный код вокруг модели, который вы пишете сами.

История инструментов изменилась в 2025–2026 годах. MCP, Model Context Protocol, предоставил вендорам единый способ подключать внешние сервисы. Агенты с выполнением кода показали, что иногда модель может эффективнее собрать небольшую программу, чем отправить длинную последовательность JSON-вызовов. Anthropic сообщила о сокращении числа токенов на 98,7% в одном сценарии Google Drive-to-Salesforce, а в статье о CodeAct сообщается об улучшении результатов до 20% на используемом наборе бенчмарков. Эти результаты относятся к их задачам и харнессам, а не доказывают универсальное преимущество выполнения кода.

Я сравню JSON-вызовы инструментов, MCP, Skills, CLI-инструменты и выполнение кода именно в таком порядке. В следующем разделе принципы проектирования Agent-Computer Interface (ACI) применяются к Market Analyst Agent — небольшому исследовательскому агенту на LangGraph, которого я создал для части 1: он получает рыночные данные и пишет аналитический отчёт.

Краткое решение по выбору интерфейса см. в статье Интерфейсы инструментов ИИ-агентов.


Пять способов использования инструментов ИИ-агентами

В части 1 reasoning loop выбирал следующий шаг. Часть 2 сохраняла состояние, необходимое для возобновления работы. Граница инструментов находится между ними: она проверяет предложенный циклом вызов, передаёт его на выполнение и возвращает результат обратно в цикл. Эти пять паттернов по-разному балансируют стоимость в токенах, гибкость и контроль исполнения.

Пять модальностей инструментов ИИ-агентов и их компромиссыПять модальностей инструментов ИИ-агентов и их компромиссы

1. JSON-вызовы инструментов: базовый вариант

Исходный паттерн: вы описываете схемы инструментов в JSON, LLM выдаёт структурированные вызовы функций, а ваш код их выполняет. Этот подход хорошо изучен и вполне подходит для небольших наборов инструментов.

# Traditional tool definition — each tool consumes ~550-1,400 tokens (Apideck benchmark)
tools = [
    {
        "name": "get_stock_price",
        "description": "Get the current stock price for a ticker symbol",
        "input_schema": {
            "type": "object",
            "properties": {
                "ticker": {"type": "string", "description": "Stock ticker (e.g., NVDA)"}
            },
            "required": ["ticker"]
        }
    }
]

При 5–10 инструментах накладные расходы приемлемы. Проблема возникает при масштабировании: каждое описание инструмента стоит 550–1 400 токенов. При 20 инструментах вы расходуете 11–28 тыс. токенов ещё до того, как агент начинает ризонинг.

2. MCP для общих интеграций

MCP — стандарт, на котором сошлось большинство вендоров. MCP-сервер — это процесс, который публикует список инструментов через определённый wire protocol: stdio для локального процесса и HTTP для удалённого. Ваш ИИ-агент запускает MCP-клиент, подключается к серверу, запрашивает список доступных инструментов и проксирует к нему вызовы модели. Поэтому один и тот же сервер работает с любым клиентом, поддерживающим этот протокол. В декабре 2025 года Anthropic передала протокол Linux Foundation в рамках Agentic AI Foundation, которую она основала совместно с OpenAI и Block. Google, Microsoft и AWS поддерживают фонд как платиновые участники. OpenAI добавила поддержку MCP в Responses API. Согласно анонсу Anthropic о передаче протокола в декабре 2025 года, экосистема насчитывала более 10 000 активных публичных MCP-серверов и более 97 млн ежемесячных загрузок SDK для Python и TypeScript.

MCP подходит для SaaS-интеграций между вендорами (Figma, Notion, Salesforce), сервисов без CLI-аналогов и сред, которым нужна оркестрация OAuth. Его ценность — в общем слое discovery и транспорта. При этом управление всё ещё зависит от средств аутентификации, авторизации, логирования и деплоя самого сервера.

История с продакшеном сложнее, чем позволяют предположить эти заголовочные цифры.

Первая проблема — поверхность атаки. Проект Vulnerable MCP Project отслеживает 50 уязвимостей в MCP-серверах, 13 из которых имеют уровень Critical; их обнаружили 32 исследователя безопасности. Классы атак включают промпт-инъекции, ошибки валидации входных данных, пробелы в аутентификации и уязвимости сетевой безопасности. Первый реальный вредоносный MCP-сервер появился в сентябре 2025 года: пакет под названием postmark-mcp, который отправлял скрытую копию каждого исходящего письма на адрес злоумышленника.

Больше всего меня беспокоит класс атак с отравлением инструментов. Invariant Labs показала, что отравленные MCP-инструменты могут эксфильтровать данные, даже если их никогда не вызывают. Для запуска атаки модели достаточно просто прочитать метаданные инструмента. В бенчмарках MCPTox, где тестировали 20 LLM-агентов на 45 реальных MCP-серверах, доля успешных атак достигала 72,8%.

Операционная проблема — перерасход токенов. Одна команда, использовавшая MCP-серверы для GitHub, Slack и Sentry (около 40 инструментов), обнаружила, что 55 000 токенов определений схем подставляются ещё до того, как пользователь что-либо спросит. Другая команда сообщила, что 143 000 из 200 000 доступных токенов (72%) занимают одни только определения инструментов.

Сравнение перерасхода токеновСравнение перерасхода токенов

Отчёт Anthropic о Tool Search Tool показал сокращение общего потребления контекста на 85%: примерно с 77 000 токенов до начала работы до 8700, при этом в традиционной конфигурации около 72 000 токенов занимали определения инструментов. Механизм загружает только от трёх до пяти инструментов, нужных запросу, но добавляет этап discovery перед вызовом; для небольших компактных наборов инструментов, которые часто используются в каждой сессии, он менее полезен.

3. Skills: экспертиза, а не выполнение

Agent skills — это открытый формат для упаковки инструкций и вспомогательных файлов. Tools предоставляют возможности (что могут делать агенты), а skills — экспертизу (что агенты знают о способах выполнения сложных задач).

Формат SKILL.md определяет skill как Markdown-файл с YAML frontmatter. Открытый стандарт требует только name и description; в примере ниже также используются два расширения Claude Code — argument-hint и user-invocable, а также его positional-argument placeholder $0:

---
name: deploy
description: Deploy the application to production
argument-hint: "[environment]"
user-invocable: true
---
Deploy the application to the $0 environment (default: staging).
Steps:
1. Run the test suite
2. Build the production bundle
3. Deploy using the deploy script
4. Verify the deployment health check

Skills используют progressive disclosure. При старте загружается около 100 токенов метаданных, а полные инструкции — только после активации skill. Для сравнения: примерно 55 000 токенов могут потребить около 40 MCP tools ещё до начала ризонинга.

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

4. CLI и shell-инструменты

CLI-интерфейсы могут требовать значительно меньше контекста, если модель уже знает нужную команду. Scalekit сообщил о разнице в 4–32 раза по числу токенов между CLI- и MCP-путями по результатам 75 запусков. Это исследование измеряет их tools и задачи; оно не заменяет сравнение ваших собственных определений tools и вывода команд.

Для широко документированных команд, таких как git, docker, kubectl, gh, curl и jq, часто требуется совсем немного вводного текста со схемой. Менее распространённым или внутренним CLI по-прежнему нужны доступная для обнаружения справка, примеры и стабильный машиночитаемый вывод.

В руководстве Ugo Enyioha “Writing CLI Tools That AI Agents Actually Want to Use” сформулированы восемь правил дизайна:

  1. Структурированный вывод обязателен — поддерживайте --json
  2. Коды завершения — это control flow — используйте разные коды для разных типов ошибок
  3. Команды должны быть идемпотентными
  4. Самодокументируемость--help с реалистичными примерами
  5. Проектируйте с учётом компонуемости--quiet для необработанных значений, поддержка stdin
  6. Предоставляйте флаги --dry-run и --yes
  7. Поддерживайте интроспекцию версии
  8. Обрабатывайте аутентификацию через переменные окружения

В CLI отсутствует discovery на уровне протокола. Вызов tools через JSON может передавать типизированные схемы, а MCP стандартизирует discovery tools и для HTTP-транспортов предоставляет модель авторизации. Однако ни один из этих вариантов сам по себе не обеспечивает governance: host, server или харнесс должны применять политики и записывать вызовы, которые требуется аудировать. Судя по тому, к чему приходит большинство команд, CLI лучше использовать для разработки и локальных операций, а MCP — для общей интеграции с внешними сервисами.

5. Выполнение кода для многошаговой работы

Это самое существенное изменение в инструментах для агентов из всех, что я наблюдаю. Вместо того чтобы по одному эмитить структурированный JSON для вызова заранее определённых функций, агент пишет скрипт на Python или bash. Скрипт вызывает несколько tools, обрабатывает результаты с помощью циклов и условных конструкций и возвращает в контекст модели только итоговое резюме.

Anthropic представила Programmatic Tool Calling (PTC) как одну из трёх бета-функций Claude API. Академическая основа подхода — статья CodeAct (Wang et al., ICML 2024). В исследовании проверили 17 LLM и выяснили, что code actions обеспечивали до 20% более высокую успешность выполнения задач и требовали на 30% меньше шагов, чем JSON-альтернативы.

Поток выполнения кодаПоток выполнения кода

Три кейса от вендоров показывают, где этот паттерн может быть полезен: ниже — Vercel и Cloudflare, затем пример Anthropic с анализом расходов. Рассматривайте их как свидетельства от вендоров и повторите сравнение на собственных задачах.

  • Vercel переработала d0 — data agent для преобразования естественного языка в SQL. В старом примере кода указаны 17 tools, а в новом доступны ExecuteCommand и ExecuteSQL. Vercel описывает редизайн как удаление 80% tools, но это заявление из заголовка Vercel, а не процент, который следует из перечисленных в примерах tools. На пяти репрезентативных запросах Vercel сообщает, что успешность задач выросла с 4/5 до 5/5, среднее время выполнения сократилось в 3,5 раза (с 274,8 до 77,4 с), а среднее использование токенов снизилось на 37% (примерно со 102 тыс. до 61 тыс.). Формулировка Vercel: «Лучшими могут оказаться агенты с наименьшим числом tools».

  • Cloudflare разработала «Code Mode», который позволяет агентам писать TypeScript для вызова их API вместо определения схем tools, снижая накладные расходы на контекст. Их аргументация: «В обучающей выборке LLM огромное количество реального TypeScript, но лишь небольшой набор искусственных примеров вызова tools».

Ниже приведён паттерн из документации Anthropic по PTC. В последовательной иллюстрации Anthropic с анализом расходов традиционный вызов tools требует более 20 отдельных проходов инференса, а промежуточные данные проходят через контекст. После поиска команды хост, поддерживающий параллельные вызовы tools, может объединить независимые запросы по расходам в один batch; это не делает оценку «более 20» невозможной. Anthropic сообщает, что сгенерированный код, отвечающий на тот же вопрос, сокращает объём данных, попадающих в контекст, с 200 КБ исходных строк расходов — более 2 000 позиций — до 1 КБ результатов. При выполнении кода агент пишет единый скрипт:

# Agent generates this code, executes in sandbox
import asyncio
import json

async def main() -> None:
    team = await get_team_members("engineering")
    levels = list(set(member["level"] for member in team))
    budgets = dict(zip(
        levels,
        await asyncio.gather(*(get_budget_by_level(level) for level in levels)),
    ))
    expenses = await asyncio.gather(
        *(get_expenses(member["id"], "Q3") for member in team)
    )
    over_budget = []
    for member, employee_expenses in zip(team, expenses):
        total = sum(expense["amount"] for expense in employee_expenses)
        limit = budgets[member["level"]]["travel_limit"]
        if total > limit:
            over_budget.append(
                {"name": member["name"], "spent": total, "limit": limit}
            )
    # Only this final summary returns to the LLM context
    print(json.dumps(over_budget))

asyncio.run(main())

LLM видит только итоговую JSON-сводку, а не тысячи строк расходов, обработанных в сэндбоксе. Экономия характерна не только для отчётов о расходах: в отдельном материале Anthropic о выполнении кода приведено наиболее наглядное число для этого паттерна — workflow от Google Drive до Salesforce, где объём данных сократился примерно со 150 000 токенов до 2 000, то есть на 98,7%.

Эффективность использования токенов — самый очевидный выигрыш. Циклы и условные конструкции почти ничего не стоят, а выполнение кода позволяет обрабатывать ошибки явными обработчиками вместо того, чтобы заставлять модель рассуждать о сбоях на естественном языке. Путь с выполнением кода может не передавать чувствительные промежуточные данные в контекст модели, но это не обеспечивает конфиденциальность: изоляцию, контроль исходящего трафика, credentials с ограниченной областью действия и логирование нужно обеспечивать отдельно.

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


Сравнительная таблица tool calling для ИИ-агентов

ИзмерениеJSON Tool CallingMCPSkills (SKILL.md)CLI/BashCode Execution (PTC)
Лучше всего подходит дляПростых одиночных действийSaaS от разных вендоровДоменных знанийDev-воркфлоу, локальных операцийМногошаговой оркестрации
Накладные расходы на токеныВысокие (550–1 400 на tool)Очень высокие (много tools одновременно)Очень низкие (~100 токенов)Почти нулевыеНизкие (2 meta-tools)
Свидетельства выполнения задачиБазовый уровень в цитируемых исследованияхЗависит от сервера и задачиN/A (слой экспертизы)Измерять на CLI-native задачахВ отчётах CodeAct — до +20%
КомпонуемостьОпределяется харнессом; зависимые вызовы добавляют ходыОпределяется харнессом; зависимые вызовы добавляют ходыВысокая (процедурные знания)Высокая (пайпы, чейнинг)Очень высокая (флоу и фильтрация на стороне кода)
Поверхность безопасностиУмереннаяВысокая (50 отслеживаемых уязвимостей)Зависит от хоста и ресурсовВысокая (доступ к shell)Высокая (нужен сэндбоксинг)
Сложность настройкиНизкаяСредняя (деплой сервера)Очень низкая (markdown)Очень низкая (существующие CLI)Средняя (инфраструктура сэндбокса)
Латентность зависимых вызововОбычно 1 ход модели на вызовОбычно 1 ход модели + транспорт/вызовN/A (слой инструкций)Обычно 1 ход модели на вызов1 ход генерации скрипта; хост выполняет флоу
ОтладкаХорошая (структурированные I/O)Умеренная (транспортный слой)Хорошая (читаемый markdown)Отличная (всё видно)Хорошая (читаемый код)

«Meta-tools» в строке о накладных расходах на токены — это несколько обобщённых точек входа, необходимых агенту, выполняющему код, например ExecuteCommand и ExecuteSQL у Vercel, вместо отдельной схемы для каждой базовой операции. Строки о компонуемости и латентности относятся к вызовам, чьи последующие аргументы зависят от предыдущих результатов в рассматриваемом харнессе или цикле. JSON tool calling и MCP могут выдавать независимые вызовы одновременно, а хост — выполнять их параллельно; для зависимых вызовов обычно нужен ещё один ход модели, чтобы выбрать следующее действие. PTC переносит управление зависимым флоу и фильтрацию на стороне кода в скрипт, а затем возвращает модели сводку; он также может выполнять независимые вызовы параллельно. Значения в ячейках о токенах и успешности задач суммируют приведённые примеры, а не результаты одного контролируемого бенчмарка по всем пяти колонкам.


Интерфейс «ИИ-агент — компьютер» (ACI) для инструментов ИИ-агентов

Термин «Agent-Computer Interface» (ACI) ввели John Yang, Carlos E. Jimenez и их коллеги из Принстона в статье о SWE-agent (NeurIPS 2024). Качество интерфейсов для людей стало предметом отдельной дисциплины — взаимодействия человека и компьютера, или HCI. Авторы статьи утверждают, что агенты на базе языковых моделей заслуживают такого же подхода: это «новая категория конечных пользователей со своими потребностями и возможностями, которым были бы полезны специально разработанные интерфейсы».

Их результаты абляционного исследования позволяют количественно оценить этот эффект. При использовании одной и той же базовой модели GPT-4 Turbo в абляционном исследовании SWE-bench Lite полный ACI SWE-agent достиг 18,0% на 300 задачах, тогда как в режиме только с shell без рабочего демо результат составил 7,3%, а с одним демо — 11,0%. Сравнение показывает, что в этой конфигурации интерфейс и наличие демо существенно меняли производительность; оно не отделяет влияние дизайна интерфейса от всех остальных различий и не доказывает, что модель не выполняла никакой работы. В рамках той же абляции интерфейса включение линтинга повысило результат в режиме редактирования с 15,0% до 18,0%; на полном тестовом наборе SWE-bench в 51,7% запусков SWE-agent была выполнена хотя бы одна правка, отклонённая линтером до того, как она могла попасть дальше по пайплайну.

Принципы дизайна ACIПринципы дизайна ACI

Anthropic сделали ACI фундаментальной концепцией в своём руководстве «Создание эффективных ИИ-агентов», включив его в число трёх ключевых принципов: «Тщательно проектируйте интерфейс между ИИ-агентом и компьютером, уделяя особое внимание документации и тестированию инструментов». Их практическая рекомендация звучит так: «Полезно подумать о том, сколько усилий вкладывается в интерфейсы взаимодействия человека с компьютером, и планировать такие же затраты на создание качественных интерфейсов для ИИ-агентов».

Четыре принципа ACI на практике

1. Действия должны быть простыми и понятными. Самая распространённая ошибка — сопоставлять API-эндпоинты и действия один к одному. Вместо list_users, list_events, create_event реализуйте schedule_event, который за один вызов находит доступные варианты и создаёт расписание. Вместо read_logs реализуйте search_logs, который возвращает только релевантные строки с контекстом.

2. Действия должны быть компактными и эффективными. Объединяйте важные операции в минимальное число действий. В Market Analyst Agent я объединяю получение цен и базовых метрик в один инструмент get_stock_snapshot, вместо того чтобы требовать отдельные вызовы для цены, объёма, капитализации и коэффициента PE.

3. Обратная связь от окружения должна быть информативной, но краткой. Не возвращайте сырой HTML или полный payload API. Преобразуйте малопонятные ID в семантические имена. В тестировании Anthropic добавили enum response_format, чтобы агент мог запрашивать краткий ответ (~72 токена) или подробный (~206 токенов), то есть разница в стоимости по токенам составляет примерно 3 раза.

4. Валидация должна снижать распространение ошибок. Автоматическое обнаружение ошибок помогает агентам быстро распознавать и исправлять ошибки. В SWE-agent кастомный редактор файлов со встроенным линтингом автоматически отклоняет синтаксические ошибки — это и есть шаг валидации, лежащий в основе указанного выше показателя 51,7%. Здесь валидируются входы и выходы инструмента, а не выполняется фильтрация контента вокруг вызова модели, которую делают продукты с гардрейлами из части 4; для обоих случаев используется одно и то же слово. Я применяю тот же принцип в Market Analyst Agent, валидируя аргументы инструментов с помощью схем Pydantic перед выполнением:

from pydantic import BaseModel, Field, field_validator

from market_analyst.utils import normalize_ticker

class StockQuery(BaseModel):
    """Validated input for stock queries.

    Pydantic catches malformed tickers before the API call,
    preventing error propagation through the reasoning loop.
    """
    ticker: str = Field(description="Stock ticker symbol (e.g., NVDA)")

    @field_validator("ticker")
    @classmethod
    def validate_ticker(cls, v: str) -> str:
        return normalize_ticker(v)

class StockHistoryQuery(StockQuery):
    """Validated input for price history queries."""

    period: str = Field(default="1mo", description="Time period: 1d, 5d, 1mo, 3mo, 6mo, 1y")

    @field_validator("period")
    @classmethod
    def validate_period(cls, v: str) -> str:
        valid = {"1d", "5d", "1mo", "3mo", "6mo", "1y"}
        if v not in valid:
            raise ValueError(f"Invalid period: {v}. Must be one of {valid}")
        return v

Общий нормализатор удаляет пробелы по краям и переводит значение в верхний регистр, после чего принимает цифры в тикере и суффиксы с точками или дефисами, например BRK.B и BF-B; StockHistoryQuery, а не StockQuery, владеет period.


Рабочие паттерны дизайна инструментов для ИИ-агентов

В руководстве Anthropic “Writing effective tools for agents” инструменты описываются как «новый вид ПО, отражающий контракт между детерминированными системами и недетерминированными агентами».

Рассматривайте описания инструментов как промпт-инжиниринг

Описания должны занимать как минимум три-четыре предложения и охватывать случаи использования инструмента, обязательные и необязательные параметры, формат вывода и пограничные случаи. Anthropic сообщает, что выбор между неймспейсингом на основе префиксов и суффиксов (asana_search и search_asana соответственно) оказал «нетривиальное влияние» на собственные эвалуации использования инструментов. При этом не уточняется, какая схема лучше, поэтому протестируйте обе на своём наборе инструментов, а не выбирайте префиксы по умолчанию. Anthropic также передала транскрипты своих эвалуационных агентов обратно в Claude Code и позволила ему переписать инструменты. На отложенных тестовых наборах этот цикл выявил дополнительные улучшения — «даже сверх достигнутых нами с помощью “экспертных” реализаций инструментов», независимо от того, были ли эти инструменты написаны исследователями вручную или сгенерированы Claude.

# Bad: vague, no context for when to use
tools = [{
    "name": "search",
    "description": "Search for items",
}]

# Good: specific, with input examples and edge cases
tools = [{
    "name": "search_news",
    "description": (
        "Search for recent news articles about a specific stock or company. "
        "Use this tool when the user asks about recent events, earnings, "
        "announcements, or market-moving news for a specific ticker. "
        "Returns up to 10 articles sorted by relevance. "
        "For company competitors rather than news, use search_competitors instead."
    ),
    "input_schema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "Search query. Examples: 'NVDA earnings Q3 2025', 'Tesla delivery numbers'"
            },
            "max_results": {
                "type": "integer",
                "description": "Max articles to return (1-10, default 5)",
                "default": 5
            }
        },
        "required": ["query"]
    }
}]

Внутреннее тестирование Anthropic показало, что добавление поля input_examples повысило точность обработки сложных параметров с 72% до 90%.

Возвращайте информативный машиночитаемый вывод

Избегайте низкоуровневых идентификаторов (uuid, mime_type). Преобразуйте нечитаемые ID в семантические имена. Структурируйте ответ так, чтобы агент мог рассуждать по нему без парсинга шаблонного служебного текста:

# Bad: raw API response dumped to agent
def get_stock_snapshot(ticker: str) -> dict:
    response = api.get(f"/v1/quotes/{ticker}")
    return response.json()  # 500+ tokens of nested JSON

# Good: high-signal summary the agent can immediately reason about
def get_stock_snapshot(ticker: str) -> dict:
    data = api.get(f"/v1/quotes/{ticker}").json()
    return {
        "ticker": ticker,
        "price": data["regularMarketPrice"],
        "change_pct": round(data["regularMarketChangePercent"], 2),
        "volume": data["regularMarketVolume"],
        "market_cap_b": round(data["marketCap"] / 1e9, 1),
        "pe_ratio": data.get("trailingPE"),
        "summary": f"{ticker} at ${data['regularMarketPrice']:.2f} "
                   f"({'up' if data['regularMarketChangePercent'] > 0 else 'down'} "
                   f"{abs(data['regularMarketChangePercent']):.1f}%)"
    }

Возвращайте ошибки, с которыми агентный цикл может работать

Обработка ошибок требует четырёх отдельных механизмов, поскольку они предназначены для разных классов сбоев:

  1. Повторные попытки с экспоненциальной задержкой для временных ошибок
  2. Цепочки fallback моделей при сбоях провайдера
  3. Роутинг по классификации ошибок — временные ошибки отправляются на повторную попытку, ошибки, которые может исправить LLM, возвращаются агенту вместе с контекстом, а ошибки, требующие участия человека, эскалируются
  4. Восстановление из чекпоинта для переживания падений

В “Writing effective tools for agents” Anthropic выступает за понятные ошибки инструментов и дизайн инструментов на основе эвалуаций, но не называет универсальное значение того, какую долю сбоев восстанавливают эти четыре механизма. Измеряйте долю восстановлений, количество повторных попыток и эскалаций на собственном наборе задач.

import httpx
from tenacity import retry, retry_if_exception, stop_after_attempt, wait_exponential

def is_transient_error(error: BaseException) -> bool:
    if isinstance(error, (httpx.TimeoutException, httpx.NetworkError)):
        return True
    if isinstance(error, httpx.HTTPStatusError):
        return error.response.status_code == 429 or 500 <= error.response.status_code < 600
    return False

@retry(
    retry=retry_if_exception(is_transient_error),
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=10),
    reraise=True,
)
def call_stock_api(ticker: str) -> dict:
    """Fetch stock data with automatic retry on transient failures.

    Mechanism 1 of the four above: exponential backoff for rate limits
    and network blips.
    If all retries fail, the error propagates to the agent with
    enough context to decide whether to try a different approach.
    """
    response = httpx.get(
        f"https://api.example.com/v1/quotes/{ticker}",
        timeout=10.0,
    )
    response.raise_for_status()
    return response.json()

Применение паттернов к Market Analyst Agent

Market Analyst Agent из части 1 наглядно показывает эффект такого интерфейса.

Консолидация инструментов

В исходных модулях инструментов были определены get_stock_price, get_company_metrics, get_price_history, два поисковых инструмента и execute_trade. Для базового анализа агенту приходилось выбирать и вызов цены, и вызов метрик; капитализация и P/E были полями get_company_metrics, а не отдельными инструментами. Исходный код до консолидации показывает прежнюю поверхность.

Я преобразовал поверхность market data в 5 высокоуровневых инструментов, следуя принципу ACI — компактным и эффективным действиям. В списке инструментов ReAct репозитория рядом с ними есть ещё четыре: загрузчик навыков, две обёртки над CLI и ограниченный in-process Python evaluator (allowlist для AST, а не сэндбокс; часть 4 подробнее рассматривает этот вопрос). Вместе они покрывают три из пяти описанных выше модальностей. MCP представлен sidecar-компонентом, а не инструментом в этом списке:

До (исходные инструменты)После (инструменты market data)Зачем
get_stock_price + get_company_metricsget_stock_snapshotОдин вызов возвращает базовый снапшот цены и оценки
get_price_historyget_price_historyСохраняется с валидируемыми периодами и сводкой среднего объёма
search_newssearch_newsВозвращает структурированные элементы с извлечёнными ключевыми тезисами
search_competitorssearch_competitorsСохраняет поисковое действие, ориентированное на конкурентов
Нет инструмента для финансовой отчётностиget_financialsВыбирает данные о прибылях и убытках, балансе или движении денежных средств по параметру

Так цена и оценка объединяются в одно определение, отражающее форму задачи, а финансовая отчётность добавляется как отдельное явное действие. Улучшает ли это выбор инструментов, — утверждение, которое нужно проверять на репрезентативных запросах и трейсах.

Структурированные результаты инструментов

Инструменты для акций и новостей возвращают ответы, валидированные Pydantic. CLI- и code-execution-обёртки возвращают str, поэтому приведённые ниже модели описывают структурированные результаты инструментов, а не каждую обёртку в репозитории:

from pydantic import BaseModel

class StockSnapshot(BaseModel):
    """Structured tool response — the agent never sees raw API noise."""
    ticker: str
    price: float
    change_pct: float
    volume: int
    market_cap_b: float
    pe_ratio: float | None
    summary: str  # Human-readable one-liner for direct use in reports

class NewsItem(BaseModel):
    """One news item pre-processed for agent consumption."""
    headline: str
    source: str
    date: str
    relevance_score: float  # Pre-ranked so the agent doesn't waste tokens sorting
    key_points: list[str]  # Extracted by the tool, not the agent

class NewsSearchResult(BaseModel):
    query: str
    results: list[NewsItem]
    summary: str

Поле summary предоставляет агенту готовую строку, которую можно напрямую добавить в отчёт. NewsItem.key_points извлекаются самим инструментом, а не агентом, что экономит токены инференса, которые иначе потребовались бы для разбора текстов статей.


Компромиссы и соображения

Помимо caveat, специфичных для каждого описанного выше паттерна, на выбор влияют несколько общих факторов:

  • Операционные затраты зависят от измерения. Выполнение кода экономит токены, но добавляет латентность холодного старта сэндбокса. MCP экономит время разработки для SaaS-интеграций, но увеличивает накладные расходы на деплой сервера. CLI бесплатен на старте, но его сложнее контролировать при масштабировании. Оптимизируйте решение под фактический боттлнек — стоимость токенов, латентность или операционную сложность.

  • Навыки команды имеют значение. Выполнение кода предполагает, что ваши агенты (и лежащие в их основе модели) умеют надежно генерировать Python или TypeScript. CLI требует знакомства с соглашениями Unix. MCP требует понимания транспортных протоколов и OAuth-флоу. Выбирайте модальность с учетом сильных сторон команды.

  • Консолидация инструментов может зайти слишком далеко. Если один инструмент накапливает несвязанные режимы и аргументы, агент сталкивается с отдельной задачей выбора уже внутри схемы. Используйте эвалуации выбора инструментов и успешности выполнения задач, чтобы найти подходящий интерфейс для вашей нагрузки.

  • Skills основаны на промптах, а не обеспечиваются принудительно. Skill содержит инструкции, которым агент должен следовать, но не гардрейлы, которым он обязан следовать. Skill-бандл может включать произвольные файлы и исполняемые скрипты, поэтому проверяйте источник, ревьювьте бандл, а хост должен применять разрешения для каждого ресурса, который агент может читать, изменять или выполнять. Для критичных воркфлоу сочетайте skills с детерминированной валидацией.

  • Требования к аудиту влияют на выбор. Структурированные вызовы MCP и JSON — удобные события для логирования, но ни один из протоколов из коробки не создает полный аудиторский след. Хост, сервер или харнесс должны записывать вызовы и результаты, а затем применять авторизацию, политики, правила хранения и ревью. Для выполнения кода нужна такая же инструментализация вокруг сэндбокса; одного скрипта и его вывода недостаточно для compliance-аудита.


Три направления развития инструментов для ИИ-агентов в масштабе

Первое — tool RAG для масштабирования. В бенчмарке задач RAG-MCP и стресс-тесте MCP точность выбора инструментов в baseline составила 13,62%; retrieval повысил ее до 43,13%, то есть в 3,2 раза, одновременно сократив количество токенов в промпте более чем на 50%. Этот результат относится к данной конфигурации эвалуации и не является универсальным показателем для наивного выбора инструментов при росте toolset.

Второе — агенты, создающие собственные инструменты. Фреймворк LATM («LLMs As Tool Makers») сформировал двухфазную парадигму: мощная LLM создает переиспользуемые функции на Python, а легковесная LLM использует их. В бенчмарке ToolMaker, включавшем 15 задач по научным статьям с публичными репозиториями кода, где на вход подавались URL GitHub и краткие описания задач, он корректно реализовал 80% задач. Оба направления выводят нас за пределы использования инструментов — к их созданию, а затем к управлению библиотекой сгенерированных инструментов.

Третье — двупротокольный стек A2A + MCP. Google передала A2A Linux Foundation в июне 2025 года. В документации протокола A2A разграничены их зоны ответственности: MCP подключает агента к инструментам и ресурсам, а A2A позволяет независимым агентам находить друг друга, согласовывать взаимодействия, управлять общими задачами и делегировать работу.


Ключевые выводы

  1. Выбирайте интерфейс, исходя из действия: JSON-вызовы — для небольших типизированных операций, MCP — для общих сервисов, Skills — для процедур, CLI — для устоявшихся команд, а код в сэндбоксе — для локальной композиции.
  2. Фиксируйте условия бенчмарка вместе с результатом. CodeAct, Anthropic, Vercel, Cloudflare, Apideck и Scalekit измеряли разные модели, задачи, инструменты и харнессы.
  3. Качество ACI сохраняется при смене протокола. Чёткие действия, компактная обратная связь, валидация и полезные ошибки помогают любой модальности.
  4. Объединяйте пересекающиеся инструменты только после того, как эвалы покажут: меньшая поверхность улучшает выбор или успешность выполнения задач.
  5. Безопасность должна соответствовать мощности исполнения. Shell- и кодовые интерфейсы требуют сэндбоксинга; MCP — ограниченной идентичности и политики сервера; Skills остаются инструкциями, а не механизмом enforcement.

Следующий уровень — политика

Часть 4, Безопасность ИИ-агентов, помещает проверку политики между предложенным вызовом инструмента и его исполнением. Это та же граница инструмента, описанная выше, но с точки зрения стороны, которая говорит «нет». Затем часть 5 помещает инструмент и его сэндбокс внутрь восстанавливаемого рантайма, а часть 6 добавляет второй контракт, который модель никогда не видит: категорию эффекта, правило ретрая и структурированный результат, который acceptance-check может прочитать без парсинга прозы.


Ссылки

Статьи

Инженерные материалы Anthropic

  • Advanced Tool Use / Programmatic Tool Calling — Tool Search (на 85% меньшее суммарное потребление контекста, примерно с 77K до 8,7K), PTC и примеры использования инструментов
  • Code Execution with MCP — сокращение числа токенов на 98,7% (со 150K до 2K токенов) благодаря оркестрации инструментов на основе кода
  • Writing Effective Tools for Agents — инженерия описаний инструментов; примеры входных данных повышают точность; enum response_format (72 против 206 токенов)
  • Building Effective Agents — ACI как фундаментальный принцип дизайна

Спецификации протоколов

Отраслевые кейсы

  • Vercel: мы удалили 80% инструментов нашего агента — в старом примере указано 17 инструментов; новый пример предоставляет ExecuteCommand и ExecuteSQL; Vercel описывает редизайн как удаление 80% инструментов; успешность на пяти типовых запросах выросла с 4/5 до 5/5, скорость увеличилась в 3,5 раза, а число токенов сократилось на 37%
  • Cloudflare: Code Mode — вызовы API на TypeScript вместо схем инструментов
  • Apideck: MCP-сервер съедает ваше контекстное окно — 550–1 400 токенов на инструмент, 55 тыс. токенов для примерно 40 MCP-инструментов, израсходовано 143 тыс. из 200 тыс. токенов контекста
  • Scalekit: бенчмарк токенов MCP и CLI — MCP создаёт в 4–32 раза больше токенов, чем CLI, по результатам 75 прогонов бенчмарка

Безопасность

Дизайн CLI

Демо-проект


Полный код агента-аналитика рынка, включая описанные в этой статье дизайны инструментов, доступен на GitHub.