Урок 2: агент, який знає, коли досить.

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

Урок 2: Планувальник і контроль

Image: METAHEURISTIC

Alexander Myasoedov

+Alexander Myasoedov Alexander будує AI-агентів і пише про те, що лишається за кадром красивих демок: цикл агента, межі доступу і контроль людини, який не вбиває автономність.

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

Після уроку ваш агент завжди закінчує роботу рішенням. Агент не пише «зупинився, бо кроки закінчилися». Агент робить 1 з 2 речей:

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

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

Аксіоматична ідея 1
Дія - це ще не прогрес. Виклик інструмента сам не наближає рішення.
Аксіоматична ідея 2
STOP і DONE мають різне значення. Зупинка без рішення - це теж збій.
Системна ідея
План - це гіпотеза з критерієм прогресу і бюджетами. Якщо факти не збігаються з планом, агент робить новий план або ескалює. Агент завжди закінчує роботу рішенням.

Аналіз проблеми

Почнемо з журналу, а не з коду. Це реальний прогін наївної версії агента з Уроку 1. Ця версія не має запобіжника від повторів. Вона має тільки ліміт кроків:

01:02 read_ticket(T-1042)
01:02 get_subscription(C-4471)
01:03 check_system(export)
01:03 check_system(billing)
01:03 check_system(auth)
01:03 check_system(email)
01:04 check_system(export)
01:04 get_subscription(C-4471)
01:04 check_system(export)
01:04 STOP

Задача: знайдіть усі проблеми, а не одну. Перед тим, як читати далі, вивчайте цей журнал 3 хвилини. Не шукайте 1 «баг». Шукайте все, що вам не подобається. Більшість людей бачить нескінченний цикл і зупиняється. Але журнал має мінімум 8 окремих проблем.

Порівняйте свій список з нашим. Уважний аналіз цих 10 рядків показує такі проблеми:

  • Зайві виклики. Тікет стосується export. Чому агент перевіряв auth і email? Кожен виклик коштує гроші і час. Для цих 2 перевірок не було причин.
  • Повторне читання. Агент викликав get_subscription(C-4471) 2 рази. Відповідь не могла змінитися за 2 хвилини. Також відповідь вже була у state.
  • Немає критерію прогресу. Після четвертого виклику агент уже мав усі факти для рішення. Жоден компонент не запитав: «Які нові факти дав цей крок?»
  • Слабкий запобіжник. Guard на точний повтор або відсутній, або не спрацьовує. check_system(export) повторився 3 рази.
  • Немає кінцевого рішення. Прогін закінчився словом STOP. Тікет залишився без власника. Ніхто не призначив тікет, не закрив тікет і не позначив тікет як проблемний.
  • Немає причин. Чому агент вирішив перевірити billing? Журнал не містить reason. Тому ми не можемо знайти місце, де міркування агента стали неправильними.
  • Немає обліку вартості. 9 викликів інструментів дають також приблизно 18 LLM-викликів: вибір і стиснення на кожному кроці. Скільки коштував прогін? Журнал не має цих даних.
  • Немає ескалації. Це найгірша проблема. Агент не вирішив задачу, і ніхто про це не дізнався. Людина не отримала тікет. Клієнт продовжує чекати.

Тепер головне питання. Я ставлю це питання на співбесідах. Поставте це питання собі: які 3 зміни ви зробите першими і чому саме ці? Запам’ятайте відповідь. У кінці уроку порівняйте її з нашою.

Чому очевидні виправлення не допоможуть

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

Збільшити max_steps. Агент не знає, коли фактів достатньо. З 16 кроками такий агент зробить те саме, що з 8 кроками, але за подвійну ціну. Ліміт кроків захищає гроші, але не дає рішення. Ліміт каже «далі не можна». Ліміт не каже «фактів уже достатньо».

Додати в промт «не повторюйся». Урок 1 вже показав це на межах доступу. Прохання в промті - це прохання, а не обмеження. Модель «знає», що повтори погані. Але модель однаково повторює виклики. Контекст моделі не має чіткого сигналу, що крок не дав результату.

