8. Tóm tắt bộ nhớ (Summarization Middleware)

Nam

Nam Hoang / Feb 08, 2026

7 min read

Trong môi trường thực tế, các cuộc hội thoại kéo dài hàng ngày hoặc hàng tuần sẽ tạo ra hàng nghìn tin nhắn. Điều này dẫn đến hai thách thức lớn mà chúng ta đã thảo luận ở Bài 1: Độ trễ (Latency) tăng cao và Chi phí (Cost) Token khổng lồ. Bài học này sẽ hướng dẫn bạn cách sử dụng Summarization Middleware để tự động "nén" bộ nhớ mà không làm mất đi ngữ cảnh quan trọng.

I. Chiến lược "Dọn dẹp" thông minh

Thay vì xóa bỏ các tin nhắn cũ một cách mù quáng, Summarization Middleware thực hiện quy trình:

  1. Trigger (Điểm kích hoạt): Khi số lượng tin nhắn vượt ngưỡng (ví dụ: 5 tin nhắn), hệ thống bắt đầu làm việc.
  2. Summarize (Tóm tắt): Gom các tin nhắn cũ nhất và gửi tới một LLM để viết lại thành một đoạn văn ngắn gọn.
  3. Keep (Giữ lại): Luôn giữ lại một số lượng tin nhắn gần đây nhất ở dạng nguyên bản để AI hiểu được những gì người dùng vừa nói tức thì.

II. Tối ưu chi phí với mô hình Đa tầng

Một kỹ thuật chuyên nghiệp trong thiết kế Agent là sử dụng các model khác nhau cho các mục đích khác nhau:

  • Main Model (Gemini 2.0 Flash): Xử lý logic chính, suy luận phức tạp.
  • Summary Model (Gemini 1.5 Flash): Một model rẻ hơn và nhanh hơn, chuyên trách việc đọc tin nhắn cũ và tóm tắt.

III. Mã nguồn: 08-summarization-middleware.ts

Chúng ta sẽ sử dụng tiện ích createGeminiModel từ util-langchain để khởi tạo cả hai model với cấu hình chuẩn.

// apps/langchain/scripts/08-summarization-middleware.ts
// pnpm --filter=ai-notes-langchain run tsx scripts/08-summarization-middleware.ts

import './env';
import { createGeminiModel, generateImage } from '@workspace/util-langchain';
import { createAgent, summarizationMiddleware } from 'langchain';
import { MemorySaver } from '@langchain/langgraph';

async function main() {
  // 1. Initialize models: Flash 2.0 for logic, Flash 1.5 for efficiency
  const mainModel = createGeminiModel({ model: 'gemini-2.0-flash' });
  const summaryModel = createGeminiModel({ model: 'gemini-1.5-flash' });

  // 2. Configure Agent with Summarization Middleware
  const agent = createAgent({
    model: mainModel,
    tools: [],
    middleware: [
      summarizationMiddleware({
        model: summaryModel,
        trigger: { messages: 5 }, // Start summarizing after 5 messages
        keep: { messages: 2 }, // Always keep the 2 most recent messages intact
        summaryPrefix: '[Previous conversation history summarized]: ',
      }),
    ],
    checkpointer: new MemorySaver(),
  });

  // 3. Generate visual diagram
  await generateImage(agent.graph, 'graph-ignore/scripts-08-summarization.jpg');

  const config = { configurable: { thread_id: 'long-session-999' } };

  // 4. Simulate a long sequence of messages to trigger summarization
  console.log('--- Sending a sequence of messages... ---');
  const messages = [
    'Hi, I am Nam.',
    'I am learning LangChain.',
    'I love eating Pho.',
    'I live in Ho Chi Minh City.',
    'I work as a developer.',
    'I enjoy hiking.',
  ];

  for (const content of messages) {
    console.log(`User: ${content}`);
    await agent.invoke({ messages: [{ role: 'user', content }] }, config);
  }

  // 5. Test if the Agent still remembers info from the "compressed" history
  console.log('\n--- Testing Memory of Summarized Content ---');
  const response = await agent.invoke(
    {
      messages: [
        {
          role: 'user',
          content:
            'What is my name, what do I like to eat, and what is my job?',
        },
      ],
    },
    config,
  );

  console.log('\nAI Response:');
  console.log(response.messages.at(-1).content);

  // 6. Verify actual message count in state
  const state = await agent.getState(config);
  console.log(`\nMessages in memory: ${state.values.messages.length}`);
}

main().catch(console.error);

IV. Phân tích kỹ thuật

  • Tính bền bỉ: Toàn bộ quá trình tóm tắt được lưu vào MemorySaver. Khi Agent khởi động lại, nó sẽ nạp bản tóm tắt thay vì nạp lại hàng trăm tin nhắn gốc.
  • Hiệu quả Token: Bằng cách giữ messages.length luôn ở mức thấp, bạn giảm thiểu rủi ro AI bị "loạn" (hallucination) do có quá nhiều dữ liệu thừa trong ngữ cảnh.
  • Trải nghiệm người dùng: Việc nén dữ liệu giúp giảm thời gian phản hồi (TTFT - Time To First Token) vì Model phải xử lý ít dữ liệu đầu vào hơn.

Sơ đồ hoạt động:

Sơ đồ Summarization Agent

V. Tổng kết

  • Summarization Middleware là "vũ khí" tối thượng để quản lý các cuộc hội thoại kéo dài trong sản xuất.
  • Sử dụng mô hình Gemini 1.5 Flash cho việc tóm tắt giúp tối ưu hóa đáng kể chi phí vận hành.
  • Kết hợp với hệ thống env.tsutil-langchain giúp bạn duy trì một cấu trúc mã nguồn sạch sẽ, dễ bảo trì.

Trong bài học tiếp theo, chúng ta sẽ học cách làm cho giao diện ứng dụng trở nên mượt mà và chuyên nghiệp hơn bằng kỹ thuật Streaming tin nhắn!

👉 Bài tiếp theo: 9. Streaming tin nhắn thời gian thực