Одна з головних переваг Laravel AI SDK — відсутність прив’язки до конкретного провайдера. Ви можете легко замінити OpenAI на Anthropic або додати Gemini як резервний варіант (failover), майже не змінюючи код агента. Це головна ідея інструменту, і вона загалом працює.
Поки вашому агенту не знадобиться доступ до вебу.
Обіцянка незалежності має вразливе місце
SDK пропонує два інструменти для роботи з мережею: WebSearch та WebFetch. Вони зручні: кілька рядків коду — і агент шукає інформацію або завантажує сторінку. Проте вони не є частиною уніфікованого шару SDK. Їх реалізують самі AI-провайдери, тому доступність цих інструментів повністю залежить від обраної моделі.
WebSearch працює з Anthropic, OpenAI, Gemini та OpenRouter. WebFetch підтримують лише Anthropic та Gemini. Якщо у вашому ланцюжку відмовостійкості є Groq, DeepSeek, Mistral або xAI, і один із них стане активним, агент «тихо» втратить можливість переглядати веб. Без помилок чи попереджень — він просто перестане цитувати джерела або помічати зміни на сторінках.
Виявити таке в продакшені неприємно. Ви налаштовували failover саме для того, щоб уникнути збоїв через ліміти запитів або вимкнення сервісів, а виявилося, що один із резервних провайдерів просто не має потрібної функції.
Навіть коли це працює, результат досить поверхневий
Забудьте на мить про проблеми з провайдерами. Навіть там, де WebSearch та WebFetch доступні, ви отримуєте «сирі» дані: результати пошуку або контент сторінки, які модель має проаналізувати самостійно. Тут немає чіткої схеми чи гарантованого відстеження цитат. Якщо вам потрібна структурована відповідь із посиланнями на джерела, цей аналіз відбувається всередині інференсу моделі, а не на рівні, який ви можете контролювати чи протестувати.
Для багатьох завдань цього достатньо. Але для досліджень, конкурентного аналізу або будь-яких випадків, де користувач може запитати «звідки ця інформація?», — цього замало.
Створіть власний інструмент, незалежний від провайдера
Вихід — відмовитися від нативних інструментів провайдера на користь кастомного рішення. Використовуйте зовнішній API замість функцій моделі. Саме для цього в Laravel AI SDK існує Tool class.
Пакет juststeveking/tabstack надає клієнт для такої реалізації. Метод agent()->research() приймає запитання, шукає інформацію в різних джерелах, синтезує відповідь і повертає звіт із цитатами за один виклик.
Оскільки пакет не має вбудованої інтеграції з Laravel, спершу зареєструйте його в service provider:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use JustSteveKing\Tabstack\Tabstack;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(Tabstack::class, fn () => Tabstack::make(
apiKey: config('services.tabstack.key'),
));
}
}
Додайте ключ у config/services.php:
'tabstack' => [
'key' => env('TABSTACK_API_KEY'),
],
Тепер створимо сам інструмент. Він обгортає agent()->research() і повертає агенту звіт зі списком джерел:
<?php
namespace App\Ai\Tools;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use JustSteveKing\Tabstack\Requests\AgentResearch;
use JustSteveKing\Tabstack\Requests\ResearchMode;
use JustSteveKing\Tabstack\Tabstack;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
use Stringable;
class WebResearch implements Tool
{
public function __construct(
private readonly Tabstack $tabstack,
) {}
public function description(): Stringable|string
{
return 'Answers a question by researching multiple sources on the web and returns a synthesized, cited report. Use this when you need current information not in your training data.';
}
public function handle(Request $request): Stringable|string
{
$result = $this->tabstack->agent()->research(
params: new AgentResearch(
query: $request['query'],
mode: ResearchMode::Fast,
),
)->result();
$sources = collect($result->metadata->get('citedPages', []))
->map(fn ($page) => "- {$page['title']}: {$page['url']}")
->implode("\n");
return "{$result->report}\n\nSources:\n{$sources}";
}
public function schema(JsonSchema $schema): array
{
return [
'query' => $schema->string()
->required()
->description('The question to research'),
];
}
}
Виклик ->result() очікує завершення стріму і повертає типізований ResearchResult. Це спрощує метод handle. Якщо ви хочете транслювати прогрес агенту в реальному часі, клієнт підтримує ->each(), але для виклику інструменту зазвичай краще дочекатися повного результату.
Підключіть його до будь-якого агента через метод tools:
<?php
namespace App\Ai\Agents;
use App\Ai\Tools\WebResearch;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Promptable;
class MarketAnalyst implements Agent, HasTools
{
use Promptable;
public function instructions(): string
{
return 'You help analyze markets and competitors. Use the research tool whenever you need current information. Always mention your sources.';
}
public function tools(): iterable
{
return [
app(WebResearch::class),
];
}
}
Тепер змінюйте провайдерів як завгодно:
$response = (new MarketAnalyst)->prompt(
'What are the current pricing trends for cloud browser automation APIs?',
provider: [Lab::OpenAI, Lab::Anthropic, Lab::Groq],
);
Здатність агента шукати інформацію більше не залежить від того, яка модель відповідає на запит. Інструмент ваш, і він працює однаково для всіх.
Чому це краще за звичайний fetch?
Схоже рішення можна було б створити на базі WebFetch, вказавши конкретний URL. Але це працює лише тоді, коли ви знаєте, на якій сторінці шукати відповідь. Метод /research створений для випадків, коли джерело невідоме: він сам обирає потрібні сайти, аналізує їх та узагальнює дані. Це складніший процес, який вбудовані інструменти SDK навіть не намагаються охопити.
Підсумки
Незалежність від провайдерів у Laravel AI SDK — це чудово, поки ви не стикаєтеся з інструментами, які цю незалежність порушують. Доступ до вебу не має зникати залежно від того, яка модель обробляє запит. Створення власного Tool class на базі API гарантує стабільну роботу вашого агента.
Якщо ви розробляєте застосунки на Laravel AI SDK і хочете мати такий інструмент під рукою, раджу почати з juststeveking/tabstack на Packagist.