Laravel AI SDK повертає типізований об’єкт відповіді: $response->text, $response->usage, $response->meta тощо. Ці властивості містять лише базові дані, спільні для всіх провайдерів. Раніше заголовки лімітів (rate limit headers), специфічні ID запитів провайдера та інші додаткові поля залишалися недосяжними.
Версія 0.10.3, випущена 6 серпня 2026 року, відкриває до них доступ. Розробник @dumbbellcode у межах #714 додав публічну властивість raw. Вона містить об’єкт Illuminate\Http\Client\Response — результат того самого запиту, який SDK виконує замість вас:
$response = (new SupportAgent)->prompt('Summarize this document.');
$response->raw->header('x-ratelimit-remaining-requests');
$response->raw->json('id');
Це той самий HTTP client response, який повертає Http::get(), тому методи header(), json() та status() працюють як зазвичай.
# Кожен крок зберігає власну відповідь
Коли агент викликає інструменти (tools), він робить кілька запитів поспіль. Провайдер ініціює виклик інструменту, SDK виконує його, надсилає результат назад і повторює це, доки модель не припинить запити. Властивість $response->raw повертає HTTP-відповідь фінального запиту — того самого, що згенерував підсумковий текст.
Проте кожен проміжний крок також зберігає свій raw:
foreach ($response->steps as $step) {
$step->raw?->header('x-ratelimit-remaining-tokens');
}
Якщо виконання складалося з п'яти кроків, було зроблено п'ять запитів. Ліміт токенів у такому разі розподіляється між усіма п'ятьма заголовками, а не лише останнім.
Слухачі подій отримують той самий об'єкт, оскільки AgentPrompted містить власне відповідь:
use Laravel\Ai\Events\AgentPrompted;
Event::listen(AgentPrompted::class, function (AgentPrompted $event) {
$remaining = $event->response->raw?->header('x-ratelimit-remaining-requests');
if ($remaining !== null & (int) $remaining < 10) {
Log::warning('Provider request budget running low.', [
'provider' => $event->response->meta->provider,
'remaining' => $remaining,
]);
}
});
Якщо перевіряти заголовки безпосередньо у місці виклику, їх доведеться передавати далі через усю структуру коду. Слухач подій дозволяє тримати логіку перевірки в одному місці та застосовувати її до кожного запуску.
# Зв'язок невдалих запусків із провайдером
Коли запит до моделі працює некоректно і ви звертаєтеся до підтримки провайдера, вони зазвичай просять надати ID запиту з їхнього боку. До появи raw єдиним способом отримати цей ID було логування всього запиту через middleware для HTTP-клієнта, що часто призводило до потрапляння конфіденційних промптів у логи.
Тепер ID можна просто прочитати з отриманої відповіді:
Log::info('Agent run completed.', [
'invocation' => $response->invocationId,
'provider_request_id' => $response->raw?->header('request-id'),
]);
Назви заголовків у різних провайдерів відрізняються, тому звіряйтеся з документацією сервісу, який використовуєте.
# Коли raw дорівнює null
Властивість може бути порожньою, тому варто використовувати безпечний оператор ?->. Існує чотири випадки, коли повертається null:
- Стрімінг (Streamed responses).
$agent->stream()та подіяAgentStreamedзавжди повертають null, оскільки потокова відповідь збирається по частинах, а не з одного цілісного об'єкта. - Bedrock. Для викликів використовується AWS SDK, тому стандартної HTTP-відповіді клієнта просто немає. Усі інші провайдери на базі HTTP (Anthropic, OpenAI, Azure OpenAI, DeepSeek, Gemini, Groq, Mistral, Ollama, OpenAI-compatible, OpenRouter та xAI) підтримують цю властивість.
- Серіалізовані відповіді. Тіло відповіді — це потік Guzzle, який неможливо серіалізувати (виникає
LogicException). Тому SDK видаляєrawу методі__serialize(). Якщо відповідь пройшла через чергу (queue) або кеш,rawбуде null. Якщо заголовок потрібен у черзі, прочитайте його перед відправкою та передайте окремим значенням. - Faked agents, якщо для фейкової відповіді не було вказано
raw.
# Тестування фейкових відповідей
Тестувати обробку лімітів складно, бо вона спрацьовує лише на межі відмови провайдера. Фейкові відповіді тепер підтримують власний raw через метод withRawResponse():
use GuzzleHttp\Psr7\Response as Psr7Response;
use Illuminate\Http\Client\Response;
use Laravel\Ai\Responses\TextResponse;
SupportAgent::fake([
(new TextResponse('Hello', new Usage, new Meta))->withRawResponse(new Response(
new Psr7Response(200, ['x-ratelimit-remaining-requests' => '99'], '{}')
)),
]);
$response = (new SupportAgent)->prompt('Hi');
$response->raw->header('x-ratelimit-remaining-requests'); // '99'
Ви можете сконструювати потрібні заголовки та перевірити, чи правильно відпрацював ваш слухач подій. Зверніть увагу, що метод називається саме withRawResponse(), а не withRaw().
# Що ще почитати
Властивість $response->raw з'явилася у версії v0.10.3. Свіжий реліз v0.11.0 розвиває цю ідею, додаючи події життєвого циклу та таймінги для кожного кроку та виклику інструменту під час роботи агента.
Більше про пакет можна дізнатися з анонсу AI SDK та нашого матеріалу про підтвердження дій інструментів людиною (human-in-the-loop). Вихідний код доступний на GitHub у репозиторії laravel/ai.