Xây dựng Autonomous Agents trong Laravel (Chi tiết)
Xây dựng Autonomous Agents trong Laravel
Nếu RAG là về "Đọc", thì Agents là về "Làm".
Một Autonomous Agent (Tác nhân tự chủ) là hệ thống nơi LLM đóng vai trò người điều phối. Nó quyết định đoạn code nào cần chạy để giải quyết vấn đề của người dùng.
Hôm nay, chúng ta sẽ xây dựng một "Support Agent" (Agent hỗ trợ) có thể:
- Kiểm tra trạng thái đơn hàng của user.
- Hoàn tiền đơn hàng nếu đủ điều kiện.
- Tìm kiếm trong kho tri thức (knowledge base).
Cơ chế cốt lõi: Định nghĩa Tool (Công cụ)
Các model OpenAI chấp nhận tham số tools. Đây là mô tả JSON schema về các hàm PHP của bạn.
Bước 1: Ánh xạ PHP Classes thành Tools
Hãy tạo cấu trúc để quản lý tools một cách sạch sẽ.
// app/AI/Tools/CheckOrderStatus.php
namespace App\AI\Tools;
use Closure;
class CheckOrderStatus
{
public function definition(): array
{
return [
'type' => 'function',
'function' => [
'name' => 'check_order_status',
'description' => 'Lấy trạng thái hiện tại và thông tin vận chuyển của đơn hàng.',
'parameters' => [
'type' => 'object',
'properties' => [
'order_id' => [
'type' => 'string',
'description' => 'Mã tham chiếu đơn hàng (ví dụ: ORD-123)'
]
],
'required' => ['order_id']
]
]
];
}
public function handle(array $arguments): string
{
$order = \App\Models\Order::where('reference', $arguments['order_id'])->first();
if (!$order) {
return json_encode(['error' => 'Order not found']);
}
return json_encode([
'status' => $order->status,
'shipped_at' => $order->shipped_at,
'items' => $order->items->pluck('name')
]);
}
}
Bước 2: Agent Runner
Sự phức tạp của agent nằm ở vòng lặp "Re-Act" (Reason + Action - Suy luận + Hành động).
- LLM nghĩ: "Mình cần kiểm tra trạng thái đơn hàng ORD-999".
- LLM trả về:
tool_call: check_order_status(ORD-999). - App thực thi: Code PHP chạy query DB.
- App trả về:
{"status": "shipped"}. - LLM nhận đầu ra và nghĩ: "Ok, báo cho user là hàng đã gửi rồi".
- LLM phản hồi cuối cùng: "Đơn hàng của bạn đã được gửi đi!"
Đây là triển khai Runner đơn giản hóa:
// app/AI/AgentRunner.php
class AgentRunner
{
protected array $tools = [];
public function registerTool($class)
{
$this->tools[] = new $class;
}
public function chat(array $history)
{
// 1. Chuẩn bị định nghĩa (definitions)
$definitions = array_map(fn($t) => $t->definition(), $this->tools);
// 2. Cuộc gọi ban đầu
$response = Http::withToken(config('services.openai.key'))->post('...', [
'model' => 'gpt-4o',
'messages' => $history,
'tools' => $definitions,
]);
$message = $response->json('choices.0.message');
// 3. Kiểm tra xem có Tool Calls không
if (isset($message['tool_calls'])) {
// Nối "suy nghĩ" của assistant vào lịch sử
$history[] = $message;
foreach ($message['tool_calls'] as $toolCall) {
$functionName = $toolCall['function']['name'];
$arguments = json_decode($toolCall['function']['arguments'], true);
// Tìm tool instance tương ứng
$tool = collect($this->tools)->first(fn($t) => $t->definition()['function']['name'] === $functionName);
// THỰC THI CODE PHP
$result = $tool->handle($arguments);
// Báo cáo lại cho LLM
$history[] = [
'role' => 'tool',
'tool_call_id' => $toolCall['id'],
'content' => $result
];
}
// 4. Gọi đệ quy (The Loop)
// Gọi lại API với kết quả tool vừa chạy để nó sinh câu trả lời cuối cùng
return $this->chat($history);
}
return $message['content'];
}
}
Bước 3: An toàn và Phân quyền
Cho phép AI chạy code là rủi ro.
- Read-Only vs Write: Đánh dấu tool là "Safe" (Chỉ đọc) hoặc "Unsafe" (Hoàn tiền, Xóa).
- Xác nhận (Confirmation): Nếu agent quyết định gọi
refund_order, đừng chạy ngay. Hãy trả về một trạng thái UI đặc biệt để hỏi người dùng "Bạn có chắc chắn muốn hoàn tiền không?". - Cô lập ngữ cảnh (Context isolation): Lý tưởng nhất là tool chỉ nên truy cập dữ liệu thuộc về user đang đăng nhập.
public function handle(array $arguments): string
{
// Lấy user hiện tại từ context, KHÔNG phải từ tham số AI đưa vào
$user = auth()->user();
$order = $user->orders()->find($arguments['order_id']); // Scoped query đảm bảo an toàn
// ...
}
Kết luận
Agents về cơ bản cho phép bạn "mở" toàn bộ tầng Service của Laravel ra cho giao diện ngôn ngữ tự nhiên. Mô hình này lý tưởng cho các trang quản trị nội bộ ("Admin Panels"), ví dụ: "Hiển thị tất cả user đăng ký hôm qua và xuất ra CSV", nơi mà việc xây dựng nút bấm UI cụ thể cho mọi trường hợp là bất khả thi.