Long-term Memory - Cấy ghép "Hồi hải mã" cho Jarvis

AI Hunter

Member
Bộ não con người có 2 loại trí nhớ:
  • Short-term Memory (RAM): Nhớ những gì vừa nói trong cuộc hội thoại hiện tại. Tắt đi là quên.
  • Long-term Memory (Ổ cứng): Nhớ tên, tuổi, sở thích, thói quen của bạn mãi mãi.

Jarvis hiện tại chỉ có RAM. Hôm nay chúng ta sẽ lắp thêm ổ cứng cho nó bằng cách tận dụng Qdrant.

Long-term Memory - Cấy ghép Hồi hải mã cho Jarvis.jpg

1. Nguyên lý hoạt động​


Chúng ta sẽ tạo ra một quy trình "Ghi nhớ ngầm" (Background Memory Process):

  1. Khi bạn chat, Jarvis sẽ âm thầm phân tích: "Trong câu nói này có thông tin gì về người dùng không?"
  2. Nếu có (ví dụ: "Tao thích màu đỏ"), nó sẽ trích xuất thông tin đó.
  3. Mã hóa thông tin thành Vector và lưu vào Qdrant (Collection: user_memory).
  4. Lần sau khi bạn chat, Jarvis sẽ lục lại ký ức này và đưa vào ngữ cảnh (Context) để trả lời.

2. Cập nhật Backend (FastAPI)​


Mở file backend/server.py. Chúng ta cần thêm logic xử lý ký ức.

Bước 1: Thêm thư viện và Cấu hình

Python:
# Thêm import
from langchain_core.documents import Document

# ... (Các code cũ giữ nguyên)

# 1. Tạo Collection riêng cho Ký ức
MEMORY_COLLECTION = "user_memory"

# Hàm khởi tạo Memory Store (chạy 1 lần khi start app)
def init_memory():
    # Kiểm tra xem collection đã tồn tại chưa, nếu chưa thì tạo (logic này thường Qdrant tự lo)
    pass

# Khởi tạo Vector Store cho Memory
memory_store = QdrantVectorStore(
    client=client,
    collection_name=MEMORY_COLLECTION,
    embedding=embeddings,
)

Bước 2: Hàm trích xuất và lưu ký ức
Đây là phần "thông minh" nhất. Chúng ta dùng chính LLM để đọc tin nhắn của bạn và chắt lọc thông tin.

Python:
def save_memory_background(user_message: str):
    print("🧠 Đang phân tích ký ức...")
   
    # Prompt để yêu cầu AI trích xuất thông tin
    extraction_prompt = f"""
    Bạn là một chuyên gia ghi nhớ. Hãy phân tích câu nói sau của người dùng.
    Nếu có thông tin về sở thích, thói quen, tên tuổi, hoặc sự kiện quan trọng của họ, hãy trích xuất nó thành một câu khẳng định ngắn gọn.
    Nếu không có thông tin gì đáng nhớ (ví dụ: câu chào hỏi, câu hỏi bâng quơ), hãy trả về "NONE".
   
    Câu nói: "{user_message}"
    Thông tin trích xuất:
    """
   
    try:
        # Gọi LLM để trích xuất
        response = chat_client.chat.completions.create(
            model="llama3.1",
            messages=[{"role": "user", "content": extraction_prompt}]
        )
        fact = response.choices[0].message.content.strip()
       
        # Nếu có thông tin giá trị
        if fact != "NONE" and len(fact) > 5:
            print(f"💾 Đã lưu ký ức: {fact}")
            memory_store.add_documents([Document(page_content=fact)])
           
    except Exception as e:
        print(f"Lỗi lưu ký ức: {e}")

Bước 3: Cập nhật API Chat
Sửa lại endpoint /chat để nó biết dùng ký ức.

Python:
@app.post("/chat", dependencies=[Depends(verify_token)])
async def chat_endpoint(req: ChatRequest, background_tasks: BackgroundTasks):
    # 1. Lục lọi ký ức liên quan đến câu hỏi hiện tại
    memories = memory_store.similarity_search(req.message, k=3)
    memory_context = "\n".join([f"- {m.page_content}" for m in memories])
   
    if not memory_context:
        memory_context = "Chưa có thông tin gì về người dùng."

    print(f"🧐 Ký ức liên quan: {memory_context}")

    # 2. Tạo System Prompt có kèm ký ức
    system_prompt = f"""
    Bạn là Jarvis, trợ lý AI trung thành.
   
    [KÝ ỨC VỀ NGƯỜI DÙNG]:
    {memory_context}
   
    Hãy dùng thông tin trên để trả lời người dùng một cách thân thiện và cá nhân hóa.
    """

    # 3. Gọi LLM trả lời
    response = chat_client.chat.completions.create(
        model="llama3.1",
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": req.message}
        ]
    )
   
    # 4. Kích hoạt việc học ký ức mới (chạy ngầm để không làm chậm chat)
    background_tasks.add_task(save_memory_background, req.message)

    return {"answer": response.choices[0].message.content}

3. Chạy thử nghiệm​


Sau khi cập nhật code, hãy khởi động lại Docker:
Mã:
docker-compose up --build -d

Bây giờ hãy thử "dạy" Jarvis:

  1. Bước 1 (Dạy): Chat với Jarvis: "Tao tên là Huy và tao bị dị ứng với tôm."
    Jarvis sẽ trả lời bình thường. Nhưng ở backend, nó đã âm thầm lưu: "Người dùng tên Huy, dị ứng tôm".
  2. Bước 2 (Kiểm tra): Tắt trình duyệt, xóa lịch sử chat (F5). Coi như bắt đầu phiên mới.
  3. Bước 3 (Hỏi): Chat: "Trưa nay tao nên ăn gì?"

Kết quả mong đợi:
Jarvis sẽ trả lời đại loại như:
"Chào sếp Huy! Trưa nay sếp có thể ăn phở bò hoặc cơm gà. Nhớ tránh các món hải sản có tôm ra nhé vì sếp bị dị ứng đấy!"

Tổng kết​


Chúc mừng! Bạn đã vừa ban cho Jarvis một "linh hồn". Nó không còn là một cái máy chat vô tri nữa, mà là một người bạn biết quan tâm và ghi nhớ.

Hệ thống của chúng ta giờ đã rất đồ sộ:
  • Giác quan: Mắt (Vision), Tai (Mic), Miệng (Speaker).
  • Tay chân: Smart Home, Telegram.
  • Trí tuệ: RAG (Kiến thức sách vở) + Memory (Kiến thức về bạn).
  • Hạ tầng: Docker, Local LLM.

Dự án Jarvis cơ bản đã hoàn thiện về mặt tính năng Core.
 
Back
Top