Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Події
Інше
Про нас
Новини 22 серпня 2026

Реліз Laravel AI SDK 0.11: Спостережуваність Виконання Агентів і Розширені Можливості Відмовостійкості

Laravel AI v0.11.0 надає виконанню агента єдиний ідентифікатор кореляції та набір подій життєвого циклу, які спрацьовують навколо кожного круготрипу провайдера та кожного виклику інструменту. До цього виконання, що потребувало п'яти круготрипів для вирішення своїх викликів інструментів, виглядало ідентично тому, що завершилося за один виклик, а виконання, яке зазнало невдачі в шлюзі, не звітувало про це взагалі. Реліз вийшов 19 серпня 2026 року з 36 об'єднаними pull request та дванадцятьма новими контриб'юторами.

Трасування Повного Виконання Агента

Сім pull request від @pushpak1300 переробили спосіб звітування виконання агента про себе.

streamPrompt() вже генерував ідентифікатор виконання на рівні run, але prompt() цього не робив, тому синхронне middleware бачило $prompt->invocationId === null. Натомість streaming middleware бачило реальне значення, а відмовостійкість на трьох провайдерах виробляла три непов'язані ID для одного виконання. prompt() тепер генерує ID заздалегідь, а провайдер повторно використовує те, що надав викликач ( #871).

