Урок 11 · Совместная работа

Агент, который сам ищет себе работу

«The agent finds work itself.» Не нужно назначать задачи — агент сам берёт их из доски.

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

От «разбуженного» к «ищущему работу»

Teammate из s09/s10 пассивен: кто-то отправляет сообщение в inbox — тогда начинает работать; завершает — переходит в idle, ждёт следующего пробуждения.

Autonomous teammate из s11 активен: даже без работы он не остаётся полностью бездействующим — каждые 5 секунд сканирует директорию .tasks/. Видит незанятую задачу — вызывает claim_task, берётся за работу.

Жизненный цикл teammate:
  +-------+
  | spawn |
  +---+---+
      |
      v
  +-------+
  | WORK  | <-- цикл LLM + tool_use
  +---+---+
      |
      | stop_reason != tool_use OR tool_use("idle")
      v
  +-------+
  | IDLE  | опрос каждые 5с, всего 12 раз = таймаут 60с
  +---+---+
      |
      +--> есть новые сообщения в inbox?  → возобновить WORK
      |
      +--> сканирует .tasks/, находит незанятую → claim → возобновить WORK
      |
      +--> 60с прошло без событий → status = shutdown, поток завершается

Auto-claim · «взять заказ» с доски задач

Ключевая функция:

def scan_unclaimed_tasks() -> list:
    unclaimed = []
    for f in sorted(TASKS_DIR.glob("task_*.json")):
        task = json.loads(f.read_text())
        if (task.get("status") == "pending"
                and not task.get("owner")
                and not task.get("blockedBy")):
            unclaimed.append(task)
    return unclaimed

Три фильтра = pending + нет owner + нет blockedBy. Все три обязательны.

Само действие claim защищено локом (_claim_lock), чтобы два агента, одновременно увидевшие одну незанятую задачу, не взяли её оба — лок перечитывает задачу, проверяет, что owner ещё пустой, затем атомарно записывает «in_progress» и owner на диск.

Симуляция: несколько агентов одновременно сканируют доску задач

3 teammate в состоянии idle, 3 задачи ждут. Нажмите «следующий опрос» и наблюдайте, кто первым возьмёт задачу (по алфавиту).

Identity reinjection · помнит ли агент себя после сжатия?

В s06 auto_compact заменяет messages на summary. Autonomous agent легко работает несколько часов и попадает под сжатие — после которого модель не знает, как её зовут и какова её роль.

Решение s11: при claim новой задачи, если len(messages) ≤ 3 (признак недавнего сжатия), автоматически вставляем identity-блок в начало:

if len(messages) <= 3:
    messages.insert(0, {
        "role": "user",
        "content": f"<identity>You are 'alice', role: coder, team: my-team. Continue your work.</identity>",
    })
    messages.insert(1, {"role":"assistant", "content": f"I am alice. Continuing."})

Этот паттерн называется identity reinjection — искусственно сконструированный диалоговый раунд «говорит модели, кто она», возвращая ей ощущение роли.

Интерактив

Виджет 1 · Task Scanner · 3 агента разбирают 3 задачи

alice / bob / charlie — все в состоянии idle. Нажмите «следующий опрос» и смотрите, кто по алфавиту первым claim-ит незанятую задачу.

Директория .tasks/
Статусы teammate
Все в idle, ожидают сканирования
Интерактив

Виджет 2 · Identity Drift · помнит ли агент себя после сжатия?

Симулируйте сжатие контекста и сравните, как агент отвечает на «кто ты?» — с identity reinjection и без.

Без identity reinjection
С identity reinjection
Интерактив

Виджет 3 · Autonomous vs Assisted · какие роли подходят для автономии

Решите, запускать ли роль в автономном цикле или оставить в режиме ожидания. Думайте о «цене потери контроля» и «частоте ручного вмешательства».

Правильно: 0 / 5