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

Помедитировав немного над этим, я пришёл к интересным эвристикам:

  • Большинство высокоуровневой работы более алгоритмично, чем кажется на первый взгляд.

  • Большинство низкоуровневой работы менее алгоритмично, чем кажется на первый взгляд.

Например, существует масса формализованных циклов проектирования (PDCA, OODA, DMAIC, 8D и etc.) — по сути, тривиальных мета-алгоритмов; однако каждый шаг этих алгоритмов — это куда более сложная и нетривиальная задача.

Значит, стоит стремиться давать агентам низкоуровневые задачи с небольшим, ясным контекстом, а высокоуровневые процессы описывать алгоритмически.

После нескольких месяцев экспериментов у меня получилось что-интересное — Donna — https://github.com/Tiendil/donna — утилита, которая делает ровно это.

Donna позволяет агентам выполнять сотни последовательных операций, не отклоняясь от заданного алгоритма работы. Ветвления, циклы, вложенные вызовы, рекурсия — всё возможно.

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

В итоге агент выполняет только конкретные «приземлённые» команды, а Donna переключает состояния и отслеживает переходы между ними.

При этом Donna — не оркестратор; это просто утилита: её можно использовать где угодно, без API-ключей, паролей, etc.

Workflow (стейт-машина) в Donna — это Markdown-файл с дополнительными Jinja2 инструкциями. То есть его может написать и человек, и агент.

Поэтому агенты с помощью Donna могут создавать стейт-машины для самих себя и исполнять их. То есть заниматься самопрограммированием.

Например, вместе с Donna поставляется workflow, который:

  1. Выбирает наиболее подходящий workflow для создания документа Request for Change (RFC) и запускает его.

  2. На основе созданного RFC генерирует workflow для реализации изменений, описанных в RFC.

  3. Запускает получившийся workflow.

  4. Выбирает наиболее подходящий workflow для «полировки» кода и запускает его.

  5. Выбирает наиболее подходящий workflow для обновления CHANGELOG и запускает его.

Ниже — упрощённый пример workflow для полировки Python кода.

Схема:

                                no issues
[ run_black ] ──▶ [ run_mypy ] ───────────▶ [ finish ]
      ▲                │
      │  issues fixed  │
      └────────────────┘

Workflow:

# Polishing Workflow

```toml donna
kind = "donna.lib.workflow"
start_operation_id = "run_black"
```

Polish and refine the codebase.

## Run Black

```toml donna
id = "run_black"
kind = "donna.lib.request_action"
```

1. Run `black .` to format the codebase.
2. `{{ goto("run_mypy") }}`

## Run Mypy

```toml donna
id = "run_mypy"
kind = "donna.lib.request_action"
```

1. Run `mypy .` to check the codebase for type annotation issues.
2. If there are issues found that you can fix, fix them.
3. Ask the developer to fix any remaining issues manually.
4. If you made changes `{{ goto("run_black") }}`.
5. If no issues are found `{{ goto("finish") }}`.

## Finish

```toml donna
id = "finish"
kind = "donna.lib.finish"
```

Polishing is complete.

Более сложный вариант этого workflow можно найти в репозитории Donna.

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

Спасибо за ваше время!

Комментарии (4)


  1. rPman
    10.02.2026 20:30

    Очень очень абстрактно... можно какой-нибудь красивый пример, который бы показал, вот классический подход (алгоритм задается текстом) дает вот такой косяк, а вот 'мой подход' в такой задаче работает стабильно?!


    1. Tiendil Автор
      10.02.2026 20:30

      Хм, похоже я перестарался с редактированием поста и удалил пару релевантных абзацев.

      Упрошённый пример.

      Допустим мы сделали правки в своём коде и хотим, чтобы агент поправил наши мелкие косяки: синхронизировал типы, починил тесты и так далее.

      Для этого ему надо итерационно запускать тесты, линтеры, форматтеры и так далее (и править проблемы), пока все ошибки не будут исправлены.

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

      Можно сделать один скрипт, который прогоняет все утилиты и сказать агенту запускать его по кругу. Это в целом работает, на мой взгляд, довольно неопрятно и создаёт трудности. Например, для такого скрипта нуно будет рядом держать большую спеку о том как реагировать на разные типы ошибок.

      А можно сделать стейт машину, которая управляет последовательностью запуска утилит (как в посте, но больше шагов) и знает как реагировать на каждую ошибку.

      Например:

      • агент запускает workflow, вызывая что-то в духе donna sessions run project:work:polish

      • Donna начинает интерпретировать FSM

      • Первой оперцией идёт запуск, допустим, mypy и Donna это и делает (нет взаимодействия с агентом).

      • Если mypy отработал без ошибок, то FSM переходит к шагу с запуском следующей утилиты.

      • Если mypy отработал с ошибками, то FSM переходит к шагу, который отвечает за обработку ошибок mypy. На этом шаге Donna отображает сообщение агенту с описанием конкретной ошибки и правилами её исправления (специфичными для mypy).

      • Агент читает это сообщение и выполняет инструкцию, ему не надо подгружать отдельные спеки или помнить большую инструкцию как фиксить ошибки для любых линтеров.

      • Когда агент решает, что исправил ошибку, он говорит Donna продолжать, и та переключает FSM на следующий шаг (например, на форматирование кода).

      Вот пример большого workflow для полировки кода: https://github.com/Tiendil/donna/blob/main/.donna/project/work/polish.md

      И вот как выглядит шаблон сообщения для агента от конкретного шага FSM (исправление ошибок от flake8):

      {{ donna.lib.task_variable("flake8_output") }}
      
      1. Fix the flake8 issues based on the output above.
      2. Ensure your changes are saved.
      3. {{ donna.lib.goto("run_autoflake_script") }}
      
      Instructions on fixing special cases:
      
      - E800 Found commented out code — remove the commented out code.
      - CCR001 Cognitive complexity is too high — ignore by adding # noqa: CCR001 at the end of the line.
      - F821 undefined name when there are missing imports — add the necessary import statements at the top of the file.
      - F821 undefined name in all other cases — ask the developer to fix it manually.
      

      То есть вместо больших инструкций агент всегда имеет короткие и чёткие шагии (в данном случае 3 шага).


      1. rPman
        10.02.2026 20:30

        можно сделать стейт машину

        кто создает этот алгоритм? разработчик хардкодит в агенте? или агент формирует детерменированный алгоритм (вместо human readable план) и запускает его на выполнение?


        1. Tiendil Автор
          10.02.2026 20:30

          Стейт-машина описывается читаемым текстом в Markdown формате.

          Поэтому создать её может и человек и агент. Можно и совместно — попросить агента сгенерировать workflow, а потом его отревьювить.

          Например, базу для workflow по ссылке выше я сделал руками, потом в несколько итераций доработал агентом — так быстрее.

          В целом, предполагаемую стратегию использования Donna я вижу так:

          • Постоянные workflow делаются человеком с помощью агента.

          • Workflow для выполнения разовой задачи генерируются агентом (при выполнении workflow из предыдущего пункта, например) и выполняются без участия человека. Полная автоматизация может потребовать некоторой работы (создать спеки по проекту, создать правильные meta-workflow, etc.).

          Изменения в саму утилиту, например, мой агент сейчас вносит в основном самостоятельно: создаёт workflow и исполняет его.