Trong bài học trước, chúng ta đã nắm được lý do tại sao LangGraph lại quan trọng đối với các ứng dụng AI thực tế. Bây giờ, chúng ta sẽ đi sâu vào cấu tạo bên trong. Bài học này tập trung vào hai thành phần quan trọng nhất của mọi đồ thị: Nodes và State.
I. Khái niệm về Nodes và State
Hãy tưởng tượng LangGraph giống như một sơ đồ quy trình công việc (workflow). Để sơ đồ này hoạt động, chúng ta cần ba yếu tố:
- State (Trạng thái): Đây là "bộ nhớ" chung của toàn bộ ứng dụng. Nó là một đối tượng (object) chứa dữ liệu được truyền qua lại giữa các Node.
- Nodes (Nút xử lý): Đây là các "nhân viên" thực hiện nhiệm vụ. Trong mã nguồn, Node đơn giản là một hàm nhận vào State hiện tại, thực hiện một logic nào đó và trả về một bản cập nhật cho State.
- Edges (Cạnh điều hướng): Đây là các "con đường" nối các Node lại với nhau, xác định bước tiếp theo Graph sẽ đi đâu.
II. Định nghĩa State với Zod
Trong TypeScript, chúng ta cần đảm bảo dữ liệu trong State luôn đúng cấu trúc để tránh lỗi runtime. Chúng ta sử dụng thư viện Zod để định nghĩa một Schema (lược đồ dữ liệu).
import z from 'zod';
const StateDefinition = z.object({
nlist: z.array(z.string()), // State sẽ chứa một mảng các chuỗi (strings)
});
// Trích xuất Type từ Zod để sử dụng trong TypeScript
type State = z.infer<typeof StateDefinition>;III. Mã nguồn: 02-nodes-and-state.ts
Dưới đây là ví dụ minh họa cách định nghĩa State và khởi tạo một Node đơn giản. Chúng ta cũng sử dụng công cụ xuất ảnh để quan sát cấu trúc graph.
// path: 02-nodes-and-state.ts
import { END, START, StateGraph } from '@langchain/langgraph';
import { generateImage } from '@workspace/util-langchain';
import z from 'zod';
// 1. Define State structure
const StateDefinition = z.object({
nlist: z.array(z.string()),
});
type State = z.infer<typeof StateDefinition>;
// 2. Define Node function
// Node receives 'state' and returns the specific data to be updated
function nodeA(state: State) {
console.log(`Node A is receiving data: ${JSON.stringify(state.nlist)}`);
const note = 'Hello World from Node A';
console.log(`Action: ${note}`);
// Return an object to update the state.
// LangGraph will automatically merge this into the global state.
return { nlist: [note] };
}
// 3. Build and Compile the Graph
export const graph = new StateGraph(StateDefinition)
.addNode('a', nodeA) // Add a Node named 'a' with the nodeA processing function
.addEdge(START, 'a') // Flow goes from START into Node 'a'
.addEdge('a', END) // After Node 'a' finishes, terminate (END)
.compile();
// 4. Execution
async function run() {
// Generate a diagram of the graph
await generateImage(graph, 'graph-ignore/scripts-02-nodes-and-state.jpg');
console.log('\n=== L2: Nodes and State Example ===\n');
const initialState: State = {
nlist: ['Initial data'],
};
console.log('Running graph with initial state:', initialState);
const result = await graph.invoke(initialState);
console.log('\n=== FINAL RESULT ===');
console.log(result);
}
run();IV. Giải thích cơ chế hoạt động
- Cơ chế cập nhật (Merging): Lưu ý rằng hàm
nodeAkhông cần trả về toàn bộ đối tượng State. Nó chỉ cần trả về thuộc tính nó muốn thay đổi (ở đây lànlist). LangGraph Runtime sẽ tự động hợp nhất kết quả này vào State chung. - START và END: Đây là các hằng số đặc biệt.
STARTđại diện cho điểm tiếp nhận dữ liệu đầu vào, vàENDlà điểm dừng khi luồng công việc hoàn thành. - Tính bất biến (Immutability): LangGraph quản lý các phiên bản State một cách cẩn thận. Điều này cho phép chúng ta thực hiện các tính năng nâng cao như "Time Travel" (xem lại lịch sử) mà chúng ta sẽ học ở các bài sau.
Sơ đồ minh họa:

V. Thử nghiệm: Lab 01
Hãy thực hiện các bước sau để tự mình kiểm chứng:
- Mở terminal và đảm bảo bạn đã cài đặt các thư viện cần thiết.
- Tạo file
02-nodes-and-state.tsvới nội dung trên. - Thay đổi nội dung biến
notetrong hàmnodeAthành bất kỳ lời chào nào bạn thích. - Chạy lệnh sau để thực thi:
npx tsx 02-nodes-and-state.ts
VI. Tổng kết
- State là dữ liệu dùng chung (Data).
- Nodes là các hàm thực thi logic (Functions).
- Sử dụng Zod giúp kiểm soát chặt chẽ kiểu dữ liệu, giảm thiểu lỗi khi Agent trở nên phức tạp hơn.
Trong bài học tới, chúng ta sẽ tìm hiểu về Edges để điều hướng luồng dữ liệu qua nhiều Node khác nhau và cách xử lý các tác vụ song song!