---
title: "Laravel AI: завантаження інструментів на вимогу з ToolSearch"
url: https://laravelukraine.com/blog/laravel-ai-zavantazennia-instrumentiv-na-vimogu-z-toolsearch
date: 2026-08-27
source: https://laravel-news.com/laravel-ai-tool-search?utm_medium=feed&utm_source=feedpress.me&utm_campaign=Feed%3A+laravelnews
---

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

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

Laravel AI v0.11.0 додає спосіб відкласти частину цього каталогу. Контрибутор [@behzadsp](https://github.com/behzadsp) реалізував обгортку `ToolSearch` у [pull request #697](https://github.com/laravel/ai/pull/697), яка відображається на вже існуючий пошук інструментів, що пропонують OpenAI та Anthropic: провайдер отримує пошуковий запис плюс відкладені визначення і завантажує повне визначення інструменту тільки тоді, коли вирішує його використати.

## Обгортання інструментів для відкладеного завантаження

`ToolSearch` приймає інструменти для відкладення як перший аргумент. Все, що залишається поза обгорткою, надсилається так само, як і раніше:

```php
use Laravel\Ai\Providers\Tools\ToolSearch;

public function tools(): iterable
{
    return [
        new LookupAccount,
        new ToolSearch(tools: [
            new IssueRefund,
            new ChangePlan,
            new ResendInvoice,
            new TransferSeat,
            // ...решта каталогу back office
        ]),
    ];
}
```

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

Стратегія пошуку Anthropic є другим аргументом конструктора - `regex` або `bm25`, яка валідується при створенні об'єкта:

```php
new ToolSearch(tools: [new IssueRefund, new ChangePlan], strategy: 'bm25');
```

Будь-яке інше значення викидає `InvalidArgumentException` там, де ви його написали, а за відсутності аргументу надсилається `regex`. Інші поля пошукового запису провайдера, включно з `cache_control`, передаються через `withProviderOptions()` на обгортці. У Anthropic обгортка - єдине місце, де може бути точка розриву кешу, оскільки їхній API повертає 400 для будь-якого інструменту, що містить і `defer_loading: true`, і `cache_control`. Пакет розміщує опції провайдера тільки на пошуковому записі і ніколи на відкладених визначеннях, тому таку комбінацію тут створити неможливо.

## Що отримує кожен провайдер

На OpenAI обгортка перетворюється на запис `{"type": "tool_search"}`. На Anthropic вона стає версіонованим типом `tool_search_tool_regex_20251119` або еквівалентом `bm25`. В обох випадках відкладені інструменти йдуть слідом як звичайні визначення з `defer_loading: true`, що відображає те, як обидва провайдери моделюють це нативно: один пошуковий інструмент плюс відкладення для кожного інструменту.

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

Обидва провайдери по-різному звітують про пошук у відповіді. Anthropic повертає блок `server_tool_use`, що містить патерн або запит, який шукав Claude, потім блок `tool_search_tool_result` зі списком `tool_reference` записів для знайденого, і розгортає їх у повні визначення до того, як Claude їх побачить. Цей блок не є викликом інструменту, на який ви відповідаєте: повернення `tool_result` для його `srvtoolu_` ID призводить до відхилення запиту Anthropic. OpenAI вирішує розміщений пошук всередині того ж виклику і звітує про це як елементи `tool_search_call` та `tool_search_output`. Laravel AI відображає тільки бік запиту, тому жодна форма не парситься в щось, що експонує SDK.

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

## Перевірка того, що було надіслано

Створіть фейковий HTTP-виклик і інспектуйте масив `tools`. Відкладене визначення містить `defer_loading: true`, а визначення верхнього рівня - ні:

```php
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;

Http::fake(['*' => Http::response([
    'id' => 'resp_123',
    'status' => 'completed',
    'model' => 'gpt-5.4',
    'output' => [[
        'type' => 'message',
        'status' => 'completed',
        'content' => [['type' => 'output_text', 'text' => 'ok']],
    ]],
    'usage' => ['input_tokens' => 1, 'output_tokens' => 1],
])]);

(new SupportAgent)->prompt('Refund order 41');

Http::assertSent(function (Request $request) {
    $tools = collect(data_get($request->data(), 'tools'));
    $deferred = $tools->firstWhere('name', 'IssueRefund');
    $plain = $tools->firstWhere('name', 'LookupAccount');
    
    return $tools->contains(fn ($tool) => ($tool['type'] ?? null) === 'tool_search')
        && ($deferred['defer_loading'] ?? false) === true
        && ! isset($plain['defer_loading']);
});
```

Імена беруться з `ToolNameResolver`, який повертає basename класу інструменту, якщо клас не визначає метод `name()`. На Anthropic те саме твердження справджується з `tool_search_tool_regex_20251119` замість `tool_search`, а фейкове тіло має форму відповіді Anthropic, а не OpenAI.

Агент, єдиним інструментом якого є порожня обгортка, не надсилає ключа `tools` взагалі, і не надсилає `tool_choice`.

## Підтримка провайдерів та обмеження

Тільки `OpenAiProvider` та `AnthropicProvider` реалізують маркер `SupportsToolSearch`. Всі інші провайдери викидають `LogicException` до того, як запит виходить, а не відкидають інструменти обгортки. Це стосується Azure, шлюзів chat-completions (Groq, DeepSeek, Mistral, OpenRouter), Gemini, xAI, Bedrock та Ollama. Чи підтримує конкретна модель це, перевіряється API провайдера, а не локально.

Три додаткові правила керують використанням обгортки:

- Перевірка підтримки виконується щоразу, коли присутня обгортка, включно з порожньою, тому неправильно налаштований провайдер викидає виняток у розробці, а не тоді, коли список відкладених вперше стає непорожнім у продакшені.
- На один запит може бути зареєстрована тільки одна обгортка. Друга `ToolSearch` викидає виняток.
- На OpenAI пакет відхиляє `ToolSearch` у поєднанні з `store=false`, а не дозволяє запиту провалитися на API.

Порожня обгортка на підтримуваному провайдері нічого не генерує.

## Бюджетування кроків

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

`ToolSearch::budget()` розгортає кожну обгортку в кількість її відкладених інструментів, тому бюджет кроків не змінюється залежно від того, як упаковані інструменти.

## Коли використовувати

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

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

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

Два обмеження застосовуються незалежно від розміру каталогу. Тільки OpenAI та Anthropic підтримують обгортку, тому ланцюг failover викидає виняток, коли досягає будь-якого іншого провайдера. Розміщений пошук OpenAI також вимагає збережених відповідей, тому додаток, який встановлює `store=false` для збереження промптів поза серверами провайдера, не може використовувати його там.

## Клієнтський пошук інструментів

Ранжування каталогу всередині бібліотеки, яке працювало б на кожному провайдері, є окремою функцією. [Pull request #805](https://github.com/laravel/ai/pull/805) запропонував це поряд з цим pull request і був закритий без злиття, тому це не поставляється сьогодні. `ToolSearch` - це розміщена обгортка: провайдер виконує пошук, і тільки OpenAI та Anthropic підтримують це.

## Додаткова інформація

`ToolSearch` вийшов у версії v0.11.0 разом з подіями життєвого циклу виконання та ширшим failover провайдерів. Той самий pull request також додав stateless відтворення виводу для OpenAI, яке захоплює повний упорядкований вивід відповіді та відтворює його при продовженні, коли зберігання відповідей вимкнено.

Для ознайомлення з пакетом дивіться анонс AI SDK та наше висвітлення схвалення інструментів human-in-the-loop. Вихідний код знаходиться в репозиторії [laravel/ai](https://github.com/laravel/ai) на GitHub.
