Технологии

Агенты на маленькой локальной модели: где предел

Компактные модели плохо соблюдают формат вызова инструментов и разваливаются на третьем-четвёртом шаге цепочки. Разбираем причины по отдельности и приёмы упрощения задач.

«Модель отвечает нормально, но инструменты не вызывает» — либо вызывает один раз, а на третьем шаге начинает пересказывать, что она якобы сделала, не сделав ничего. Дальше следует круг: поменять модель, переписать промпт, поменять обратно.

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

#Быстрая проверка

Две пробы, отсекающие половину случаев. Обе выполняются за минуту.

Проба 1. Один инструмент, одна фраза. Оставьте включённым ровно один читающий инструмент и задайте запрос, где он очевидно нужен: «покажи список файлов». Посмотрите в лог.

  • Вызова нет вовсе → проблема в описании инструмента или в промпте, а не в размере модели.
  • Вызов есть и правильный → формат модель держит, дело в длине цепочки. Идите к причине 2.
  • Вызов есть, но синтаксис сломан → причина 1.

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

#Причина 1. Сломанный синтаксис вызова

Признак. В ответе модели видны обрывки конструкции вызова, но парсер её не распознал: не закрыта скобка, кавычки не того типа, имя инструмента написано с ошибкой, аргументы не в том формате.

Проверка. Посмотрите сырой текст ответа модели до разбора, а не итоговый ответ. Если конструкция там есть, но кривая — это она.

Решение. Сделайте парсер снисходительным: в Persona разбор принимает и корректный JSON, и одиночный позиционный аргумент, который трактуется как путь — компактные модели регулярно пишут list_dir(D:\Projects) вместо полноценного объекта. Принимайте синонимы имён параметров: path, filepath, file, filename — дешевле принять все, чем добиваться одного. И давайте в описании пример значения, а не тип: модель копирует пример надёжнее, чем выводит формат из слова «строка».

Механика самого протокола вызова разобрана в материале про function calling.

#Причина 2. Развал на третьем-четвёртом шаге

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

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

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

#Причина 3. Контекст переполнен наблюдениями

Признак. Ответы становятся общими, модель «забывает» исходную задачу, повторяет то, что уже делала.

Проверка. Сложите объём: описания инструментов плюс системный промпт плюс все наблюдения. Сравните с окном модели. Часто выясняется, что половину окна занимает содержимое одного прочитанного файла.

Решение. Поставьте предел на один результат инструмента и на сумму результатов за ход — в коде чата Persona это 4000 символов на вызов и 24000 суммарно, не потому что числа правильные для всех, а потому что предел должен существовать. Инструменты должны отдавать выдержки, а не всё содержимое: поиск по файлу лучше чтения файла. И держите список инструментов коротким — каждое описание занимает место.

#Причина 4. Слишком много инструментов

Признак. Модель вызывает не тот инструмент: вместо поиска — чтение, вместо списка каталога — поиск по коду.

Проверка. Сократите список до двух-трёх инструментов, нужных для конкретной задачи, и повторите. Если выбор стал правильным — причина найдена.

Решение. Для компактной модели держите на задачу единицы инструментов. Имена должны быть непохожими: read_file и open_file в одном списке дают случайный выбор.

#Причина 5. Модель не понимает, что инструменты настоящие

Признак. Ответы вида «я не могу открыть файл», «запустите скрипт сами», «вот как это сделать вручную» — при том что инструмент включён.

Проверка. Есть ли в системном промпте явное утверждение, что инструменты работают по-настоящему, и явный запрет отвечать отказом при наличии подходящего инструмента.

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

#Наблюдаемое качество по размерам

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

Размер модели Один вызов Цепочка 3–4 шага Длинная цепочка Практический вывод
До 3B Нестабильно Как правило, нет Нет Для агентных задач непригодна
7–8B Обычно да Часто ломается к 3–4 шагу Нет Годится для коротких цепочек
13–14B Да Чаще выдерживает Ненадёжно Рабочий минимум для агента
30B и выше Да Да Ограничена окном Ограничение смещается к контексту

Две переменные, которые регулярно упускают. Первая: дообучение на вызовы инструментов важнее размера — компактная модель, которую учили формату вызова, держит его лучше более крупной без такого дообучения; обзор среднего сегмента — в материале про модели 7B и 8B. Вторая: квантизация. Агрессивно сжатая версия сильнее ошибается именно в структурированном выводе, где важен каждый символ.

