← Модуль 4: Architect
4.2

Tool design: описания = главный механизм выбора

Цель: писать описания инструментов так, чтобы модель выбирала правильный инструмент **надёжно**. Это Домен 2 экзамена Architect (18%).

Главный принцип

Описания инструментов — основной механизм, по которому LLM выбирает, какой инструмент вызвать.

Минимальные описания → ненадёжный выбор. Похожие описания у разных инструментов → модель путается и вызывает не то.

Пример ломающейся системы

У тебя два инструмента:

analyze_content — Analyzes content
analyze_document — Analyzes documents

Что выберет модель когда пользователь говорит "analyze this file"? Никто не знает. Оба описания бесполезны.

Лечение

analyze_content — Analyzes structured text inputs (emails, messages, reviews).
  Input: raw text string.
  Returns: sentiment score + key entities.
  Use when user provides text directly.

analyze_document — Analyzes file-based documents (PDF, DOCX, images).
  Input: file path or URL.
  Returns: OCR + structured extraction.
  Use when user provides a file path or uploaded document.

Теперь выбор однозначный.

Чеклист хорошего описания

  1. Назначение — что именно делает
  2. Форматы ввода — что принимает
  3. Примеры запросов — типичные вызовы
  4. Граничные случаи — когда НЕ вызывать
  5. Пояснения границ — чем отличается от похожих
  6. Формат вывода — что возвращает

Вопрос экзамена (реальный пример)

Логи показывают что агент часто вызывает get_customer когда пользователи спрашивают о заказах ("проверь мой заказ #12345"), вместо lookup_order. Оба инструмента имеют минимальные описания и принимают похожие форматы идентификаторов. Какой первый шаг улучшит надёжность выбора инструментов?

  • A) Добавить few-shot примеры в системный промпт
  • B) Расширить описание каждого инструмента: форматы, примеры, граничные случаи
  • C) Реализовать слой маршрутизации на основе ключевых слов
  • D) Объединить оба в один lookup_entity

Правильный ответ — B. Корневая причина — недостаточные описания. Few-shot (A) добавляет токены без фикса основной проблемы. Маршрутизация (C) — избыточно. Объединение (D) — допустимо архитектурно, но требует больше усилий чем оправдано.

Влияние системного промпта

Осторожно: формулировки в системном промпте могут переопределить описания инструментов.

Пример: системный промпт содержит "always prefer analyze_content for user messages". Даже если описания чёткие — Claude может выбрать analyze_content для файлов.

Правило: держи системный промпт свободным от прямых указаний на инструменты. Пиши роль и цели. Выбор инструментов — через их описания.

tool_choice — принуждение

Агент SDK/API позволяет заставить модель вызвать инструмент:

tool_choice = "auto"              # модель решает (дефолт)
tool_choice = "any"               # обязана вызвать любой
tool_choice = {"type": "tool", "name": "extract_metadata"}  # конкретный

Когда "any"

Когда любой текстовый ответ — ошибка. Например, извлечение структурированных данных: если модель "задумается текстом" вместо вызова extractor'а — пайплайн ломается.

Когда {name: "X"}

Когда порядок обязательный: "сначала валидируй, потом обрабатывай". Forced first call → extract → потом free auto → оставшаяся часть.

Разделение универсальных инструментов

Плохо:

fetch_url — Fetches URL content

Агент может вызвать на любой URL, включая опасные. Нет контекста о типе контента.

Хорошо (разделение):

load_document — Loads PDF/DOCX/TXT from URL. Validates content-type.
  Rejects: images, video, executables.

fetch_api_data — Makes GET request to trusted API endpoints.
  Allowed domains: api.company.com, api.partner.com.

fetch_image — Downloads image for analysis.
  Max size: 10MB. Formats: PNG, JPG, WebP.

Каждый — с чётким контрактом ввода/вывода.

Структурированные ответы об ошибках

Плохо:

{"error": "Operation failed"}

Агент не знает — повторить? Эскалировать? Попробовать альтернативу?

Хорошо:

{
  "isError": true,
  "errorCategory": "transient",
  "isRetryable": true,
  "retryAfter": 30,
  "message": "Database connection timed out",
  "partialResults": null
}

Категории ошибок:

errorCategoryЗначитДействие агента
transientВременная (таймаут, сервис недоступен)Повторить с backoff
validationНекорректный вводНЕ повторять, спросить пользователя
permissionНет доступаЭскалировать на человека
businessНарушение политикиЭскалировать, объяснить

Различие: сбой доступа vs валидный пустой результат

Это часто путают. Но агенту критически важно различать:

  • search_products("foobar") вернул []валидный пустой результат. Продуктов просто нет. Не надо повторять, надо сказать пользователю.
  • search_products("foobar") вернул {isError: true, errorCategory: "transient"}сбой. Повторить.

Если API всегда возвращает [] на оба случая — агент не может принять правильное решение.

Ограничение набора инструментов

18 инструментов у одного агента → надёжность выбора падает катастрофически.

4-5 релевантных роли инструментов → работает хорошо.

Пример: агент "returns specialist" не нуждается в инструментах для новых заказов. Ограничь его.

Практика (20 минут)

Задача 1. Аудит описаний

Возьми свой код где ты используешь Agent SDK или Claude API с инструментами. Прочитай описания. Задай 5 вопросов каждому:

  1. Понятно что делает?
  2. Видны форматы ввода?
  3. Есть граничные случаи?
  4. Можно спутать с другим инструментом из набора?
  5. Есть пример вызова?

Если на 3+ нет — переписывай.

Задача 2. Структурированные ошибки

Добавь isError, errorCategory, isRetryable в свои tool-ответы. Посмотри как агент меняет поведение — повторяет transient, эскалирует business, спрашивает при validation.

Что дальше

Урок 4.3: структурированный вывод. tool_use + JSON schema + Pydantic retry loops. Как получить стабильный JSON от LLM который никогда не ломается.