Laravel AI SDK повертає типізований об'єкт відповіді з властивостями $response->text, $response->usage, $response->meta тощо. Ці властивості охоплюють лише те, що є спільним для всіх провайдерів, і нічого більше. Заголовки обмеження швидкості (rate limit), власні ідентифікатори запитів провайдера та поля payload поза загальною структурою раніше були недоступними.
Версія 0.10.3, випущена 6 серпня 2026 року, робить їх доступними. Контрибутор @dumbbellcode додав публічну властивість raw у pull request #714, яка зберігає Illuminate\Http\Client\Response від виклику, здійсненого SDK від вашого імені:
$response = (new SupportAgent)->prompt('Summarize this document.');
$response->raw->header('x-ratelimit-remaining-requests');
$response->raw->json('id');
Це той самий об'єкт HTTP-клієнта, який повертається з Http::get(), тому методи header(), json() та status() працюють як зазвичай.
Кожен крок зберігає власну відповідь
Виконання агента, який викликає інструменти, здійснює більше одного запиту. Провайдер повертає виклики інструментів, SDK виконує їх, надсилає результати назад і повторює цикл, доки модель не припинить запитувати інструменти. $response->raw надає HTTP-відповідь фінального запиту в цьому циклі - того, що згенерував текст, який ви отримали.
Кожен крок зберігає власну властивість raw:
foreach ($response->steps as $step) {
$step->raw?->header('x-ratelimit-remaining-tokens');
}
Виконання з п'яти кроків зробило п'ять запитів, і бюджет rate limit, який воно спожило, розподілений між усіма п'ятьма заголовками, а не лише останнім.
Обробники подій отримують той самий об'єкт, оскільки 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,
]);
}
});
Читання заголовка в місці виклику означає передачу його назад до того, хто викликав агента. Слухач зберігає перевірку в одному місці й застосовує її до кожного виконання.
Кореляція проблемного виконання з провайдером
Коли виконання генерує щось неправильне і ви звертаєтесь до провайдера, вони запитують ідентифікатор запиту з їхнього боку. Без raw єдиним способом отримати його було логування всього запиту самостійно через middleware HTTP-клієнта, що означало захоплення промптів, які ви можливо не хочете бачити в логах.
Тепер ви можете прочитати його з відповіді, яка вже є у вас:
Log::info('Agent run completed.', [
'invocation' => $response->invocationId,
'provider_request_id' => $response->raw?->header('request-id'),
]);
Назви заголовків відрізняються залежно від провайдера, тому перевірте той, який ви викликаєте.
Коли raw повертає null
Властивість є nullable, тому використовуйте ?-> для безпеки. Чотири випадки можуть повернути null:
- Потокові відповіді.
$agent->stream() та подія AgentStreamed завжди повертають null, оскільки потокова відповідь складається з stream events, а не з одного response body.
- Bedrock. AWS SDK виконує виклик, тому немає HTTP-відповіді клієнта для повернення. Усі інші провайдери на основі HTTP заповнюють її: Anthropic, OpenAI, Azure OpenAI, DeepSeek, Gemini, Groq, Mistral, Ollama, OpenAI-compatible, OpenRouter та xAI.
- Серіалізовані відповіді. Response body є Guzzle stream, і Guzzle викидає
LogicException, якщо щось намагається його серіалізувати. SDK-відповідь видаляє raw у власному __serialize() з цієї причини, тому відповідь, що пройшла через чергу або кеш, повертається з raw, встановленим у null. ЯкщоJob у черзі потребує заголовка, прочитайте його перед відправкою та передайте значення.
- Підроблені агенти, якщо тільки fake не надає власний. Дивіться наступний розділ.
Підробка відповідей у тестах
Обробка rate limit виконується лише тоді, коли провайдер близький до блокування, що ускладнює тестування. Підроблені відповіді можуть нести власний 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'
Створіть заголовки, які хочете тестувати, потім перевірте, що ваш listener зробив те, що повинен був. Зверніть увагу, що метод називається withRawResponse(), а не withRaw().
Додаткове читання
$response->raw був випущений у версії v0.10.3. Найновіший реліз v0.11.0 розширює ту саму ідею подіями життєвого циклу та таймінгами для кожного кроку й виклику інструменту в роботі агента.
Для контексту про пакет дивіться анонс AI SDK та матеріал про схвалення інструментів human-in-the-loop. Вихідний код знаходиться в репозиторії laravel/ai на GitHub.