Головна / Статті

Сім тихих способів, яки забруднення контексту псують агентів LangGraph.

Застарілий стан, величезні купи інструментів, дублікати фрагментів RAG, сумаризації з втратами та надмірно об’ємні набори інструментів: сім проблем, які не викликають помилок, разом із способами їх виправлення та методами виявлення.

Видавець: REACTAPP.TOP9 хв читання2174 слів

Джерела: 7 Ways Context Pollution Quietly Killed My LangGraph Agents

Уявіть собі агента LangGraph, який повідомляє користувачеві, що його проект «йде за графіком та буде доставлений у липні». Однак календар показує серпень. Журнали не фіксують жодних винятків чи невдалих викликів інструментів, і ніде немає попереджень про проблеми. Згідно з усіма показниками, якими керується команда, агент працює нормально, і протягом трьох днів він тихо вводить людей у оману, поки хтось не помічає цього.

Подібні інциденти мають одну невидиму причину — забруднення контексту, і всі сім описаних нижче випадків мають у своїй основі саме її. Кожен з них не спричинив жодних помилок. Ці сценарії є умовними та ілюстративними; назви компаній та цифри вигадані, але механізми, які за ними стоять, є тими, з якими регулярно стикаються розробники агентів.

Забруднення контексту за дві хвилини

Коли агент міркує, він не бачить вашого застосунку. Він бачить лише один довгий блок тексту — вікно контексту, і нічого більше. Уявіть собі це як стіл: все, що на столі, є доступним для використання, а все, що поза ним, не існує для агента, навіть якщо це знаходиться у вашій базі даних за кілька футів.

Кожного разу на цей стіл додається кілька елементів:

  • промпт системи, тобто інструкції
  • визначення інструментів, тобто те, що агент може використовувати
  • історія розмови, тобто все, що було сказано досі
  • результати роботи інструментів, тобто все, що повернули ваші API
  • стан, тобто те, що зберігають та передають вузли LangGraph
  • отримані документи, якщо ви використовуєте RAG

Початківці рідко про це чують: у робочому столі є обмеження за розміром, і увага не розподіляється на ньому рівномірно. Контент може технічно бути присутнім, але на практиці ігноруватися. Він також може бути застарілим, дубльованим або суперечливим, а модель не буде заперечувати. Вона аналізує цей „сміття“ без жодних коментарів.

Забруднення контексту — це неправильний, застарілий, надмірний або суперечливий матеріал, який знаходиться у системі та погіршує її роботу, не викликаючи жодної помилки. Ось у чому небезпека. Збій змушує вас прокинутися о 2 годині ночі, тоді як забруднення просто змушує ваш агент працювати з помилкою 20% протягом необмеженого часу.

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

Випадок 1: агент застряг у липні

Симптом. Візьмемо пример агента звітності для вигаданого сервісу під назвою Meridian Energy. Він постійно наводив „цьогорічні“ цифри, які насправді належали попередньому місяцю. Користувачі звинувачували канал передачі даних, але з цим усе було гаразд.

Коренева причина. На початку сеансу розробник зберіг активний період звітності у стані LangGraph лише один раз (ключ під назвою current_period з значенням 2026-07), і чекпоїнт його зберіг. Пізніше користувачі відновлювали старі сеанси — це була популярна функція — і збережений чекпоїнт повертав значення липня. Агент не плутався; він дотримувався свого контексту, а в цьому контексті було зазначено липень.

Виправлення. Впровадіть правило, яке змінює підхід до проектування стану: ніколи не зберігайте те, що можна дешево перерахувати заново. Текуща дата, поточний період часу та все, що позначене як „сьогодні“, мають обчислюватися заново на початку кожного запуску, а не зберігатися. Переміщення змінної current_period зі стану, який зберігається під час перевірки, у невелику структуру, яка перераховує її значення при кожному виклику, коштує одного рядка коду та усуває всю категорію помилок.

Виявлення. Під час розробки друкуйте словник стану на початку кожного запуску та перевіряйте для кожного ключа, чи може він бути застарілим та чи помітите ви це. Кожен ключ, який містить дату, статус чи слово „текущий“, є підозрілим.

Случай 2: викид даних інструменту об’ємом 8 000 токенів, який заглушив інструкції

Симптом. Агент почав ігнорувати правила форматування. У системних інструкціях було сказано відкривати кожну відповідь із таблицею узагальнень. Він так і робив, але іноді цього не робив. Випадково, що є найгіршим видом багу.

Коренева причина. Один інструмент під назвою API вставляв необроблену JSON-відповідь у контекст. Для невеликих запитів це становило 400 токенів. Для великих запитів кількість токенів стрімко зростала до понад 8 000 токенів вкладених JSON-даних, наповнених ID, метаданими, полями типу null та деталями сторінкування, які нікому не були потрібні. Через це ретельні інструкції перетворювалися на тихий голос у шумній кімнаті. Увага зосереджувалася на цьому „стіні JSON“, і правила форматування фактично зникали.

