Vì sao tìm kiếm hybrid của AgentKits Memory phải giải quyết tiếng Nhật hai lần
BM25 bỏ lỡ ý nghĩa. Tìm kiếm vector bỏ lỡ chuỗi lỗi chính xác. AgentKits Memory kết hợp cả hai — nhưng với truy vấn tiếng Nhật, tiếng Trung, tiếng Hàn, nửa 'từ khóa' của phép kết hợp đó cần thêm một quyết định nữa bên dưới.
Hai loại truy vấn, hai kiểu thất bại khác nhau
Hỏi bộ nhớ của một trợ lý lập trình AI về “authentication pattern” (mẫu xác thực), bạn muốn nó tìm ra mục ghi “dùng JWT với refresh token” dù không từ nào trong câu hỏi trùng khớp theo nghĩa đen — đây là bài toán về ý nghĩa, và tìm kiếm từ khóa vốn dở ở việc này. Hỏi chính bộ nhớ đó về chuỗi chính xác ModuleNotFoundError: No module named 'networkx', bạn muốn đúng một mục chứa lỗi đó, không phải năm mục “có vẻ liên quan đến Python” — đây là bài toán về tính đồng nhất, và tìm kiếm vector vốn dở ở việc này, vì độ tương đồng embedding làm nhòe các chuỗi chính xác vào một vùng lân cận gồm những văn bản “gần giống”.
AgentKits Memory — lớp bộ nhớ bền vững, local-first cho trợ lý lập trình AI mà chúng tôi đã từng viết — không chọn một trong hai. HybridSearchEngine của nó chạy cả tìm kiếm từ khóa SQLite FTS5 lẫn tìm kiếm vector bằng embedding cục bộ trên mọi truy vấn, rồi kết hợp hai điểm số lại. Đây không phải là một quyết định theo cảm tính — nó khớp với những gì các nghiên cứu về truy xuất thông tin liên tục tìm thấy mỗi khi đo riêng hai cách tiếp cận này. Trên bộ benchmark tìm kiếm thương mại điện tử WANDS, một cấu hình hybrid được tinh chỉnh đạt NDCG 0,7497, so với 0,6983 của riêng BM25 và 0,6953 của riêng tìm kiếm vector — mỗi bên thắng một số truy vấn và thua ở những truy vấn khác, và việc kết hợp cả hai tốt hơn là chọn một bên. (Denser AI)
Cơ chế kết hợp hoạt động thế nào
Cách triển khai là một phép trộn có trọng số đơn giản, không phải hộp đen: mặc định điểm từ khóa nhân 0,3 cộng điểm ngữ nghĩa nhân 0,7, cả hai đều được chuẩn hóa về khoảng 0–1 trước khi cộng lại. Điểm xếp hạng BM25 lấy từ hàm bm25() có sẵn của FTS5; độ tương đồng ngữ nghĩa được tính từ khoảng cách cosine giữa embedding của truy vấn được tạo cục bộ và embedding của các mục đã lưu — không gọi API embedding trên cloud, sử dụng mô hình đa ngôn ngữ multilingual-e5-small dạng ONNX như README đã ghi rõ. Khi chỉ một bên tìm thấy kết quả khớp, mục đó vẫn giữ nguyên điểm số riêng lẻ của mình thay vì bị trừ điểm vì bên còn lại im lặng.
Trọng số mặc định nghiêng 70/30 về phía ngữ nghĩa thể hiện một cược thực sự: vì phần lớn các mục trong hệ thống bộ nhớ này là văn xuôi — quyết định, tóm tắt — chứ không phải mã sản phẩm, nên ý nghĩa thường quan trọng hơn cách diễn đạt chính xác — nhưng ngưỡng sàn 30% dành cho từ khóa chính là thứ ngăn một chuỗi lỗi hay tên hàm chính xác bị lạc mất trong không gian embedding, đúng là kiểu thất bại đã được ghi nhận ở tìm kiếm chỉ dựa trên vector.
Vấn đề CJK ẩn bên trong “từ khóa”
Đây là phần không nằm trong những lời khuyên RAG chung chung: “tìm kiếm từ khóa” giả định rằng bạn có thể xác định một từ kết thúc ở đâu và từ tiếp theo bắt đầu từ đâu, còn văn bản tiếng Nhật, tiếng Trung, tiếng Hàn thì không cho bạn điều đó một cách miễn phí — giữa các từ không có khoảng trắng. Tokenizer chuẩn unicode61 của FTS5, được xây dựng dựa trên ranh giới từ, đơn giản là không thể phân đoạn văn bản CJK thành thứ gì có thể tìm kiếm được. Câu trả lời của AgentKits Memory là mặc định dùng tokenizer trigram của FTS5, đánh chỉ mục theo các chuỗi 3 ký tự chồng lấp nhau thay vì theo từ — một chiến lược được thiết kế riêng cho trường hợp bạn không thể xác định đáng tin cậy ranh giới từ ngay từ đầu.
Lựa chọn mặc định đó không phải là không có đánh đổi, và mã nguồn cũng không giấu điều này. Việc đánh chỉ mục theo n-gram ký tự cho tiếng Nhật được tài liệu về truy xuất thông tin ghi nhận là dễ sinh ra “kết quả giả” — những từ không liên quan tình cờ chia sẻ chung một n-gram và bị khớp nhầm — trong khi lựa chọn thay thế, phân đoạn từ đúng nghĩa bằng phân tích hình thái học, lại mang một vấn đề ngược lại: từ điển của bộ phân đoạn luôn không đầy đủ, nên nó âm thầm bỏ sót bất cứ điều gì nó chưa từng học. (Tài liệu Whoosh về đánh chỉ mục n-gram; các khảo sát chung về tokenize tiếng Nhật cũng chỉ ra rõ đánh đổi này theo cả hai chiều.) HybridSearchEngine của AgentKits Memory viết mã để xử lý việc này thay vì chọn mù quáng một bên: nó thương lượng tokenizer tốt nhất mà bản dựng SQLite cục bộ thực sự hỗ trợ (trigram, rồi đến porter, rồi đến unicode61, được kiểm tra trực tiếp lúc khởi tạo), và với truy vấn CJK ngắn hơn 3 ký tự — quá ngắn để tạo thành một trigram — nó chuyển sang quét LIKE đơn giản thay vì trả về rỗng. Với những đội muốn phân đoạn từ tiếng Nhật thực sự thay vì thỏa hiệp bằng n-gram, gói phần mềm này cung cấp backend lindera-sqlite tùy chọn như một hướng nâng cấp rõ ràng, thay vì áp đặt sự đánh đổi đó lên tất cả mọi người theo mặc định.
Phần tiết kiệm phải được bảo vệ, không chỉ giành được rồi thôi
Chạy hai công cụ tìm kiếm và dung hòa hai chiến lược tokenizer sẽ là công sức kỹ thuật lãng phí nếu kết quả bị đổ thẳng toàn văn vào cửa sổ ngữ cảnh của mô hình. Đó chính là lý do tồn tại của TokenEconomicsTracker đi kèm và thiết kế 3 lớp của công cụ tìm kiếm (compact → timeline → full): lớp một chỉ trả về khoảng 50 token cho mỗi kết quả — id, phân tích điểm số, đoạn trích 100 ký tự, số token ước tính — để trợ lý có thể xem qua mười ứng viên với chi phí bằng một lần lấy toàn văn một mục, trước khi quyết định mục nào đáng lấy đầy đủ. README ghi nhận mẫu hình tiết lộ dần (progressive disclosure) này tiết kiệm khoảng 70% token so với việc lấy mọi thứ ngay từ đầu, và ở một số cấu hình còn được ghi nhận lên tới 87%. Dù con số nào, điểm mấu chốt vẫn vậy: việc kết hợp hai tín hiệu truy xuất chỉ thực sự đáng giá nếu lớp nằm phía trên nó không lập tức tiêu hết phần tiết kiệm đó.
Nói thẳng ra
Không có điều nào ở trên khiến tìm kiếm của AgentKits Memory trở thành “đã giải quyết xong” theo nghĩa cuối cùng nào cả — tokenize bằng trigram là một sự thỏa hiệp đã được lựa chọn và ghi nhận rõ ràng như vậy, chứ không phải là tuyên bố nó ngang bằng một bộ phân tích hình thái học đúng nghĩa. Điều được thể hiện ở đây là một kiểu kỷ luật thiết kế cụ thể: một công cụ tìm kiếm hybrid kết hợp điểm từ khóa và điểm ngữ nghĩa đã là kiến trúc RAG cơ bản, ai cũng làm, vào năm 2026 — nhưng việc thừa nhận rằng “từ khóa” không phải là một thao tác được định nghĩa giống hệt nhau giữa tiếng Anh và văn bản CJK, và xây dựng hẳn một chuỗi dự phòng tường minh thay vì mặc định rằng unicode61 phù hợp với tất cả mọi người — đó là phần chỉ lộ ra khi bạn thực sự cố làm cho tìm kiếm hoạt động được với một truy vấn viết bằng tiếng Nhật.
AgentKits Memory có sẵn trên GitHub và trên npm với tên gói @aitytech/agentkits-memory. Có câu hỏi về cách nó phù hợp với quy trình làm việc của bạn? Liên hệ tại [email protected].
Khám phá mã nguồn mở
Chúng tôi xây dựng và duy trì các công cụ mã nguồn mở cho nhà phát triển. Xem trên GitHub.
Xem trên GitHubBài viết liên quan
Hầu Hết Công Cụ Hiện Đại Hóa COBOL Chỉ Dừng Lại Ở Chương Trình. Nơi Các Dự Án Di Trú Thực Sự Đổ Vỡ Là Job Batch Gọi Nó.
Các công cụ ánh xạ phụ thuộc xoay quanh COBOL thường coi JCL chỉ là một lớp bọc mỏng — một tên job và vài câu lệnh DD. Nhưng phân nhánh theo mã điều kiện, PROC lồng nhau, và các thế hệ GDG mang theo luồng điều khiển thực sự của riêng chúng, và điều này thường xuyên bị bỏ sót khỏi đồ thị phụ thuộc. Vì sao Legacy Dragon phân tích cú pháp JCL như một ngôn ngữ hạng nhất trong cùng một AST, chứ không phải như siêu dữ liệu gắn thêm sau này.
Hướng dẫn322 Giọng Nói, 142 Ngôn Ngữ, Không Máy Chủ: Để Nhét Được Từng Đó Giọng Nói Vào Một Tab Trình Duyệt
Công cụ chuyển văn bản thành giọng nói của PrivateAI phủ hơn 322 giọng trên 142 ngôn ngữ, chạy hoàn toàn trên thiết bị. Tại sao độ phủ giọng nói và ngôn ngữ — chứ không phải tốc độ — mới là bài toán khó thực sự với TTS chạy trong trình duyệt, và con số này so với các lựa chọn mã nguồn mở và trả phí ra sao.
Hướng dẫnAgentKits Marketing có 28 kỹ năng. Nhưng không bao giờ nạp quá 5 kỹ năng cùng lúc
File skills-registry.json của Marketing Kit phân loại 28 kỹ năng vào 5 danh mục, kèm một sơ đồ phụ thuộc đầy đủ. Tài liệu nghiên cứu nội bộ của dự án nêu thẳng lý do phải giới hạn số lượng nạp cùng lúc: 'context rot' (suy thoái do ngữ cảnh quá tải). Đây là cách bộ chọn kỹ năng thực tế vận hành, và vì sao nó đơn giản hơn nhiều so với đề xuất nghiên cứu ban đầu.