Менше токенів — не означає дешевше: агенти для коду марнують роботу, а не токени
Стиснення виводу інструментів може здорожчити все завдання. Чому варто вимірювати ціну виконаного завдання, лишати шлях відновлення й проєктувати інструменти під агентів.
Відколи агенти для коду злетіли, розробники зациклилися на одній цифрі — токенах. Скільки згенерувала модель, скільки повернув інструмент, якого розміру контекст, скільки спалив агент? Логіка здається залізною: менше токенів — менший рахунок.
Аналіз GitHub щодо агента Copilot для коду показує, чому це припущення ризиковане. Якщо урізати кожну відповідь інструмента, усе завдання може подорожчати, коли у відрізаному тексті було щось важливе. Агент тоді перезапускає команди, викопує початковий вивід, витрачає зайві ходи на міркування й тягне роздутий контекст крізь усе, що йде далі.
Тож найдешевша взаємодія — не обовʼязково та, де найменше токенів. Насправді потрібне виконане завдання з мінімумом змарнованої роботи, і це змінює те, як варто оцінювати роботу агента.
Пастка локальної оптимізації
Припустімо, агент запускає команду тестів:
npm test
Вона друкує 50 000 токенів. Це виглядає марнотратно, тож ви пишете обгортку, яка стискає вивід до 2 000. На папері це перемога: 48 000 токенів зникли.
А тепер уявіть, що до цих 2 000 токенів не потрапило те, що було потрібно агентові. Він відповідає приблизно так:
I need more information about the failing test.
І ось він перезапускає команду, шукає в збереженому виводі, відкриває лог-файл або пробує вужчу команду. Процес перетворюється на такий:
Original command
↓
Compressed output
↓
Missing information
↓
Agent searches again
↓
Command runs again
↓
More context
↓
More reasoning
Окремий крок подешевшав, а завдання подорожчало. GitHub зіткнувся з цим, коли пробував способи скоротити вивід для Copilot. В одному експерименті інструмент під назвою RTK скорочував вивід оболонки, і агенти часто знову відкривали або перезапускали команди, щойно відсутня деталь виявлялася важливою. У підсумку ходів стало більше, а в середньому зросли й токени, і час виконання. Заднім числом це звучить очевидно, але легко проґавити, коли оптимізуєш не ту цифру.
Оцінюйте завдання, а не виклик
Агент потрібен, щоб довести до кінця завдання з розробки, а не щоб мінімізувати вартість одного API-запиту. Різниця між цими цілями більша, ніж здається. Порівняймо двох агентів. Агент A:
Task
↓
8 tool calls
↓
100K tokens
↓
Completed in 4 minutes
і агент B:
Task
↓
15 tool calls
↓
80K tokens
↓
Completed in 9 minutes
Якщо дивитися лише на токени, виграє B. Але якщо ви керуєте інженерною організацією, відповідь уже не така ясна. A закінчив раніше, імовірно, потребував менше повторів, міг витратити менше обчислень, міг видати кращий патч і менше змусив розробника чекати. Якщо комусь довелося ще пʼять хвилин няньчитися з B, реальна ціна B зростає ще більше.
Тому GitHub стверджує, що кількість токенів на одну взаємодію мало що каже про ефективність агента. Оптимізувати треба результат усього завдання.
Модель вартості від початку до кінця
Досвідчені інженери знають це з іншої роботи. Скоротіть запит до бази з 200 мс до 100 мс, і це звучить як явний виграш. Але якщо новий запит змушує інший сервіс надіслати три зайві запити, система загалом може стати повільнішою. Налаштовують систему, а не окрему операцію.
З агентами те саме правило. Корисна ментальна модель повної вартості:
Total agent cost =
model inference
+ tool execution
+ retries
+ repeated work
+ context growth
+ developer waiting
+ infrastructure
І закономірність, яка трапляється часто:
smaller response
+
missing context
=
more recovery work
Ось чому ШІ-інженерія дедалі більше схожа на системну інженерію.
Не будь-який вивід однаково цінний
Важливе спостереження: щільність інформації у виводі команд буває дуже різною. Одноманітні логи встановлення, збирання, тестів і прогресу можуть бути забиті шумом. А вивід, схожий на вихідний код, і результати довільних команд, навпаки, можуть містити саме те, що потрібно агентові. Замість одного правила стиснення для всього GitHub зробив вибірковий підхід. Концептуально він влаштований так:
Command output
│
▼
┌──────────────────────┐
│ What kind of output? │
└──────────┬───────────┘
│
┌─────┼─────┐
│ │ │
▼ ▼ ▼
Source Search Noise
output results logs
│ │ │
▼ ▼ ▼
Keep Reorganize Compress
all without selectively
losing
content
Це краще за грубу альтернативу:
if output.length > X:
truncate()
Грубе правило оптимізує цифру. Вибіркове — здатність агента працювати далі.
Чого вчить git diff
Уявіть агента, який відредагував пʼять файлів і тепер запускає:
git diff
Вивід довгий. Наївний компресор вирішив би, що він великий, і стиснув би його. Але в дифі може бути саме те, що потрібно агентові, щоб зрозуміти, чи правильні його зміни. GitHub повідомляє, що ранні версії його компресора справді стискали git diff, і бенчмарки показали, що агенти знову відкривали початковий вивід, щоб повернути інформацію. Тому від цього фільтра відмовилися.
Це чудовий урок саме для ШІ: не можна назвати щось марним лише тому, що воно велике. Одні великі виводи — цінний контекст, інші крихітні нічого не варті. За кількістю токенів їх не розрізнити.
Як проєктувати власні інструменти
Якщо ви робите агента для коду, можна написати так:
const result = await exec(command);
а потім жорсткий ліміт:
return result.stdout.slice(0, 5000);
Виглядає розумно, але мовчки припускає, що в перших 5 000 символах є все, що потрібно агентові. Розумніше спершу класифікувати вивід. Початок той самий:
const result = await exec(command);
Далі розгалуження за типом виводу:
const outputType = classifyOutput(result);switch (outputType) {
case "source":
return result.stdout; case "search":
return reorganize(result.stdout); case "repetitive-log":
return compress(result.stdout); default:
return result.stdout;
}
Навіть тут потрібен запасний вихід, щоб агент міг повернути оригінал:
return {
summary,
compressedOutput,
fullOutputAvailable: true
};
Агент отримує компактне подання, і при цьому нічого насправді не зникає. Для автономних систем це набагато краща архітектура.
Стиснення має відкладати, а не видаляти
Стиснення не повинно означати видалення інформації. Воно має означати, що інформація відкладається до моменту, коли знадобиться. Порівняйте два підходи. Погане стиснення виглядає так:
Original output
↓
Throw away 90%
↓
Agent cannot recover it
Краще стиснення лишає шлях назад відкритим:
Original output
↓
Create useful summary
↓
Agent continues
↓
Needs more detail?
↓
Retrieve original
Це ближче до того, як працює кешування у звичайному софті. Агентові не потрібне все одразу, але він не повинен втрачати доступ ні до чого важливого. Підхід, який GitHub випустив у роботу, дає прямий шлях відновлення після стиснення виводу.
Іноді більше контексту дешевше
Звучить навпаки. Розробники роками урізали контекст. Але більший контекст може запобігти зайвій роботі. Припустімо, агент бачить стиснене повідомлення про збій:
Test failed:
Expected 401
Received 500
Повний вивід міг би показати ще й це:
Database connection refused
JWT middleware initialized correctly
Request reached /api/auth/login
PostgreSQL timeout after 5 seconds
Коротка версія повідомляє агентові, що щось упало. Повна каже, що логіка автентифікації, найпевніше, ні до чого, а винне підключення до бази. Друга коштує більше токенів і може заощадити пʼять викликів інструментів. Контекст має ціну, але і його брак теж. Інженерне завдання — знайти баланс між ними.
Чому агенти ніби ходять по колу
Ви напевно бачили, як агент робить щось таке:
Run command
↓
Read partial output
↓
Run another command
↓
Search same file
↓
Run original command again
↓
Read more output
↓
Change code
↓
Run test
↓
Go back to original command
Схоже на розгубленість, і іноді так і є. Але часом інфраструктура просто не дала моделі достатньо інформації, і агент компенсує неповний інтерфейс. Якщо агент знову й знову просить одне й те саме, проблема може бути в будові інструментів, а не в моделі.
Дизайн інструментів — це UX для моделей
Розробники зазвичай оцінюють API за входами, виходами, затримкою, помилками й автентифікацією. Для інструментів під ШІ потрібне ще одне питання: як цей вивід вплине на наступне рішення моделі? Візьмімо дві відповіді. API A:
{
"status": "failed"
}
і API B:
{
"status": "failed",
"error": "PostgreSQL connection timeout",
"service": "auth-api",
"retryable": true,
"attempt": 2,
"duration_ms": 5040
}
У B більше даних, але він може знизити загальну вартість системи, бо агент одразу ухвалює правильне рішення. Мета — не найменший JSON. Мета — інформація, яка дає агентові змогу зробити наступний правильний крок.
Налаштування всього циклу
GitHub не вважає це окремим завданням стиснення. У його розборі перелічено кілька змін в обвʼязці: зберігати корисний контекст і прибирати повтори, викидати форматування, яке не допомагає завданню, скорочувати інструкції без зміни поведінки й уникати непотрібних кроків пошуку для фонової роботи. Кожну зміну оцінювали офлайн на бенчмарках агентного програмування, а потім перед випуском перевіряли в контрольованих онлайн-експериментах.
Це і є інженерія продуктивності для агентів. Питання зміщується з «як зробити відповідь коротшою» на «як допомогти агентові закінчити з меншими втратами», і це куди вдаліше питання.
Спостережуваність для агентів
Це змінює те, що ви відстежуєте в продакшені. Для звичайних сервісів ви б дивилися на:
Latency
Error rate
CPU
Memory
Throughput
Для агентів додайте ще:
Task completion rate
Tool-call count
Retry rate
Repeated-command rate
Context growth
Model escalation rate
Time to completion
Cost per completed task
Human intervention rate
Більшість із цього — метрики робочого процесу, а не токенів. Токени й далі важливі, але вони входять в економіку, а не визначають ефективність.
Вартість успішного завдання
Найпростіша зміна — перестати відстежувати ось це:
cost per request
і відстежувати натомість ось це:
cost per successfully completed task
Це не одне й те саме. Візьмімо агента з такими цифрами:
Agent A
$0.20/task
70% success rate
і порівняймо з цим:
Agent B
$0.35/task
95% success rate
Дешевший запит — не обовʼязково дешевша система. Нормалізуймо:
Effective cost
= inference cost / successful tasks
Для A:
$0.20 / 0.70
≈ $0.286
Для B:
$0.35 / 0.95
≈ $0.368
За цією простою метрикою A все одно виграє. Але якщо A потребує набагато більше нагляду з боку розробника, економіка знову змінюється. Тому командам зрештою потрібне ширше визначення вартості завдання.
Та сама ідея працює під час вибору моделей
Це повʼязано з переходом до маршрутизації моделей. Дослідницьке превʼю HydraFusion від GitHub уже розглядає робочі процеси розробки як задачу оптимізації й під кожне завдання обирає між однією моделлю, ескалацією до сильніших або другою моделлю в ролі незалежного критика. За наявними даними, офлайн-тести в контрольованих умовах показали велику розрахункову економію, а якість на деяких бенчмарках була не нижчою за базовий рівень Opus 5, який використовували для порівняння, або вищою.
Поєднайте це з уроком про вивід. Розумний агент не просто питає, яка модель дешевша. Він питає, який робочий процес завершить це завдання з найменшими втратами. Такий процес може поєднувати:
Cheap model
+
Good context
+
Efficient tools
+
Verification
і обійти ось такий:
Expensive model
+
Poor context
+
Repeated tool calls
Інтелект більше не живе лише в моделі. Він розподілений по всій системі.
Якщо ви робите ШІ-продукти
Спокусливо спершу оптимізувати очевидні цифри: менше токенів, коротші промпти, коротший вивід, дешевші моделі. Не налаштовуйте лише їх. Інструментуйте весь робочий процес:
User request
↓
Model inference
↓
Tool call
↓
Tool response
↓
Model reasoning
↓
Another tool call
↓
Verification
↓
Final result
Вимірюйте кожен етап, а потім шукайте, де агент робить зайву роботу. Може, інструмент для бази повертає замало контексту, а пошук — забагато нерелевантного. Може, агент без потреби повторює спроби або ваш промпт змушує його планувати зайвий раз. Може, сильніша модель розвʼязала б задачу вдвічі швидше за кількістю ходів, а для першої спроби вистачило б і дешевої. Усе це задачі програмної інженерії.
Майбутнє — не в меншій кількості токенів
Спокусливо звести всю проблему вартості до цього:
tokens ↓
cost ↓
Насправді залежність виглядає радше так:
Useful context
↓
Better decisions
↓
Fewer retries
↓
Fewer unnecessary tool calls
↓
Shorter task duration
↓
Lower total cost
Іноді шлях до меншої вартості починається з того, що моделі дають більше інформації. Це контрінтуїтивна частина, і саме тому ШІ-інженерія перетворюється на системну дисципліну, а не на вправу з написання промптів.
Вимірюйте виконану роботу
Оцінюючи агента, питайте не лише, скільки токенів він витратив. Питайте, скільки корисного софту він зробив і скільки роботи змарнував дорогою. Отже, треба відстежувати коректність, затримку, виклики інструментів, повтори, розмір контексту, вартість інференсу, втручання людини й успішне завершення.
Переможна система для коду не обовʼязково видаватиме найменше токенів. Радше переможе та звʼязка, яка перетворює кожен токен, виклик інструмента й вибір моделі на реальний прогрес. Нещодавня інженерна робота GitHub показує напрям: оптимізувати завдання цілком, зберігати інформацію, потрібну агентові, і урізати роботу, лише коли точно знаєш, що вона не допомагає. Сенс не в тому, щоб агенти робили менше. Сенс у тому, щоб вони менше марнували.