Chào mừng bạn đến với phần cuối của khóa học! Chúng ta sẽ cùng nhau lắp ghép tất cả các mảnh ghép đã học để xây dựng một AI Email Support Agent chuyên nghiệp. Thay vì chỉ trả lời tin nhắn, Agent này sẽ hoạt động như một nhân viên thực thụ: biết phân loại vấn đề, tra cứu tài liệu, tạo ticket báo lỗi và chờ người quản lý duyệt nếu gặp vấn đề nghiêm trọng.
I. Sơ đồ kiến trúc Agent
Quy trình của chúng ta sẽ bao gồm các bước chiến lược sau:
- Classify (Phân loại): Nhận email và xác định ý định (Billing, Technical, Feature) cùng mức độ khẩn cấp.
- Parallel Tasks (Tác vụ song song): Đồng thời tra cứu tài liệu (Search) và tạo ticket trên Jira (Bug Tracking) nếu cần.
- Draft (Soạn thảo): Viết bản thảo phản hồi dựa trên thông tin đã thu thập.
- HITL (Can thiệp): Tạm dừng để con người duyệt nếu mức độ khẩn cấp là
critical.
II. Thiết kế State Schema phức tạp
Trong một ứng dụng thực tế, State cần lưu trữ nhiều thông tin chuyên sâu. Chúng ta sử dụng Zod để định nghĩa các object lồng nhau, giúp quản lý dữ liệu nghiệp vụ một cách chặt chẽ.
import { z } from 'zod';
// Define schema for classification results
const ClassificationSchema = z.object({
intent: z.enum(['billing', 'technical', 'feature_request', 'general']),
urgency: z.enum(['low', 'medium', 'high', 'critical']),
summary: z.string().describe('Short summary of the email content'),
});
// Global Agent State
export const EmailStateDefinition = z.object({
emailContent: z.string(),
senderEmail: z.string(),
classification: ClassificationSchema.optional(),
searchResults: z.array(z.string()).default([]),
ticketId: z.string().optional(),
draftResponse: z.string().optional(),
finalStatus: z.string().optional(),
});
type EmailState = z.infer<typeof EmailStateDefinition>;III. Node Phân loại với Structured Output
Đây là "đầu não" điều phối toàn bộ Graph. Chúng ta sử dụng Gemini model với tính năng withStructuredOutput để đảm bảo LLM trả về đúng định dạng JSON, giúp code rẽ nhánh chính xác 100%.
import { createGeminiModel } from '@workspace/util-langchain';
const llm = createGeminiModel();
async function classifyIntent(state: EmailState) {
console.log('--- NODE: Classify Email ---');
const structuredLlm = llm.withStructuredOutput(ClassificationSchema);
const result = await structuredLlm.invoke(`
Analyze this support email and extract intent, urgency, and a short summary:
Email: ${state.emailContent}
`);
return { classification: result };
}IV. Xử lý song song (Parallel Fan-out)
Sau khi phân loại, nếu là lỗi kỹ thuật, Agent sẽ vừa đi tìm tài liệu hướng dẫn, vừa tạo ticket để kỹ sư xử lý. Việc chạy song song giúp giảm đáng kể thời gian phản hồi.
async function searchDocs(state: EmailState) {
console.log('--- NODE: Search Documentation (Parallel) ---');
// Simulate vector database lookup
if (state.classification?.intent === 'technical') {
return { searchResults: ['Guide: Fixing Login Failure v2.0'] };
}
return { searchResults: ['General FAQ Article'] };
}
async function bugTracking(state: EmailState) {
if (state.classification?.intent === 'technical') {
console.log('--- NODE: Create Jira Ticket (Parallel) ---');
return { ticketId: 'JIRA-101' };
}
return {};
}V. Sơ đồ hoạt động của Project
Dưới đây là kiến trúc tổng thể của Agent mà chúng ta đang xây dựng:

VI. Tổng kết bài học
- Complex State: Sử dụng Zod lồng nhau là cách tốt nhất để quản lý dữ liệu Agent trong thực tế.
- Structured Output: Là "chìa khóa" để xây dựng logic rẽ nhánh tin cậy, tránh việc LLM trả về văn bản tự do gây lỗi code.
- Efficiency: Tận dụng Parallelism để thực hiện các tác vụ phụ trợ (như tra cứu và ghi log) cùng một lúc.
Trong bài học cuối cùng, chúng ta sẽ hoàn thiện logic soạn thảo, tích hợp cơ chế Human-in-the-loop và chạy thử nghiệm các kịch bản thực tế!
👉 Bài tiếp theo: 17. Project: Email Assistant - Thực thi & HITL