Виправлення помилок у штучних інтелектуальних агентах пошарово: формулювання запитів, контекст, організація роботи чи цикли.
Багатошарова модель для виявлення несправностей штучних інтелектуальних агентів: у чому відмінності між техніками формулювання запитів, використання контексту, організації роботи та створення циклів, а також процедура з використанням трасування для визначення пошкодженого шару.
Коли штучний інтелект у продакшені поводиться неправильно, команди схильні сперечатися щодо термінології замість того, щоб аналізувати докази: один інженер пропонує кращий запит, інший звинувачує контекст, ще один — інфраструктуру. Інженерія запитів, контексту, інфраструктури та циклів не є суперечливими підходами; це чотири взаємопов’язані рівні, і кожен з них може зламатися по-своєму. У цьому посібнику кожен рівень описується на прикладі простого кодового агента, а потім наводиться процедура, яка допомагає визначити, який саме рівень зламався, перш ніж змінювати будь-який код.
Коротка версія
- Інженерія запитів визначає інструкції, які надсилаються до моделі.
- Інженерія контексту визначає, що бачить модель перед тим, як дати відповідь.
- Інженерія інфраструктури створює середовище, в якому працює модель: інструменти, пам’ять, файли, дозволи та механізми відновлення.
Найбільш дорогі інциденти з агентами виникають через виправлення проблем у неправильному з цих рівнів.
Коли демо працює, а продакшн — ні
Ця ситуація знайома. У демо агент виглядає бездоганним. Через кілька днів після запуску він починає повторювати одні й ті самі дії, спалювати токени, забувати інформацію, про яку йому повідомляли годину раніше, або зламується при першому ж отриманні від інструменту непередбаченого даних.
Команда розділяється на групи. Хтось пропонує переписати інструкцію, хтось вважає проблемою контекст, а ще хтось підозрює сам інструмент. Без спільного підходу до виявлення причини несправності дводенне виправлення перетворюється на двотижневу роботу над переписуванням, оскільки кожен патч застосовується до рівня, який раніше працював без проблем.
Це практична причина, чому потрібно тримати ці чотири поняття окремо. Кожне з них позначає окреме місце, де можуть виникнути проблеми, і як тільки ви можете їх розрізнити, налагодження стає процесом, а не грою у здогадки.
PACT: мнемонічний принцип для чотирьох рівнів
Компактний спосіб запам’ятати ці рівні під час інциденту — PACT: Prompt, Awareness, Control, Trajectory. Кожне слово відповідає одному запитанню:
- Prompt: чи було завдання чітко визначене?
- Awareness: чи отримав модель інформацію, необхідну для цього кроку?
- Control: чи може система безпечно та надійно виконати те, про що просить модель?
- Trajectory: чи рухається цей повторюваний процес до завершення, яке можна перевірити?
Метою не є створення ще одного шару жаргону. Мета — зробити межі між типами невдач настільки зрозумілими, щоб ви могли легко їх згадати під час ситуації, коли щось горить.
Як з’являлися ці шари та чому важливий порядок
Ці терміни з’являлися приблизно в певній послідовності, по мірі того, як агенти отримували нові можливості:
- Інженерія запитів (приблизно з 2022 по 2024 рік) була першою навичкою: формулювання запитів, приклади, обмеження та шаблони для кількох запитів, спрямовані на один виклик моделі.
Ці дати вказують на моменти, коли ці терміни набули популярності, а не на формальні віхи; крім того, на момент написання цього тексту термінологія ще формується. Важливо зазначити, що нічого не було замінено — кожен рівень додавався поверх попереднього, оскільки кожне збільшення автономії вимагало власного механізму керування.
Інженерія запитів: локальний контракт
Інженерія запитів — це мистецтво формулювання, структурування та ілюстрування інструкції так, щоб відповідь була більш прогнозованою. Без неї виникають нечіткі інструкції, непостійні формати вихідних даних та ситуація, коли модель змушена вгадувати, що ви мали на увазі.
У кодувальному агенті запит на перегляд коду може виглядати так:
SYSTEM: You are a code reviewer.
Given a diff, output ONLY valid JSON:
{"issues": [{"line": int,
"severity": "low|medium|high", "note": str}]}
No prose. No markdown fences.
If there are no issues, return {"issues": []}.
Цей запит встановлює локальний контракт. Він призначає роль, описує процес трансформації (вхідні зміни, список проблем), визначає формат вихідних даних аж до назв полів та допустимих значень серйозності, а також визначає сценарій порожнього результату, щоб подальший парсинг ніколи не мусив обробляти прозу чи відсутні ключі.
Поширеною думкою є те, що інжиніринг запитів вже застарів. Це не так; це найглибший шар обробки. Кожен процес обробки контексту зрештою передає моделі інструкцію, і слабка інструкція в межах чудової інфраструктури все одно дасть слабкі результати, тільки тепер упаковані в вражаючу інфраструктуру.
Інжиніринг контексту: відбір у межах бюджету
Інжиніринг контексту — це процес вибору для кожного запиту тих документів, історичних даних, визначень інструментів та записів пам’яті, які потраплять у поле зору моделі, а також, так само свідомо, тих, які не потраплять. Якщо цього не робити, модель відповідає на основі застарілої інформації, відхиляється від правильного напрямку через нерелевантні дані чи втрачає фокус через надмірну кількість матеріалу, доданого на випадок.
Інструмент для створення контексту для кодувального агента може знаходити потенційні варіанти, переранжувати їх та стискувати історичні дані:
def build_context(query, full_history, kb):
relevant = retrieve(query, kb, top_k=8)
reranked = rerank(relevant, query)[:3]
summary = summarize_if_long(
full_history, max_tokens=800
)
return {
"docs": reranked,
"history": summary,
"query": query,
}
Цей процес можна уявити як воронку. Під час отримання даних формується широкий набір з восьми кандидатів, після чого відбувається переранжування, щоб залишити три найбільш релевантні варіанти. Історія розмови узагальнюється до приблизно 800 токенів лише тоді, коли вона стає занадто довгою. Функція повертає невеликий, структурований пакет даних, а не сирі матеріали. Ключовими навичками тут є відбір, ранжування та стиснення інформації, а не її обсяг.
Саме тому найпоширеніше непорозуміння — що інжиніринг контексту означає надання моделі більше інформації — зазвичай є хибним. Більший обсяг контексту часто містить більше „шуму“: застарілі інструкції, повторювані факти та суперечливі дані. Більша частина роботи полягає у виборі того, що слід виключити.
Інжиніринг контексту є ширшим за RAG
Генерація з підсиленням за допомогою пошуку — це одна з технік у рамках інженерії контексту, яка охоплює етап пошуку інформації. Пайплайн RAG може отримати вісім фрагментів та перевіднести їх до трьох, як описано вище. Інженерія контексту також включає стиснення історії, форматування визначень інструментів, підтримку актуального стану критичних завдань, надсилання результатів перевірки назад до моделі та вирішення питання про те, що слід пропустити.
Кодувальний агент без будь-якого сховища векторів все одно має реальну проблему з контекстом, яку потрібно вирішити. Статус Git, відкриті файли, помилки компілятора, результати тестування, поточний план та журнал попередніх дій — усе це має надходити до моделі у придатному для використання форматі.
Інженерія використання: межа між наміром та ефектом
Харчування є тією частиною системи, яка не пов’язана з моделлю: інструменти та доступ до файлів, постійна пам’ять, правила дозволів, сандбокси, відстеження та все, що відбувається у разі збою. Без якісного харчування у вас буде агент, який добре міркує, але не може діяти відповідно до цих міркувань, або агент, який діє, але не має надійного способу відновлення у разі помилки покликання інструменту.
Приклад обгортки для покликання інструменту ілюструє цю ідею:
def call_tool(tool_name, args, retries=2):
for attempt in range(retries + 1):
try:
result = TOOLS[tool_name](**args)
log_trace(tool_name, args, result, status="ok")
return result
except ToolError as e:
log_trace(tool_name, args, str(e), status="failed")
if attempt == retries:
return {"error": str(e), "recoverable": False}
args = repair_args(args, e)
Обгортка не намагається вирішити завдання. Вона контролює межу між тим, що запитала модель, та тим, що робить справжня система. Кожна спроба відстежується разом із її аргументами, результатом та статусом. Збій викликає обмежену кількість спроб повторного виконання з виправленими аргументами, і після вичерпання всіх спроб повертається структурована помилка, позначена як невідновлювана, щоб викликаючий отримав дані, за допомогою яких може міркувати, замість винятку, який призводить до завершення виконання.
Є спокуса ототожнювати харнес із будь-якою рамкою агента, яку ви встановили. Рамка надає структуру; харнес — це сукупність конкретних рішень, які ви приймаєте на її основі: що записується, що робить агент у разі невдачі, який стан зберігається після збою, які команди дозволені та як результати виконання повертаються назад до моделі.
Інженерія циклів: контракт завершення
Інженерія циклів визначає завдання кожної ітерації, спосіб, яким агент оцінює, чи досягає він прогресу, та, що найважливіше, умови для зупинки. Характерною ознакою невдачі є необмежений цикл: агент продовжує викликати інструменти та витрачати токени, оскільки ніхто не повідомляє йому, що він завершив роботу чи застряг.
Мінімальний контролер виглядає так:
def run_loop(task, harness, max_iters=15, stall_limit=3):
state = init_state(task)
stalls = 0
for i in range(max_iters):
action = plan_next_step(state)
result = harness.call_tool(action.tool, action.args)
state = update_state(state, result)
if is_goal_met(state):
return state, "success"
if made_no_progress(state):
stalls += 1
if stalls >= stall_limit:
return state, "stalled — escalate"
else:
stalls = 0
return state, "max iterations reached"
Тут застосовано кілька обмежень. max_iters встановлює максимальну кількість ітерацій, is_goal_met дозволяє завершити виконання у разі досягнення мети, а лічильник затримок відстежує послідовні ітерації без прогресу, скидаючись щоразу, коли прогрес відновлюється. Після stall_limit ітерацій з затримкою цикл повертає окремий статус, який вимагає подальшого розгляду ситуації, замість того щоб продовжувати роботу без змін. Кожен шлях вихіду повертає чітку причину, що полегшує подальшу класифікацію виконань.
Центральною ідеєю є контракт завершення: чітка мета, показники прогресу для вимірювання, обмежена кількість спроб, бюджети на час та токени, крок верифікації та чітко визначена політика дій у разі зупинки прогресу. Щодо реалізацій цих ідей у TypeScript, дивіться обмежені агентні цикли для використання інструментів LLM.
Інженерія циклів та інструментальних компонентів часто плутають. Інструментальні компоненти визначають, що може обробляти агент та як поводитися зі збоями на рівні окремих інструментів. Цикл знаходиться над ними та визначає поведінку на кожному кроці, включаючи момент, коли весь процес слід завершити.
Чотири шари поруч
- Prompt (P): відповідає за інструкцію. Типова проблема: модель неправильно розуміє намір або повертає інформацію у неправильному форматі. Спочатку потрібно перевірити сам вихідний результат.
- Context (A): відповідає за стан інформації, готовий до використання моделлю. Типова проблема: модель використовує застарілу, відсутню або відволікаючу інформацію. Спочатку потрібно перевірити знімки контексту за кожен етап.
- Harness (C): відповідає за виконання та відновлення роботи. Типова проблема: помилки під час виклику інструментів, сліпі спроби повторного виконання або неможливість відновлення. Спочатку потрібно перевірити записи про невдачі у логах інструментів.
- Loop (T): відповідає за прогрес та зупинку процесу. Типова проблема: агент ніколи не досягає результату чи не зупиняється. Спочатку потрібно перевірити повторні успішні виклики з майже ідентичними параметрами.
Як відрізнити помилку harness від помилки loop
Найефективніший спосіб заощадити час — це усвідомлення того, що два різні баги ззовні виглядають однаково. Агент, застряглий у циклі через несправний контролер, та агент, застряглий через несправну обробку інструментів, проявляють однакові симптоми: вони продовжують працювати, рахунок постійно зростає, і ніхто не розуміє причини. Короткий чек-лист допомагає відрізнити їх від інших проблем.
1. Перегляньте трек викликів інструментів
Якщо всі виклики успішні з логічними результатами, тоді як агент постійно використовує один і той самий інструмент з майже незмінними параметрами, це вказує на цикл.
2. Шукайте постійні збої інструментів
Якщо один і той самий інструмент постійно збивається, а агент продовжує спроби без зміни підходу, слід підозрювати систему кріплення.
3. Перевірте, що може бачити модель
Якщо модель, здається, забуває певний факт у процесі виконання завдання, перевірте створення контексту: обрізку, заміну, стиснення чи спосіб передачі стану між кроками.
4. Перевірте результат в кінці
Якщо інструменти працювали, контекст був точним та цикл завершився коректно, але відповідь все одно неправильна, перегляньте запит.
Орієнтовне правило
Баги в циклах полягають у рішенні щодо подальших дій. Баги у механізмах виконання — у тому, що відбувається при збоях. Баги у контексті — у тому, що бачить модель. Баги у запиті — у тому, про що ви просили.
Відповідайте на запитання, яке з чотирьох є актуальним, перш ніж щось редагувати.
Приклад з практики: рецензент pull-request, який не хоче зупинятися
Уявіть собі команду, яка використовує агента для кодування, що переглядає запити на зміни. Тестування проходить без проблем. Однак у продакшені деякі перегляди тривають понад 40 хвилин за один запит на зміни, що призводить до несподіваних рахунків.
Перша теорія полягає у тому, що інструкція занадто нечітка, тому агент занадто багато думає. Інструкцію перепишують, але нічого не змінюється. Друга теорія стосується контексту: можливо, агент щоразу перечитує весь репозиторій. Однак дані про процес показують інше — отримання інформації відбувається правильно, і завантажуються лише важливі файли.
Потім хтось уважно аналізує запис викликів інструментів. Агент неодноразово викликає свій інструмент тестування, і кожен виклик завершується без помилок. Насправді набір тестів провалюється через нестабільний інтеграційний тест, який не пов’язаний із запитом на зміни. Агент продовжує намагатися виправити цей провал за допомогою непов’язаних змін у коді та повторного запуску тестів, оскільки ніщо не підказує йому, що він зробив достатню кількість спроб щодо цієї підмети та має зупинитися та передати справу на вищий рівень.
Це не проблема запиту, не проблема контексту та не проблема інструментального комплексу; інструменти працювали саме так, як було спроєктовано. Це суто помилка циклу. Послідовний аналіз крок за кроком дозволяє дійти такого висновку.
Крок 1: підтвердити, що інструменти працюють
Успішні виконання, зазначені у записі, виключають найпростіші проблеми інструментального комплексу, такі як команда, яка ніколи не виконується, або адаптер, який постійно викидає помилки.
Крок 2: порівняння стану між ітераціями
Результати тестування знаходяться в контексті агента, а їх отримання відбувається у правильних межах, тому модель не втрачає доказів.
Крок 3: перевірка на збіжність
У репозиторії відбуваються зміни на кожній ітерації, але сигнал перевірки, який має значення, ніколи не покращується. Не існує детектора застою та жодних обмежень на кількість спроб досягнення однієї й тієї самої підмети.
Крок 4: навчання контролера виявляти застій
Рішенням є невелика частина логіки контролера, яка порівнює показники прогресу між кроками:
if progress_signature == previous_signature:
stagnant_steps += 1
else:
stagnant_steps = 0
if stagnant_steps >= 3:
escalate("no measurable progress")
stop()
progress_signature може бути чим завгодно, що відображає значущий прогрес — наприклад, набір несправних тестів разом із їхніми повідомленнями про помилки. Якщо він не змінюється, лічильник застою зростає; після трьох кроків застою контролер піднімає ситуацію на вищий рівень із поясненням причини та зупиняється. Будь-яка реальна зміна скидає цей лічильник.
Можна піти ще далі та обмежити кількість спроб для кожної конкретної причини несправності, а не лише загальну кількість ітерацій. Це розрізнення має велике значення: п’ятнадцять продуктивних ітерацій можуть бути цілком прийнятними, тоді як п’ятнадцять спроб щодо однієї нерозв’язної проблеми у тесті є суцільною марнотратством. Справжнє рішення полягає не у тому, щоб зробити модель менш впертою, а у тому, щоб надати контролеру чітке визначення стану застою.
Кейс-дослідження: обмеження, яке зникає з контексту
Уявіть тепер агента, який на початку міграції встановлює правило, згідно з яким ніщо не повинно пошкодити існуючих клієнтів. Через сорок кроків розмова стискається, і це обмеження зникає у резюме. Тоді агент пропонує зміну схеми, яка може спричинити проблеми.
Це виглядає як помилкове міркування, але причина криється в іншому. Порівняйте контекст, який модель фактично отримувала на різних етапах. Якщо обмеження було на п’ятому кроці, але відсутнє на сороковому, рішення полягає у оптимізації контексту: зберігати критичні інваріанти окремо від розмови, змушувати резюме передавати чіткі обмеження, та припинити вважати сиру історію єдиним джерелом правди.
Фраза „модель забула“ ніколи не є повною діагнозом. Корисне запитання — що саме було надано моделі.
Шари, а не заміна
Кожна новіша дисципліна ґрунтується на старіших, а не замінює їх. Агент виробництва обгортає чіткий запит у ретельно підібраний контекст, виконує його у надійному середовищі та керує всім цим за допомогою свідомо створеного циклу. Послідовність елементів відображає те, що командам доводилося додавати з часом: спочатку більш чіткі інструкції, потім краще підібрана інформація, далі середовище виконання для моделі та нарешті контролер, який підтримує це середовище у роботі без постійного нагляду. Якщо ви вирішуєте, чи має ваш власний двигун виконання, чи фреймворк керувати цим зовнішнім циклом, порівняння двигунів виконання та складених фреймворків розглядає всі можливі варіанти.
Перефразовано через PACT:
- Запит: визначення інструкції.
Потім необхідно прив’язати рішення до причини збою. Модель, яка неправильно інтерпретує чітко визначене завдання, потребує негайних коректив. Модель, якій бракує фактів, від яких вона залежить, потребує додаткового контексту. Розумні рішення, які не перетворюються на надійні дії, вимагають оптимізації. Дії, які успішні, хоча загальний процес так і не досягає стабільного стану, вимагають корекції логіки циклу.
Поширені запитання
Чи є інженерія harness просто іншою назвою для фреймворку агентів?
Ні. Фреймворк надає будівельні блоки. Комплекс інструментів складається з рішень, які ви приймаєте під час їх об’єднання: поведінка у разі збою інструменту, збережений стан, логування, дозволи та спосіб повернення результатів до моделі.
Чи потребує асистент з одним запитанням інженерія циклів?
Не дуже. Інженерія циклів стає важливою, коли агент виконує кілька дій за завданням та мусить самостійно або через код-контролер вирішити, що робота завершена. Бот для запитань та відповідей з одним етапом майже не потребує проектування циклів.
Який шар вам слід вивчати спочатку?
Почніть з інженерії запитів та контексту, потім переходьте до комплексу інструментів та циклів. Перш ніж ви зможете налаштовувати роботу програми та код-контролера, вам потрібно розрізняти погані інструкції та відсутність стану.
Чи може одна помилка охоплювати кілька шарів?
Так, і саме вони часто є найскладнішими. Баг у контексті може приховати сигнал прогресу від циклу, через що все виглядає як баг циклу. Слідкуйте за причиною збою на всіх рівнях, а не просто усувайте перший помітний симптом.
Ключові висновки
- Ці чотири терміни описують механізми керування, а не конкуруючі тенденції: інструкція, стан готовності моделі, виконання та відновлення, а також поступовий прогрес із правилом зупинки.
- Починайте кожне розслідування з запису дій, а не з запиту: запитайте, що бачила модель, що робив двигун виконання, що змінилося між ітераціями та чому контролер вирішив продовжити роботу.
- Успішні виклики інструментів, які повторюються з майже ідентичними аргументами, вказують на проблему в циклі; постійні збої під час сліпих спроб повторення вказують на проблему з механізмом керування.
- Надайте циклам чітке визначення стану застрягання, бажано для кожної конкретної сигнатури збою, а також шлях для ескалації проблеми.
Пов’язана література
- Як протокол Model Context Protocol дозволяє AI-агентам знаходити та викликати інструменти — чітке пояснення MCP: як хости, клієнти та сервери дозволяють AI-додаткам знаходити інструменти, викликати їх за допомогою структурованих вхідних даних та що є їхніми обмеженнями.
- CodeBuddy: Розумніше отримання контексту для AI-агентів з кодування — пояснює, як система отримання контексту на основі графа залежностей допомагає AI-агентам з кодування уникати як нестачі контексту, так і його надмірної кількості у великих кодових базах.
- Від написання коду на Kotlin до керування агентами: нова роль інженера мобільних додатків — Як агенти-кодувальники змінюють роботу інженера Android у напрямку виконання специфікацій, урахування контексту, обмежень архітектури та перевірки, та які основи стають важливішими, ніж будь-коли.