#Приёмы упрощения задачи

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

  1. Разбейте на прогоны. Три запуска по два шага надёжнее одного на шесть, даже с потерей контекста между ними.
  2. Уберите выбор там, где его нет. Инструмент, который вызывается всегда первым, вызовите кодом и подайте результат как данные.
  3. Замените универсальный инструмент узким. Не «выполнить запрос», а «получить список задач на сегодня».
  4. Заранее подставьте константы. Рабочий каталог, формат даты, имя проекта не должны быть аргументами.
  5. Дайте один пример полного вызова прямо в промпте — готовый, который можно скопировать.
  6. Ограничьте число раундов явно. Упершийся в предел цикл должен вернуть частичный результат, а не молчание.

#Таблица «симптом — причина — проверка»

Симптом Вероятная причина Проверка
Вызовов нет вовсе Описание инструмента или отказной шаблон Один инструмент, прямой запрос
Конструкция вызова кривая Формат в компактной модели Смотреть сырой ответ до разбора
Первый шаг ок, третий нет Предел длины цепочки Десять прогонов, где ломается
Вызван не тот инструмент Слишком много похожих Сократить список до двух
«Я не могу» при включённом инструменте Промпт не утверждает обратное Проверить абзац про инструменты
Тот же вызов трижды Нет дедупликации Сравнить тексты вызовов в логе
Ответ обрывается Контекст переполнен Сложить объём наблюдений

#Если ничего не помогло

Проверьте три вещи, прежде чем менять модель.

Шаблон чата. Неправильно применённый шаблон ломает поведение сильнее всего остального вместе взятого, и симптомы выглядят как «модель глупая». Симптом — ответы формально осмысленные, но не следуют системному промпту.

Уровень квантизации. Сильно сжатая версия хуже держит структурированный вывод. Попробуйте менее агрессивный вариант той же модели, прежде чем брать другую.

Что именно вы просите. Значительная часть жалоб на локальные агенты — это задачи, которые не нужно было отдавать агенту вовсе. Разбор того, когда виновата не модель, — в материале про то, когда модель не виновата.

И честный вывод, если ни одно из перечисленного не помогло: часть агентных сценариев на компактной локальной модели не работает. Не «работает хуже», а не работает. Разумные варианты — сократить сценарий до двух шагов, взять модель крупнее либо для этой конкретной задачи использовать облачную модель, понимая, что текст запроса уйдёт её провайдеру.

#Частые вопросы

#Почему локальная модель не вызывает инструменты?

Три частые причины по убыванию: описание инструмента не даёт модели понять, когда его применять; в системном промпте нет прямого утверждения, что инструменты действительно работают; модель ломает синтаксис вызова, и парсер его не распознаёт. Проверяется по сырому ответу модели до разбора.

#Какая минимальная модель годится для агента?

По наблюдениям, рабочий минимум для цепочек в несколько шагов начинается примерно с 13–14B, а модели 7–8B пригодны для коротких цепочек в один-два вызова. Числа ориентировочные и требуют проверки: дообучение на формат вызова и уровень квантизации влияют не меньше размера.

#Помогает ли увеличение контекстного окна?

Отодвигает предел, но не устраняет его: вместе с окном растёт объём, в котором модель должна удерживать формат, а это как раз слабое место компактных моделей. Обрезка результатов инструментов даёт больший эффект, чем удвоение окна.

#Что делать, если модель повторяет один и тот же вызов?

Добавить дедупликацию по точному тексту вызова на стороне кода и убедиться, что ошибки инструментов возвращаются осмысленным текстом. Модель повторяет вызов, когда видит его в контексте и не понимает из результата, что повторять бессмысленно; разбор механизмов — в материале про зацикливание агента.

#Стоит ли переходить на облачную модель ради агента?

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

#Как понять, где именно ломается цепочка?

Прогнать задачу десять раз и посмотреть по логам, на каком шаге впервые нарушается формат. Стабильное место означает предел модели, разброс — проблему в описаниях инструментов. Как читать такой лог — в материале про трассировку агента.

#Вывод

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

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

Хотите ИИ, который помнит вас?

Persona держит контекст между чатами и работает на вашем железе — если развернуть её у себя и подключить локальную модель.

Создать аккаунт