Зробити запобіжник суворішим. Точний повтор легко знайти. Але подивіться на реальний цикл:

check_system("export")
check_system("billing")
check_system("export")
check_system("billing")

Жоден виклик не повторює попередній виклик. Сигнатури чергуються. Інструмент може мати ще 1 параметр. Тоді порівняння рядків не знайде цикл:

check_system("export", since="14:00")
check_system("export", since="14:01")
check_system("export", since="14:02")

Кожен виклик унікальний. Агент «працює»: викликає інструменти, отримує відповіді, використовує токени. Але агент не рухається до рішення. Це головна думка уроку.

Дія - це ще не прогрес. Виклик інструмента - це дія. Прогрес є тоді, коли після дії агент знає більше, ніж до дії. Нескінченний цикл - це не «однакові виклики». Це послідовність дій без нових знань. Тому не шукайте цикл порівнянням рядків. Шукайте відповідь на питання «Які нові факти дав цей крок?»

Агент - це процес, а не цикл

В Уроці 1 ми казали «агент - це цикл». Для першого уроку це визначення правильне. Але тепер ми бачимо, що воно занадто вузьке. Цикл - це механіка: повторювати дію до події. Журнал вище показує цикл, який працює без помилок. Проблема не в циклі. Проблема в тому, що навколо циклу немає інших частин.

Точніше визначення таке: агент - це процес. Процес має цикл і також має такі частини:

  • стан;
  • бюджети;
  • точки контролю;
  • визначені виходи.

Виходи - найважливіша частина. Процес не просто «зупиняється». Процес завершується одним з визначених результатів.

Запам’ятайте також суміжне поняття. workflow - це фіксована послідовність кроків. Workflow щоразу виконує однакові кроки. Агент змінює послідовність кроків на основі нових фактів. Але зміна кроків без контролю дає журнал вище.

Цикл
loop
Механіка роботи: вибрати крок, виконати крок, подивитися на результат.
Прогрес
progress
Критерій руху. Кожен крок повинен додавати знання. Інакше крок порожній.
Бюджети
budgets
Межі процесу: кроки, гроші, час. Кінець бюджету - це подія, а не аварія.
Виходи
outcomes
Визначені завершення: дія або ескалація. Тихої зупинки немає.

Запишемо це як вимоги. Ці вимоги доповнюють контракт з Уроку 1. Агент тріажу той самий. Але тепер ми вимагаємо від агента контролю, а не тільки функціональності:

Контроль агента - вимоги
01
План
Агент робить план перед першим викликом. План містить інструменти, їхній порядок і критерій достатності фактів.
02
Прогрес
Кожен крок повинен додавати нові факти. 2 порожні кроки підряд - сигнал змінити підхід.
03
Нові плани
Агент може змінити план 2 рази. Після третьої невдачі агент ескалює.
04
Завершення
Тільки 1 явний вихід: дія або ескалація зі звітом. STOP без рішення неможливий.
05
Бюджет
Агент рахує кроки, гроші і час. Якщо бюджет закінчився, агент ескалює і не зупиняється без звіту.
06
Походження
Кожен крок має причину. Людина може прочитати причину в журналі після прогону.

Крок 1: прогрес замість повторів

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

before = dict(state.facts)
for f in extract(obs, state):
    state.facts[f["key"]] = f["value"]
state.no_progress = 0 if state.facts != before else state.no_progress + 1

Кожен крок з новими фактами скидає лічильник no_progress на 0. Кожен порожній крок збільшує лічильник. Після 2 порожніх кроків підряд агент змінює підхід. Подивіться на той самий прогін із зависанням:

read_ticketget_subscriptioncheck(export)check(billing)check(auth)+2 факти+1 факт+1 факт0 нових0 новихno_progress = 00012два порожні кроки поспіль - міняємо підхід, а не викликаємо далі
Прогрес - це нові факти, а не нові виклики. Аргументи можуть змінюватися будь-як. Якщо словник фактів не збільшується, агент не рухається.

