Agent-Plugin
Ein ReAct-stiliges Werkzeugnutzungs-Agent. Erweitern Sie das Werkzeug, um ihm jede PHP-Fähigkeit zu geben, die Sie schreiben können.
Das Agent-Plugin ermöglicht es Ihnen, einer LLM die Fähigkeit zu geben — SQL-Abfragen auszuführen, HTTP-Endpunkte anzusprechen, Dateien zu lesen oder alles andere zu tun, was Sie als PHP-Methode ausdrücken können. Es führt eine ReAct-artige Schleife durch: Denken → Werkzeug-Aufruf → Beobachten → Wiederholen → Antworten.
Fünf Zeilen, ein Agent
Abschnitt betitelt „Fünf Zeilen, ein Agent“use Nibiru\Module\Ai\Ai;use Nibiru\Module\Ai\Plugin\Tools\PdoQuery;
$ai = new Ai();echo $ai->agent() ->withTools([new PdoQuery()]) ->run('How many active users do we have?');// → "We have 1,247 active users." (after the agent ran SELECT count(*)…)Wie es funktioniert
Abschnitt betitelt „Wie es funktioniert“user task ↓LLM gets system prompt with tool definitions ↓LLM emits ```tool {"tool":"pdo_query","args":{"sql":"SELECT…"}}``` ↓Agent runs the tool, captures result ↓LLM gets observation, decides: more tools or final answer? ↓"FINAL: 1,247 active users."Das Protokoll verwendet einen gepufferten JSON-Sentinel — \“tool {…}```— den jeder Modell erzeugen kann. Es ist keine native Tool-Aufruf-API erforderlich, daher funktioniert es auf jedem Ollama-Modell out of the box. (Modelle, die eine native Tool-Aufruf-API unterstützen, können über einen Subclass eingesetzt werden, derparseToolCall()` überschreibt.)
Eingebaute Tools
Abschnitt betitelt „Eingebaute Tools“Nibiru bietet drei Produkte an:
| Werkzeug | Was es macht |
|---|---|
Tools\PdoQuery | Einzelner schreibgeschützter SELECT-Befehl gegen die App-Datenbank. Blockiert INSERT/UPDATE/DELETE/DROP/TRUNCATE/ALTER. Gibt bis zu 50 Zeilen als JSON zurück. |
Tools\HttpGet | Holt eine HTTP/HTTPS-URL mit optionalen Headern. Gibt den Body zurück, abgeschnitten auf 8 KB. |
Tools\FileRead | Liest eine Projektdatei über einen relativen Pfad. Blockiert die ..-Reise. Gibt bis zu 8 KB zurück. |
use Nibiru\Module\Ai\Plugin\Tools;
$agent = $ai->agent()->withTools([ new Tools\PdoQuery(), new Tools\HttpGet(), new Tools\FileRead(),]);
// Multi-step taskecho $agent->run( 'Read application/controller/loginController.php and tell me ' . 'whether it implements rate limiting.');Der Agent wird file_read mit dem Pfad aufrufen, die Quelle beobachten und basierend auf dem tatsächlichen Gesehenen antworten – nicht auf das, was es sich vorstellt.
Ein benutzerdefiniertes Tool schreiben
Abschnitt betitelt „Ein benutzerdefiniertes Tool schreiben“Erweitern Sie Tool:
namespace App\AiTools;
use Nibiru\Module\Ai\Plugin\Tool;
class StripeRefund extends Tool{ public function name(): string { return 'stripe_refund'; }
public function description(): string { return 'Issue a Stripe refund for a charge ID.'; }
public function schema(): array { return [ 'charge_id' => [ 'type' => 'string', 'description' => 'A Stripe charge ID, e.g. ch_3K…', 'required' => true, ], 'amount_cents' => [ 'type' => 'integer', 'description' => 'Amount to refund in cents. Omit for full refund.', 'required' => false, ], ]; }
public function execute(array $args): mixed { $stripe = new \Stripe\StripeClient(getenv('STRIPE_SECRET_KEY')); $refund = $stripe->refunds->create(array_filter([ 'charge' => $args['charge_id'], 'amount' => $args['amount_cents'] ?? null, ])); return json_encode([ 'refund_id' => $refund->id, 'status' => $refund->status, 'amount' => $refund->amount, ]); }}Dann stecken Sie es ein:
$ai->agent() ->withTools([new \App\AiTools\StripeRefund(), new Tools\PdoQuery()]) ->run('Refund order #4421 — they were charged twice.');Der Agent wird pdo_query verwenden, um die Gebühr zu finden, und dann stripe_refund mit dieser Gebührs-ID aufrufen.
Den Trace betrachten
Abschnitt betitelt „Den Trace betrachten“$agent = $ai->agent()->withTools([new Tools\PdoQuery()]);$answer = $agent->run('How many products in the gold-plating category?');
foreach ($agent->trace() as $step) { echo "Step {$step['step']}: action={$step['action']}\n obs={$step['observation']}\n";}Nützlich für das Debuggen, die Nachverfolgung von Abläufen oder zum Erstellen einer “Zeige dein Arbeitsvorgehen”-Benutzeroberfläche.
Sicherheit
Abschnitt betitelt „Sicherheit“PdoQueryblocks writes. Wenn Sie Schreibzugriff benötigen, erstellen Sie eine subklasse mit erhöhten Rechten und einer Überwachungsnachverfolgung. Heben Sie die SELECT-nur-Einschränkung im eingebauten Tool nicht auf.HttpGetallows any URL by default. Sperren Sie es über eine Zulassungsliste in[AI] http_allowed_hosts[](geplant) oder erstellen Sie eineRestrictedHttpGet-Subklasse, die URLs filtert.FileReadblocks... Es ist auf den Anwendungsstamm beschränkt.- Max iterations.
agent.max_iterations = 6in der INI verhindert unkontrollierte Schleifen. Erhöhen Sie vorsichtig. - Tool timeout.
agent.tool_timeout = 30(Sekunden). Ein Tool, das hängt, wird die Anfrage nicht ewig blockieren.
Häufige Fallen
Abschnitt betitelt „Häufige Fallen“- Vergessen Sie
withTools(). Ohne Werkzeuge ist der Agent nur ein regulärerChat. - Lassen Sie dem Agenten Geheimnisse sehen. Legen Sie niemals API-Schlüssel, rohe Passwörter oder PII in die Antwort eines Tools — das Modell erhält den vollständigen String.
- Lange Werkzeugausgaben. Jede Beobachtung wird an die Konversation angehängt. Ein Tool, das 50 KB ausgibt, erschöpft schnell den Kontext. Die eingebaute Tools haben eine Obergrenze von 8 KB; tun Sie das gleiche in Ihren benutzerdefinierten Tools.
- Kein Werkzeugaufruf in der Antwort = endgültige Antwort. Wenn das Modell eine endgültige Antwort produziert, die aussehen wie einen Werkzeugaufruf, aber nicht validiert wird, behandelt der Agent es als endgültig. Seien Sie explizit im Prompt: “Geben Sie einen Werkzeugaufruf ODER eine endgültige Antwort aus, niemals beides.”