vyvchy
    Теми розділу

    14 · AI для QA

    Агенти й agentic loop

    Зміст

    У попередній главі модель викликала інструмент один раз і повертала відповідь: спитав — отримав. Але справжня робота рідко вкладається в один крок. «Полагодь оцей червоний тест», «відтвори баг зі скріншота», «онови локатори після редизайну» — це не одна дія, а цикл: спробував, подивився на результат, підправив, спробував знову. Агент (agent) — це і є мовна модель (large language model, LLM), поставлена в такий цикл.

    Для QA це вже не футурологія: термінальні агенти на кшталт Claude Code самі проганяють тести, читають трейси й правлять код у кілька ітерацій. А на співбесідах усе частіше просять не «розкажи про AI», а відрізнити «чат-бот з інструментами» від справжнього агента й пояснити, де автономію давати безпечно, а де — ні. Плутанина тут коштує дорого: агент, якому дали забагато волі без запобіжників, здатний за хвилину видалити тестові дані на спільному стенді або зафорспушити в main.

    Агент vs чат-бот

    Різниця не в «розумі» моделі, а в тому, хто вирішує наступний крок.

    Чат-бот (і навіть заскриптований воркфлоу з викликами інструментів) веде людина або наперед прописаний код: кроки відомі заздалегідь, модель заповнює проміжки. Агент навпаки — модель сама диктує собі наступну дію, спираючись на результат попередньої, і крутить цей цикл, доки не досягне мети або доки не спрацює умова зупинки.

    Anthropic у своєму інженерному матеріалі проводить цю межу так: воркфлоу (workflow) — це система, де LLM та інструменти зʼєднані наперед визначеними шляхами в коді; агент — це система, де модель динамічно керує власним процесом і використанням інструментів, сама вирішуючи, як досягти результату.

    Чат-бот / воркфлоуАгент
    Хто веде крокиЛюдина або кодСама модель
    Кількість дійФіксована, відома напередНевідома, залежить від результатів
    ЗупинкаОдна відповідьМета досягнута / ліміт / вето людини
    Приклад«Згенеруй тест-кейси з цієї вимоги»«Досягни, щоб auth.spec.ts був зелений»

    Ключова думка: тул-виклик (tool call) сам собою ще не робить систему агентом. Агентом її робить цикл, у якому модель спостерігає наслідок своєї дії і сама вирішує, що робити далі. Механіку окремого виклику розібрано в главі Tool use і function calling — тут інструмент стає одним «ударом» усередині петлі.

    Agentic loop: план → дія → спостереження → корекція

    Серце агента — цикл із чотирьох тактів. Це узагальнення патерну ReAct (reasoning + acting): модель чергує міркування і дії, підмішуючи в контекст спостереження за наслідками.

    1. План (reasoning). Маючи мету й історію, модель вирішує, який крок наблизить до результату: «локатор не спрацював — треба глянути, як тепер виглядає сторінка».
    2. Дія (act). Модель викликає інструмент: запускає тест, читає файл, робить запит до API, відкриває трейс.
    3. Спостереження (observation). Результат інструмента повертається в контекст моделі — рядок помилки, вивід команди, стан сторінки.
    4. Корекція (correction). Модель звіряє спостереження з метою й оновлює план: гіпотеза підтвердилась чи ні, який наступний крок.

    Далі — знову план, і так по колу. Цикл має обриватися за однією з умов: модель сама сигналізує «готово», вичерпано ліміт ітерацій, скінчився бюджет помилок/токенів, або людина наклала вето на дію.

    Так

    Ні

    Так

    Ні

    Мета + контекст

    План: наступний крок

    Дія: виклик інструмента

    Спостереження: результат у контекст

    Мету досягнуто?

    Стоп: готово

    Ліміт / бюджет вичерпано?

    Стоп: здатися або спитати людину

    Так

    Ні

    Так

    Ні

    Мета + контекст

    План: наступний крок

    Дія: виклик інструмента

    Спостереження: результат у контекст

    Мету досягнуто?

    Стоп: готово

    Ліміт / бюджет вичерпано?

    Стоп: здатися або спитати людину

    Розглянемо конкретно — агент тріажить червоний Playwright-тест. Мета: checkout.spec.ts має пройти.

    • Ітерація 1. План: запустити тест і побачити помилку. Дія: npx playwright test checkout.spec.ts. Спостереження: TimeoutError на локаторі getByRole('button', { name: 'Pay' }). Корекція: кнопки з такою назвою немає — треба глянути реальний DOM.
    • Ітерація 2. План: відкрити трейс і подивитися на сторінку. Дія: читає trace/знімок. Спостереження: кнопка тепер підписана Checkout, а не Pay. Корекція: оновити локатор.
    • Ітерація 3. Дія: править локатор, перезапускає тест. Спостереження: зелено. Модель сигналізує «готово».

    Схематично (це не API конкретного SDK, а форма циклу):

    // Схематично: агент як цикл
    let context = [systemPrompt, goal];
    for (let step = 0; step < MAX_STEPS; step++) {
      const decision = await model.decide(context);        // план
      if (decision.done) break;                            // зупинка за сигналом моделі
      const result = await runTool(decision.tool, decision.args); // дія
      context.push(decision, result);                      // спостереження лягає в контекст
      // наступна ітерація — корекція плану на основі result
    }

    Зверніть увагу на рядок if (decision.done) break та step < MAX_STEPS: без явних умов зупинки агент або крутитиметься вічно, або спалить увесь контекст. Умови зупинки — не деталь, а частина дизайну агента.

    Контекст агента

    Агент бачить рівно те, що лежить у його контекстному вікні (context window), і нічого більше. А саме:

    • системний промпт — інструкції поведінки й описи доступних інструментів (їхні імена та JSON-схеми);
    • мету — те, що просив користувач;
    • наростаючу історію — усі попередні дії та спостереження;
    • стан середовища — файли, сторінку, відповіді API, до яких дотягуються інструменти.

    Головний наслідок: з кожною ітерацією історія росте, бо туди лягає результат чергового інструмента. Довгий цикл роздуває контекст — а це прямо бʼє і по вартості, і по якості. Кожен крок фактично перевідсилає всю попередню історію моделі, тож токени накопичуються нелінійно; на довгому контексті модель ще й гірше тримає деталі. Механіку токенів і деградації розібрано в главі Токени, контекст і вартість.

    Тому зрілі агенти керують контекстом: підсумовують (компактують) стару історію, викидають застарілі спостереження, виносять пам'ять у файли, або делегують шматки роботи субагентам зі свіжим контекстом (див. Сабагенти й оркестрація). Для QA практичний висновок простий: якщо агент «забув», що робив 20 кроків тому, і почав ходити по колу — швидше за все, релевантне вже витіснене з вікна.

    Автономність і human-in-the-loop

    Автономність — це шкала, а не перемикач. На одному кінці — повністю автономний агент, що доводить задачу до кінця без людини. Посередині — human-in-the-loop (HITL): людина підтверджує окремі дії перед виконанням. Ближче до автономного — human-on-the-loop: людина лише наглядає й може втрутитися.

    Компроміс очевидний: автономія масштабує роботу, але масштабує й помилки. Одна невірна дія без нагляду вкладається в наступні, і каскад помітиш уже за наслідками.

    Практичне правило для QA — гейтити саме незворотні дії, а зворотні лишати автономними:

    • потребують підтвердження людини: видалення даних, TRUNCATE/DROP на спільному стенді, git push --force, розсилка листів чи повідомлень, деплой;
    • можна автономно: редагування файлу в робочій копії, read-only SQL-запит, запуск тесту, читання логів.

    Саме так влаштовані дозволи в агентних інструментах: Claude Code за замовчуванням питає дозвіл перед виконанням команд, і цей запобіжник знімають свідомо, а не «щоб не заважав». Базовий воркфлоу з дозволами розібрано в главі Claude Code: базовий воркфлоу для QA.

    Типові помилки

    Виглядає як прогрес, а насправді агент застряг у циклі. Модель повторює ту саму невдалу дію або осцилює між двома станами (править локатор → ламає інший → вертає назад). Лікується лімітом ітерацій, детекцією повторів і сигналом «здайся й спитай людину».

    Виглядає як одна невдала дія, а насправді отруєно весь контекст. Рання хибна гіпотеза лишається в історії, і кожен наступний крок міркує вже від неї — каскад помилок (error cascade). Тому одну зіпсовану ітерацію інколи дешевше почати з чистого контексту, ніж «дотягувати».

    Виглядає як виконана задача, а насправді агент згубив мету. На довгому циклі початкова ціль тоне в контексті (goal drift): агент акуратно робить не те, що просили. Симптом — бездоганні дії, що не наближають до результату.

    Виглядає як зелений тест, а насправді агент зшахраював. Замість полагодити баг агент видаляє червоний тест, ставить test.skip, або хардкодить очікуване значення під фактичне. Формально мета «тести зелені» досягнута — по суті перевірку знищено. Це різновид reward hacking; ловиться тільки рев'ю виводу — див. Верифікація результатів AI.

    Виглядає як виклик інструмента, а насправді інструмент вигаданий. Модель кличе тул, якого немає, або передає параметр не тієї схеми. Спостереження — помилка інструмента, і добрий агент має вміти її прочитати й виправитись, а не зациклитись.

    Виглядає як «майже готово», а насправді агент палить бюджет. Без ліміту кроків цикл тягне десятки ітерацій, кожна перевідсилає всю історію — рахунок і латентність ростуть тихо, доки не глянеш у метрики.

    Коли агент доречний

    Головний принцип від Anthropic: починай з найпростішого рішення й нарощуй складність лише за потреби. Один промпт із хорошими прикладами дешевший, швидший і передбачуваніший за агента. Заскриптований воркфлоу з фіксованими кроками надійніший там, де шлях відомий наперед.

    Агент виправданий, коли збігаються кілька умов:

    • задача багатокрокова, і послідовність кроків невідома заздалегідь (шлях залежить від проміжних результатів);
    • є зворотний звʼязок — оракул, за яким агент бачить, чи наближається до мети (тест пройшов/впав, компілятор лається, стан сторінки змінився);
    • помилки зворотні або обмежені — або є HITL-гейти на небезпечні дії;
    • цінність задачі виправдовує вартість токенів і латентність.

    Агент зайвий, коли: задача детермінована (візьми скрипт), немає сигналу зворотного звʼязку (агенту нема на що спертися), помилки катастрофічні й незворотні без гейтів, або задача проста й чутлива до затримки.

    QA-приклад по обидва боки межі: тріаж флакі-падіння — гарна робота для агента (оракул = результат тесту, шлях наперед невідомий). А прогін того самого фіксованого смоук-набору за розкладом — це воркфлоу, а не агент: тут нема чого «вирішувати» динамічно.

    Мультиагентні системи (оглядово)

    Коли задача завелика для одного контексту, кілька агентів ділять роботу. Найпоширеніший патерн — оркестратор-виконавці (orchestrator-workers): провідний агент розбиває задачу, роздає підзадачі субагентам (у кожного — власне свіже контекстне вікно), а потім зводить їхні результати.

    Оркестратор: розбиває мету

    Субагент 1: свій контекст

    Субагент 2: свій контекст

    Субагент 3: свій контекст

    Оркестратор: зводить результати

    Оркестратор: розбиває мету

    Субагент 1: свій контекст

    Субагент 2: свій контекст

    Субагент 3: свій контекст

    Оркестратор: зводить результати

    Навіщо це: паралелізм (кілька гілок роботи одночасно), ізоляція контексту (один роздутий брудний контекст замінюється кількома чистими), спеціалізація (окремий агент-«суддя», окремий агент-«кодер»).

    Ціна теж реальна: координація додає складності, дебажити систему з кількох агентів важче, а токенів вона зʼїдає значно більше. За оцінкою Anthropic, багатоагентні системи в їхньому дослідницькому продукті спалювали приблизно у 15 разів більше токенів, ніж звичайна чат-взаємодія, — тому вони виправдані лише там, де цінність задачі це покриває.

    Тож мультиагентність доречна для задач, що добре паралеляться і виграють від ізоляції контексту (широкий пошук, дослідження), і зайва для тісно звʼязаної послідовної роботи, де один агент упорається дешевше. Глибше — у главі Сабагенти й оркестрація.

    Підсумок

    • Агент = LLM у циклі, що сам вирішує наступний крок. У чат-бота чи воркфлоу крок веде людина або код; тул-виклик сам собою агента не робить.
    • Agentic loop — це план → дія → спостереження → корекція, доки не досягнуто мети або не спрацювала умова зупинки. Зупинка — частина дизайну, а не дрібниця.
    • Контекст росте з кожним кроком, тягнучи за собою вартість і деградацію; зрілий агент керує контекстом (компакт, пам'ять, субагенти).
    • Незворотні дії — за human-in-the-loop. Автономія масштабує роботу і помилки водночас; гейти ставлять на видалення, деплой, force-push, розсилки.
    • Спершу найпростіше рішення. Агент виправданий лише там, де шлях невідомий, є зворотний звʼязок і помилки обмежені; інакше дешевший скрипт або один промпт.

    Що питають на співбесіді

    • «Чим агент відрізняється від чат-бота?» — інтервʼюер слухає, чи назвете цикл і хто вирішує наступний крок, а не «агент розумніший». Слабка відповідь тоне в базвордах; сильна — «модель сама веде петлю дія-спостереження до зупинки».
    • «Опишіть agentic loop.» — очікують чотири такти (план/дія/спостереження/корекція) плюс умови зупинки. Бонус — згадка, що спостереження лягає в контекст і той росте.
    • «Де б ви НЕ дали агенту повну автономію?» — перевіряють інстинкт безпеки: незворотні дії (видалення даних, деплой, force-push) — за підтвердженням людини. Це майже дослівно збігається з тим, як QA думає про ризик.
    • «Ваш агент застряг у циклі / зробив тести зеленими, але щось не так — що сталося?» — чекають знання фейлів: зациклення, каскад помилок, goal drift, reward hacking (видалив тест / хардкодив значення), і що ловиться це рев'ю виводу та лімітами.
    • «Коли агент — це overkill?» — червоний прапорець для інтервʼюера, якщо кандидат тулить агента всюди. Сильний кандидат назве «найпростіше рішення спершу»: детермінована задача → скрипт, немає оракула → агенту нема на що спертися.

    Джерела