Цей запобіжник значно сильніший за порівняння сигнатур з Уроку 1. Виклик check_system("export", since="14:01") після since="14:00" має нову сигнатуру. Але цей виклик не дає нових фактів, і лічильник це бачить. Ми знаходимо цикл за формою поведінки, а не за текстом викликів.

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

Крок 2: планувальник

До цього моменту агент працював по 1 кроку. Агент дивився на факти, вибирав інструмент і повторював. У цьому режимі агент не має з чим порівняти свої дії. Будь-який виклик здається однаково розумним, бо агент не бачить усю задачу.

planner змінює це. Перед першим викликом інструмента модель робить план. План містить:

  • інструменти;
  • порядок інструментів;
  • мету кожного інструмента;
  • критерій достатності: факти, які агент повинен знати перед дією.

План - це структурований вихід, а не есе. Тут ми використовуємо ту саму техніку structured outputs, що й у extract:

PLAN_SCHEMA = {
    "type": "object",
    "properties": {
        "steps": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "tool": {"type": "string", "enum": LOOKUPS},
                    "goal": {"type": "string"},
                },
                "required": ["tool", "goal"],
                "additionalProperties": False,
            },
        },
        "done_when": {"type": "string"},
    },
    "required": ["steps", "done_when"],
    "additionalProperties": False,
}

2 поля роблять усю роботу:

  • steps - упорядкований список кроків. Кожен крок має інструмент і мету. Тепер журнал відповідає на питання «Чому агент перевіряв billing?». Або план просто не містить цієї перевірки.
  • done_when - критерій достатності. Це явна відповідь на питання «Коли фактів достатньо?». Урок 1 не мав цієї відповіді.

Для нашого тікета план приблизно такий:

1. read_ticket - зрозуміти, про що звернення і хто клієнт
2. get_subscription - дізнатися план і статус клієнта
3. check_system(export) - перевірити систему, на яку скаржаться
done_when: відомий план клієнта і статус export - цього досить для рішення

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

Граф інструментів з Уроку 1 залишився. Тепер граф - нижній шар. Граф перевіряє, що перехід дозволений. Але маршрут тепер визначає план:

def choose(ticket_id: str, plan: Plan, state: State) -> tuple[str, dict]:
    allowed = ([plan.current()] if plan.current() else []) + sorted(TERMINAL)
    r = client.messages.create(
        model=MODEL, max_tokens=1024,
        tools=[TOOLS[name].schema for name in allowed] + [REPLAN],
        tool_choice={"type": "any"},
        messages=[{"role": "user", "content": (
            f"You are a support triage agent working ticket {ticket_id}.\n"
            f"Plan:\n{plan.pretty()}\n"
            f"Known facts: {state.facts}\n"
            "Follow the plan step by step. Act as soon as done_when is satisfied. "
            "If the facts contradict the plan, call replan and say why."
        )}],
    )
    block = next(b for b in r.content if b.type == "tool_use")
    return block.name, block.input

Подивіться на результат. Петля check_system -> check_system спричинила проблему в Уроці 1. Тепер агент не може безцільно ходити по цій петлі. План містить перевірку export 1 раз і з метою. Порожніх перевірок auth і email немає, бо план їх не містить. Відповідь на «Коли фактів достатньо?» тепер не є інтуїцією моделі. Це рядок, який видно в журналі.

ПЛАН1. read_ticket2. get_subscription3. check_system(export)done_when: план клієнта +статус export відоміВИКОНАННЯкрок плануінструментзвірка з планомдіяфакти розійшлися з планом - replan (до двох разів)done_when виконано
Планувальник розділяє 2 питання, які раніше були в 1 виклику. Агент відповідає на питання «Що робити загалом?» 1 раз у плані. Агент відповідає на питання «Що робити зараз?» на кожному кроці і порівнює відповідь з планом.

