Chào mừng các bạn đến với series xây dựng AI Agent! Trong phần đầu tiên này, chúng ta sẽ cùng nhau khám phá cách kiến tạo một hệ thống AI Agent mạnh mẽ bằng sự kết hợp giữa NestJS, một framework Node.js tiến bộ, và LangChain, thư viện hàng đầu cho việc phát triển ứng dụng dựa trên mô hình ngôn ngữ lớn (LLM). Đặc biệt, chúng ta sẽ tích hợp Gemini, một LLM tiên tiến từ Google, làm "bộ não" xử lý ngôn ngữ cho agent của mình. Đây là bước đệm vững chắc, giúp bạn tạo ra một agent có khả năng tiếp nhận và xử lý prompt một cách thông minh, mở đường cho việc tích hợp các tính năng nâng cao như công cụ (tools), bộ nhớ (memory), hay các quy trình làm việc (workflows) phức tạp trong tương lai.
1. Khái niệm: Agent là gì? – Vượt Lên Giới Hạn Của Prompt Đơn Thuần
Trong thế giới của các mô hình ngôn ngữ lớn (LLM), có hai cấp độ tương tác chính mà bạn cần phân biệt:
Cách Tương Tác | Giống như... | Giải thích |
---|---|---|
Prompt Đơn Lẻ | “Google Search” | Bạn đưa ra một câu lệnh hoặc câu hỏi, và LLM sẽ trực tiếp trả về một câu trả lời. Tương tác này thường đơn giản và không có tính liên tục. |
Agent | “Trợ lý ảo thông minh” | không chỉ trả lời. Nó có khả năng suy luận (reasoning), tự quyết định hành động (action), sử dụng công cụ (tools) bên ngoài (ví dụ: gọi API, truy vấn database), và ghi nhớ thông tin (memory) từ các tương tác trước đó để đưa ra phản hồi phù hợp và có ngữ cảnh hơn. |
Trong khuôn khổ phần 1 này, chúng ta sẽ tập trung vào việc xây dựng nền tảng ban đầu: tạo ra một hệ thống backend có khả năng tiếp nhận câu hỏi từ người dùng, chuyển tiếp nó đến LLM (cụ thể là Gemini) để xử lý, sau đó nhận lại câu trả lời đã được sinh ra và gửi về cho người dùng. Đây là viên gạch đầu tiên và quan trọng nhất để xây dựng nên một AI Agent hoàn chỉnh.
2. Kiến trúc hệ thống – Cái Nhìn Tổng Quan
Trước khi bắt tay vào viết những dòng code đầu tiên, việc hình dung rõ ràng kiến trúc hệ thống là vô cùng quan trọng. Nó giúp chúng ta hiểu được luồng dữ liệu và trách nhiệm của từng thành phần:
graph TD A[Client: HTTP Request <br/> (e.g., /ask?q=AI là gì)] --▶ B(NestJS Controller: app.controller.ts <br/> Tiếp nhận và xác thực request); B --▶ C(AgentService: simple-agent.service.ts <br/> Chứa logic AI, điều phối LangChain); C --▶ D(LangChain Core: LLMChain, PromptTemplate <br/> Xây dựng prompt, gọi LLM); D --▶ E(Gemini LLM via LangChain: @langchain/google-genai <br/> Xử lý ngôn ngữ tự nhiên, sinh câu trả lời); E --▶ F(Text Response <br/> Câu trả lời từ LLM); F --▶ C; C --▶ B; B --▶ G(Client: HTTP Response <br/> { question: "...", answer: "..." });
Sự tách biệt rõ ràng về trách nhiệm (Separation of Concerns):
NestJS Controller (app.controller.ts)
: Đóng vai trò như một người gác cổng, chịu trách nhiệm tiếp nhận các HTTP request từ client. Nó xác thực dữ liệu đầu vào (nếu cần) và chuyển tiếp yêu cầu đến lớp service phù hợp.AgentService (simple-agent.service.ts)
: Đây là nơi logic AI cốt lõi được triển khai. Service này sẽ sử dụng LangChain để định dạng prompt, tương tác với LLM, và xử lý kết quả trả về.LangChain (langchain, @langchain/google-genai)
: Hoạt động như một bộ khung và điều phối viên mạnh mẽ. LangChain cung cấp các công cụ để xây dựng prompt một cách linh hoạt (PromptTemplate), tạo chuỗi xử lý (LLMChain) để kết nối prompt với LLM, và quản lý việc gọi đến LLM.Gemini (GoogleGenerativeAI)
: Là LLM engine chính, "trái tim" của agent, chịu trách nhiệm hiểu và sinh ra ngôn ngữ tự nhiên dựa trên prompt đầu vào.
Kiến trúc này đảm bảo tính module hóa, dễ dàng bảo trì và mở rộng hệ thống trong tương lai.
3. Khởi tạo Project NestJS – Đặt Nền Móng Vững Chắc
Đầu tiên, chúng ta cần một môi trường NestJS sẵn sàng. Nếu bạn chưa cài đặt NestJS CLI, hãy chạy lệnh sau:
yarn global add @nestjs/cli
Sau đó, tạo một project NestJS mới với tên ai-agent-nest
:
nest new ai-agent-nest
Sau khi quá trình tạo project hoàn tất, di chuyển vào thư mục dự án và khởi động server ở chế độ development:
cd ai-agent-nest
yarn start:dev
Truy cập vào http://localhost:3000
trên trình duyệt của bạn. Nếu thấy thông báo "Hello World!", xin chúc mừng, bạn đã khởi tạo project NestJS thành công!
4. Cài đặt LangChain & Gemini – Trang Bị "Vũ Khí" Cho Agent
Tiếp theo, chúng ta sẽ cài đặt các thư viện cần thiết để làm việc với LangChain và Gemini:
yarn add langchain @langchain/core @langchain/google-genai @nestjs/config dotenv
langchain
: Trước đây là gói chính, giờ đây nhiều thành phần cốt lõi đã được chuyển sang @langchain/core. Vẫn có thể cần cho một số chain hoặc agent phức tạp hơn.@langchain/core
: Chứa các interface và thành phần cơ bản như BaseChatModel, BaseMessage, PromptTemplate, OutputParser, v.v.@langchain/google-genai
: Gói tích hợp cụ thể cho phép LangChain tương tác với các mô hình Gemini của Google, bao gồm ChatGoogleGenerativeAI.
Sau đó, tạo một file tên là .env
ở thư mục gốc của project (ai-agent-nest/.env
) và thêm vào API key của bạn từ Google AI Studio:
GEMINI_API_KEY=your_google_generative_ai_key_goes_here
Quan trọng: Hãy chắc chắn rằng bạn đã thay your_google_generative_ai_key_goes_here bằng API key thực sự của mình. Đừng quên thêm file .env vào .gitignore để tránh commit API key lên Git.
5. Cấu trúc thư mục gợi ý – Tổ Chức Code Mạch Lạc
src/
├— ai/
│ ├— langchain.module.ts
│ └— gemini-chat.provider.ts # Cung cấp ChatGoogleGenerativeAI
├— agents/
│ └— simple-agent.service.ts # Logic agent
├— app.controller.ts
├— app.module.ts
└— main.ts
6. Tạo Gemini Chat Provider – Cung Cấp BaseChatModel
Tạo file src/ai/gemini-chat.provider.ts
với nội dung sau:
import { Provider } from '@nestjs/common';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai'; export const GeminiChatProvider: Provider = { provide: 'GEMINI_CHAT_MODEL', useFactory: () => { const apiKey = process.env.GEMINI_API_KEY; if (!apiKey) { throw new Error('GEMINI_API_KEY is not defined in your .env file. Ensure @nestjs/config is set up.'); } return new ChatGoogleGenerativeAI({ apiKey: apiKey, model: 'gemini-2.5-flash-preview-05-20', }); },
};
Tiếp theo, đăng ký GeminiChatProvider
vào một module. Tạo file src/ai/langchain.module.ts
:
import { Module } from '@nestjs/common';
import { GeminiChatProvider } from './gemini-chat.provider'; @Module({ providers: [GeminiChatProvider], exports: [GeminiChatProvider],
})
export class LangchainModule {}
7. Tạo Simple Agent dùng LangChain – Sử dụng BaseChatModel và BaseMessage
Giờ là lúc tạo SimpleAgentService
, nơi sẽ sử dụng BaseChatModel
(chính là ChatGoogleGenerativeAI
đã được provide) để tương tác với Gemini.
Tạo file src/agents/simple-agent.service.ts
:
import { Injectable, Inject } from '@nestjs/common';
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { BaseMessage, HumanMessage, SystemMessage } from '@langchain/core/messages'; @Injectable()
export class SimpleAgentService { constructor( @Inject('GEMINI_CHAT_MODEL') private readonly llm: BaseChatModel, ) {} async ask(question: string): Promise<string> { const messages: BaseMessage[] = [ new SystemMessage( 'Bạn là một trợ lý AI thông minh và thân thiện. Hãy trả lời câu hỏi một cách rõ ràng, chi tiết và bằng tiếng Việt.', ), new HumanMessage(question), ]; const response = await this.llm.invoke(messages); if (typeof response.content === 'string') { return response.content; } else if (Array.isArray(response.content)) { let textContent = ''; for (const part of response.content) { if (part.type === 'text') { textContent += (part as any).text; } } if (textContent) { return textContent; } } return "Xin lỗi, tôi không thể xử lý phản hồi hoặc không nhận được nội dung văn bản mong muốn từ AI."; }
}
Để service này có thể được sử dụng, bạn cần đăng ký nó và LangchainModule
vào AppModule
.
Mở src/app.module.ts
và cập nhật:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { LangchainModule } from './ai/langchain.module';
import { SimpleAgentService } from './agents/simple-agent.service';
import { ConfigModule } from '@nestjs/config'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, envFilePath: '.env', }), LangchainModule, ], controllers: [AppController], providers: [ SimpleAgentService, ],
})
export class AppModule {}
8. Controller để demo API – Mở Cổng Giao Tiếp
Trong src/app.controller.ts
:
import { Controller, Get, Query, BadRequestException, InternalServerErrorException } from '@nestjs/common';
import { SimpleAgentService } from './agents/simple-agent.service'; @Controller()
export class AppController { constructor(private readonly agentService: SimpleAgentService) {} @Get('ask') async askTheAgent(@Query('question') question: string) { if (question?.trim() === '') { throw new BadRequestException('Query parameter "question" cannot be empty.'); } try { const answer = await this.agentService.ask(question); return { question: question, answer: answer, timestamp: new Date().toISOString(), }; } catch (error) { console.error('Error interacting with AI Agent:', error); throw new InternalServerErrorException(`Sorry, an error occurred while processing your request. Please try again later.`); } }
}
Hãy thử nghiệm API của bạn! Sử dụng một công cụ như Postman hoặc trình duyệt web, truy cập URL:
GET http://localhost:3000/ask?question=AI%20là%20gì
Hoặc một câu hỏi khác:
GET http://localhost:3000/ask?question=NestJS%20có%20ưu%20điểm%20gì
🥮 Kết quả mẫu – Thành Quả Đầu Tiên
{ "question": "AI là gì", "answer": "AI (Trí tuệ nhân tạo) là một lĩnh vực khoa học máy tính tập trung vào việc tạo ra các cỗ máy thông minh có khả năng thực hiện các tác vụ thường đòi hỏi trí thông minh của con người. Điều này bao gồm học hỏi, lý luận, giải quyết vấn đề, nhận dạng mẫu, hiểu ngôn ngữ tự nhiên và ra quyết định.", "timestamp": "2025-05-24T01:50:00.000Z"
}
Tổng kết phần 1 – Những Gì Bạn Đã Đạt Được
- Hoàn thành khởi tạo dự án NestJS với cấu trúc rõ ràng.
- Thiết lập và tích hợp thành công LangChain với ChatGoogleGenerativeAI (thông qua BaseChatModel).
- Xây dựng được Agent cơ bản, có khả năng nhận diện và phản hồi câu hỏi sử dụng BaseMessage và phương thức llm.invoke().
- Tạo API endpoint để tương tác và kiểm thử Agent.