Глава 03 · Расширения
Tools — руки и глаза агента
Инструменты — это санкционированный прокол sandbox: модель просит harness что-то сделать в реальном мире и получает результат обратно как новое сообщение. Без них агент только пишет текст; с ними — читает файлы, ходит в API и переписывает код.
Что добавляют tools к обычному чату
Языковая модель сама по себе — это функция «текст → текст». Она не открывает файлы, не ходит в сеть, не выполняет shell-команды; без расширений она может только описать, как такое сделать. Tools — механизм, через который модель получает санкционированный доступ к окружению: вместо того чтобы написать «прочитай main.py», она формирует структурированный запрос, harness его исполняет и кладёт результат в историю. Anthropic формулирует это так: «Tool use lets Claude call functions you define or that Anthropic provides. Claude decides when to call a tool based on the user's request and the tool's description, then returns a structured call that your application executes».
Главное: модель никогда не «звонит» сама. Она возвращает блок tool_use — структурированную просьбу; всё, что происходит в реальном мире, делает harness и только он отвечает за побочные эффекты. Эта строгая граница и есть фундамент безопасности: позволенный набор инструментов плюс правила вокруг них (глава «Permissions») полностью описывают то, что агент способен сделать с системой.
Tool schema: name, description, input_schema
Чтобы модель «узнала» об инструменте, harness кладёт его описание в параметр tools при вызове /v1/messages. У каждого инструмента три обязательных поля: name (короткий идентификатор), description (что инструмент делает и когда его звать) и input_schema (JSON Schema аргументов). Минимальный пример:
{
"name": "list_files",
"description": "Возвращает список файлов и подкаталогов внутри указанного абсолютного пути. Используй, когда нужно понять структуру каталога перед чтением конкретного файла.",
"input_schema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Абсолютный путь к каталогу (например, /home/dev/projects)."
}
},
"required": ["path"]
}
}
Описание важнее имени. Модель «понимает» инструмент по description, не по имени переменной в коде. Anthropic в «Building Effective Agents» советует относиться к этому как к docstring для джуниора: примеры, edge-кейсы, формат ввода, явные границы между похожими инструментами. Они же приводят показательный пример из SWE-bench: на оптимизацию tools у них ушло больше времени, чем на основной промпт, а замена относительных путей на абсолютные в схеме FileEdit устойчиво улучшила качество — модель перестала путаться после cd.
Протокол: tool_use → tool_result
Поворот цикла с инструментом всегда выглядит одинаково. Сначала модель возвращает в ответе блок tool_use с собственным id, именем инструмента и аргументами. Поле stop_reason у такого ответа — "tool_use", это сигнал harness, что нужно действовать. Harness целиком копирует ответ модели (включая tool_use-блоки) в messages как сообщение assistant, исполняет вызов и формирует следующее сообщение с ролью user, внутри которого — блок tool_result:
{
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": "toolu_01A...",
"content": "main.py\nsrc/\ntests/\nREADME.md"
}]
}
Ключевое поле — tool_use_id: оно ссылается на id блока tool_use, который мы закрываем. Отсюда центральный инвариант: каждый tool_use в assistant-сообщении обязан быть закрыт tool_result в следующем user-сообщении. Если хоть один tool_use_id не найдёт пары, API вернёт ошибку валидации и цикл оборвётся. Логика как у скобок: открыли — закрывай.
Содержимое tool_result.content может быть строкой или массивом блоков (включая image). Модель видит ровно то, что вы туда положили. Ошибку инструмента передают тем же блоком с полем is_error: true — это не исключение для цикла, а другой результат, на который модель сама решает, как реагировать (повторить, поправить, спросить пользователя).
Параллельные tool calls
Модель не обязана просить по одному инструменту за раз. В одном ответе может быть несколько tool_use-блоков подряд — например, «прочитай эти три файла». В таком случае harness может (и часто должен) исполнить их параллельно: для read-only-инструментов это очевидный выигрыш по латентности. Главное правило — симметрия: сколько tool_use ушло, столько tool_result должно вернуться в следующем user-сообщении, в одном content-массиве и с правильными tool_use_id. Порядок результатов может не совпадать с порядком запросов — связь идёт по id.
Параллельность — свойство harness, а не модели. claude-cli помечает каждый tool флагом isConcurrencySafe: read-only по умолчанию параллелится, write-операции — нет. Если хоть один вызов в пачке небезопасен, harness исполняет всю пачку последовательно. В 07-tool-surface это видно в дефолтах: «every tool starts assumed-unsafe; opt-in via override».
Built-in vs custom vs MCP
С точки зрения протокола все инструменты одинаковы — единый Tool-контракт: name, description, input_schema, исполняющая функция. Источник реализации различает три класса.
Built-in tools — базовый набор, который харнесс приносит с собой: в claude-cli это BashTool, FileReadTool, FileEditTool, GrepTool, WebFetchTool, TodoWriteTool и ещё десяток, собираемый функцией getAllBaseTools. Custom tools — инструменты, которые добавляет конкретное приложение через тот же параметр tools API: «найди пользователя по email», «сделай платёж». Снаружи модель не видит разницы — это одинаковые JSON-схемы. MCP tools приходят из внешних серверов по Model Context Protocol: harness держит клиента, MCP-сервер публикует свои инструменты, harness склеивает их с остальной поверхностью. Имя MCP-инструмента префиксуется (mcp__server__tool), чтобы permission-слой мог адресовать целый сервер.
Главное следствие единого контракта: permission gate, hooks, рендеринг и логика повторов работают одинаково для всех трёх классов. claude-cli формулирует это так: «Built-in tools, MCP tools, REPL inner tools, agent skills, and bundled-via-feature-flag tools all implement the same Tool interface». Цена нового инструмента — одна запись в каталоге и одна функция.
Что ВАЖНО не делать
Самые частые ошибки при работе с tools — не на уровне протокола, а на уровне дизайна. Не описывайте инструменты «слишком вежливо». Размытая фраза вроде «помогает работать с файлами» оставляет модели слишком большой простор для интерпретации, и она начинает путать ваш инструмент с соседним. Пишите конкретно: что возвращает, что не возвращает, в каком формате аргументы. OpenAI прямо предупреждает: «issue isn't solely the number of tools, but their similarity or overlap» — десять «похожих» инструментов работают хуже, чем пятнадцать с чёткими границами.
Не смешивайте слишком много в один tool. Соблазнительно сделать универсальный do_anything(action, params), но модель плохо выбирает действие «по строке», особенно когда вариантов больше трёх. Лучше разделить на send_email, create_user, cancel_order — каждый с минимальным input_schema. Не забывайте про идемпотентность. Модель может повторить вызов из-за recovery-итерации, частичного сбоя или просто потому, что «не уверена». Если tool кладёт деньги или пишет в БД, проектируйте его так, чтобы повторный вызов с теми же аргументами не дублировал эффект — и явно пишите это в description.
И последнее: tools без permissions — это дверь без замка. Контракт «модель просит, harness делает» элегантен ровно до тех пор, пока harness слепо исполняет всё подряд. Реальная безопасность собирается в главе «Permissions»: allow/deny-правила, две фазы валидации, hooks на PreToolUse/PostToolUse.
Tool access is one of the highest-leverage primitives you can give an agent. On benchmarks like LAB-Bench FigQA (scientific figure interpretation) and SWE-bench (real-world software engineering), adding even basic tools produces outsized capability gains, often surpassing human expert baselines.
— Anthropic Docs, «Tool use with Claude»Источники главы
- [ant] Tool use with Claude — Anthropic Docs (контракт
tool_use/tool_result, client vs server tools, strict tool use) - [ant] Building Effective Agents — Anthropic Engineering (Appendix 2: «Prompt engineering your tools»: ACI, абсолютные пути, poka-yoke)
- [oai] A Practical Guide to Building Agents — OpenAI (Defining tools: Data / Action / Orchestration; tool overload и similarity)
- [cli] Конспект: Tool Surface (единый
Tool-контракт, fail-closed defaults, MCP-tail merge,shouldDefer/alwaysLoad)