Неприємна деталь полягає у тому, що це траплялося лише з великими відповідями. Невеликі запити працювали нормально, тож з’єднання концепцій „агент поводиться неналежно“ та „користувач поставив складне запитання“ зайняло тижні.

Виправлення. Інструменти повинні повертати факти, а не великі об’єми даних. Додайте всередину кожного інструменту простий шар трансформації, який вибере кілька необхідних полів, структурує їх компактно та видалить решту. Один такий інструмент скоротив обсяг даних з приблизно 8 000 токенів до близько 300.

# Before: return response.json()          # 8,000 tokens of noise
# After:
def summarize_response(data: dict) -> dict:
    return {
        "project": data["name"],
        "status": data["status"],
        "owner": data["owner"]["displayName"],
        "due": data["dueDate"],
        "open_risks": len(data.get("risks", [])),
    }                                       # ~300 tokens of signal

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

Случай 3: корекція, яка так і не замінила початковий запит

Симптом. Користувач просить інформацію про Північно-Східний регіон, а потім негайно виправляється та просить інформацію про Північно-Західний. Агент правильно відповідає про Північно-Західний регіон. Проте через чотири кроки розмови, без додаткових запитів, він знову починає надавати інформацію про Північно-Східний регіон.

Коренева причина. Історія розмов за замовчуванням дозволяє лише додавати нові записи, тому помилкове запитання та його корекція залишаються в контексті назавжди. Зазвичай модель правильно враховує новіше повідомлення, але не завжди. У міру зростання обсягу розмови ці дві версії стають однаково правдоподібними фактами. Агент не запам’ятовував неправильно — він запам’ятовував занадто багато.

Виправлення. Існують два варіанти.

  1. Вирішуйте проблему, не накопичуйте її. Як тільки ви помітили помилку, не просто додавайте її. Запишіть нове значення у структурований блок даних у стані (регіон встановлений як Північний Захід), який агент вважатиме авторитетним, щоб не доводилося знову сперечатися про заплутаний текст у кожному кроці.
  2. Редагуйте історію. LangGraph дозволяє скорочувати або переписувати повідомлення перед тим, як вони знову потраплять у контекст, тож застарілі інструкції можна просто видалити.

Загальний урок полягає у тому, що історія розмови — це журнал, а не база знань. Не змушуйте агента щоразу виводити істину з тексту розмови.

Виявлення. Додайте до своїх тестів сценарій самовиправлення: користувач каже X, потім виправляється на Y, а потім ставить ще п’ять запитань. Якщо агент знову повертається до X, у вас є ця помилка.

Случай 4: RAG повернув одну відповідь п’ять разів та сховав справжню

Симптом. Люди поставили запитання, на яке в документації була чітка відповідь, а система надала розмиту, неповну відповідь. Журнали пошуку показали шість отриманих фрагментів, тож здавалося, що система справно виконує свою роботу.

Коренева причина. У корпусі даних були майже ідентичні тексти: один абзац політики був вставлений у п’ять різних документів, як це часто роблять справжні компанії. Пошук за схожістю працював ідеально та повернув п’ять майже однакових фрагментів, які витіснили єдиний інший фрагмент з справжньою відповіддю. П’ять місць за столом дісталися одному й тому ж „гостю“.

Виправлення. Усувати дублікати під час отримання даних. Навіть примітивний метод добре працює: отримати 20 кандидатів, видалити будь-який фрагмент, занадто схожий на вже обраний, та залишити найбільш різноманітний набір. Якщо ваша база векторів підтримує максимальну маржинальну релевантність, ця ідея вже вбудована. Якість відповідей на питання з правилами миттєво покращується без змін у моделі чи запиті.

Виявлення. Фіксувати отримані фрагменти та щотижня їх переглядати. Якщо одне речення регулярно з’являється двічі в одній партії, ви оплачуєте дублювання за рахунок релевантності.

Случай 5: анотація, яка проігнорувала єдине важливе правило

Симптом. Щоб зробити довгі сеанси доступними за ціною, команда додала функцію поступового узагальнення: кожні N кроків старіші повідомлення компресуються. Це стандартний підхід, який широко рекомендується. Потім співробітник почав додавати чернетки до офіційних звітів, хоча користувач ще на одинадцяти кроках раніше просив „виключити чернетки“.

Коренева причина. Засіб узагальнення поводився як засіб узагальнення. Він зберігав основну інформацію (користувач хотів регіональні звіти та говорив про форматування) та видаляв те, що він вважав другорядним. Проте прохання „виключити чернетки“ не було другорядним – це була обмеження, а обмеження не можна перефразувати: вони або залишаються недоторканими, або зникають. Серед усіх семи невдач саме ця викликає найбільше занепокоєння, адже узагальнення на демонстраціях здається абсолютно очевидним перевагою.

Виправлення. Розділити пам’ять на два канали ще до початку компресії.

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

У запиті на узагальнення можна прямо це зазначити: перед узагальненням слід дослівно скопіювати всі інструкції, обмеження та рішення до списку обмежень.

