Laravel AI v0.11.0 bringt ToolSearch, beigesteuert von behzadsp in Pull Request #697. Bislang wurde jede Tool-Definition eines Agenten bei jeder Anfrage an den Provider gesendet, ein Fixpreis, der bei Dutzenden Tools schmerzt und die Treffergenauigkeit des Modells bei der Tool-Auswahl verschlechtert. Der Wrapper bildet die gehostete Tool-Suche ab, die OpenAI und Anthropic bereits anbieten: Der Provider erhält einen Sucheintrag plus zurückgestellte Definitionen und lädt die vollständige Definition eines Tools erst, wenn er es nutzen will.

app/Ai/SupportAgent.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,
        ]),
    ];
}

ToolSearch nimmt die zurückzustellenden Tools als erstes Konstruktor-Argument entgegen. Alles außerhalb des Wrappers wird wie bisher gesendet, und die Tool-Klassen selbst brauchen keine Änderungen: kein Interface, keine Option pro Tool. Dieselbe Klasse kann in einem Agenten zurückgestellt und in einem anderen direkt gesendet werden. Ein zweites Argument wählt Anthropics Suchstrategie, regex (Standard) oder bm25, validiert bei der Erstellung mit einer InvalidArgumentException für alles andere. Weitere Provider-Felder wie cache_control gehen über withProviderOptions() durch; bei Anthropic ist der Wrapper der einzige Ort für einen Cache-Breakpoint, weil deren API Tools mit defer_loading: true und cache_control ablehnt.

Bei OpenAI wird der Wrapper zu einem {"type": "tool_search"}-Eintrag, bei Anthropic zu einem versionierten Typ wie tool_search_tool_regex_20251119. Die zurückgestellten Tools folgen als normale Definitionen mit defer_loading: true. Ruft das Modell ein solches Tool auf, löst das Gateway es namentlich aus dem Wrapper auf, die Ausführung verhält sich also identisch zu einem Top-Level-Tool. Anthropic meldet die Suche als server_tool_use- und tool_search_tool_result-Blöcke (die nicht mit einem tool_result beantwortet werden dürfen), OpenAI als tool_search_call- und tool_search_output-Items; das SDK bildet nur die Anfragenseite ab und parst keine der beiden Formen.

Nur OpenAiProvider und AnthropicProvider implementieren den Marker SupportsToolSearch. Alle anderen Provider, darunter Azure, Groq, DeepSeek, Mistral, OpenRouter, Gemini, xAI, Bedrock und Ollama, werfen eine LogicException, bevor eine Anfrage rausgeht. Drei weitere Regeln gelten: Die Support-Prüfung läuft auch bei leerem Wrapper, nur ein ToolSearch ist pro Anfrage erlaubt, und bei OpenAI lehnt das Paket ToolSearch in Kombination mit store=false ab, da die gehostete Suche gespeicherte Antworten voraussetzt. Ein leerer Wrapper auf einem unterstützten Provider sendet nichts.

ToolSearch::budget() rechnet jeden Wrapper beim Ableiten des Standard-maxSteps-Budgets in seine Tool-Anzahl um, sodass das Step-Budget nicht schrumpft, wenn zwanzig Tools verpackt werden. Zurückgestellte Tools fügen nie eigene Steps hinzu, weil der Provider sie innerhalb seines eigenen Aufrufs lädt. Zum Testen genügt ein gefakter HTTP-Call mit der Assertion, dass zurückgestellte Definitionen defer_loading: true tragen; die Namen kommen vom ToolNameResolver, der den Klassen-Basenamen nutzt, sofern die Klasse keine name()-Methode definiert.

Der Rat des Artikels: Das Zurückstellen lohnt sich nur bei großen Katalogen. Vier Tools sind es nicht wert, da das Modell erst suchen muss. Failover-Ketten werfen eine Exception, sobald sie einen nicht unterstützten Provider erreichen, und Anwendungen mit store=false können OpenAIs gehostete Suche nicht nutzen. Ein clientseitiger Ranking-Ansatz für alle Provider wurde in PR #805 vorgeschlagen, aber ohne Merge geschlossen. ToolSearch erschien in v0.11.0 zusammen mit Run-Lifecycle-Events, breiterem Provider-Failover und stateless Output Replay für OpenAI.