Инструменты: руки агента

Петля из прошлого занятия умеет решать и останавливаться, но её мир — один read_file, притом выдуманный. Пора выдать агенту настоящие руки: набор инструментов, по которому он сам выбирает, чем коснуться репозитория. Заодно выяснится неудобная правда: качество агента зависит от описаний инструментов едва ли не больше, чем от качества модели.

Инструмент = функция + паспорт

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

Отсюда правила паспортов, один в один из промпт-инжиниринга первого модуля:

  • имя — глагол действия: read_file, list_dir, search. Не fs_util.

  • описание отвечает на «когда это звать», а не «как это устроено»: «читает текстовый файл целиком; возвращает ошибку, если файла нет» — хорошо; «функция открывает дескриптор с буферизацией» — никому.

  • аргумент описан форматом: «относительный путь от корня репозитория, например src/app.py».

Паспорта живут в том же месте, что и функции, и попадают в промпт первым шагом. Промпт шага теперь трёхчастный: задача → список паспортов инструментов → наблюдения. Модель читает паспорта на каждом шаге — и это не расточительство, а плата за осмысленный выбор (позже вы увидите, что этот блок тоже кэшируется).

Диспетчер: словарь и ничего больше

Механика вызова умещается в словарь имя -> функция. Петля из прошлого занятия уже умеет с ним работать: tools.get(name), вызов, наблюдение. Два решения, которые стоит принять сразу:

Единая сигнатура. Все инструменты принимают одну строку и возвращают одну строку. Это урезание — настоящий tool calling принимает структурные аргументы — но для текстового протокола оно честное: разбор аргумента остаётся внутри инструмента, а петля не знает о типах.

Ошибка — тоже строка. «ошибка: файла нет» как возврат функции, не как исключение. Исключение из инструмента пробьёт петлю насквозь; строка-ошибка станет наблюдением, и модель попробует другой путь. Порог тот же, что в прошлом занятии: падает только нечинимое следующим шагом.

Песочница: агент в клетке

Первые настоящие инструменты — файловые: list_dir, read_file, search. И тут же первый настоящий вопрос безопасности: агенту, который читает файлы по строке от модели, нельзя доверять произвольный путь. read_file("../../../../etc/passwd") или read_file("C:\\Users\\...") — не злонамеренность, а обычный промах модели; но результат одинаковый.

Решение — песочница: все пути вычисляются от корня-репозитория, и выход за корень пресекается. Проверка «путь внутри корня» в питоне — Path.resolve() плюс is_relative_to(); после resolve() всякие ../ схлопываются, и сравнение становится честным. То же правило будет сопровождать весь курс: у агента не больше прав, чем нужно для задачи, — а в модуле про продакшен мы досмотрим эту тему до конца (там появятся лимиты и запреты посложнее).

Function calling: то же самое, но структурно

Ручной протокол ACT: имя аргумент вы сделали сами и теперь понимаете каждую строку. В бою у провайдеров есть готовый механизм — function calling (он же tool calling): вы отдаёте API схемы инструментов (имя, описание, типы параметров), а модель возвращает структурированный вызов — готовый словарь с аргументами, без парсинга строк. Смысл ровно тот же, что у вашего протокола: выбрать действие и аргумент. Разница — в надёжности и типах: нет опечаток в имени инструмента (схема валидируется), аргументы приходят типизированными.

Почему курс не переходит на function calling немедленно? Потому что сначала вы должны почувствовать, что именно фреймворк берёт на себя: парсинг, валидацию аргументов, возврат результата в контекст. Это знание стоит дороже удобства. В devbuddy мы останемся на текстовом протоколе до конца (он работает с любым OpenAI-совместимым провайдером, включая локальные, где tool calling бывает капризен) — а в боевом коде выбор за вами.

Что запомнить:

  • Инструмент = функция + паспорт; паспорт — «когда звать», не «как устроено». По паспортам модель выбирает.

  • Единая сигнатура str -> str и ошибки-наблюдения вместо исключений — конвенции, на которых держится петля.

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

  • Function calling — тот же выбор действия, но со схемами и типами; свой протокол вы теперь понимаете изнутри.

Дальше — про память: почему контекст агента растёт с каждым шагом и как его приручить.

  • theory icon

    Петля агента: решить → сделать → посмотреть

    5 мин

  • homework icon

    Домашка: агент с одним инструментом

    3 мин

  • quiz icon

    Квиз: Петля агента: решить → сделать → посмотреть

    6 мин

  • theory icon

    Инструменты: руки агента

    5 мин

  • homework icon

    Домашка: набор разведчика

    3 мин

  • quiz icon

    Квиз: Инструменты: руки агента

    5 мин

  • theory icon

    Память и контекст: что тащим, что выбрасываем

    5 мин

  • homework icon

    Домашка: сжатие истории

    3 мин

  • quiz icon

    Квиз: Память и контекст: что тащим, что выбрасываем

    6 мин

  • theory icon

    Свой цикл против LangChain и LlamaIndex

    4 мин

  • homework icon

    HARD-задача: прятки в репозитории

    3 мин

  • quiz icon

    Квиз: Свой цикл против LangChain и LlamaIndex

    5 мин

  • project icon

    Проект «Разведчик»: агент, который знает ваш репозиторий

    3 мин

🎯
Тренажёр собеседованияЗакрепите знания перед интервью