Виявлення. Під час розробки порівнюйте список обмежень до та після кожної процедури узагальнення. Якщо яке-небудь обмеження залишається лише у розділку з узагальненням, це означає, що алгоритм узагальнення порушує ваші правила.

Случай 6: стек-трейс, який змусив агента не довіряти працездатному інструменту

Симптом. Один інструмент на короткий час вийшов з ладу через тайм-аут, але одразу після цього знову почав працювати під час наступного запиту. Проте протягом решти сесії агент продовжував повідомляти користувачам, що не може отримати доступ до системи звітності, хоча насправді вона працювала без проблем. Звісно, користувачі вірили словам, а не даним.

Коренева причина. Повний запис про помилку — TimeoutError через 30 секунд — був доданий до історії та так і залишився там. Для моделі твердження „система звітності ненадійна“ стало аксіомою, і кожна наступна відповідь була під впливом цього твердження. Одна тимчасова помилка перетворилася на постійне забруднення даних.

Виправлення. Розглядайте помилки як події, а не як факти. Після успішної спроби повторного виконання замініть запис про помилку в історії однорядковою приміткою на кшталт "(тимчасова помилка, вирішена під час повторної спроби)". Якщо інструмент остаточно не працює, надайте агенту чіткий структурований статус, а не стек-трейс. Стек-трейси належать до журналів, а не до контексту.

Виявлення. Шукайте у активних контекстах рядки Error, Traceback та Exception. Кожна знахідка є або триваючим інцидентом, або залишком, який забруднює подальші записи, і обидва варіанти потрібно усунути.

Случай 7: двадцять п’ять інструментів у одному вікні

Симптом. Протягом кількох місяців інструмент став повільнішим та дорожчим, що було очікувано через постійне додавання функцій. Він також почав обирати неправильний інструмент для простих запитів — наприклад, надавати експорт даних про відповідність, коли користувач хотів отримати узагальнення про проект. Нічого не зламалося; все просто стало більш хаотичним.

Коренева причина. Кількість інструментів досягла 25, кожен з яких мав довгий опис та схему JSON; разом вони споживали близько 12 000 токенів ще до того, як користувач вводив хоча б одне слово. Кожного разу модель розглядала 25 варіантів, багато з яких мали схожі описи, такі як «отримати дані про проект», «завантажити деталі проекту» та «повернути інформацію про проект». Вибір інструменту є завданням міркувань, але команда перетворила його на тест із 25 схожих варіантів відповідей.

Виправлення. Два етапи.

  1. Агресивно скорочуйте кількість інструментів. Об’єднайте ті, що перекриваються, скоротивши кількість з 25 до 11, та перепишіть опис кожного інструменту так, щоб він відповідав на одне запитання: коли моделі слід обрати саме цей інструмент замість сусідніх?
  2. Завантажуйте інструменти з урахуванням контексту. Кожному вузлу не потрібні всі інструменти. У LangGraph легко прив’язати до кожного вузла лише відповідну підмножину інструментів, тож вузел для створення звітів може бачити лише чотири інструменти, а не 25.

Витрати на токени за один хід зменшилися приблизно на третину, а випадки обрання неправильних інструментів майже зникли.

Виявлення проблем. Підрахуйте кількість токенів лише в визначеннях інструментів. Якщо їх кількість перевищує обсяг системного запиту та середньої довжини розмови разом, ваш агент складає іспит з відкритою книгою, де більшість сторінок є неправильними.

Що спільного у цих семи елементах

Якщо перечитати ці сім пунктів, стає помітна єдина закономірність. Жоден компонент не був пошкоджений, і нічого не бракувало. Забрудненням був постійний надлишок, застарілий або повторюваний контент.

Саме тому звичайне виправлення помилок тут не допомагає. Інженерів навчають шукати відсутності: відсутню перевірку на null, некеровану виняток. Для боротьби з контекстним забрудненням потрібні протилежні навички — вміння шукати те, чого не повинно бути.

Якщо ви хочете зберегти одну звичку, то нехай це буде читання сирого контексту вашого агента. Пропустіть журнали та панель контролю слідів та прочитайте справжній текст, який модель отримує під час реальної роботи. Це найцінніший час для кожного, хто створює агентів, проте майже ніхто його не використовує.

Чек-лист на шістдесят секунд перед розгортанням

  1. Чи є якесь значення стану датою, статусом чи щось на кшталт „текущий“? (Випадок 1)
  • Чи може інструмент повернути більше токенів, ніж сам системний запит? (Випадок 2)
  • Коли користувач сам себе виправляє, чи може стара версія коли-небудь перемогти? (Випадок 3)
  • Чи повторюються коли-небудь отримані фрагменти? (Випадок 4)
  • Чи може обмеження залишитися недоторканим після словесного підсумовування? (Випадок 5)
  • Чи залишаються сліди помилок у історії після відновлення? (Випадок 6)
  • Скільки токенів використовують визначення інструментів до того, як користувач щось введе? (Випадок 7)
  • Сім запитань. Будь-яка відповідь „ймовірно, але не впевнений“ — це інцидент, який чекає на дату.