В чём суть проблемы: кейс pseudobacon и типичный сбой
Пользователь Reddit под ником pseudobacon написал в r/LocalLLaMA, что идея to-do-списков для моделей ему нравится, но несколько перепробованных harness-решений, то есть обвязок, работают, по его ощущению, не очень хорошо (тред Harness to do lists - Model problem or plugin problem?).
Дальше он уточняет, где именно ломается:
Theres no issue in building the to do list, but there seems to be issues when actually checking off those items from the to do list
Список собирается без проблем, а вот отметка выполненных пунктов идёт со сбоями. По его словам, из-за этого подход «kind of makes it pointless»: если прогресс не фиксируется, смысл планирования пропадает.
Сам автор вопроса предполагает два объяснения: ограничение модели и ограничение размера контекста. Прямого ответа, который закрыл бы вопрос, в обсуждении не появилось, и это ключевая деталь для всей темы. Неизвестно, какие harness он пробовал, какая модель стояла за ними и какой был размер контекстного окна. Без этих данных поставить диагноз по одному сообщению нельзя.
Что можно сделать полезного: разобрать механику to-do-списков в агентных системах, перечислить типичные сбои при обновлении статуса и дать пошаговую диагностику. Она покажет, где искать причину в конкретном случае: в модели, в промпте или в логике обвязки.
Как устроены to-do-списки в агентных системах
Жизненный цикл списка задач состоит из четырёх этапов. Агент получает задачу и формирует план. План где-то сохраняется. По ходу работы агент обновляет статус пунктов. Актуальная версия списка влияет на следующие шаги.
Способ хранения определяет harness. Вариантов немного: текст в контекстном окне, структурированный JSON в сообщении, файл на диске, отдельный инструмент с состоянием на стороне обвязки. Отметка пункта во всех схемах означает одно: модель генерирует новое состояние списка, и harness должен корректно его принять. Галочки в человеческом смысле здесь не существует.
Если harness не даёт явного инструмента для обновления статуса, модель делает это обычной генерацией текста. Она переписывает список целиком и рассчитывает, что обвязка поймёт: этот пункт выполнен. Чем длиннее список, тем выше шанс, что при переписывании что-то поедет.
Где хранится состояние списка: контекст, файл или внешняя память
Первый вариант: список живёт в истории сообщений. Настраивать нечего, но контекстное окно конечно. В длинной сессии старые сообщения вытесняются или сжимаются, и список может уйти из поля зрения модели. Как это выглядит при работе с большой кодовой базой и какие подсистемы помогают удержать состояние, разбирали в статье про автоматизацию длительных задач с локальными LLM.
Второй вариант: список пишется в файл. Состояние переживает перезапуск и переполнение контекста, но появляется зависимость от явных операций чтения и записи. Модель должна инициировать обновление, а harness - обработать его и не потерять.
Третий вариант: внешняя память или база данных. Надёжность выше, сложность тоже. Нужен слой, который принимает изменения и отдаёт актуальный список обратно в контекст.
Claude Code закрывает смежную задачу, удержание контекста между сессиями. По документации проекта, память существует в двух формах: автоматический синтез в claude.ai и файловая система на основе CLAUDE.md в Claude Code (Memory Guide). Файловая память даёт постоянный контекст, который переживает несколько сессий и разговоров, в отличие от временных контекстных окон. Система работает на нескольких уровнях, от глобальных личных предпочтений до конкретных подкаталогов.
Файл на диске сам по себе не гарантирует актуальный статус. Кто-то должен выполнить запись. Если модель не вызвала обновление или harness не распознал его, в файле останется старая версия списка.
Почему обновление статуса сложнее, чем создание списка
Создание списка - это генерация нового текста, задача, которая хорошо ложится на языковую модель. Обновление статуса - условное редактирование. Нужно найти конкретный пункт в уже существующей структуре, изменить его состояние, не затронуть остальные пункты и сохранить целостность формата.
Модель генерирует текст последовательно, токен за токеном, и при переписывании списка заново воспроизводит всю структуру. Здесь появляются типичные ошибки: перепутанные пункты, дубликаты, потерянная вложенность. Если harness не даёт инструмента для точечного изменения, вероятность сбоя растёт вместе с длиной списка.
Типичные сбои при отметке выполненных задач
Симптомы, которые встречаются чаще всего:
- агент отмечает пункт, но на следующем шаге ведёт себя так, будто он не выполнен;
- список теряется после длинной цепочки действий;
- агент создаёт новый список вместо обновления старого;
- отмечается не тот пункт;
- после переполнения контекста агент вообще не помнит о существовании списка;
- пункт формально отмечен, а само действие не выполнено.
Симптом и причина здесь не совпадают. Один и тот же сбой могут давать потеря состояния в контексте, ошибка парсинга на стороне harness или отсутствие требования в промпте. Именно поэтому pseudobacon пишет «which kind of makes it pointless»: без надёжной отметки список теряет смысл и превращается в декорацию.
Потеря состояния после переполнения контекста
Контекстное окно конечно, и в длинных сессиях старые сообщения вытесняются или сжимаются. Если to-do-список хранится только в контексте, он может исчезнуть из поля зрения модели. Даже когда список остаётся в истории, модель может уделять ему меньше внимания из-за конкуренции с другими токенами.
Гипотеза самого pseudobacon как раз про это: он спрашивает, не ограничение ли это его модели или размера контекста. Причина правдоподобная, но не единственная. Потеря состояния объясняет сбои в долгих сессиях и ничего не объясняет в коротких.
Ошибки парсинга и интерпретации формата списка
Если список хранится текстом или JSON, модель должна его распарсить, изменить и сериализовать обратно. Ошибки формата ломают всю цепочку: лишние символы, неверная вложенность, смешение Markdown и JSON. Harness не может применить обновление или применяет его не туда.
Пример: harness ожидает JSON с полем status, а модель возвращает Markdown-чеклист с проставленными [x]. Обновление не применяется, ошибка проходит молча, и агент продолжает работать со старым состоянием. Это зона ответственности обвязки и промпта, а не только модели.
Ограничение модели и контекста или проблема обвязки: как разграничить
Полезно держать в голове три слоя, на которых может ломаться отметка пунктов. Первый: способность модели удерживать состояние на длинной последовательности шагов и редактировать структурированные данные. Второй: ограничения контекстного окна. Третий: обвязка и промпт, то есть отсутствие инструмента обновления, неверный парсинг, размытые инструкции.
На практике сбои редко укладываются в один слой. Типичный случай выглядит так: слабый промпт не требует обновления, harness не валидирует ответ, а модель в длинной сессии теряет нить. Разложить это на составляющие можно только диагностикой.
Симптомы, указывающие на ограничение контекста
- сбои появляются только в длинных сессиях;
- список исчезает после определённого числа шагов;
- агент противоречит ранее отмеченным пунктам;
- при сокращении истории проблема уходит.
Контекстное окно - временный ресурс. Без внешней памяти состояние не гарантировано. Расхождение между временным окном и постоянным хранилищем подчёркивает документация Claude Code: файловая память сохраняет контекст между сессиями, тогда как контекстное окно этого не делает (Memory Guide).
Симптомы, указывающие на недоработку harness
- сбой воспроизводится на коротких сессиях с 3-5 пунктами;
- агент отмечает пункт, но изменение не сохраняется;
- формат ответа модели не совпадает с тем, что ждёт парсер;
- нет инструмента для обновления статуса;
- в промпте не сказано, что статус вообще нужно менять.
Если в обвязке нет функции вида update_task(task_id, status), модель вынуждена имитировать обновление текстом. Такой путь ненадёжен по определению: результат зависит от того, угадает ли harness формат. Это инженерная проблема, и решается она на уровне обвязки. Как устроены слои harness и почему дизайн инструментов так сильно влияет на результат, разбирали в статье про harness engineering и четыре слоя архитектуры.
Симптомы, указывающие на промпт
Даже при аккуратном harness слабый промпт даёт сбои. Нет требования обновлять статус после каждого шага. Не задан формат списка. Не сказано, что делать после завершения пункта. Нет инструкции сохранять список в памяти.
Пример: если в системном промпте не написано «после выполнения задачи отметь её в списке», модель может просто не делать этого. Промпт - самый дешёвый для правки слой, с него и стоит начинать диагностику.
Как разные harness-решения управляют состоянием задач
Подходы различаются по надёжности и по объёму работы, который они перекладывают на разработчика.
- Список в контексте без внешней памяти. Просто, но состояние не гарантировано.
- Файловая память. Состояние переживает сессии, нужны явные операции чтения и записи.
- Внешние инструменты и API. Надёжно, но требует больше кода и поддержки.
- Автоматический синтез памяти. Удобно, но менее предсказуемо по сравнению с явным хранилищем.
Контролируемые сравнения обвязок показывают, что дизайн harness влияет на итоговый результат сильнее, чем смена модели. Разбор архитектуры нескольких harness-решений и того, какие узлы определяют надёжность, есть в статье про архитектурные ставки обвязки кодинг-агентов.
Файловая память и постоянный контекст: пример Claude Code
Команда /init создаёт файл CLAUDE.md с базовой документацией проекта и закладывает основу для сохранения контекста между сессиями. Раньше правила добавляли коротким префиксом # прямо в чате, теперь этот способ не работает: рекомендуются команда редактирования памяти или разговорные запросы.
Файл на диске переживает переполнение контекста, и это уже шаг вперёд. Отметка пунктов автоматически надёжнее не становится: запись в файл остаётся отдельной операцией, которую инициирует модель, а выполняет harness.
Явные инструменты для обновления статуса: что это даёт
Когда harness даёт модели отдельный инструмент, ей не нужно генерировать весь список заново. Она вызывает функцию с конкретными параметрами: идентификатор задачи и новый статус. Риск ошибок парсинга и потери состояния падает.
Пример: вместо переписывания Markdown-чеклиста модель вызывает update_task(task_id, status). Требования: harness поддерживает такой вызов, а описание инструмента в промпте составлено так, чтобы модель понимала, когда его применять. Промежуточные состояния агента удобно проверять отдельным слоем, о чём подробно рассказано в материале про watchdog для промежуточных состояний.
Практическая диагностика: где искать причину
Диагностика строится по принципу «меняем одну переменную за раз». Иначе причина сбоя останется неопределённой.
Минимальный тест: короткая сессия и простой список
Соберите агента с to-do-списком из 3 пунктов и выполните их в одной короткой сессии, не доводя контекст до переполнения. Если отметка работает, причина сбоя, скорее всего, в длине сессии или объёме контекста. Если не работает - ищите проблему в harness или промпте.
Формулировка для теста может быть прямой: «Составь список из трёх шагов. После каждого выполненного шага обновляй его статус в списке и показывай актуальную версию списка целиком». Простой и явный промпт убирает лишние переменные.
Проверка логов и вызовов инструментов
В логах смотрите три вещи: приходит ли от модели вызов инструмента обновления, сохраняется ли новое состояние, есть ли ошибки парсинга. Если вызов есть, а состояние не меняется, проблема в harness. Если вызова нет, причина в промпте или в модели.
Характерный пример: в логах видно, что модель сгенерировала текст с отметкой, но harness не распознал его как обновление. Формально агент «отметил» пункт, фактически состояние осталось прежним.
Замена модели и harness для локализации
Метод простой, но требует времени. Зафиксируйте harness и замените модель на другую. Если сбой исчез, дело в модели. Затем зафиксируйте модель и замените harness. Если сбой исчез, дело в обвязке.
Отдельный слой - надёжность модели на длинных задачах. Как её оценивать по проверяемым критериям, а не по общим впечатлениям, разбирали в статье про надёжность агентных моделей.
Случай pseudobacon этим методом классифицировать нельзя: в исходном сообщении нет ни модели, ни harness, ни размера контекста.
Фундаментальная проблема или инженерная недоработка: что говорит практика
Причина смешанная. Часть сбоев упирается в ограничения LLM, часть закрывается инженерией на уровне обвязки уже сегодня.
Что уже решается на уровне обвязки
- явные инструменты для обновления статуса задачи;
- внешняя память: файлы, базы данных, постоянный контекст;
- валидация формата ответа до применения обновления;
- промпт с явным требованием обновлять список после каждого шага.
Пример Claude Code с CLAUDE.md показывает один из подходов к постоянному контексту, и для этого не нужны новые модели (Memory Guide).
Что остаётся ограничением текущих моделей
- конечное контекстное окно;
- снижение внимания к старым токенам;
- ошибки при редактировании структурированных данных;
- склонность к галлюцинациям на длинных цепочках шагов.
Даже идеальный harness не отменяет этих ограничений. Это повод закладывать проверки и не полагаться на список слепо, а не повод отказываться от to-do-списков.
Практический вывод: to-do-список полезен ровно настолько, насколько надёжно harness хранит и обновляет состояние. Если обвязка не даёт инструмента обновления, промпт не требует отметки, а список живёт только в контекстном окне, стабильной работы ждать не стоит. Начните с короткого теста на трёх пунктах, посмотрите логи вызовов и только потом меняйте модель. Так вы отделите ограничение LLM от недоработки обвязки и поймёте, что именно править.