Урок 03 · Планирование

Пусть агент сам отслеживает свой прогресс

«The agent can track its own progress — and I can see it.» Заставьте модель самостоятельно составить список — и добавьте простой механизм, чтобы она не забывала его обновлять.

⏱ ~10 мин · 📝 3 интерактивных компонента · 🧑‍💻 На основе shareAI-lab · s03_todo_write.py

Структурированное self-planning

Когда Claude Code работает, ему часто нужно выполнить несколько шагов: grep для поиска ссылок → прочитать несколько файлов → изменить код → запустить тесты. Если модель действует «по наитию», первые шаги обычно хороши, но потом она начинает забывать и бросает задачу на полпути.

Решение s03 — дать ей инструмент списка задач: модель сама вызывает инструмент todo для добавления задач, а TodoManager валидирует структуру, сохраняет и возвращает текущий вид. Два преимущества:

  • Модель вынуждена явно записать «что нужно сделать» — один этот акт уже помогает ей собраться с мыслями.
  • Человек видит, о чём она думает. Отладка становится значительно проще.
# TODO-список, каждый элемент структурирован
[ ] #1: grep "TODO" across src/
[>] #2: read src/app.py and list comments     # выполняется
[ ] #3: generate summary markdown
[ ] #4: write to TODO_LIST.md

(0/4 completed)

Жёсткое правило: в один момент времени только одна задача in_progress

В TodoManager.update() есть проверка:

if in_progress_count > 1:
    raise ValueError("Only one task can be in_progress at a time")

На первый взгляд жёстко, но это помогает модели. Если разрешить одновременно 3 «выполняющихся», она начнёт разрываться и не завершит ни одну. Принудительная монозадачность заставляет заканчивать одно перед началом следующего.

Виджет ниже позволяет «сыграть за модель» — отправлять разные todo payload и смотреть, что пройдёт валидацию, а что будет отклонено.

Nag reminder: три раунда без обновления — напоминаем

Даже с инструментом todo модель иногда «забывает» его обновлять — делает кучу работы, а in_progress так и висит на 2-й задаче. Решение в s03 — простейший счётчик:

rounds_since_todo = 0
while True:
    response = LLM(messages, tools)
    ...
    used_todo = any(b.name == "todo" for b in tool_uses)
    rounds_since_todo = 0 if used_todo else rounds_since_todo + 1
    if rounds_since_todo >= 3:
        results.append({"type":"text", "text":"<reminder>Update your todos.</reminder>"})

Досчитав до 3, харнес вставляет reminder в следующее user message. Модель инстинктивно реагирует и вызывает todo. Это инженерный способ превратить мягкое ограничение («пожалуйста, обновляйте список») в принудительный стимул.

Как это называется в теории?

В мире проектирования агентов это называется structured self-planning with soft nudges — дать модели структурированное состояние, которое она обязана обновлять, и периодически напоминать ей об этом. В реальном коде Claude Code используется похожий паттерн, но более сдержанно (реже, нейтральнее).

Почему не написать «всегда обновляй todo» в system prompt? Написать можно, но соблюдение общих инструкций из system prompt ухудшается по мере роста диалога. Разбивка на «повторно инжектируемые reminders» значительно стабильнее.
Интерактив

Виджет 1 · Kanban · эволюция todo по шагам

Нажимайте Step и наблюдайте, как модель переводит задачи из pending в in_progress и затем в completed. Обратите внимание: in_progress всегда ровно одна.

[ ] ожидание
[>] выполняется
[x] завершено
Готово к запуску…
Интерактив

Виджет 2 · Validation · какие из 5 payload пройдут проверку?

При вызове инструмента todo модель передаёт массив items. TodoManager прогоняет проверки: непустой text, допустимый status, не более одного in_progress, всего ≤ 20 элементов. Нажмите, чтобы решить: прошёл или отклонён.

Правильно: 0 / 5
Интерактив

Виджет 3 · Nag Counter · что происходит, если 3 раунда подряд без обновления todo

Нажимайте Next Turn и наблюдайте, срабатывает ли счётчик и инжектируется ли reminder. Каждый раунд случайно выбирается «вызвал todo» или «нет» — так реальная модель и ведёт себя.

rounds_since_todo: 0