План - це гіпотеза, а не дозвіл. Планувальник відповідає тільки на питання «Що робити далі?». Планувальник не відповідає на питання «Що дозволено робити?». Межі доступу, перевірка аргументів і правила на зразок «максимум 1 перезапуск» залишаються в коді інструментів. Якщо план каже «зроби X», а policy каже «не можна», policy має пріоритет. Агент отримує відмову як спостереження.

Запускаємо, і план не працює

На тікеті T-1042 новий агент точно виконує план: 4 виклики без зайвих, assign у кінці. Але подивіться на інший тікет. Клієнт пише, що export віддає порожній файл. Наші дані не містять цього клієнта:

Plan v1:
  1. read_ticket - зрозуміти звернення і клієнта
  2. get_subscription - план і статус клієнта
  3. check_system(export) - статус системи зі скарги
  done_when: відомий план клієнта і статус export
Call history:
  read_ticket({'ticket_id': 'T-2077'})
  get_subscription({'customer_id': 'C-9130'})
  replan: subscription lookup returned nothing - customer unknown,
          plan assumed an active customer
Plan v2:
  1. check_system(export) - чи не масовий це збій
  done_when: зрозуміло, це проблема акаунта чи системи
Call history (продовження):
  check_system({'name': 'export'})
  request_details({'question': 'Please confirm the account email your
                   subscription is registered under.'})

Крок 2 плану повернув «no subscription on file». План v1 мав припущення: клієнт існує і має план підписки. Факти не підтвердили це припущення. Тому решта плану втратила сенс.

Агент не виконав крок 3 тільки тому, що він є в плані. Агент також не завис. Агент викликав replan і назвав причину. Агент отримав новий, коротший план і закінчив задачу дією.

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

  • Новий план - це явна подія. replan - окремий мета-інструмент з обов’язковим reason. Журнал показує, що план змінився і чому. Агент не може тихо відійти від плану і «просто перевірити email». Меню кроків містить тільки кроки плану.
  • Нові плани мають бюджет. Агент може зробити 2 нові плани. Третя невдача плану означає, що наша модель задачі не відповідає реальності. Тоді правильна дія - ескалація, а не четвертий план. Без цього бюджету нескінченний цикл переходить на рівень планів. Агент з нескінченними новими планами виглядає розумнішим за агента з нескінченними check_system. Але такий агент коштує ще більше.

Агент робить новий план з 2 причин:

  1. Модель сама бачить суперечність і викликає replan. Ви вже бачили цей випадок.
  2. Механічна причина з Кроку 1: 2 кроки без нових фактів. Модель може не бачити, що не рухається. Лічильник бачить це замість моделі:
if state.no_progress >= budget.max_no_progress:
    plan = replan(ticket_id, state, budget, "no new facts for two steps in a row")
    if plan is None:      # бюджет перепланів вичерпано - вже ескалювали
        return state
    continue

STOP і DONE мають різне значення

Тепер про найгіршу проблему з аналізу: прогін закінчився словом STOP. В Уроці 1 агент мав 3 виходи: assign, request_details, close_ticket. Також агент мав 1 діру. Якщо агент не досягав жодного виходу, агент просто зупинявся. Тікет залишався без власника.

Концепція виправлення проста: невдача - це теж рішення, і невдача має свою дію. Додайте четвертий кінцевий інструмент: escalate. Тепер кожен прогін закінчується 1 з 4 виходів. Жоден вихід не є тихим:

УРОК 1: STOPциклліміт кроківтікет висить, ніхто не знаєУРОК 2: DONEпроцесassignrequest_detailscloseescalateзі звітом: що знаю, що пробував, чому не впорався
STOP - це обрив. Процес зникає, тікет залишається без власника. DONE - це завершення 1 з визначених виходів. Невдача - один з цих виходів, і вона має свій звіт.

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

def give_up(state: State, plan: Plan, reason: str) -> State:
    report = (
        f"reason: {reason}; "
        f"plan: {[s['tool'] for s in plan.steps]}; done_when: {plan.done_when}; "
        f"facts: {state.facts}; calls: {state.calls}"
    )
    state.action = f"escalate -> {escalate(report)}"
    return state

Звіт містить причину, план, зібрані факти і історію викликів. Людина, яка відкриває тікет, не повторює роботу агента. Людина продовжує роботу з місця, де агент зупинився. Ескалація перестає бути поразкою. Ескалація стає передачею задачі.

Важлива деталь: give_up викликає код, а не модель. Модель використала бюджет. Тому модель не повинна вирішувати про ескалацію після кінця бюджету.

Тут також є відповідь на питання: як людина бере участь в агентному процесі? escalate - це звичайний інструмент. Інструмент може чекати. Процес такий:

  1. Збережіть state на диск.
  2. Поставте тікет у чергу до людини.
  3. Коли відповідь прийде, завантажте state.
  4. Продовжіть процес з того самого місця.

Відповідь може прийти через 1 годину або через 3 дні. Агент, який уміє зупинитися і продовжити, не утримує процес у пам’яті цілу добу. Це різниця між скриптом, який висить у терміналі, і процесом. Процес працює стільки часу, скільки існує задача.

Бюджети: кроки, гроші, час

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

@dataclass
class Budget:
    max_steps: int = 8         # ліміт викликів інструментів
    max_replans: int = 2       # третій зрив плану = ескалація
    max_no_progress: int = 2   # два кроки без нових фактів = міняємо підхід
    deadline_s: float = 60.0   # тріаж не тримає чергу

Подивіться на 3 деталі.

Перша деталь: агент має різні бюджети з різними задачами.

  • Ліміт кроків захищає гроші.
  • Дедлайн захищає чергу тікетів.
  • Ліміт нових планів захищає від нескінченного циклу на рівні планів.

1 число max_steps не покриває ці 3 задачі.

Друга деталь: кінець бюджету - це подія з обробником, а не аварія. Кожна перевірка бюджету веде в give_up, тобто в ескалацію зі звітом. Людина бачить «step budget exhausted» і всі факти, а не порожнє місце.

Третя деталь: state тепер також рахує LLM-виклики (state.llm_calls). Тому в кінці прогону ви знаєте точну вартість рішення. У продакшні ці числа стають метриками:

  • кількість кроків до рішення;
  • частка ескалацій;
  • вартість тікета.

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

Той самий контроль в інших доменах

Як в Уроці 1, ми перевіряємо скелет на інших доменах. Тепер ми перевіряємо шар контролю. Ми маємо 3 агенти з минулого уроку і 3 відомі проблеми.

On-call агент і каскад перезапусків. Ситуація така. Агент перезапустив сервіс. Метрики ще не змінилися, і латентність залишається високою. Модель каже: «Перезапустимо ще раз». Ось питання, яке я часто ставлю: у якому місці коду повинно бути правило «максимум 1 перезапуск»? Ви вже знаєте 3 варіанти:

  • У промті: «please restart at most once». Це прохання. Великий контекст або injection з журналів може обійти прохання.
  • У плані: план каже «1 перезапуск». Це краще, бо відхилення від плану видно. Але план пише модель. Наступний план може містити інше.
  • У коді інструмента: restart_service сам рахує перезапуски і відмовляє:
def restart_service(name: str) -> str:
    if state.restarts.get(name, 0) >= 1:
        return "denied by policy: one restart per incident. Escalate instead."
    state.restarts[name] = state.restarts.get(name, 0) + 1
    return f"{name}: restarted"

Правильна відповідь - третій варіант. Форма відмови важлива. Відмова - це спостереження, а не виняток. Агент бачить «denied by policy» як звичайний результат кроку. Агент повинен вибрати інший шлях, найчастіше escalate.

План пропонує, policy вирішує. Це той самий принцип з Уроку 1: межа в коді, а не в промті. Але тепер принцип захищає продакшн, а не дані. Додайте дедлайн з бюджету. Якщо on-call агент за визначений час не вирішив алерт і не ескалював, код ескалює примусово. Тоді нічний черговий агент під вашим контролем.

Аналітик і нескінченне уточнення. Self-loop на run_query з Уроку 1 - це точно наш випадок «дія без прогресу». Агент переписує той самий запит з малими змінами. Кожен виклик має нову сигнатуру, але жоден виклик не додає фактів. Лічильник прогресу знаходить цей цикл без спеціальної логіки.

Вихід escalate тут має корисну форму. Аналітик не зупиняється тихо. Аналітик дає часткову відповідь: «Цей запит працює, ось число. Але я не впевнений у фільтрі за датами. Людина повинна перевірити фільтр».

Кодовий агент і червоні тести. Цикл «зміна, тести, зміна» дозволений. Але цей цикл повинен мати бюджет ітерацій. Після N червоних прогонів правильна дія - зупинитися і ескалювати з diff. Людина бачить спроби агента, тести, які не проходять, і місце, де агент зупинився. Це той самий give_up. Але звіт містить патчі і вивід тестів замість фактів.

Каталог: що закрито, що залишилося

Порівняймо результат з каталогом проблем з Уроку 1:

  • Нескінченний цикл - закрито 2 рази. Прогрес знаходить цикл за формою поведінки. План прибирає безцільні кроки. Залишковий ризик - нескінченний цикл планів. Бюджет нових планів закриває цей ризик.
  • Тихий STOP - закрито. Агент має 4 явні виходи, ескалацію зі звітом і обробник для кожного бюджету.
  • Лавина повторних спроб - закрито частково. Бюджети зупиняють агента, який сам повторює кроки. Політика повторних спроб для інструментів (бекоф, jitter, circuit breaker) - тема інфраструктури. Ця тема буде в наступних уроках.
  • prompt injection і межі доступу - без змін. Це важливо сказати явно: планувальник тут не допомагає. План, який пише модель, так само вразливий до інструкцій у даних, як і вибір 1 кроку. Захист залишається в коді інструментів.
  • Колапс контексту - не закрито. Факти накопичуються в словнику. На довгих задачах словник сам стане проблемою. Це тема пам’яті.

Еволюція вимог

Зміна та сама, що й у минулому уроці. Кожна проблема, яку ми знайшли, стала рядком контракту.

Вимоги v1 (Урок 1)

  • Зібрати контекст
  • Вибрати 1 дію
  • Не працювати в нескінченному циклі

Вимоги v2 (після Уроку 2)

  • План перед першим викликом, з критерієм достатності
  • Прогрес на кожному кроці: крок без нових фактів порожній
  • До 2 нових планів, кожен з причиною в журналі
  • Бюджет кроків, грошей і часу з обробником кінця бюджету
  • Ескалація зі звітом замість тихого STOP

Повернімося до питання з аналізу: які 3 зміни зробити першими? Моя відповідь після цього уроку:

  1. Ескалація. Невидима невдача - найдорожча проблема.
  2. Прогрес. Це найдешевший запобіжник.
  3. План. План робить журнал зрозумілим, а момент «фактів достатньо» - явним.

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

Завантажте повний код

Повний файл - це 1 модуль. Модуль продовжує код Уроку 1 і містить план, прогрес, нові плани, бюджети і ескалацію. Запустіть обидва тікети. T-1042 виконає план до assign. T-2077 зламає план і покаже створення нового плану.

Завантажити lesson-2-planner.py

pip install anthropic
export ANTHROPIC_API_KEY=sk-...
python lesson-2-planner.py

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

  • база знань підтримки;
  • історія тисяч тікетів;
  • документація.

Тоді агент повинен шукати знання, а не пам’ятати їх. Наступний урок будує retrieval. Спочатку ми зробимо наївний пошук, який здається робочим. Потім ви побачите, як цей пошук програє навіть grep, і що з цим робити.

Курс Metaheuristic

Збудуй AI-агента з нуля.

11 рівнів практики: від виклику LLM до власного coding-агента. Приховані тести, failure patterns, office hours.

Записатись - early bird 9 500 UAH →