Planning Design Pattern
Cách agent chia nhỏ task phức tạp, lập kế hoạch và thực thi có cấu trúc
Vấn Đề
Nhiều tasks quá phức tạp để hoàn thành trong một bước duy nhất. Ví dụ: “Lên kế hoạch du lịch Nhật Bản 7 ngày” đòi hỏi nghiên cứu địa điểm, tìm vé máy bay, đặt khách sạn, lên lịch trình… Agent cần chia nhỏ và lập kế hoạch.
Planning Pattern
1. Nhận task phức tạp
2. Phân tích thành subtasks
3. Xác định thứ tự dependencies
4. Thực thi từng subtask
5. Đánh giá kết quả
6. Điều chỉnh kế hoạch nếu cần
Structured Output Với Zod
Thay vì để agent trả lời tự do, ta yêu cầu kế hoạch có cấu trúc:
import { generateObject } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
// Schema cho kế hoạch
const PlanSchema = z.object({
goal: z.string().describe("Mục tiêu tổng thể"),
tasks: z.array(z.object({
id: z.string(),
title: z.string(),
description: z.string(),
dependencies: z.array(z.string()).describe("IDs các tasks cần hoàn thành trước"),
estimatedTime: z.string(),
tools: z.array(z.string()).describe("Tools cần sử dụng"),
status: z.enum(["pending", "in_progress", "completed", "failed"])
})),
totalEstimate: z.string()
});
// Agent tạo kế hoạch
const { object: plan } = await generateObject({
model: openai("gpt-4o"),
schema: PlanSchema,
prompt: "Lên kế hoạch du lịch Nhật Bản 7 ngày cho 2 người, budget 50 triệu VNĐ"
});
console.log(plan);
// {
// goal: "Du lịch Nhật Bản 7 ngày cho 2 người",
// tasks: [
// { id: "1", title: "Tìm vé máy bay", dependencies: [], ... },
// { id: "2", title: "Đặt khách sạn", dependencies: ["1"], ... },
// { id: "3", title: "Lên lịch trình", dependencies: ["1", "2"], ... },
// ...
// ]
// }
Plan & Execute Pattern
Sau khi có kế hoạch, agent thực thi từng bước:
import { generateText, tool } from "ai";
// Executor agent
async function executePlan(plan: Plan) {
const completed = new Set<string>();
for (const task of topologicalSort(plan.tasks)) {
// Kiểm tra dependencies
const depsReady = task.dependencies.every(d => completed.has(d));
if (!depsReady) continue;
console.log(`\n📋 Executing: ${task.title}`);
const result = await generateText({
model: openai("gpt-4o-mini"),
tools: {
searchFlights: tool({ /* ... */ }),
searchHotels: tool({ /* ... */ }),
getWeather: tool({ /* ... */ }),
calculateBudget: tool({ /* ... */ })
},
maxSteps: 5,
system: `Bạn đang thực hiện bước "${task.title}" trong kế hoạch.
Mô tả: ${task.description}
Chỉ tập trung vào bước này, không làm bước khác.`,
prompt: `Thực hiện: ${task.description}`
});
completed.add(task.id);
console.log(`✅ Completed: ${task.title}`);
}
}
// Sắp xếp tasks theo thứ tự dependencies
function topologicalSort(tasks: Task[]): Task[] {
const sorted: Task[] = [];
const visited = new Set<string>();
function visit(task: Task) {
if (visited.has(task.id)) return;
visited.add(task.id);
for (const depId of task.dependencies) {
const dep = tasks.find(t => t.id === depId);
if (dep) visit(dep);
}
sorted.push(task);
}
tasks.forEach(visit);
return sorted;
}
Re-Planning
Agent thông minh biết điều chỉnh kế hoạch khi gặp vấn đề:
const replan = tool({
description: "Điều chỉnh kế hoạch khi phát hiện vấn đề hoặc thông tin mới",
parameters: z.object({
reason: z.string().describe("Lý do cần điều chỉnh"),
failedTaskId: z.string().optional(),
proposedChanges: z.array(z.object({
action: z.enum(["add", "remove", "modify"]),
taskId: z.string(),
details: z.string()
}))
}),
execute: async ({ reason, proposedChanges }) => {
console.log(`🔄 Re-planning: ${reason}`);
// Apply changes to plan
return { status: "plan_updated", changes: proposedChanges };
}
});
Ví Dụ Hoàn Chỉnh: Blog Writer Agent
const blogPlanSchema = z.object({
topic: z.string(),
outline: z.array(z.object({
section: z.string(),
keyPoints: z.array(z.string()),
requiredResearch: z.boolean()
})),
targetWordCount: z.number(),
tone: z.enum(["professional", "casual", "technical"])
});
// Bước 1: Lập kế hoạch
const { object: blogPlan } = await generateObject({
model: openai("gpt-4o"),
schema: blogPlanSchema,
prompt: "Viết blog về AI Agents cho developers mới"
});
// Bước 2: Thực thi từng section
for (const section of blogPlan.outline) {
const result = await generateText({
model: openai("gpt-4o"),
tools: section.requiredResearch ? { searchWeb } : {},
maxSteps: 3,
prompt: `Viết section "${section.section}" với key points: ${section.keyPoints.join(", ")}`
});
// Ghép kết quả...
}
Tổng Kết
- Planning pattern chia task phức tạp thành subtasks có cấu trúc
- Dùng Zod + generateObject cho structured output
- Topological sort để xử lý dependencies giữa tasks
- Re-planning khi gặp vấn đề — agent thích ứng với thực tế