Skip to content

Từ Grep Đến Semantic Search: Cách OpenClaw Xây Dựng Memory Cho AI Agent

Karify98 & Amy 🌸·
Cover Image for Từ Grep Đến Semantic Search: Cách OpenClaw Xây Dựng Memory Cho AI Agent

Tuần trước mình update OpenClaw lên version mới. Mọi thứ chạy bình thường — cho đến khi thử memory_search. Lỗi. Thiếu API token cho embedding model.

Mò vào config mới hiểu: versions cũ dùng grep đơn giản, version mới chuyển sang vector embedding và cần API key. Thay vì chỉ thêm token rồi bỏ qua, mình đọc source để hiểu tại sao.

Câu trả lời: grep chỉ tìm được thứ nó biết chính xác nằm ở đâu.

Vấn Đề: Grep Là Lookup Sai Cách

Cách tiếp cận cũ đơn giản: agent gọi read() trên từng file, quét nội dung, tìm thông tin liên quan. Đây là linear scan — mỗi file đọc đầy đủ từ đầu đến cuối.

Vấn đề không phải tốc độ. Vấn đề là agent cần biết trước thông tin nằm ở file nào — và không có cơ chế nào để biết điều đó.

# Agent cần tìm: "AWS instance ID"
read("MEMORY.md")             # Có thể có, có thể không
read("memory/2026-05-14.md")  # Có thể có thông tin về AWS migration
read("memory/2026-05-28.md")  # Có thông tin SSH tunnel
...                           # Hàng chục file daily notes

Không có indexing, agent phải thử từng file — hoặc dùng grep, nhưng kết quả vẫn là exact text match. Khi search "AWS setup", grep không hiểu "EC2 instance ở Singapore" cũng liên quan.

Kiến Trúc: Hybrid Retrieval Pipeline

Thay vì đọc file theo yêu cầu, toàn bộ memory được index trước và search khi cần.

graph TD
    A[Memory Files] --> B[Chunking]
    B --> C[Embedding]
    C --> D[(SQLite + sqlite-vec)]
    Q[Query] --> V[Vector Search 70%]
    Q --> K[BM25 Search 30%]
    D --> V
    D --> K
    V --> H[Hybrid Scoring]
    K --> H
    H --> R[Top-K to Agent Context]

Chunking: Tại Sao Overlap?

Mỗi file memory được chia thành chunks ~400 tokens. Các chunk overlap nhau 80 tokens — vì ý nghĩa thường nằm ở ranh giới giữa hai đoạn liền nhau. Cắt cứng không có overlap sẽ làm một số chunk mất ngữ cảnh và khó khớp đúng khi tìm kiếm.

Embedding: Biến Text Thành Tọa Độ

Embedding model nhận text và trả về một array số thực — "dấu vân tay" số học của ý nghĩa. Text có ý nghĩa tương tự cho ra arrays gần nhau trong không gian đó.

Đây là lý do "EC2 instance ở Singapore" có thể khớp với query "AWS setup". Hai cụm từ không có từ chung — nhưng embedding model hiểu chúng liên quan.

OpenClaw hỗ trợ nhiều providers, tự động chọn theo config:

Provider Tốc độ Chi phí Chất lượng
Local (GGUF / node-llama-cpp) ~50 tok/s Miễn phí Thấp
OpenAI (text-embedding-3-small) ~1000 tok/s $0.02/1M tokens ($0.01 qua Batch API) Cao
Gemini / Voyage ~800 tok/s Tùy gói dịch vụ, fallback chain Cao
BM25 only - Miễn phí Chỉ từ khóa

Hiện đang dùng embeddinggemma — model GGUF chạy local qua node-llama-cpp. Không cần GPU, không cần API key.

Lưu Trữ: SQLite Per Agent

Vectors được lưu trong SQLite với extension sqlite-vec, tại ~/.openclaw/memory/<agentId>.sqlite. Mỗi agent có database riêng — không chia sẻ index, không cần server.

SHA-256 cache đảm bảo OpenClaw không re-embed chunk đã được index. Chỉ khi nội dung file thực sự thay đổi, chunk mới được tính lại.