RunContext тепер несе ідентичність виконання та диспетчеризує події безпосередньо, замінюючи пару callback-функцій, які кожен провайдер реєстрував у циклі генерації. Стара схема відстежувала поточний ID виклику інструменту в єдиній змінній властивості, що ламалося при вкладенні: агент, викликаний як інструмент, перезаписував ID до того, як зовнішня подія ToolInvoked спрацьовувала, тому зовнішня подія несла ID внутрішнього виклику. ID тепер генерується всередині executeTool(), і інструменти можуть прочитати його за допомогою Request::toolInvocationId() ( #872).

StartingStep, StepCompleted та StepFailed спрацьовують навколо кожного круготрипу провайдера як на синхронному, так і на streaming шляху ( #873). StartingStep несе повідомлення та вирішені опції, з якими надсилається крок, StepCompleted несе повну відповідь кроку, а кожна завершальна подія несе час виконання кроку в мілісекундах, що відповідає QueryExecuted::$time. StartingStep також несе всю історію повідомлень виконання, тому ShouldQueue listener серіалізує її разом з будь-якими вкладеннями.

executeTool() раніше не мав catch, тому інструмент, обробник якого кидав виняток, поширювався прямо з циклу генерації без запису про те, який інструмент його спричинив. ToolFailed тепер повідомляє про це, несучи той самий ID виклику інструменту, що й InvokingTool, який його відкрив, і виняток все ще перекидається ( #874). На рівні run AgentFailed повідомляє про термінальну невдачу один раз на виконання, і лише після того, як виконання завершилося, що означає після того, як відмовостійкість вичерпала ланцюг провайдерів ( #876).

Виклик інструменту тепер публікує свої ID виконання run та виклику інструменту на час свого виконання, і будь-який агент, викликаний під час його роботи, підхоплює їх як parentInvocationId та parentToolInvocationId ( #875). Це зв'язує суб-агента з виконанням, яке делегувало йому завдання, і охоплює написаний вручну інструмент, який викликає агента, а не лише AgentTool. Зв'язок не перетинає межу черги, тому prompt, відправлений з promptOnQueue() зсередини інструменту, все одно починає своє власне виконання без батьківського.

Розміщений Пошук Інструментів

Кожен інструмент, який агент надає, раніше відправлявся провайдеру при кожному запиті. З великим каталогом це коштує токенів і дає моделі довге меню для вибору. @behzadsp додав обгортку ToolSearch у #697, яка відкладає інструменти всередині неї, щоб OpenAI та Anthropic завантажували їх на вимогу через власний розміщений пошук:

public function tools(): iterable
{
    return [
        new WeatherTool,
        new ToolSearch(tools: [new SearchInvoices, new RefundOrder]),
    ];
}

Самі інструменти не потребують змін: немає інтерфейсу для реалізації, немає опцій провайдера. Обгортка відображається на {"type":"tool_search"} на OpenAI та на типи tool_search_tool_* на Anthropic, а стратегія пошуку Anthropic є аргументом конструктора, валідованим проти regex та bm25:

new ToolSearch(tools: [new SearchInvoices], strategy: 'bm25')

Провайдери, які не підтримують розміщений пошук, кидають чіткий виняток до відправлення запиту, а не відкидають інструменти обгортки, і перевірка виконується навіть коли обгортка порожня, щоб неправильні конфігурації виявлялися під час розробки. Лише одна обгортка може бути зареєстрована на запит, а розміщений пошук OpenAI вимагає збережених відповідей, тому ToolSearch, використаний з store=false, кидає виняток. Той самий pull request додає відтворення виводу без стану для OpenAI, захоплюючи повний упорядкований вивід відповіді та відтворюючи його дослівно при продовженні, коли store=false.

Більше Сценаріїв Відмовостійкості

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

Коли провайдер був недоступний через те, що хост був недоступний, з'єднання було відхилено або локальний екземпляр Ollama не працював, HTTP-клієнт Laravel кидав ConnectionException. Це окрема гілка ієрархії винятків клієнта від RequestException, тому вона повністю проскочила обробник відмовостійкості. Тепер вона перекидається як ProviderConnectionException, що реалізує FailoverableException, у спільній ознаці, яку використовує кожен шлюз (@JVillator0, #781).

Набір статусів, що розглядаються як перевантажений провайдер, виріс з лише 503 до 502, 503, 504, 520, 522 та 524, додавши таймаути шлюзу та помилки Cloudflare, які провайдери за Cloudflare повертають під час інцидентів. Чистий 500 навмисно залишений поза списком, оскільки це може бути детермінована помилка, яку відмовостійкість замаскує (@sulimanbenhalim, #810). Anthropic отримав таке саме оброблення для своїх тимчасових помилок шлюзу та Cloudflare ( #884).

Anthropic також відхиляє запити з HTTP 400, коли організація досягає свого налаштованого ліміту витрат, а формулювання повідомлення не відповідало жодним існуючим шаблонам кредитів. Отже, необроблений RequestException ніколи не досягав циклу відмовостійкості. @oddvalue повідомив приблизно про 990 необроблених винятків за місяць саме з цієї причини, з другим ключем Anthropic та провайдером OpenAI, які простоювали в тому самому ланцюгу. Додавання usage limit до списку шаблонів виправляє це ( #864).

Підтримка Провайдерів

  • xAI отримав веб-пошук ( #857) та пошук файлів (@timmcleod, #894)
  • Транскрипція з'явилася для OpenAI-сумісного провайдера ( #858) та для Groq ( #868)
  • OpenRouter підтримує серверний інструмент веб-завантаження (@CamilleScholtz, #889)
  • Цитати веб-завантаження Anthropic тепер з'являються на $response->meta->citations, які раніше поверталися порожніми, оскільки читалися лише блоки web_search_tool_result. Тільки для не-streaming відповідей ( #892)
  • Текстова модель за замовчуванням Gemini перемістилася на gemini-3.7-flash ( #887)

Помічники Для Тестування

assertPromptedTimes() приєднується до фейкових тверджень у трейті Promptable, працюючи так само, як Bus::assertDispatchedTimes() та Notification::assertSentTimes() (@F1nnG, #891):

SalesCoach::assertPromptedTimes(3);

Фейкова генерація транскрипцій, зображень, аудіо та embeddings у черзі тепер запускає callback then(...), щоб тест міг стверджувати про те, що зробив callback, замість зупинки на диспетчеризації (@gdebrauwer, #797).

Інші Виправлення

  • Потокове використання підсумовується через кроки виклику інструментів у кожному шлюзі провайдера ( #698), шлюз OpenAI більше не втрачає токени запису кешу з використання ( #846), а токени кеш-попадань DeepSeek виключаються зі звітованої кількості токенів промпту ( #896)
  • Частково осиротілі виклики інструментів фільтруються при відтворенні історії розмови ( #758), а невідомі локальні виклики інструментів виправляються, а не призводять до збою виконання ( #859)
  • Відповіді Mistral, що повертають контент як список блоків, обробляються ( #866), причини зупинки Anthropic refusal та model_context_window_exceeded відображаються ( #881), markdown огорожі коду видаляються зі структурованого виводу OpenAI-сумісного провайдера ( #879), а стан текстової частини скидається після TextEnd у потоках Responses API ( #854)
  • Вкладення документів S3 реконструюються у File::fromArray ( #878), джерела текстових документів надсилаються як text/plain на Anthropic ( #886), а запит MCP залишається прив'язаним під час перетворення результатів генератора ( #888)

Примітки До Оновлення

Помилка провайдера, повідомлена всередині тіла потоку, HTTP 200, чий SSE payload несе об'єкт error, тепер кидає StreamErrorException замість завершення кроку з break. Споживачі раніше отримували частковий ->text, без причини завершення, без термінального StreamEnd та без сигналу, що виконання зазнало невдачі. Виняток несе власну подію помилки провайдера на ->error, і він навмисно не є відмовостійким, оскільки ці надходять як 200 ( #870).

Дві події отримали обов'язкові аргументи конструктора: AgentFailedOver приймає string $invocationId як свій останній аргумент ( #871), а ToolInvoked приймає float $time ( #874). Listeners не постраждали; оновлення потрібне лише коду, що конструює ці події вручну.

AgentFailedOver також більше не спрацьовує для фінального провайдера в ланцюгу. Ця спроба не має на що відступити, тому вона повідомляє про невдачу виконання через AgentFailed натомість ( #876).

Додатки, що використовують текстову модель Gemini за замовчуванням, перейдуть на gemini-3.7-flash ( #887). Встановіть модель явно, якщо потрібна стара.

Оновіться за допомогою composer update laravel/ai, або встановіть пакет вперше з composer require laravel/ai та дотримуйтесь офіційної документації для конфігурації.

6

Читати в документації

Коментарі

Увійдіть, щоб залишити коментар

Будьте першим, хто залишить коментар!

Читайте також

whereBinary()
Новини 28 серпня 2026

whereBinary(): регістрозалежні запити MySQL у Laravel

Laravel 13.27 додає новий метод whereBinary() для точного побайтового порівняння рядків у MySQL. Він вирішує проблему, коли стандартне collation utf8mb4_unicode_ci ігнорує регістр, акценти та пробіли при порівнянні токенів, slug-ів та інших критичних даних.

ToolSearch
Новини 27 серпня 2026

Laravel AI: завантаження інструментів на вимогу з ToolSearch

Laravel AI v0.11.0 додає механізм відкладеного завантаження інструментів агента через ToolSearch. Замість надсилання всіх тридцяти інструментів одразу, провайдер отримує лише пошуковий запис і завантажує повні визначення тільки тоді, коли модель вирішує їх використати.

2

Вакансії за темою

Softprom
18 днів тому

FullStack Developer (PHP Laravel + React) for Automation and AI

FullStack розробник для проектів автоматизації та AI. Розробка backend на PHP Laravel з мікросервісною архітектурою, інтеграція ERP/CRM систем (NetSuite, HubSpot), та frontend на React з AI-функціоналом (chatbots, генерація контенту). Потребує 5+ років PHP, 3+ років Laravel на рівні архітектури, досвід мікросервісів, OOP, REST API, Websockets.

Пакети за темою

Pest

pestphp/pest

Тестовий фреймворк з лаконічним синтаксисом поверх PHPUnit: тести описуються функціями замість класів. Має паралельний запуск, тести архітектури, покриття і мутаційне тестування.

11,667 v5.1.1 2

Laravel Dusk

laravel/dusk

Браузерні тести з виразним API: керує справжнім Chrome через ChromeDriver, тож перевіряє і JavaScript, і те, що бачить користувач. Робить скріншоти невдалих тестів автоматично.

1,943 v8.6.0 13 1