Инструменты: руки агента
Петля из прошлого занятия умеет решать и останавливаться, но её мир — один 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 — тот же выбор действия, но со схемами и типами; свой протокол вы теперь понимаете изнутри.
Дальше — про память: почему контекст агента растёт с каждым шагом и как его приручить.
Петля агента: решить → сделать → посмотреть
5 мин
Домашка: агент с одним инструментом
3 мин
Квиз: Петля агента: решить → сделать → посмотреть
6 мин
Инструменты: руки агента
5 мин
Домашка: набор разведчика
3 мин
Квиз: Инструменты: руки агента
5 мин
Память и контекст: что тащим, что выбрасываем
5 мин
Домашка: сжатие истории
3 мин
Квиз: Память и контекст: что тащим, что выбрасываем
6 мин
Свой цикл против LangChain и LlamaIndex
4 мин
HARD-задача: прятки в репозитории
3 мин
Квиз: Свой цикл против LangChain и LlamaIndex
5 мин
Проект «Разведчик»: агент, который знает ваш репозиторий
3 мин