Plugin del agente
Una herramienta agente estilo ReAct. Extienda la herramienta para darle cualquier capacidad de PHP que pueda escribir.
El complemento del Agente le permite darle a un LLM la capacidad de actuar — para llamar consultas SQL, golpear puntos finales HTTP, leer archivos o hacer cualquier otra cosa que pueda expresar como un método PHP. Ejecuta un bucle estilo ReAct: piensa → llamada a herramienta → observa → repite → responde.
Cinco líneas, un agente
Sección titulada «Cinco líneas, un agente»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(*)…)¿Cómo funciona
Sección titulada «¿Cómo funciona»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."El protocolo utiliza un sentinela de JSON con marcas — \“tool {…}```— que cualquier modelo puede producir. No se requiere una API nativa de llamada a herramientas, por lo que funciona en todos los modelos de Ollama sin necesidad de configuración adicional. (Los modelos que admiten llamadas a herramientas nativas pueden integrarse mediante una subclase que sobrescriba el métodoparseToolCall()`.)
Herramientas integradas
Sección titulada «Herramientas integradas»Nibiru envía tres:
| Herramienta | ¿Qué hace? |
|---|---|
Tools\PdoQuery | Lectura única y de solo lectura SELECT contra la base de datos de la aplicación. Bloquea INSERT/UPDATE/DELETE/DROP/TRUNCATE/ALTER. Devuelve hasta 50 filas como JSON. |
Tools\HttpGet | Obtiene una URL HTTP/HTTPS con encabezados opcionales. Devuelve el cuerpo, truncado a 8 KB. |
Tools\FileRead | Lee un archivo del proyecto por ruta relativa. Bloquea la traversión ... Devuelve hasta 8 KB. |
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.');El agente llamará a file_read con la ruta, observará el origen y responderá basándose en lo que realmente vio — no en lo que imaginó.
Escribiendo una herramienta personalizada
Sección titulada «Escribiendo una herramienta personalizada»Extienda 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, ]); }}Luego conéctalo:
$ai->agent() ->withTools([new \App\AiTools\StripeRefund(), new Tools\PdoQuery()]) ->run('Refund order #4421 — they were charged twice.');El agente utilizará pdo_query para encontrar la carga, luego llamará a stripe_refund con ese ID de carga.
Examinando la traza
Sección titulada «Examinando la traza»$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";}Útil para la depuración, registros de auditoría o para construir una interfaz de usuario “muestra tu trabajo”.
Seguridad
Sección titulada «Seguridad»PdoQuerybloquea escrituras. Si necesitas acceso de escritura, escribe una subclase más privilegiada con un registro de auditoría. No levantes la restricción de solo SELECT en la herramienta incorporada.HttpGetpermite cualquier URL por defecto. Bloquea mediante una lista blanca en[AI] http_allowed_hosts[](planeado), o escribe una subclaseRestrictedHttpGetque filtre las URLs.FileReadbloquea... Está confinido a la raíz de la aplicación.- Iteraciones máximas.
agent.max_iterations = 6en el INI previene bucles sin control. Aumenta con cuidado. - Tiempo de espera de herramienta.
agent.tool_timeout = 30(segundos). Una herramienta que se atasque no mantendrá la solicitud para siempre.
Trucos comunes
Sección titulada «Trucos comunes»- Olvidar
withTools(). Sin herramientas, el agente es solo unChatregular. - Permitir que el agente vea secretos. Nunca pongas claves API, contraseñas en bruto o datos personales identificables (PII) en la respuesta de una herramienta — el modelo recibe la cadena completa.
- Salidas largas de herramientas. Cada observación se anexa a la conversación. Una herramienta que vuelca 50 KB agotará rápidamente el contexto. Las herramientas integradas tienen un límite de 8 KB; haz lo mismo en tus herramientas personalizadas.
- No hay llamada a herramienta en la respuesta = respuesta final. Si el modelo produce una respuesta final que parece una llamada a herramienta pero no se valida, el agente la trata como final. Sé explícito en el aviso: “Salida una llamada a herramienta O una respuesta final, nunca ambas.”