Bối cảnh & Lý do
Hầu hết các ứng dụng LLM tương tác hiện nay đều gặp vấn đề về “mất trí nhớ ngắn hạn”. Các chatbot truyền thống thường duy trì trạng thái bằng cách truyền một sliding window gồm các tin nhắn gần nhất trở lại model. Khi phiên làm việc của người dùng kết thúc, hoặc lịch sử trò chuyện vượt quá ngân sách token, mọi chi tiết đều biến mất. Model sẽ quên mất framework ưa thích, các quy tắc kiến trúc hay tên dự án của người dùng.
RAG dựa trên tài liệu tiêu chuẩn không thể giải quyết triệt để vấn đề này. RAG hướng tới các cơ sở tri thức tĩnh bên ngoài như tài liệu wiki nội bộ hay hướng dẫn sử dụng API. Nó không theo dõi các thay đổi trạng thái hoặc thói quen của người dùng. Khi một lập trình viên nói vào thứ Hai rằng họ thích FastAPI hơn Flask, rồi đến thứ Năm lại yêu cầu một template API chuẩn, RAG thông thường không thể xâu chuỗi hai tương tác này lại với nhau.
Việc nhồi lại toàn bộ lịch sử cuộc trò chuyện vào prompt cũng kém hiệu quả không kém. Nhồi nhét prompt sẽ nhanh chóng làm cạn kiệt ngân sách context. Việc gửi 12.000 token lịch sử thô trong mỗi request sẽ làm tăng độ trễ thêm từ 400ms đến 700ms và đội chi phí API lên đáng kể. Mem0 giải quyết vấn đề này một cách gọn gàng bằng cách trích xuất trực tiếp các dữ kiện dài hạn, xử lý các mâu thuẫn thông tin và cập nhật hồ sơ cô đọng cho từng người dùng. Agent của bạn chỉ cần truy xuất từ 150 đến 300 token context có liên quan khi sinh phản hồi.
Cài đặt
Hãy bắt đầu với một môi trường Python cô lập để tránh xung đột dependency với các thư viện như LangChain, Pydantic hoặc LlamaIndex.
# Tạo và kích hoạt môi trường ảo cô lập
python3 -m venv .venv
source .venv/bin/activate
# Cài đặt thư viện Mem0 cùng với driver Qdrant và OpenAI
pip install mem0ai qdrant-client openai
Mem0 phân chia trách nhiệm qua hai lớp. Một LLM và một embedding model đảm nhận việc trích xuất dữ kiện, trong khi một vector database lập chỉ mục kết quả phục vụ truy xuất ngữ nghĩa (semantic retrieval). Chúng ta sẽ sử dụng gpt-4o-mini của OpenAI để trích xuất, text-embedding-3-small để tạo vector, cùng một instance Qdrant nhúng chạy trực tiếp trên ổ đĩa cục bộ.
Thiết lập API key trong terminal trước khi thực thi script:
export OPENAI_API_KEY="sk-proj-yourActualKeyHere"
Cấu hình
Môi trường production đòi hỏi vector index và các tham số trích xuất rõ ràng thay vì dựa vào các giá trị mặc định ngầm định của thư viện. Dưới đây là cấu hình cục bộ gọn nhẹ giúp lưu trữ vector embedding trực tiếp vào một thư mục cục bộ mà không cần chạy một Docker daemon riêng biệt.
1. Khởi tạo cấu hình bộ nhớ tùy chỉnh
import os
from mem0 import Memory
config = {
"vector_store": {
"provider": "qdrant",
"config": {
"path": "./mem0_storage",
"collection_name": "agent_memory"
}
},
"llm": {
"provider": "openai",
"config": {
"model": "gpt-4o-mini",
"temperature": 0.0
}
},
"embedder": {
"provider": "openai",
"config": {
"model": "text-embedding-3-small"
}
}
}
# Khởi tạo memory manager
memory = Memory.from_config(config)
2. Nạp dữ liệu hội thoại và trích xuất dữ kiện
Truyền các lượt hội thoại hoàn chỉnh trực tiếp vào Mem0. Pipeline của Mem0 sẽ quét cuộc trò chuyện, tách riêng các tùy chọn dài hạn và ghi chúng vào vector store dưới một user_id cố định.
user_id = "usr_dev_4821"
conversation_turn = [
{
"role": "user",
"content": "Tôi đang viết một inventory service bằng Python. Tôi chỉ sử dụng PostgreSQL với SQLAlchemy 2.0 và không dùng raw SQL."
},
{
"role": "assistant",
"content": "Đã hiểu. Tôi sẽ đảm bảo toàn bộ mã cơ sở dữ liệu đều tuân theo các pattern ORM hiện đại của SQLAlchemy 2.0."
}
]
# Nạp lượt hội thoại và trích xuất dữ kiện
result = memory.add(conversation_turn, user_id=user_id)
print(result)
Mem0 trả về các đối tượng có cấu trúc chỉ chứa những thông tin dài hạn được trích xuất từ cuộc hội thoại:
{
"results": [
{
"id": "m0-9b3f4e12",
"memory": "Chỉ sử dụng PostgreSQL với SQLAlchemy 2.0 và tránh dùng raw SQL",
"event": "ADD"
},
{
"id": "m0-5a8c2d91",
"memory": "Đang xây dựng một inventory service bằng Python",
"event": "ADD"
}
]
}
Hãy chú ý sự chuyển đổi này: Mem0 không lưu trữ những câu trò chuyện đệm như lời chào hay lời khẳng định. Nó cô lập thành hai dữ kiện ngắn gọn và lập chỉ mục chúng một cách độc lập.
Kiểm thử & Giám sát
Việc lưu trữ dữ kiện sẽ vô ích nếu agent không thể đưa chúng trở lại prompt scope trong quá trình inference. Bạn cũng cần các quy trình rõ ràng để cập nhật hoặc xóa bỏ các dữ kiện lỗi thời theo thời gian.
1. Truy xuất context trong quá trình inference
Hãy truy vấn Mem0 trước khi chuyển prompt mới của người dùng tới reasoning model. Việc tìm kiếm đối sánh ngữ nghĩa với các bản ghi bộ nhớ đã lưu chỉ mất khoảng 10ms đến 25ms trên ổ đĩa cục bộ.
# Người dùng gửi một prompt ngắn gọn sau đó vài ngày
user_query = "Viết một endpoint để truy vấn tất cả các bản ghi khách hàng đang hoạt động."
# Truy xuất tối đa 3 dữ kiện liên quan cho lập trình viên này
search_hits = memory.search(query=user_query, user_id=user_id, limit=3)
# Định dạng các dữ kiện được trích xuất thành context cho prompt
facts = [hit["memory"] for hit in search_hits.get("results", [])]
memory_context = "\n".join(f"- {fact}" for fact in facts)
system_prompt = f"""Bạn là một principal backend engineer.
User Constraints:
{memory_context}
Hãy viết code chuẩn idiomatic, production-ready và tuân thủ các ràng buộc của người dùng."""
print(system_prompt)
Prompt thu được chỉ cần chèn 48 token context:
Bạn là một principal backend engineer.
User Constraints:
- Chỉ sử dụng PostgreSQL với SQLAlchemy 2.0 và tránh dùng raw SQL
- Đang xây dựng một inventory service bằng Python
Hãy viết code chuẩn idiomatic, production-ready và tuân thủ các ràng buộc của người dùng.
2. Quản lý vòng đời bộ nhớ
Sở thích của người dùng luôn thay đổi. Framework được cập nhật, tech stack chuyển đổi và các quy định tuân thủ pháp lý yêu cầu xóa dữ liệu người dùng. Mem0 cung cấp sẵn các phương thức CRUD để xử lý rõ ràng từng thay đổi trạng thái này.
# Kiểm tra toàn bộ dữ kiện đang hoạt động để audit hoặc debug
user_profile = memory.get_all(user_id=user_id)
for item in user_profile.get("results", []):
print(f"[{item['id']}] {item['memory']}")
# Cập nhật một bản ghi khi người dùng chuyển đổi thư viện
memory.update(
memory_id="m0-9b3f4e12",
data="Đã chuyển từ SQLAlchemy sang SQLModel với AsyncEngine"
)
# Xóa bản ghi theo yêu cầu để tuân thủ Điều 17 của GDPR
memory.delete(memory_id="m0-5a8c2d91")
# Xóa toàn bộ dữ liệu người dùng khi hủy tài khoản
# memory.delete_all(user_id=user_id)
3. Checklist cho môi trường Production
- Thiết lập ranh giới tenant nghiêm ngặt phía server: Luôn lấy
user_idtừ JWT token hoặc session cookie đã được xác thực. Việc chấp nhận định danh người dùng tùy ý từ client payload tiềm ẩn nguy cơ rò rỉ bộ nhớ giữa các tài khoản. - Khóa temperature trích xuất về 0: Đặt temperature thành
0.0cho model trích xuất của bạn. Bạn cần kết quả trích xuất mang tính xác định và đúng sự thật, chứ không phải suy diễn gây ảo giác (hallucination). - Nâng cấp từ bộ lưu trữ nhúng trước khi scale: Bộ lưu trữ đĩa Qdrant nhúng hoạt động tốt cho môi trường chạy thử cục bộ và triển khai trên một container đơn lẻ. Nếu scale theo chiều ngang trên nhiều Kubernetes pod, hãy cấu hình trỏ tới một cluster Qdrant hoặc Milvus độc lập để tránh tranh chấp ghi (write contention).
Việc tách biệt bộ nhớ thích ứng khỏi lịch sử chat thô giúp context window luôn tinh gọn, giảm 60% chi phí inference trở lên, đồng thời mang lại cho assistant khả năng ghi nhớ liền mạch xuyên suốt các phiên làm việc.