Hybrid Search: Kết Hợp Hai Nhánh

Khi agent gọi memory_search("AWS setup"), pipeline chạy song song hai nhánh:

finalScore = 0.7 × vectorScore + 0.3 × bm25Score

Vector search (70%) tìm theo nghĩa — khớp kể cả khi dùng từ khác. BM25 search (30%) tìm theo từ khóa — khớp chính xác. Top-K chunks được đưa vào context trước khi gọi LLM. Toàn bộ pipeline mất dưới 100ms.

Tại Sao Hybrid, Không Phải Pure Vector?

Nhiều hệ thống chỉ dùng vector search. OpenClaw chọn hybrid vì một lý do thực tế: vector search yếu ở exact match.

Khi search "PR #17", vector embedding không hiểu đây là identifier cụ thể. Nó khớp với các chunk nói về "pull request" nói chung — không hữu ích khi cần chính xác PR #17.

BM25 xử lý exact match tốt — tính term frequency, inverse document frequency, trả về đúng chunks chứa "PR #17". Ngược lại, BM25 mù với paraphrase: "AWS infrastructure" và "cloud setup trên Amazon" có zero keyword overlap, nhưng vector search hiểu chúng liên quan.

Hybrid lấy điểm mạnh của cả hai.

Hai Tối Ưu Quan Trọng

Hybrid search giải quyết lookup problem. Nhưng còn hai vấn đề nhỏ hơn phát sinh trong thực tế.

Vấn đề 1: Top kết quả thường trùng nhau. Khi memory có nhiều chunk về "AWS EC2 setup", top-3 có thể là cùng thông tin viết lại ba lần. Agent nhận context thừa, không đa dạng.

Vấn đề 2: Memory cũ ít liên quan hơn memory mới. Note từ 3 tháng trước thường ít hữu ích hơn note hôm qua.

Temporal Decay

Giảm điểm của chunks từ files cũ theo công thức:

decayFactor = Math.pow(0.5, daysSinceCreation / halfLifeDays)
// halfLifeDays = 30 (mặc định)
// Note hôm nay: decay = 1.0
// Note 30 ngày trước: decay = 0.5
// Note 60 ngày trước: decay = 0.25

MEMORY.md — long-term memory — không bị suy giảm vì nó không lỗi thời như daily notes.

MMR (Maximal Marginal Relevance)

Thay vì chọn top-K theo score thuần, MMR cân bằng giữa độ liên quan và tính đa dạng:

Without MMR:
1. "AWS EC2 setup" (0.95)
2. "AWS EC2 configuration" (0.94)  // gần như trùng
3. "AWS EC2 instance" (0.93)       // gần như trùng

With MMR (λ=0.7):
1. "AWS EC2 setup" (0.95)
2. "AWS Lambda config" (0.82)      // chủ đề khác
3. "AWS S3 bucket" (0.78)          // chủ đề khác

Agent nhận context đa dạng hơn, bao phủ nhiều góc độ hơn với cùng token budget.

Bài Học Rút Ra

Thiếu API key là lý do mình bắt đầu debug. Hiểu được toàn bộ pipeline mới là thứ đáng giá.

Lookup problem khác speed problem. Ban đầu mình nghĩ grep chậm vì phải đọc nhiều file. Thực ra vấn đề không phải tốc độ — agent không có cơ chế để biết cần tìm ở đâu. Indexing giải quyết lookup, không giải quyết tốc độ.

Hybrid luôn tốt hơn pure trong thực tế. Pure vector search bỏ sót exact match như "PR #17" hay instance ID. Pure BM25 bỏ sót paraphrase. Hệ thống memory thực dụng cần cả hai — không phải chọn một.

Đơn giản là một quyết định kỹ thuật. SQLite thay vì dedicated vector database. Một file cho mỗi agent thay vì distributed cluster. SHA-256 cache thay vì real-time sync. Không phải vì thiếu năng lực — mà vì đủ dùng và dễ debug khi có sự cố.


Bài viết được hỗ trợ bởi Amy 🌸 - AI Assistant. Nội dung đã được kiểm duyệt bởi tác giả.

Related Posts